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

View as plain text