github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/src/cmd/compile/internal/s390x/ssa.go (about)

     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  		r := v.Reg()
   165  		r1 := v.Args[0].Reg()
   166  		r2 := v.Args[1].Reg()
   167  		if r2 == s390x.REG_R0 {
   168  			v.Fatalf("cannot use R0 as shift value %s", v.LongString())
   169  		}
   170  		p := opregreg(s, v.Op.Asm(), r, r2)
   171  		if r != r1 {
   172  			p.Reg = r1
   173  		}
   174  	case ssa.OpS390XADD, ssa.OpS390XADDW,
   175  		ssa.OpS390XSUB, ssa.OpS390XSUBW,
   176  		ssa.OpS390XAND, ssa.OpS390XANDW,
   177  		ssa.OpS390XOR, ssa.OpS390XORW,
   178  		ssa.OpS390XXOR, ssa.OpS390XXORW:
   179  		r := v.Reg()
   180  		r1 := v.Args[0].Reg()
   181  		r2 := v.Args[1].Reg()
   182  		p := opregreg(s, v.Op.Asm(), r, r2)
   183  		if r != r1 {
   184  			p.Reg = r1
   185  		}
   186  	// 2-address opcode arithmetic
   187  	case ssa.OpS390XMULLD, ssa.OpS390XMULLW,
   188  		ssa.OpS390XMULHD, ssa.OpS390XMULHDU,
   189  		ssa.OpS390XFADDS, ssa.OpS390XFADD, ssa.OpS390XFSUBS, ssa.OpS390XFSUB,
   190  		ssa.OpS390XFMULS, ssa.OpS390XFMUL, ssa.OpS390XFDIVS, ssa.OpS390XFDIV:
   191  		r := v.Reg()
   192  		if r != v.Args[0].Reg() {
   193  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   194  		}
   195  		opregreg(s, v.Op.Asm(), r, v.Args[1].Reg())
   196  	case ssa.OpS390XFMADD, ssa.OpS390XFMADDS,
   197  		ssa.OpS390XFMSUB, ssa.OpS390XFMSUBS:
   198  		r := v.Reg()
   199  		if r != v.Args[0].Reg() {
   200  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   201  		}
   202  		r1 := v.Args[1].Reg()
   203  		r2 := v.Args[2].Reg()
   204  		p := s.Prog(v.Op.Asm())
   205  		p.From.Type = obj.TYPE_REG
   206  		p.From.Reg = r1
   207  		p.Reg = r2
   208  		p.To.Type = obj.TYPE_REG
   209  		p.To.Reg = r
   210  	case ssa.OpS390XFIDBR:
   211  		switch v.AuxInt {
   212  		case 0, 1, 3, 4, 5, 6, 7:
   213  			opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt)
   214  		default:
   215  			v.Fatalf("invalid FIDBR mask: %v", v.AuxInt)
   216  		}
   217  	case ssa.OpS390XCPSDR:
   218  		p := opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg())
   219  		p.Reg = v.Args[0].Reg()
   220  	case ssa.OpS390XDIVD, ssa.OpS390XDIVW,
   221  		ssa.OpS390XDIVDU, ssa.OpS390XDIVWU,
   222  		ssa.OpS390XMODD, ssa.OpS390XMODW,
   223  		ssa.OpS390XMODDU, ssa.OpS390XMODWU:
   224  
   225  		// TODO(mundaym): use the temp registers every time like x86 does with AX?
   226  		dividend := v.Args[0].Reg()
   227  		divisor := v.Args[1].Reg()
   228  
   229  		// CPU faults upon signed overflow, which occurs when most
   230  		// negative int is divided by -1.
   231  		var j *obj.Prog
   232  		if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW ||
   233  			v.Op == ssa.OpS390XMODD || v.Op == ssa.OpS390XMODW {
   234  
   235  			var c *obj.Prog
   236  			c = s.Prog(s390x.ACMP)
   237  			j = s.Prog(s390x.ABEQ)
   238  
   239  			c.From.Type = obj.TYPE_REG
   240  			c.From.Reg = divisor
   241  			c.To.Type = obj.TYPE_CONST
   242  			c.To.Offset = -1
   243  
   244  			j.To.Type = obj.TYPE_BRANCH
   245  
   246  		}
   247  
   248  		p := s.Prog(v.Op.Asm())
   249  		p.From.Type = obj.TYPE_REG
   250  		p.From.Reg = divisor
   251  		p.Reg = 0
   252  		p.To.Type = obj.TYPE_REG
   253  		p.To.Reg = dividend
   254  
   255  		// signed division, rest of the check for -1 case
   256  		if j != nil {
   257  			j2 := s.Prog(s390x.ABR)
   258  			j2.To.Type = obj.TYPE_BRANCH
   259  
   260  			var n *obj.Prog
   261  			if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW {
   262  				// n * -1 = -n
   263  				n = s.Prog(s390x.ANEG)
   264  				n.To.Type = obj.TYPE_REG
   265  				n.To.Reg = dividend
   266  			} else {
   267  				// n % -1 == 0
   268  				n = s.Prog(s390x.AXOR)
   269  				n.From.Type = obj.TYPE_REG
   270  				n.From.Reg = dividend
   271  				n.To.Type = obj.TYPE_REG
   272  				n.To.Reg = dividend
   273  			}
   274  
   275  			j.To.Val = n
   276  			j2.To.Val = s.Pc()
   277  		}
   278  	case ssa.OpS390XADDconst, ssa.OpS390XADDWconst:
   279  		opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt)
   280  	case ssa.OpS390XMULLDconst, ssa.OpS390XMULLWconst,
   281  		ssa.OpS390XSUBconst, ssa.OpS390XSUBWconst,
   282  		ssa.OpS390XANDconst, ssa.OpS390XANDWconst,
   283  		ssa.OpS390XORconst, ssa.OpS390XORWconst,
   284  		ssa.OpS390XXORconst, ssa.OpS390XXORWconst:
   285  		r := v.Reg()
   286  		if r != v.Args[0].Reg() {
   287  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   288  		}
   289  		p := s.Prog(v.Op.Asm())
   290  		p.From.Type = obj.TYPE_CONST
   291  		p.From.Offset = v.AuxInt
   292  		p.To.Type = obj.TYPE_REG
   293  		p.To.Reg = r
   294  	case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst,
   295  		ssa.OpS390XSRDconst, ssa.OpS390XSRWconst,
   296  		ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst,
   297  		ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst:
   298  		p := s.Prog(v.Op.Asm())
   299  		p.From.Type = obj.TYPE_CONST
   300  		p.From.Offset = v.AuxInt
   301  		r := v.Reg()
   302  		r1 := v.Args[0].Reg()
   303  		if r != r1 {
   304  			p.Reg = r1
   305  		}
   306  		p.To.Type = obj.TYPE_REG
   307  		p.To.Reg = r
   308  	case ssa.OpS390XSUBEcarrymask, ssa.OpS390XSUBEWcarrymask:
   309  		r := v.Reg()
   310  		p := s.Prog(v.Op.Asm())
   311  		p.From.Type = obj.TYPE_REG
   312  		p.From.Reg = r
   313  		p.To.Type = obj.TYPE_REG
   314  		p.To.Reg = r
   315  	case ssa.OpS390XMOVDaddridx:
   316  		r := v.Args[0].Reg()
   317  		i := v.Args[1].Reg()
   318  		p := s.Prog(s390x.AMOVD)
   319  		p.From.Scale = 1
   320  		if i == s390x.REGSP {
   321  			r, i = i, r
   322  		}
   323  		p.From.Type = obj.TYPE_ADDR
   324  		p.From.Reg = r
   325  		p.From.Index = i
   326  		gc.AddAux(&p.From, v)
   327  		p.To.Type = obj.TYPE_REG
   328  		p.To.Reg = v.Reg()
   329  	case ssa.OpS390XMOVDaddr:
   330  		p := s.Prog(s390x.AMOVD)
   331  		p.From.Type = obj.TYPE_ADDR
   332  		p.From.Reg = v.Args[0].Reg()
   333  		gc.AddAux(&p.From, v)
   334  		p.To.Type = obj.TYPE_REG
   335  		p.To.Reg = v.Reg()
   336  	case ssa.OpS390XCMP, ssa.OpS390XCMPW, ssa.OpS390XCMPU, ssa.OpS390XCMPWU:
   337  		opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
   338  	case ssa.OpS390XFCMPS, ssa.OpS390XFCMP:
   339  		opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
   340  	case ssa.OpS390XCMPconst, ssa.OpS390XCMPWconst:
   341  		p := s.Prog(v.Op.Asm())
   342  		p.From.Type = obj.TYPE_REG
   343  		p.From.Reg = v.Args[0].Reg()
   344  		p.To.Type = obj.TYPE_CONST
   345  		p.To.Offset = v.AuxInt
   346  	case ssa.OpS390XCMPUconst, ssa.OpS390XCMPWUconst:
   347  		p := s.Prog(v.Op.Asm())
   348  		p.From.Type = obj.TYPE_REG
   349  		p.From.Reg = v.Args[0].Reg()
   350  		p.To.Type = obj.TYPE_CONST
   351  		p.To.Offset = int64(uint32(v.AuxInt))
   352  	case ssa.OpS390XMOVDconst:
   353  		x := v.Reg()
   354  		p := s.Prog(v.Op.Asm())
   355  		p.From.Type = obj.TYPE_CONST
   356  		p.From.Offset = v.AuxInt
   357  		p.To.Type = obj.TYPE_REG
   358  		p.To.Reg = x
   359  	case ssa.OpS390XFMOVSconst, ssa.OpS390XFMOVDconst:
   360  		x := v.Reg()
   361  		p := s.Prog(v.Op.Asm())
   362  		p.From.Type = obj.TYPE_FCONST
   363  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   364  		p.To.Type = obj.TYPE_REG
   365  		p.To.Reg = x
   366  	case ssa.OpS390XADDWload, ssa.OpS390XADDload,
   367  		ssa.OpS390XMULLWload, ssa.OpS390XMULLDload,
   368  		ssa.OpS390XSUBWload, ssa.OpS390XSUBload,
   369  		ssa.OpS390XANDWload, ssa.OpS390XANDload,
   370  		ssa.OpS390XORWload, ssa.OpS390XORload,
   371  		ssa.OpS390XXORWload, ssa.OpS390XXORload:
   372  		r := v.Reg()
   373  		if r != v.Args[0].Reg() {
   374  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   375  		}
   376  		p := s.Prog(v.Op.Asm())
   377  		p.From.Type = obj.TYPE_MEM
   378  		p.From.Reg = v.Args[1].Reg()
   379  		gc.AddAux(&p.From, v)
   380  		p.To.Type = obj.TYPE_REG
   381  		p.To.Reg = r
   382  	case ssa.OpS390XMOVDload,
   383  		ssa.OpS390XMOVWZload, ssa.OpS390XMOVHZload, ssa.OpS390XMOVBZload,
   384  		ssa.OpS390XMOVDBRload, ssa.OpS390XMOVWBRload, ssa.OpS390XMOVHBRload,
   385  		ssa.OpS390XMOVBload, ssa.OpS390XMOVHload, ssa.OpS390XMOVWload,
   386  		ssa.OpS390XFMOVSload, ssa.OpS390XFMOVDload:
   387  		p := s.Prog(v.Op.Asm())
   388  		p.From.Type = obj.TYPE_MEM
   389  		p.From.Reg = v.Args[0].Reg()
   390  		gc.AddAux(&p.From, v)
   391  		p.To.Type = obj.TYPE_REG
   392  		p.To.Reg = v.Reg()
   393  	case ssa.OpS390XMOVBZloadidx, ssa.OpS390XMOVHZloadidx, ssa.OpS390XMOVWZloadidx,
   394  		ssa.OpS390XMOVBloadidx, ssa.OpS390XMOVHloadidx, ssa.OpS390XMOVWloadidx, ssa.OpS390XMOVDloadidx,
   395  		ssa.OpS390XMOVHBRloadidx, ssa.OpS390XMOVWBRloadidx, ssa.OpS390XMOVDBRloadidx,
   396  		ssa.OpS390XFMOVSloadidx, ssa.OpS390XFMOVDloadidx:
   397  		r := v.Args[0].Reg()
   398  		i := v.Args[1].Reg()
   399  		if i == s390x.REGSP {
   400  			r, i = i, r
   401  		}
   402  		p := s.Prog(v.Op.Asm())
   403  		p.From.Type = obj.TYPE_MEM
   404  		p.From.Reg = r
   405  		p.From.Scale = 1
   406  		p.From.Index = i
   407  		gc.AddAux(&p.From, v)
   408  		p.To.Type = obj.TYPE_REG
   409  		p.To.Reg = v.Reg()
   410  	case ssa.OpS390XMOVBstore, ssa.OpS390XMOVHstore, ssa.OpS390XMOVWstore, ssa.OpS390XMOVDstore,
   411  		ssa.OpS390XMOVHBRstore, ssa.OpS390XMOVWBRstore, ssa.OpS390XMOVDBRstore,
   412  		ssa.OpS390XFMOVSstore, ssa.OpS390XFMOVDstore:
   413  		p := s.Prog(v.Op.Asm())
   414  		p.From.Type = obj.TYPE_REG
   415  		p.From.Reg = v.Args[1].Reg()
   416  		p.To.Type = obj.TYPE_MEM
   417  		p.To.Reg = v.Args[0].Reg()
   418  		gc.AddAux(&p.To, v)
   419  	case ssa.OpS390XMOVBstoreidx, ssa.OpS390XMOVHstoreidx, ssa.OpS390XMOVWstoreidx, ssa.OpS390XMOVDstoreidx,
   420  		ssa.OpS390XMOVHBRstoreidx, ssa.OpS390XMOVWBRstoreidx, ssa.OpS390XMOVDBRstoreidx,
   421  		ssa.OpS390XFMOVSstoreidx, ssa.OpS390XFMOVDstoreidx:
   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_REG
   429  		p.From.Reg = v.Args[2].Reg()
   430  		p.To.Type = obj.TYPE_MEM
   431  		p.To.Reg = r
   432  		p.To.Scale = 1
   433  		p.To.Index = i
   434  		gc.AddAux(&p.To, v)
   435  	case ssa.OpS390XMOVDstoreconst, ssa.OpS390XMOVWstoreconst, ssa.OpS390XMOVHstoreconst, ssa.OpS390XMOVBstoreconst:
   436  		p := s.Prog(v.Op.Asm())
   437  		p.From.Type = obj.TYPE_CONST
   438  		sc := v.AuxValAndOff()
   439  		p.From.Offset = sc.Val()
   440  		p.To.Type = obj.TYPE_MEM
   441  		p.To.Reg = v.Args[0].Reg()
   442  		gc.AddAux2(&p.To, v, sc.Off())
   443  	case ssa.OpS390XMOVBreg, ssa.OpS390XMOVHreg, ssa.OpS390XMOVWreg,
   444  		ssa.OpS390XMOVBZreg, ssa.OpS390XMOVHZreg, ssa.OpS390XMOVWZreg,
   445  		ssa.OpS390XLDGR, ssa.OpS390XLGDR,
   446  		ssa.OpS390XCEFBRA, ssa.OpS390XCDFBRA, ssa.OpS390XCEGBRA, ssa.OpS390XCDGBRA,
   447  		ssa.OpS390XCFEBRA, ssa.OpS390XCFDBRA, ssa.OpS390XCGEBRA, ssa.OpS390XCGDBRA,
   448  		ssa.OpS390XLDEBR, ssa.OpS390XLEDBR,
   449  		ssa.OpS390XFNEG, ssa.OpS390XFNEGS,
   450  		ssa.OpS390XLPDFR, ssa.OpS390XLNDFR:
   451  		opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg())
   452  	case ssa.OpS390XCLEAR:
   453  		p := s.Prog(v.Op.Asm())
   454  		p.From.Type = obj.TYPE_CONST
   455  		sc := v.AuxValAndOff()
   456  		p.From.Offset = sc.Val()
   457  		p.To.Type = obj.TYPE_MEM
   458  		p.To.Reg = v.Args[0].Reg()
   459  		gc.AddAux2(&p.To, v, sc.Off())
   460  	case ssa.OpCopy, ssa.OpS390XMOVDconvert, ssa.OpS390XMOVDreg:
   461  		if v.Type.IsMemory() {
   462  			return
   463  		}
   464  		x := v.Args[0].Reg()
   465  		y := v.Reg()
   466  		if x != y {
   467  			opregreg(s, moveByType(v.Type), y, x)
   468  		}
   469  	case ssa.OpS390XMOVDnop:
   470  		if v.Reg() != v.Args[0].Reg() {
   471  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   472  		}
   473  		// nothing to do
   474  	case ssa.OpLoadReg:
   475  		if v.Type.IsFlags() {
   476  			v.Fatalf("load flags not implemented: %v", v.LongString())
   477  			return
   478  		}
   479  		p := s.Prog(loadByType(v.Type))
   480  		gc.AddrAuto(&p.From, v.Args[0])
   481  		p.To.Type = obj.TYPE_REG
   482  		p.To.Reg = v.Reg()
   483  	case ssa.OpStoreReg:
   484  		if v.Type.IsFlags() {
   485  			v.Fatalf("store flags not implemented: %v", v.LongString())
   486  			return
   487  		}
   488  		p := s.Prog(storeByType(v.Type))
   489  		p.From.Type = obj.TYPE_REG
   490  		p.From.Reg = v.Args[0].Reg()
   491  		gc.AddrAuto(&p.To, v)
   492  	case ssa.OpS390XLoweredGetClosurePtr:
   493  		// Closure pointer is R12 (already)
   494  		gc.CheckLoweredGetClosurePtr(v)
   495  	case ssa.OpS390XLoweredRound32F, ssa.OpS390XLoweredRound64F:
   496  		// input is already rounded
   497  	case ssa.OpS390XLoweredGetG:
   498  		r := v.Reg()
   499  		p := s.Prog(s390x.AMOVD)
   500  		p.From.Type = obj.TYPE_REG
   501  		p.From.Reg = s390x.REGG
   502  		p.To.Type = obj.TYPE_REG
   503  		p.To.Reg = r
   504  	case ssa.OpS390XLoweredGetCallerSP:
   505  		// caller's SP is FixedFrameSize below the address of the first arg
   506  		p := s.Prog(s390x.AMOVD)
   507  		p.From.Type = obj.TYPE_ADDR
   508  		p.From.Offset = -gc.Ctxt.FixedFrameSize()
   509  		p.From.Name = obj.NAME_PARAM
   510  		p.To.Type = obj.TYPE_REG
   511  		p.To.Reg = v.Reg()
   512  	case ssa.OpS390XCALLstatic, ssa.OpS390XCALLclosure, ssa.OpS390XCALLinter:
   513  		s.Call(v)
   514  	case ssa.OpS390XFLOGR, ssa.OpS390XNEG, ssa.OpS390XNEGW,
   515  		ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR:
   516  		p := s.Prog(v.Op.Asm())
   517  		p.From.Type = obj.TYPE_REG
   518  		p.From.Reg = v.Args[0].Reg()
   519  		p.To.Type = obj.TYPE_REG
   520  		p.To.Reg = v.Reg()
   521  	case ssa.OpS390XNOT, ssa.OpS390XNOTW:
   522  		v.Fatalf("NOT/NOTW generated %s", v.LongString())
   523  	case ssa.OpS390XMOVDEQ, ssa.OpS390XMOVDNE,
   524  		ssa.OpS390XMOVDLT, ssa.OpS390XMOVDLE,
   525  		ssa.OpS390XMOVDGT, ssa.OpS390XMOVDGE,
   526  		ssa.OpS390XMOVDGTnoinv, ssa.OpS390XMOVDGEnoinv:
   527  		r := v.Reg()
   528  		if r != v.Args[0].Reg() {
   529  			v.Fatalf("input[0] and output not in same register %s", v.LongString())
   530  		}
   531  		p := s.Prog(v.Op.Asm())
   532  		p.From.Type = obj.TYPE_REG
   533  		p.From.Reg = v.Args[1].Reg()
   534  		p.To.Type = obj.TYPE_REG
   535  		p.To.Reg = r
   536  	case ssa.OpS390XFSQRT:
   537  		p := s.Prog(v.Op.Asm())
   538  		p.From.Type = obj.TYPE_REG
   539  		p.From.Reg = v.Args[0].Reg()
   540  		p.To.Type = obj.TYPE_REG
   541  		p.To.Reg = v.Reg()
   542  	case ssa.OpS390XInvertFlags:
   543  		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
   544  	case ssa.OpS390XFlagEQ, ssa.OpS390XFlagLT, ssa.OpS390XFlagGT:
   545  		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
   546  	case ssa.OpS390XAddTupleFirst32, ssa.OpS390XAddTupleFirst64:
   547  		v.Fatalf("AddTupleFirst* should never make it to codegen %v", v.LongString())
   548  	case ssa.OpS390XLoweredNilCheck:
   549  		// Issue a load which will fault if the input is nil.
   550  		p := s.Prog(s390x.AMOVBZ)
   551  		p.From.Type = obj.TYPE_MEM
   552  		p.From.Reg = v.Args[0].Reg()
   553  		gc.AddAux(&p.From, v)
   554  		p.To.Type = obj.TYPE_REG
   555  		p.To.Reg = s390x.REGTMP
   556  		if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
   557  			gc.Warnl(v.Pos, "generated nil check")
   558  		}
   559  	case ssa.OpS390XMVC:
   560  		vo := v.AuxValAndOff()
   561  		p := s.Prog(s390x.AMVC)
   562  		p.From.Type = obj.TYPE_CONST
   563  		p.From.Offset = vo.Val()
   564  		p.SetFrom3(obj.Addr{
   565  			Type:   obj.TYPE_MEM,
   566  			Reg:    v.Args[1].Reg(),
   567  			Offset: vo.Off(),
   568  		})
   569  		p.To.Type = obj.TYPE_MEM
   570  		p.To.Reg = v.Args[0].Reg()
   571  		p.To.Offset = vo.Off()
   572  	case ssa.OpS390XSTMG2, ssa.OpS390XSTMG3, ssa.OpS390XSTMG4,
   573  		ssa.OpS390XSTM2, ssa.OpS390XSTM3, ssa.OpS390XSTM4:
   574  		for i := 2; i < len(v.Args)-1; i++ {
   575  			if v.Args[i].Reg() != v.Args[i-1].Reg()+1 {
   576  				v.Fatalf("invalid store multiple %s", v.LongString())
   577  			}
   578  		}
   579  		p := s.Prog(v.Op.Asm())
   580  		p.From.Type = obj.TYPE_REG
   581  		p.From.Reg = v.Args[1].Reg()
   582  		p.Reg = v.Args[len(v.Args)-2].Reg()
   583  		p.To.Type = obj.TYPE_MEM
   584  		p.To.Reg = v.Args[0].Reg()
   585  		gc.AddAux(&p.To, v)
   586  	case ssa.OpS390XLoweredMove:
   587  		// Inputs must be valid pointers to memory,
   588  		// so adjust arg0 and arg1 as part of the expansion.
   589  		// arg2 should be src+size,
   590  		//
   591  		// mvc: MVC  $256, 0(R2), 0(R1)
   592  		//      MOVD $256(R1), R1
   593  		//      MOVD $256(R2), R2
   594  		//      CMP  R2, Rarg2
   595  		//      BNE  mvc
   596  		//      MVC  $rem, 0(R2), 0(R1) // if rem > 0
   597  		// arg2 is the last address to move in the loop + 256
   598  		mvc := s.Prog(s390x.AMVC)
   599  		mvc.From.Type = obj.TYPE_CONST
   600  		mvc.From.Offset = 256
   601  		mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()})
   602  		mvc.To.Type = obj.TYPE_MEM
   603  		mvc.To.Reg = v.Args[0].Reg()
   604  
   605  		for i := 0; i < 2; i++ {
   606  			movd := s.Prog(s390x.AMOVD)
   607  			movd.From.Type = obj.TYPE_ADDR
   608  			movd.From.Reg = v.Args[i].Reg()
   609  			movd.From.Offset = 256
   610  			movd.To.Type = obj.TYPE_REG
   611  			movd.To.Reg = v.Args[i].Reg()
   612  		}
   613  
   614  		cmpu := s.Prog(s390x.ACMPU)
   615  		cmpu.From.Reg = v.Args[1].Reg()
   616  		cmpu.From.Type = obj.TYPE_REG
   617  		cmpu.To.Reg = v.Args[2].Reg()
   618  		cmpu.To.Type = obj.TYPE_REG
   619  
   620  		bne := s.Prog(s390x.ABLT)
   621  		bne.To.Type = obj.TYPE_BRANCH
   622  		gc.Patch(bne, mvc)
   623  
   624  		if v.AuxInt > 0 {
   625  			mvc := s.Prog(s390x.AMVC)
   626  			mvc.From.Type = obj.TYPE_CONST
   627  			mvc.From.Offset = v.AuxInt
   628  			mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()})
   629  			mvc.To.Type = obj.TYPE_MEM
   630  			mvc.To.Reg = v.Args[0].Reg()
   631  		}
   632  	case ssa.OpS390XLoweredZero:
   633  		// Input must be valid pointers to memory,
   634  		// so adjust arg0 as part of the expansion.
   635  		// arg1 should be src+size,
   636  		//
   637  		// clear: CLEAR $256, 0(R1)
   638  		//        MOVD  $256(R1), R1
   639  		//        CMP   R1, Rarg1
   640  		//        BNE   clear
   641  		//        CLEAR $rem, 0(R1) // if rem > 0
   642  		// arg1 is the last address to zero in the loop + 256
   643  		clear := s.Prog(s390x.ACLEAR)
   644  		clear.From.Type = obj.TYPE_CONST
   645  		clear.From.Offset = 256
   646  		clear.To.Type = obj.TYPE_MEM
   647  		clear.To.Reg = v.Args[0].Reg()
   648  
   649  		movd := s.Prog(s390x.AMOVD)
   650  		movd.From.Type = obj.TYPE_ADDR
   651  		movd.From.Reg = v.Args[0].Reg()
   652  		movd.From.Offset = 256
   653  		movd.To.Type = obj.TYPE_REG
   654  		movd.To.Reg = v.Args[0].Reg()
   655  
   656  		cmpu := s.Prog(s390x.ACMPU)
   657  		cmpu.From.Reg = v.Args[0].Reg()
   658  		cmpu.From.Type = obj.TYPE_REG
   659  		cmpu.To.Reg = v.Args[1].Reg()
   660  		cmpu.To.Type = obj.TYPE_REG
   661  
   662  		bne := s.Prog(s390x.ABLT)
   663  		bne.To.Type = obj.TYPE_BRANCH
   664  		gc.Patch(bne, clear)
   665  
   666  		if v.AuxInt > 0 {
   667  			clear := s.Prog(s390x.ACLEAR)
   668  			clear.From.Type = obj.TYPE_CONST
   669  			clear.From.Offset = v.AuxInt
   670  			clear.To.Type = obj.TYPE_MEM
   671  			clear.To.Reg = v.Args[0].Reg()
   672  		}
   673  	case ssa.OpS390XMOVWZatomicload, ssa.OpS390XMOVDatomicload:
   674  		p := s.Prog(v.Op.Asm())
   675  		p.From.Type = obj.TYPE_MEM
   676  		p.From.Reg = v.Args[0].Reg()
   677  		gc.AddAux(&p.From, v)
   678  		p.To.Type = obj.TYPE_REG
   679  		p.To.Reg = v.Reg0()
   680  	case ssa.OpS390XMOVWatomicstore, ssa.OpS390XMOVDatomicstore:
   681  		p := s.Prog(v.Op.Asm())
   682  		p.From.Type = obj.TYPE_REG
   683  		p.From.Reg = v.Args[1].Reg()
   684  		p.To.Type = obj.TYPE_MEM
   685  		p.To.Reg = v.Args[0].Reg()
   686  		gc.AddAux(&p.To, v)
   687  	case ssa.OpS390XLAA, ssa.OpS390XLAAG:
   688  		p := s.Prog(v.Op.Asm())
   689  		p.Reg = v.Reg0()
   690  		p.From.Type = obj.TYPE_REG
   691  		p.From.Reg = v.Args[1].Reg()
   692  		p.To.Type = obj.TYPE_MEM
   693  		p.To.Reg = v.Args[0].Reg()
   694  		gc.AddAux(&p.To, v)
   695  	case ssa.OpS390XLoweredAtomicCas32, ssa.OpS390XLoweredAtomicCas64:
   696  		// Convert the flags output of CS{,G} into a bool.
   697  		//    CS{,G} arg1, arg2, arg0
   698  		//    MOVD   $0, ret
   699  		//    BNE    2(PC)
   700  		//    MOVD   $1, ret
   701  		//    NOP (so the BNE has somewhere to land)
   702  
   703  		// CS{,G} arg1, arg2, arg0
   704  		cs := s.Prog(v.Op.Asm())
   705  		cs.From.Type = obj.TYPE_REG
   706  		cs.From.Reg = v.Args[1].Reg() // old
   707  		cs.Reg = v.Args[2].Reg()      // new
   708  		cs.To.Type = obj.TYPE_MEM
   709  		cs.To.Reg = v.Args[0].Reg()
   710  		gc.AddAux(&cs.To, v)
   711  
   712  		// MOVD $0, ret
   713  		movd := s.Prog(s390x.AMOVD)
   714  		movd.From.Type = obj.TYPE_CONST
   715  		movd.From.Offset = 0
   716  		movd.To.Type = obj.TYPE_REG
   717  		movd.To.Reg = v.Reg0()
   718  
   719  		// BNE 2(PC)
   720  		bne := s.Prog(s390x.ABNE)
   721  		bne.To.Type = obj.TYPE_BRANCH
   722  
   723  		// MOVD $1, ret
   724  		movd = s.Prog(s390x.AMOVD)
   725  		movd.From.Type = obj.TYPE_CONST
   726  		movd.From.Offset = 1
   727  		movd.To.Type = obj.TYPE_REG
   728  		movd.To.Reg = v.Reg0()
   729  
   730  		// NOP (so the BNE has somewhere to land)
   731  		nop := s.Prog(obj.ANOP)
   732  		gc.Patch(bne, nop)
   733  	case ssa.OpS390XLoweredAtomicExchange32, ssa.OpS390XLoweredAtomicExchange64:
   734  		// Loop until the CS{,G} succeeds.
   735  		//     MOV{WZ,D} arg0, ret
   736  		// cs: CS{,G}    ret, arg1, arg0
   737  		//     BNE       cs
   738  
   739  		// MOV{WZ,D} arg0, ret
   740  		load := s.Prog(loadByType(v.Type.FieldType(0)))
   741  		load.From.Type = obj.TYPE_MEM
   742  		load.From.Reg = v.Args[0].Reg()
   743  		load.To.Type = obj.TYPE_REG
   744  		load.To.Reg = v.Reg0()
   745  		gc.AddAux(&load.From, v)
   746  
   747  		// CS{,G} ret, arg1, arg0
   748  		cs := s.Prog(v.Op.Asm())
   749  		cs.From.Type = obj.TYPE_REG
   750  		cs.From.Reg = v.Reg0()   // old
   751  		cs.Reg = v.Args[1].Reg() // new
   752  		cs.To.Type = obj.TYPE_MEM
   753  		cs.To.Reg = v.Args[0].Reg()
   754  		gc.AddAux(&cs.To, v)
   755  
   756  		// BNE cs
   757  		bne := s.Prog(s390x.ABNE)
   758  		bne.To.Type = obj.TYPE_BRANCH
   759  		gc.Patch(bne, cs)
   760  	case ssa.OpClobber:
   761  		// TODO: implement for clobberdead experiment. Nop is ok for now.
   762  	default:
   763  		v.Fatalf("genValue not implemented: %s", v.LongString())
   764  	}
   765  }
   766  
   767  var blockJump = [...]struct {
   768  	asm, invasm obj.As
   769  }{
   770  	ssa.BlockS390XEQ:  {s390x.ABEQ, s390x.ABNE},
   771  	ssa.BlockS390XNE:  {s390x.ABNE, s390x.ABEQ},
   772  	ssa.BlockS390XLT:  {s390x.ABLT, s390x.ABGE},
   773  	ssa.BlockS390XGE:  {s390x.ABGE, s390x.ABLT},
   774  	ssa.BlockS390XLE:  {s390x.ABLE, s390x.ABGT},
   775  	ssa.BlockS390XGT:  {s390x.ABGT, s390x.ABLE},
   776  	ssa.BlockS390XGTF: {s390x.ABGT, s390x.ABLEU},
   777  	ssa.BlockS390XGEF: {s390x.ABGE, s390x.ABLTU},
   778  }
   779  
   780  func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
   781  	switch b.Kind {
   782  	case ssa.BlockPlain:
   783  		if b.Succs[0].Block() != next {
   784  			p := s.Prog(s390x.ABR)
   785  			p.To.Type = obj.TYPE_BRANCH
   786  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   787  		}
   788  	case ssa.BlockDefer:
   789  		// defer returns in R3:
   790  		// 0 if we should continue executing
   791  		// 1 if we should jump to deferreturn call
   792  		p := s.Prog(s390x.ACMPW)
   793  		p.From.Type = obj.TYPE_REG
   794  		p.From.Reg = s390x.REG_R3
   795  		p.To.Type = obj.TYPE_CONST
   796  		p.To.Offset = 0
   797  		p = s.Prog(s390x.ABNE)
   798  		p.To.Type = obj.TYPE_BRANCH
   799  		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   800  		if b.Succs[0].Block() != next {
   801  			p := s.Prog(s390x.ABR)
   802  			p.To.Type = obj.TYPE_BRANCH
   803  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   804  		}
   805  	case ssa.BlockExit:
   806  		s.Prog(obj.AUNDEF) // tell plive.go that we never reach here
   807  	case ssa.BlockRet:
   808  		s.Prog(obj.ARET)
   809  	case ssa.BlockRetJmp:
   810  		p := s.Prog(s390x.ABR)
   811  		p.To.Type = obj.TYPE_MEM
   812  		p.To.Name = obj.NAME_EXTERN
   813  		p.To.Sym = b.Aux.(*obj.LSym)
   814  	case ssa.BlockS390XEQ, ssa.BlockS390XNE,
   815  		ssa.BlockS390XLT, ssa.BlockS390XGE,
   816  		ssa.BlockS390XLE, ssa.BlockS390XGT,
   817  		ssa.BlockS390XGEF, ssa.BlockS390XGTF:
   818  		jmp := blockJump[b.Kind]
   819  		var p *obj.Prog
   820  		switch next {
   821  		case b.Succs[0].Block():
   822  			p = s.Prog(jmp.invasm)
   823  			p.To.Type = obj.TYPE_BRANCH
   824  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
   825  		case b.Succs[1].Block():
   826  			p = s.Prog(jmp.asm)
   827  			p.To.Type = obj.TYPE_BRANCH
   828  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   829  		default:
   830  			p = s.Prog(jmp.asm)
   831  			p.To.Type = obj.TYPE_BRANCH
   832  			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
   833  			q := s.Prog(s390x.ABR)
   834  			q.To.Type = obj.TYPE_BRANCH
   835  			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
   836  		}
   837  	default:
   838  		b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
   839  	}
   840  }