...

Source file src/pkg/cmd/compile/internal/s390x/ssa.go

     1	// Copyright 2016 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package s390x
     6	
     7	import (
     8		"math"
     9	
    10		"cmd/compile/internal/gc"
    11		"cmd/compile/internal/ssa"
    12		"cmd/compile/internal/types"
    13		"cmd/internal/obj"
    14		"cmd/internal/obj/s390x"
    15	)
    16	
    17	// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
    18	func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
    19		flive := b.FlagsLiveAtEnd
    20		if b.Control != nil && b.Control.Type.IsFlags() {
    21			flive = true
    22		}
    23		for i := len(b.Values) - 1; i >= 0; i-- {
    24			v := b.Values[i]
    25			if flive && v.Op == ssa.OpS390XMOVDconst {
    26				// The "mark" is any non-nil Aux value.
    27				v.Aux = v
    28			}
    29			if v.Type.IsFlags() {
    30				flive = false
    31			}
    32			for _, a := range v.Args {
    33				if a.Type.IsFlags() {
    34					flive = true
    35				}
    36			}
    37		}
    38	}
    39	
    40	// loadByType returns the load instruction of the given type.
    41	func loadByType(t *types.Type) obj.As {
    42		if t.IsFloat() {
    43			switch t.Size() {
    44			case 4:
    45				return s390x.AFMOVS
    46			case 8:
    47				return s390x.AFMOVD
    48			}
    49		} else {
    50			switch t.Size() {
    51			case 1:
    52				if t.IsSigned() {
    53					return s390x.AMOVB
    54				} else {
    55					return s390x.AMOVBZ
    56				}
    57			case 2:
    58				if t.IsSigned() {
    59					return s390x.AMOVH
    60				} else {
    61					return s390x.AMOVHZ
    62				}
    63			case 4:
    64				if t.IsSigned() {
    65					return s390x.AMOVW
    66				} else {
    67					return s390x.AMOVWZ
    68				}
    69			case 8:
    70				return s390x.AMOVD
    71			}
    72		}
    73		panic("bad load type")
    74	}
    75	
    76	// storeByType returns the store instruction of the given type.
    77	func storeByType(t *types.Type) obj.As {
    78		width := t.Size()
    79		if t.IsFloat() {
    80			switch width {
    81			case 4:
    82				return s390x.AFMOVS
    83			case 8:
    84				return s390x.AFMOVD
    85			}
    86		} else {
    87			switch width {
    88			case 1:
    89				return s390x.AMOVB
    90			case 2:
    91				return s390x.AMOVH
    92			case 4:
    93				return s390x.AMOVW
    94			case 8:
    95				return s390x.AMOVD
    96			}
    97		}
    98		panic("bad store type")
    99	}
   100	
   101	// moveByType returns the reg->reg move instruction of the given type.
   102	func moveByType(t *types.Type) obj.As {
   103		if t.IsFloat() {
   104			return s390x.AFMOVD
   105		} else {
   106			switch t.Size() {
   107			case 1:
   108				if t.IsSigned() {
   109					return s390x.AMOVB
   110				} else {
   111					return s390x.AMOVBZ
   112				}
   113			case 2:
   114				if t.IsSigned() {
   115					return s390x.AMOVH
   116				} else {
   117					return s390x.AMOVHZ
   118				}
   119			case 4:
   120				if t.IsSigned() {
   121					return s390x.AMOVW
   122				} else {
   123					return s390x.AMOVWZ
   124				}
   125			case 8:
   126				return s390x.AMOVD
   127			}
   128		}
   129		panic("bad load type")
   130	}
   131	
   132	// opregreg emits instructions for
   133	//     dest := dest(To) op src(From)
   134	// and also returns the created obj.Prog so it
   135	// may be further adjusted (offset, scale, etc).
   136	func opregreg(s *gc.SSAGenState, op obj.As, dest, src int16) *obj.Prog {
   137		p := s.Prog(op)
   138		p.From.Type = obj.TYPE_REG
   139		p.To.Type = obj.TYPE_REG
   140		p.To.Reg = dest
   141		p.From.Reg = src
   142		return p
   143	}
   144	
   145	// opregregimm emits instructions for
   146	//	dest := src(From) op off
   147	// and also returns the created obj.Prog so it
   148	// may be further adjusted (offset, scale, etc).
   149	func opregregimm(s *gc.SSAGenState, op obj.As, dest, src int16, off int64) *obj.Prog {
   150		p := s.Prog(op)
   151		p.From.Type = obj.TYPE_CONST
   152		p.From.Offset = off
   153		p.Reg = src
   154		p.To.Reg = dest
   155		p.To.Type = obj.TYPE_REG
   156		return p
   157	}
   158	
   159	func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
   160		switch v.Op {
   161		case ssa.OpS390XSLD, ssa.OpS390XSLW,
   162			ssa.OpS390XSRD, ssa.OpS390XSRW,
   163			ssa.OpS390XSRAD, ssa.OpS390XSRAW,
   164			ssa.OpS390XRLLG, ssa.OpS390XRLL:
   165			r := v.Reg()
   166			r1 := v.Args[0].Reg()
   167			r2 := v.Args[1].Reg()
   168			if r2 == s390x.REG_R0 {
   169				v.Fatalf("cannot use R0 as shift value %s", v.LongString())
   170			}
   171			p := opregreg(s, v.Op.Asm(), r, r2)
   172			if r != r1 {
   173				p.Reg = r1
   174			}
   175		case ssa.OpS390XADD, ssa.OpS390XADDW,
   176			ssa.OpS390XSUB, ssa.OpS390XSUBW,
   177			ssa.OpS390XAND, ssa.OpS390XANDW,
   178			ssa.OpS390XOR, ssa.OpS390XORW,
   179			ssa.OpS390XXOR, ssa.OpS390XXORW:
   180			r := v.Reg()
   181			r1 := v.Args[0].Reg()
   182			r2 := v.Args[1].Reg()
   183			p := opregreg(s, v.Op.Asm(), r, r2)
   184			if r != r1 {
   185				p.Reg = r1
   186			}
   187		case ssa.OpS390XADDC:
   188			r1 := v.Reg0()
   189			r2 := v.Args[0].Reg()
   190			r3 := v.Args[1].Reg()
   191			if r1 == r2 {
   192				r2, r3 = r3, r2
   193			}
   194			p := opregreg(s, v.Op.Asm(), r1, r2)
   195			if r3 != r1 {
   196				p.Reg = r3
   197			}
   198		case ssa.OpS390XSUBC:
   199			r1 := v.Reg0()
   200			r2 := v.Args[0].Reg()
   201			r3 := v.Args[1].Reg()
   202			p := opregreg(s, v.Op.Asm(), r1, r3)
   203			if r1 != r2 {
   204				p.Reg = r2
   205			}
   206		case ssa.OpS390XADDE, ssa.OpS390XSUBE:
   207			r1 := v.Reg0()
   208			if r1 != v.Args[0].Reg() {
   209				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   210			}
   211			r2 := v.Args[1].Reg()
   212			opregreg(s, v.Op.Asm(), r1, r2)
   213		case ssa.OpS390XADDCconst:
   214			r1 := v.Reg0()
   215			r3 := v.Args[0].Reg()
   216			i2 := int64(int16(v.AuxInt))
   217			opregregimm(s, v.Op.Asm(), r1, r3, i2)
   218		// 2-address opcode arithmetic
   219		case ssa.OpS390XMULLD, ssa.OpS390XMULLW,
   220			ssa.OpS390XMULHD, ssa.OpS390XMULHDU,
   221			ssa.OpS390XFADDS, ssa.OpS390XFADD, ssa.OpS390XFSUBS, ssa.OpS390XFSUB,
   222			ssa.OpS390XFMULS, ssa.OpS390XFMUL, ssa.OpS390XFDIVS, ssa.OpS390XFDIV:
   223			r := v.Reg()
   224			if r != v.Args[0].Reg() {
   225				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   226			}
   227			opregreg(s, v.Op.Asm(), r, v.Args[1].Reg())
   228		case ssa.OpS390XFMADD, ssa.OpS390XFMADDS,
   229			ssa.OpS390XFMSUB, ssa.OpS390XFMSUBS:
   230			r := v.Reg()
   231			if r != v.Args[0].Reg() {
   232				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   233			}
   234			r1 := v.Args[1].Reg()
   235			r2 := v.Args[2].Reg()
   236			p := s.Prog(v.Op.Asm())
   237			p.From.Type = obj.TYPE_REG
   238			p.From.Reg = r1
   239			p.Reg = r2
   240			p.To.Type = obj.TYPE_REG
   241			p.To.Reg = r
   242		case ssa.OpS390XFIDBR:
   243			switch v.AuxInt {
   244			case 0, 1, 3, 4, 5, 6, 7:
   245				opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt)
   246			default:
   247				v.Fatalf("invalid FIDBR mask: %v", v.AuxInt)
   248			}
   249		case ssa.OpS390XCPSDR:
   250			p := opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg())
   251			p.Reg = v.Args[0].Reg()
   252		case ssa.OpS390XDIVD, ssa.OpS390XDIVW,
   253			ssa.OpS390XDIVDU, ssa.OpS390XDIVWU,
   254			ssa.OpS390XMODD, ssa.OpS390XMODW,
   255			ssa.OpS390XMODDU, ssa.OpS390XMODWU:
   256	
   257			// TODO(mundaym): use the temp registers every time like x86 does with AX?
   258			dividend := v.Args[0].Reg()
   259			divisor := v.Args[1].Reg()
   260	
   261			// CPU faults upon signed overflow, which occurs when most
   262			// negative int is divided by -1.
   263			var j *obj.Prog
   264			if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW ||
   265				v.Op == ssa.OpS390XMODD || v.Op == ssa.OpS390XMODW {
   266	
   267				var c *obj.Prog
   268				c = s.Prog(s390x.ACMP)
   269				j = s.Prog(s390x.ABEQ)
   270	
   271				c.From.Type = obj.TYPE_REG
   272				c.From.Reg = divisor
   273				c.To.Type = obj.TYPE_CONST
   274				c.To.Offset = -1
   275	
   276				j.To.Type = obj.TYPE_BRANCH
   277	
   278			}
   279	
   280			p := s.Prog(v.Op.Asm())
   281			p.From.Type = obj.TYPE_REG
   282			p.From.Reg = divisor
   283			p.Reg = 0
   284			p.To.Type = obj.TYPE_REG
   285			p.To.Reg = dividend
   286	
   287			// signed division, rest of the check for -1 case
   288			if j != nil {
   289				j2 := s.Prog(s390x.ABR)
   290				j2.To.Type = obj.TYPE_BRANCH
   291	
   292				var n *obj.Prog
   293				if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW {
   294					// n * -1 = -n
   295					n = s.Prog(s390x.ANEG)
   296					n.To.Type = obj.TYPE_REG
   297					n.To.Reg = dividend
   298				} else {
   299					// n % -1 == 0
   300					n = s.Prog(s390x.AXOR)
   301					n.From.Type = obj.TYPE_REG
   302					n.From.Reg = dividend
   303					n.To.Type = obj.TYPE_REG
   304					n.To.Reg = dividend
   305				}
   306	
   307				j.To.Val = n
   308				j2.To.Val = s.Pc()
   309			}
   310		case ssa.OpS390XADDconst, ssa.OpS390XADDWconst:
   311			opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt)
   312		case ssa.OpS390XMULLDconst, ssa.OpS390XMULLWconst,
   313			ssa.OpS390XSUBconst, ssa.OpS390XSUBWconst,
   314			ssa.OpS390XANDconst, ssa.OpS390XANDWconst,
   315			ssa.OpS390XORconst, ssa.OpS390XORWconst,
   316			ssa.OpS390XXORconst, ssa.OpS390XXORWconst:
   317			r := v.Reg()
   318			if r != v.Args[0].Reg() {
   319				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   320			}
   321			p := s.Prog(v.Op.Asm())
   322			p.From.Type = obj.TYPE_CONST
   323			p.From.Offset = v.AuxInt
   324			p.To.Type = obj.TYPE_REG
   325			p.To.Reg = r
   326		case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst,
   327			ssa.OpS390XSRDconst, ssa.OpS390XSRWconst,
   328			ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst,
   329			ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst:
   330			p := s.Prog(v.Op.Asm())
   331			p.From.Type = obj.TYPE_CONST
   332			p.From.Offset = v.AuxInt
   333			r := v.Reg()
   334			r1 := v.Args[0].Reg()
   335			if r != r1 {
   336				p.Reg = r1
   337			}
   338			p.To.Type = obj.TYPE_REG
   339			p.To.Reg = r
   340		case ssa.OpS390XMOVDaddridx:
   341			r := v.Args[0].Reg()
   342			i := v.Args[1].Reg()
   343			p := s.Prog(s390x.AMOVD)
   344			p.From.Scale = 1
   345			if i == s390x.REGSP {
   346				r, i = i, r
   347			}
   348			p.From.Type = obj.TYPE_ADDR
   349			p.From.Reg = r
   350			p.From.Index = i
   351			gc.AddAux(&p.From, v)
   352			p.To.Type = obj.TYPE_REG
   353			p.To.Reg = v.Reg()
   354		case ssa.OpS390XMOVDaddr:
   355			p := s.Prog(s390x.AMOVD)
   356			p.From.Type = obj.TYPE_ADDR
   357			p.From.Reg = v.Args[0].Reg()
   358			gc.AddAux(&p.From, v)
   359			p.To.Type = obj.TYPE_REG
   360			p.To.Reg = v.Reg()
   361		case ssa.OpS390XCMP, ssa.OpS390XCMPW, ssa.OpS390XCMPU, ssa.OpS390XCMPWU:
   362			opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
   363		case ssa.OpS390XFCMPS, ssa.OpS390XFCMP:
   364			opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
   365		case ssa.OpS390XCMPconst, ssa.OpS390XCMPWconst:
   366			p := s.Prog(v.Op.Asm())
   367			p.From.Type = obj.TYPE_REG
   368			p.From.Reg = v.Args[0].Reg()
   369			p.To.Type = obj.TYPE_CONST
   370			p.To.Offset = v.AuxInt
   371		case ssa.OpS390XCMPUconst, ssa.OpS390XCMPWUconst:
   372			p := s.Prog(v.Op.Asm())
   373			p.From.Type = obj.TYPE_REG
   374			p.From.Reg = v.Args[0].Reg()
   375			p.To.Type = obj.TYPE_CONST
   376			p.To.Offset = int64(uint32(v.AuxInt))
   377		case ssa.OpS390XMOVDconst:
   378			x := v.Reg()
   379			p := s.Prog(v.Op.Asm())
   380			p.From.Type = obj.TYPE_CONST
   381			p.From.Offset = v.AuxInt
   382			p.To.Type = obj.TYPE_REG
   383			p.To.Reg = x
   384		case ssa.OpS390XFMOVSconst, ssa.OpS390XFMOVDconst:
   385			x := v.Reg()
   386			p := s.Prog(v.Op.Asm())
   387			p.From.Type = obj.TYPE_FCONST
   388			p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   389			p.To.Type = obj.TYPE_REG
   390			p.To.Reg = x
   391		case ssa.OpS390XADDWload, ssa.OpS390XADDload,
   392			ssa.OpS390XMULLWload, ssa.OpS390XMULLDload,
   393			ssa.OpS390XSUBWload, ssa.OpS390XSUBload,
   394			ssa.OpS390XANDWload, ssa.OpS390XANDload,
   395			ssa.OpS390XORWload, ssa.OpS390XORload,
   396			ssa.OpS390XXORWload, ssa.OpS390XXORload:
   397			r := v.Reg()
   398			if r != v.Args[0].Reg() {
   399				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   400			}
   401			p := s.Prog(v.Op.Asm())
   402			p.From.Type = obj.TYPE_MEM
   403			p.From.Reg = v.Args[1].Reg()
   404			gc.AddAux(&p.From, v)
   405			p.To.Type = obj.TYPE_REG
   406			p.To.Reg = r
   407		case ssa.OpS390XMOVDload,
   408			ssa.OpS390XMOVWZload, ssa.OpS390XMOVHZload, ssa.OpS390XMOVBZload,
   409			ssa.OpS390XMOVDBRload, ssa.OpS390XMOVWBRload, ssa.OpS390XMOVHBRload,
   410			ssa.OpS390XMOVBload, ssa.OpS390XMOVHload, ssa.OpS390XMOVWload,
   411			ssa.OpS390XFMOVSload, ssa.OpS390XFMOVDload:
   412			p := s.Prog(v.Op.Asm())
   413			p.From.Type = obj.TYPE_MEM
   414			p.From.Reg = v.Args[0].Reg()
   415			gc.AddAux(&p.From, v)
   416			p.To.Type = obj.TYPE_REG
   417			p.To.Reg = v.Reg()
   418		case ssa.OpS390XMOVBZloadidx, ssa.OpS390XMOVHZloadidx, ssa.OpS390XMOVWZloadidx,
   419			ssa.OpS390XMOVBloadidx, ssa.OpS390XMOVHloadidx, ssa.OpS390XMOVWloadidx, ssa.OpS390XMOVDloadidx,
   420			ssa.OpS390XMOVHBRloadidx, ssa.OpS390XMOVWBRloadidx, ssa.OpS390XMOVDBRloadidx,
   421			ssa.OpS390XFMOVSloadidx, ssa.OpS390XFMOVDloadidx:
   422			r := v.Args[0].Reg()
   423			i := v.Args[1].Reg()
   424			if i == s390x.REGSP {
   425				r, i = i, r
   426			}
   427			p := s.Prog(v.Op.Asm())
   428			p.From.Type = obj.TYPE_MEM
   429			p.From.Reg = r
   430			p.From.Scale = 1
   431			p.From.Index = i
   432			gc.AddAux(&p.From, v)
   433			p.To.Type = obj.TYPE_REG
   434			p.To.Reg = v.Reg()
   435		case ssa.OpS390XMOVBstore, ssa.OpS390XMOVHstore, ssa.OpS390XMOVWstore, ssa.OpS390XMOVDstore,
   436			ssa.OpS390XMOVHBRstore, ssa.OpS390XMOVWBRstore, ssa.OpS390XMOVDBRstore,
   437			ssa.OpS390XFMOVSstore, ssa.OpS390XFMOVDstore:
   438			p := s.Prog(v.Op.Asm())
   439			p.From.Type = obj.TYPE_REG
   440			p.From.Reg = v.Args[1].Reg()
   441			p.To.Type = obj.TYPE_MEM
   442			p.To.Reg = v.Args[0].Reg()
   443			gc.AddAux(&p.To, v)
   444		case ssa.OpS390XMOVBstoreidx, ssa.OpS390XMOVHstoreidx, ssa.OpS390XMOVWstoreidx, ssa.OpS390XMOVDstoreidx,
   445			ssa.OpS390XMOVHBRstoreidx, ssa.OpS390XMOVWBRstoreidx, ssa.OpS390XMOVDBRstoreidx,
   446			ssa.OpS390XFMOVSstoreidx, ssa.OpS390XFMOVDstoreidx:
   447			r := v.Args[0].Reg()
   448			i := v.Args[1].Reg()
   449			if i == s390x.REGSP {
   450				r, i = i, r
   451			}
   452			p := s.Prog(v.Op.Asm())
   453			p.From.Type = obj.TYPE_REG
   454			p.From.Reg = v.Args[2].Reg()
   455			p.To.Type = obj.TYPE_MEM
   456			p.To.Reg = r
   457			p.To.Scale = 1
   458			p.To.Index = i
   459			gc.AddAux(&p.To, v)
   460		case ssa.OpS390XMOVDstoreconst, ssa.OpS390XMOVWstoreconst, ssa.OpS390XMOVHstoreconst, ssa.OpS390XMOVBstoreconst:
   461			p := s.Prog(v.Op.Asm())
   462			p.From.Type = obj.TYPE_CONST
   463			sc := v.AuxValAndOff()
   464			p.From.Offset = sc.Val()
   465			p.To.Type = obj.TYPE_MEM
   466			p.To.Reg = v.Args[0].Reg()
   467			gc.AddAux2(&p.To, v, sc.Off())
   468		case ssa.OpS390XMOVBreg, ssa.OpS390XMOVHreg, ssa.OpS390XMOVWreg,
   469			ssa.OpS390XMOVBZreg, ssa.OpS390XMOVHZreg, ssa.OpS390XMOVWZreg,
   470			ssa.OpS390XLDGR, ssa.OpS390XLGDR,
   471			ssa.OpS390XCEFBRA, ssa.OpS390XCDFBRA, ssa.OpS390XCEGBRA, ssa.OpS390XCDGBRA,
   472			ssa.OpS390XCFEBRA, ssa.OpS390XCFDBRA, ssa.OpS390XCGEBRA, ssa.OpS390XCGDBRA,
   473			ssa.OpS390XLDEBR, ssa.OpS390XLEDBR,
   474			ssa.OpS390XFNEG, ssa.OpS390XFNEGS,
   475			ssa.OpS390XLPDFR, ssa.OpS390XLNDFR:
   476			opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg())
   477		case ssa.OpS390XCLEAR:
   478			p := s.Prog(v.Op.Asm())
   479			p.From.Type = obj.TYPE_CONST
   480			sc := v.AuxValAndOff()
   481			p.From.Offset = sc.Val()
   482			p.To.Type = obj.TYPE_MEM
   483			p.To.Reg = v.Args[0].Reg()
   484			gc.AddAux2(&p.To, v, sc.Off())
   485		case ssa.OpCopy, ssa.OpS390XMOVDreg:
   486			if v.Type.IsMemory() {
   487				return
   488			}
   489			x := v.Args[0].Reg()
   490			y := v.Reg()
   491			if x != y {
   492				opregreg(s, moveByType(v.Type), y, x)
   493			}
   494		case ssa.OpS390XMOVDnop:
   495			if v.Reg() != v.Args[0].Reg() {
   496				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   497			}
   498			// nothing to do
   499		case ssa.OpLoadReg:
   500			if v.Type.IsFlags() {
   501				v.Fatalf("load flags not implemented: %v", v.LongString())
   502				return
   503			}
   504			p := s.Prog(loadByType(v.Type))
   505			gc.AddrAuto(&p.From, v.Args[0])
   506			p.To.Type = obj.TYPE_REG
   507			p.To.Reg = v.Reg()
   508		case ssa.OpStoreReg:
   509			if v.Type.IsFlags() {
   510				v.Fatalf("store flags not implemented: %v", v.LongString())
   511				return
   512			}
   513			p := s.Prog(storeByType(v.Type))
   514			p.From.Type = obj.TYPE_REG
   515			p.From.Reg = v.Args[0].Reg()
   516			gc.AddrAuto(&p.To, v)
   517		case ssa.OpS390XLoweredGetClosurePtr:
   518			// Closure pointer is R12 (already)
   519			gc.CheckLoweredGetClosurePtr(v)
   520		case ssa.OpS390XLoweredRound32F, ssa.OpS390XLoweredRound64F:
   521			// input is already rounded
   522		case ssa.OpS390XLoweredGetG:
   523			r := v.Reg()
   524			p := s.Prog(s390x.AMOVD)
   525			p.From.Type = obj.TYPE_REG
   526			p.From.Reg = s390x.REGG
   527			p.To.Type = obj.TYPE_REG
   528			p.To.Reg = r
   529		case ssa.OpS390XLoweredGetCallerSP:
   530			// caller's SP is FixedFrameSize below the address of the first arg
   531			p := s.Prog(s390x.AMOVD)
   532			p.From.Type = obj.TYPE_ADDR
   533			p.From.Offset = -gc.Ctxt.FixedFrameSize()
   534			p.From.Name = obj.NAME_PARAM
   535			p.To.Type = obj.TYPE_REG
   536			p.To.Reg = v.Reg()
   537		case ssa.OpS390XLoweredGetCallerPC:
   538			p := s.Prog(obj.AGETCALLERPC)
   539			p.To.Type = obj.TYPE_REG
   540			p.To.Reg = v.Reg()
   541		case ssa.OpS390XCALLstatic, ssa.OpS390XCALLclosure, ssa.OpS390XCALLinter:
   542			s.Call(v)
   543		case ssa.OpS390XLoweredWB:
   544			p := s.Prog(obj.ACALL)
   545			p.To.Type = obj.TYPE_MEM
   546			p.To.Name = obj.NAME_EXTERN
   547			p.To.Sym = v.Aux.(*obj.LSym)
   548		case ssa.OpS390XLoweredPanicBoundsA, ssa.OpS390XLoweredPanicBoundsB, ssa.OpS390XLoweredPanicBoundsC:
   549			p := s.Prog(obj.ACALL)
   550			p.To.Type = obj.TYPE_MEM
   551			p.To.Name = obj.NAME_EXTERN
   552			p.To.Sym = gc.BoundsCheckFunc[v.AuxInt]
   553			s.UseArgs(16) // space used in callee args area by assembly stubs
   554		case ssa.OpS390XFLOGR, ssa.OpS390XPOPCNT,
   555			ssa.OpS390XNEG, ssa.OpS390XNEGW,
   556			ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR:
   557			p := s.Prog(v.Op.Asm())
   558			p.From.Type = obj.TYPE_REG
   559			p.From.Reg = v.Args[0].Reg()
   560			p.To.Type = obj.TYPE_REG
   561			p.To.Reg = v.Reg()
   562		case ssa.OpS390XNOT, ssa.OpS390XNOTW:
   563			v.Fatalf("NOT/NOTW generated %s", v.LongString())
   564		case ssa.OpS390XSumBytes2, ssa.OpS390XSumBytes4, ssa.OpS390XSumBytes8:
   565			v.Fatalf("SumBytes generated %s", v.LongString())
   566		case ssa.OpS390XMOVDEQ, ssa.OpS390XMOVDNE,
   567			ssa.OpS390XMOVDLT, ssa.OpS390XMOVDLE,
   568			ssa.OpS390XMOVDGT, ssa.OpS390XMOVDGE,
   569			ssa.OpS390XMOVDGTnoinv, ssa.OpS390XMOVDGEnoinv:
   570			r := v.Reg()
   571			if r != v.Args[0].Reg() {
   572				v.Fatalf("input[0] and output not in same register %s", v.LongString())
   573			}
   574			p := s.Prog(v.Op.Asm())
   575			p.From.Type = obj.TYPE_REG
   576			p.From.Reg = v.Args[1].Reg()
   577			p.To.Type = obj.TYPE_REG
   578			p.To.Reg = r
   579		case ssa.OpS390XFSQRT:
   580			p := s.Prog(v.Op.Asm())
   581			p.From.Type = obj.TYPE_REG
   582			p.From.Reg = v.Args[0].Reg()
   583			p.To.Type = obj.TYPE_REG
   584			p.To.Reg = v.Reg()
   585		case ssa.OpS390XInvertFlags:
   586			v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
   587		case ssa.OpS390XFlagEQ, ssa.OpS390XFlagLT, ssa.OpS390XFlagGT, ssa.OpS390XFlagOV:
   588			v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
   589		case ssa.OpS390XAddTupleFirst32, ssa.OpS390XAddTupleFirst64:
   590			v.Fatalf("AddTupleFirst* should never make it to codegen %v", v.LongString())
   591		case ssa.OpS390XLoweredNilCheck:
   592			// Issue a load which will fault if the input is nil.
   593			p := s.Prog(s390x.AMOVBZ)
   594			p.From.Type = obj.TYPE_MEM
   595			p.From.Reg = v.Args[0].Reg()
   596			gc.AddAux(&p.From, v)
   597			p.To.Type = obj.TYPE_REG
   598			p.To.Reg = s390x.REGTMP
   599			if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
   600				gc.Warnl(v.Pos, "generated nil check")
   601			}
   602		case ssa.OpS390XMVC:
   603			vo := v.AuxValAndOff()
   604			p := s.Prog(s390x.AMVC)
   605			p.From.Type = obj.TYPE_CONST
   606			p.From.Offset = vo.Val()
   607			p.SetFrom3(obj.Addr{
   608				Type:   obj.TYPE_MEM,
   609				Reg:    v.Args[1].Reg(),
   610				Offset: vo.Off(),
   611			})
   612			p.To.Type = obj.TYPE_MEM
   613			p.To.Reg = v.Args[0].Reg()
   614			p.To.Offset = vo.Off()
   615		case ssa.OpS390XSTMG2, ssa.OpS390XSTMG3, ssa.OpS390XSTMG4,
   616			ssa.OpS390XSTM2, ssa.OpS390XSTM3, ssa.OpS390XSTM4:
   617			for i := 2; i < len(v.Args)-1; i++ {
   618				if v.Args[i].Reg() != v.Args[i-1].Reg()+1 {
   619					v.Fatalf("invalid store multiple %s", v.LongString())
   620				}
   621			}
   622			p := s.Prog(v.Op.Asm())
   623			p.From.Type = obj.TYPE_REG
   624			p.From.Reg = v.Args[1].Reg()
   625			p.Reg = v.Args[len(v.Args)-2].Reg()
   626			p.To.Type = obj.TYPE_MEM
   627			p.To.Reg = v.Args[0].Reg()
   628			gc.AddAux(&p.To, v)
   629		case ssa.OpS390XLoweredMove:
   630			// Inputs must be valid pointers to memory,
   631			// so adjust arg0 and arg1 as part of the expansion.
   632			// arg2 should be src+size,
   633			//
   634			// mvc: MVC  $256, 0(R2), 0(R1)
   635			//      MOVD $256(R1), R1
   636			//      MOVD $256(R2), R2
   637			//      CMP  R2, Rarg2
   638			//      BNE  mvc
   639			//      MVC  $rem, 0(R2), 0(R1) // if rem > 0
   640			// arg2 is the last address to move in the loop + 256
   641			mvc := s.Prog(s390x.AMVC)
   642			mvc.From.Type = obj.TYPE_CONST
   643			mvc.From.Offset = 256
   644			mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()})
   645			mvc.To.Type = obj.TYPE_MEM
   646			mvc.To.Reg = v.Args[0].Reg()
   647	
   648			for i := 0; i < 2; i++ {
   649				movd := s.Prog(s390x.AMOVD)
   650				movd.From.Type = obj.TYPE_ADDR
   651				movd.From.Reg = v.Args[i].Reg()
   652				movd.From.Offset = 256
   653				movd.To.Type = obj.TYPE_REG
   654				movd.To.Reg = v.Args[i].Reg()
   655			}
   656	
   657			cmpu := s.Prog(s390x.ACMPU)
   658			cmpu.From.Reg = v.Args[1].Reg()
   659			cmpu.From.Type = obj.TYPE_REG
   660			cmpu.To.Reg = v.Args[2].Reg()
   661			cmpu.To.Type = obj.TYPE_REG
   662	
   663			bne := s.Prog(s390x.ABLT)
   664			bne.To.Type = obj.TYPE_BRANCH
   665			gc.Patch(bne, mvc)
   666	
   667			if v.AuxInt > 0 {
   668				mvc := s.Prog(s390x.AMVC)
   669				mvc.From.Type = obj.TYPE_CONST
   670				mvc.From.Offset = v.AuxInt
   671				mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()})
   672				mvc.To.Type = obj.TYPE_MEM
   673				mvc.To.Reg = v.Args[0].Reg()
   674			}
   675		case ssa.OpS390XLoweredZero:
   676			// Input must be valid pointers to memory,
   677			// so adjust arg0 as part of the expansion.
   678			// arg1 should be src+size,
   679			//
   680			// clear: CLEAR $256, 0(R1)
   681			//        MOVD  $256(R1), R1
   682			//        CMP   R1, Rarg1
   683			//        BNE   clear
   684			//        CLEAR $rem, 0(R1) // if rem > 0
   685			// arg1 is the last address to zero in the loop + 256
   686			clear := s.Prog(s390x.ACLEAR)
   687			clear.From.Type = obj.TYPE_CONST
   688			clear.From.Offset = 256
   689			clear.To.Type = obj.TYPE_MEM
   690			clear.To.Reg = v.Args[0].Reg()
   691	
   692			movd := s.Prog(s390x.AMOVD)
   693			movd.From.Type = obj.TYPE_ADDR
   694			movd.From.Reg = v.Args[0].Reg()
   695			movd.From.Offset = 256
   696			movd.To.Type = obj.TYPE_REG
   697			movd.To.Reg = v.Args[0].Reg()
   698	
   699			cmpu := s.Prog(s390x.ACMPU)
   700			cmpu.From.Reg = v.Args[0].Reg()
   701			cmpu.From.Type = obj.TYPE_REG
   702			cmpu.To.Reg = v.Args[1].Reg()
   703			cmpu.To.Type = obj.TYPE_REG
   704	
   705			bne := s.Prog(s390x.ABLT)
   706			bne.To.Type = obj.TYPE_BRANCH
   707			gc.Patch(bne, clear)
   708	
   709			if v.AuxInt > 0 {
   710				clear := s.Prog(s390x.ACLEAR)
   711				clear.From.Type = obj.TYPE_CONST
   712				clear.From.Offset = v.AuxInt
   713				clear.To.Type = obj.TYPE_MEM
   714				clear.To.Reg = v.Args[0].Reg()
   715			}
   716		case ssa.OpS390XMOVBZatomicload, ssa.OpS390XMOVWZatomicload, ssa.OpS390XMOVDatomicload:
   717			p := s.Prog(v.Op.Asm())
   718			p.From.Type = obj.TYPE_MEM
   719			p.From.Reg = v.Args[0].Reg()
   720			gc.AddAux(&p.From, v)
   721			p.To.Type = obj.TYPE_REG
   722			p.To.Reg = v.Reg0()
   723		case ssa.OpS390XMOVWatomicstore, ssa.OpS390XMOVDatomicstore:
   724			p := s.Prog(v.Op.Asm())
   725			p.From.Type = obj.TYPE_REG
   726			p.From.Reg = v.Args[1].Reg()
   727			p.To.Type = obj.TYPE_MEM
   728			p.To.Reg = v.Args[0].Reg()
   729			gc.AddAux(&p.To, v)
   730		case ssa.OpS390XLAA, ssa.OpS390XLAAG:
   731			p := s.Prog(v.Op.Asm())
   732			p.Reg = v.Reg0()
   733			p.From.Type = obj.TYPE_REG
   734			p.From.Reg = v.Args[1].Reg()
   735			p.To.Type = obj.TYPE_MEM
   736			p.To.Reg = v.Args[0].Reg()
   737			gc.AddAux(&p.To, v)
   738		case ssa.OpS390XLoweredAtomicCas32, ssa.OpS390XLoweredAtomicCas64:
   739			// Convert the flags output of CS{,G} into a bool.
   740			//    CS{,G} arg1, arg2, arg0
   741			//    MOVD   $0, ret
   742			//    BNE    2(PC)
   743			//    MOVD   $1, ret
   744			//    NOP (so the BNE has somewhere to land)
   745	
   746			// CS{,G} arg1, arg2, arg0
   747			cs := s.Prog(v.Op.Asm())
   748			cs.From.Type = obj.TYPE_REG
   749			cs.From.Reg = v.Args[1].Reg() // old
   750			cs.Reg = v.Args[2].Reg()      // new
   751			cs.To.Type = obj.TYPE_MEM
   752			cs.To.Reg = v.Args[0].Reg()
   753			gc.AddAux(&cs.To, v)
   754	
   755			// MOVD $0, ret
   756			movd := s.Prog(s390x.AMOVD)
   757			movd.From.Type = obj.TYPE_CONST
   758			movd.From.Offset = 0
   759			movd.To.Type = obj.TYPE_REG
   760			movd.To.Reg = v.Reg0()
   761	
   762			// BNE 2(PC)
   763			bne := s.Prog(s390x.ABNE)
   764			bne.To.Type = obj.TYPE_BRANCH
   765	
   766			// MOVD $1, ret
   767			movd = s.Prog(s390x.AMOVD)
   768			movd.From.Type = obj.TYPE_CONST
   769			movd.From.Offset = 1
   770			movd.To.Type = obj.TYPE_REG
   771			movd.To.Reg = v.Reg0()
   772	
   773			// NOP (so the BNE has somewhere to land)
   774			nop := s.Prog(obj.ANOP)
   775			gc.Patch(bne, nop)
   776		case ssa.OpS390XLoweredAtomicExchange32, ssa.OpS390XLoweredAtomicExchange64:
   777			// Loop until the CS{,G} succeeds.
   778			//     MOV{WZ,D} arg0, ret
   779			// cs: CS{,G}    ret, arg1, arg0
   780			//     BNE       cs
   781	
   782			// MOV{WZ,D} arg0, ret
   783			load := s.Prog(loadByType(v.Type.FieldType(0)))
   784			load.From.Type = obj.TYPE_MEM
   785			load.From.Reg = v.Args[0].Reg()
   786			load.To.Type = obj.TYPE_REG
   787			load.To.Reg = v.Reg0()
   788			gc.AddAux(&load.From, v)
   789	
   790			// CS{,G} ret, arg1, arg0
   791			cs := s.Prog(v.Op.Asm())
   792			cs.From.Type = obj.TYPE_REG
   793			cs.From.Reg = v.Reg0()   // old
   794			cs.Reg = v.Args[1].Reg() // new
   795			cs.To.Type = obj.TYPE_MEM
   796			cs.To.Reg = v.Args[0].Reg()
   797			gc.AddAux(&cs.To, v)
   798	
   799			// BNE cs
   800			bne := s.Prog(s390x.ABNE)
   801			bne.To.Type = obj.TYPE_BRANCH
   802			gc.Patch(bne, cs)
   803		case ssa.OpS390XSYNC:
   804			s.Prog(s390x.ASYNC)
   805		case ssa.OpClobber:
   806			// TODO: implement for clobberdead experiment. Nop is ok for now.
   807		default:
   808			v.Fatalf("genValue not implemented: %s", v.LongString())
   809		}
   810	}
   811	
   812	var blockJump = [...]struct {
   813		asm, invasm obj.As
   814	}{
   815		ssa.BlockS390XEQ:  {s390x.ABEQ, s390x.ABNE},
   816		ssa.BlockS390XNE:  {s390x.ABNE, s390x.ABEQ},
   817		ssa.BlockS390XLT:  {s390x.ABLT, s390x.ABGE},
   818		ssa.BlockS390XGE:  {s390x.ABGE, s390x.ABLT},
   819		ssa.BlockS390XLE:  {s390x.ABLE, s390x.ABGT},
   820		ssa.BlockS390XGT:  {s390x.ABGT, s390x.ABLE},
   821		ssa.BlockS390XGTF: {s390x.ABGT, s390x.ABLEU},
   822		ssa.BlockS390XGEF: {s390x.ABGE, s390x.ABLTU},
   823	}
   824	
   825	func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   826		switch b.Kind {
   827		case ssa.BlockPlain:
   828			if b.Succs[0].Block() != next {
   829				p := s.Prog(s390x.ABR)
   830				p.To.Type = obj.TYPE_BRANCH
   831				s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   832			}
   833		case ssa.BlockDefer:
   834			// defer returns in R3:
   835			// 0 if we should continue executing
   836			// 1 if we should jump to deferreturn call
   837			p := s.Prog(s390x.ACMPW)
   838			p.From.Type = obj.TYPE_REG
   839			p.From.Reg = s390x.REG_R3
   840			p.To.Type = obj.TYPE_CONST
   841			p.To.Offset = 0
   842			p = s.Prog(s390x.ABNE)
   843			p.To.Type = obj.TYPE_BRANCH
   844			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   845			if b.Succs[0].Block() != next {
   846				p := s.Prog(s390x.ABR)
   847				p.To.Type = obj.TYPE_BRANCH
   848				s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   849			}
   850		case ssa.BlockExit:
   851		case ssa.BlockRet:
   852			s.Prog(obj.ARET)
   853		case ssa.BlockRetJmp:
   854			p := s.Prog(s390x.ABR)
   855			p.To.Type = obj.TYPE_MEM
   856			p.To.Name = obj.NAME_EXTERN
   857			p.To.Sym = b.Aux.(*obj.LSym)
   858		case ssa.BlockS390XEQ, ssa.BlockS390XNE,
   859			ssa.BlockS390XLT, ssa.BlockS390XGE,
   860			ssa.BlockS390XLE, ssa.BlockS390XGT,
   861			ssa.BlockS390XGEF, ssa.BlockS390XGTF:
   862			jmp := blockJump[b.Kind]
   863			switch next {
   864			case b.Succs[0].Block():
   865				s.Br(jmp.invasm, b.Succs[1].Block())
   866			case b.Succs[1].Block():
   867				s.Br(jmp.asm, b.Succs[0].Block())
   868			default:
   869				if b.Likely != ssa.BranchUnlikely {
   870					s.Br(jmp.asm, b.Succs[0].Block())
   871					s.Br(s390x.ABR, b.Succs[1].Block())
   872				} else {
   873					s.Br(jmp.invasm, b.Succs[1].Block())
   874					s.Br(s390x.ABR, b.Succs[0].Block())
   875				}
   876			}
   877		default:
   878			b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
   879		}
   880	}
   881	

View as plain text