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