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

View as plain text