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

View as plain text