Source file src/cmd/compile/internal/ppc64/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 ppc64
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  	"cmd/compile/internal/logopt"
    11  	"cmd/compile/internal/objw"
    12  	"cmd/compile/internal/ssa"
    13  	"cmd/compile/internal/ssagen"
    14  	"cmd/compile/internal/types"
    15  	"cmd/internal/obj"
    16  	"cmd/internal/obj/ppc64"
    17  	"internal/buildcfg"
    18  	"math"
    19  	"strings"
    20  )
    21  
    22  // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
    23  func ssaMarkMoves(s *ssagen.State, b *ssa.Block) {
    24  	//	flive := b.FlagsLiveAtEnd
    25  	//	if b.Control != nil && b.Control.Type.IsFlags() {
    26  	//		flive = true
    27  	//	}
    28  	//	for i := len(b.Values) - 1; i >= 0; i-- {
    29  	//		v := b.Values[i]
    30  	//		if flive && (v.Op == v.Op == ssa.OpPPC64MOVDconst) {
    31  	//			// The "mark" is any non-nil Aux value.
    32  	//			v.Aux = v
    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 ppc64.AFMOVS
    51  		case 8:
    52  			return ppc64.AFMOVD
    53  		}
    54  	} else {
    55  		switch t.Size() {
    56  		case 1:
    57  			if t.IsSigned() {
    58  				return ppc64.AMOVB
    59  			} else {
    60  				return ppc64.AMOVBZ
    61  			}
    62  		case 2:
    63  			if t.IsSigned() {
    64  				return ppc64.AMOVH
    65  			} else {
    66  				return ppc64.AMOVHZ
    67  			}
    68  		case 4:
    69  			if t.IsSigned() {
    70  				return ppc64.AMOVW
    71  			} else {
    72  				return ppc64.AMOVWZ
    73  			}
    74  		case 8:
    75  			return ppc64.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  	if t.IsFloat() {
    84  		switch t.Size() {
    85  		case 4:
    86  			return ppc64.AFMOVS
    87  		case 8:
    88  			return ppc64.AFMOVD
    89  		}
    90  	} else {
    91  		switch t.Size() {
    92  		case 1:
    93  			return ppc64.AMOVB
    94  		case 2:
    95  			return ppc64.AMOVH
    96  		case 4:
    97  			return ppc64.AMOVW
    98  		case 8:
    99  			return ppc64.AMOVD
   100  		}
   101  	}
   102  	panic("bad store type")
   103  }
   104  
   105  func ssaGenValue(s *ssagen.State, v *ssa.Value) {
   106  	switch v.Op {
   107  	case ssa.OpCopy:
   108  		t := v.Type
   109  		if t.IsMemory() {
   110  			return
   111  		}
   112  		x := v.Args[0].Reg()
   113  		y := v.Reg()
   114  		if x != y {
   115  			rt := obj.TYPE_REG
   116  			op := ppc64.AMOVD
   117  
   118  			if t.IsFloat() {
   119  				op = ppc64.AFMOVD
   120  			}
   121  			p := s.Prog(op)
   122  			p.From.Type = rt
   123  			p.From.Reg = x
   124  			p.To.Type = rt
   125  			p.To.Reg = y
   126  		}
   127  
   128  	case ssa.OpPPC64LoweredMuluhilo:
   129  		// MULHDU	Rarg1, Rarg0, Reg0
   130  		// MULLD	Rarg1, Rarg0, Reg1
   131  		r0 := v.Args[0].Reg()
   132  		r1 := v.Args[1].Reg()
   133  		p := s.Prog(ppc64.AMULHDU)
   134  		p.From.Type = obj.TYPE_REG
   135  		p.From.Reg = r1
   136  		p.Reg = r0
   137  		p.To.Type = obj.TYPE_REG
   138  		p.To.Reg = v.Reg0()
   139  		p1 := s.Prog(ppc64.AMULLD)
   140  		p1.From.Type = obj.TYPE_REG
   141  		p1.From.Reg = r1
   142  		p1.Reg = r0
   143  		p1.To.Type = obj.TYPE_REG
   144  		p1.To.Reg = v.Reg1()
   145  
   146  	case ssa.OpPPC64LoweredAdd64Carry:
   147  		// ADDC		Rarg2, -1, Rtmp
   148  		// ADDE		Rarg1, Rarg0, Reg0
   149  		// ADDZE	Rzero, Reg1
   150  		r0 := v.Args[0].Reg()
   151  		r1 := v.Args[1].Reg()
   152  		r2 := v.Args[2].Reg()
   153  		p := s.Prog(ppc64.AADDC)
   154  		p.From.Type = obj.TYPE_CONST
   155  		p.From.Offset = -1
   156  		p.Reg = r2
   157  		p.To.Type = obj.TYPE_REG
   158  		p.To.Reg = ppc64.REGTMP
   159  		p1 := s.Prog(ppc64.AADDE)
   160  		p1.From.Type = obj.TYPE_REG
   161  		p1.From.Reg = r1
   162  		p1.Reg = r0
   163  		p1.To.Type = obj.TYPE_REG
   164  		p1.To.Reg = v.Reg0()
   165  		p2 := s.Prog(ppc64.AADDZE)
   166  		p2.From.Type = obj.TYPE_REG
   167  		p2.From.Reg = ppc64.REGZERO
   168  		p2.To.Type = obj.TYPE_REG
   169  		p2.To.Reg = v.Reg1()
   170  
   171  	case ssa.OpPPC64LoweredAtomicAnd8,
   172  		ssa.OpPPC64LoweredAtomicAnd32,
   173  		ssa.OpPPC64LoweredAtomicOr8,
   174  		ssa.OpPPC64LoweredAtomicOr32:
   175  		// LWSYNC
   176  		// LBAR/LWAR	(Rarg0), Rtmp
   177  		// AND/OR	Rarg1, Rtmp
   178  		// STBCCC/STWCCC Rtmp, (Rarg0)
   179  		// BNE		-3(PC)
   180  		ld := ppc64.ALBAR
   181  		st := ppc64.ASTBCCC
   182  		if v.Op == ssa.OpPPC64LoweredAtomicAnd32 || v.Op == ssa.OpPPC64LoweredAtomicOr32 {
   183  			ld = ppc64.ALWAR
   184  			st = ppc64.ASTWCCC
   185  		}
   186  		r0 := v.Args[0].Reg()
   187  		r1 := v.Args[1].Reg()
   188  		// LWSYNC - Assuming shared data not write-through-required nor
   189  		// caching-inhibited. See Appendix B.2.2.2 in the ISA 2.07b.
   190  		plwsync := s.Prog(ppc64.ALWSYNC)
   191  		plwsync.To.Type = obj.TYPE_NONE
   192  		// LBAR or LWAR
   193  		p := s.Prog(ld)
   194  		p.From.Type = obj.TYPE_MEM
   195  		p.From.Reg = r0
   196  		p.To.Type = obj.TYPE_REG
   197  		p.To.Reg = ppc64.REGTMP
   198  		// AND/OR reg1,out
   199  		p1 := s.Prog(v.Op.Asm())
   200  		p1.From.Type = obj.TYPE_REG
   201  		p1.From.Reg = r1
   202  		p1.To.Type = obj.TYPE_REG
   203  		p1.To.Reg = ppc64.REGTMP
   204  		// STBCCC or STWCCC
   205  		p2 := s.Prog(st)
   206  		p2.From.Type = obj.TYPE_REG
   207  		p2.From.Reg = ppc64.REGTMP
   208  		p2.To.Type = obj.TYPE_MEM
   209  		p2.To.Reg = r0
   210  		p2.RegTo2 = ppc64.REGTMP
   211  		// BNE retry
   212  		p3 := s.Prog(ppc64.ABNE)
   213  		p3.To.Type = obj.TYPE_BRANCH
   214  		p3.To.SetTarget(p)
   215  
   216  	case ssa.OpPPC64LoweredAtomicAdd32,
   217  		ssa.OpPPC64LoweredAtomicAdd64:
   218  		// LWSYNC
   219  		// LDAR/LWAR    (Rarg0), Rout
   220  		// ADD		Rarg1, Rout
   221  		// STDCCC/STWCCC Rout, (Rarg0)
   222  		// BNE         -3(PC)
   223  		// MOVW		Rout,Rout (if Add32)
   224  		ld := ppc64.ALDAR
   225  		st := ppc64.ASTDCCC
   226  		if v.Op == ssa.OpPPC64LoweredAtomicAdd32 {
   227  			ld = ppc64.ALWAR
   228  			st = ppc64.ASTWCCC
   229  		}
   230  		r0 := v.Args[0].Reg()
   231  		r1 := v.Args[1].Reg()
   232  		out := v.Reg0()
   233  		// LWSYNC - Assuming shared data not write-through-required nor
   234  		// caching-inhibited. See Appendix B.2.2.2 in the ISA 2.07b.
   235  		plwsync := s.Prog(ppc64.ALWSYNC)
   236  		plwsync.To.Type = obj.TYPE_NONE
   237  		// LDAR or LWAR
   238  		p := s.Prog(ld)
   239  		p.From.Type = obj.TYPE_MEM
   240  		p.From.Reg = r0
   241  		p.To.Type = obj.TYPE_REG
   242  		p.To.Reg = out
   243  		// ADD reg1,out
   244  		p1 := s.Prog(ppc64.AADD)
   245  		p1.From.Type = obj.TYPE_REG
   246  		p1.From.Reg = r1
   247  		p1.To.Reg = out
   248  		p1.To.Type = obj.TYPE_REG
   249  		// STDCCC or STWCCC
   250  		p3 := s.Prog(st)
   251  		p3.From.Type = obj.TYPE_REG
   252  		p3.From.Reg = out
   253  		p3.To.Type = obj.TYPE_MEM
   254  		p3.To.Reg = r0
   255  		// BNE retry
   256  		p4 := s.Prog(ppc64.ABNE)
   257  		p4.To.Type = obj.TYPE_BRANCH
   258  		p4.To.SetTarget(p)
   259  
   260  		// Ensure a 32 bit result
   261  		if v.Op == ssa.OpPPC64LoweredAtomicAdd32 {
   262  			p5 := s.Prog(ppc64.AMOVWZ)
   263  			p5.To.Type = obj.TYPE_REG
   264  			p5.To.Reg = out
   265  			p5.From.Type = obj.TYPE_REG
   266  			p5.From.Reg = out
   267  		}
   268  
   269  	case ssa.OpPPC64LoweredAtomicExchange32,
   270  		ssa.OpPPC64LoweredAtomicExchange64:
   271  		// LWSYNC
   272  		// LDAR/LWAR    (Rarg0), Rout
   273  		// STDCCC/STWCCC Rout, (Rarg0)
   274  		// BNE         -2(PC)
   275  		// ISYNC
   276  		ld := ppc64.ALDAR
   277  		st := ppc64.ASTDCCC
   278  		if v.Op == ssa.OpPPC64LoweredAtomicExchange32 {
   279  			ld = ppc64.ALWAR
   280  			st = ppc64.ASTWCCC
   281  		}
   282  		r0 := v.Args[0].Reg()
   283  		r1 := v.Args[1].Reg()
   284  		out := v.Reg0()
   285  		// LWSYNC - Assuming shared data not write-through-required nor
   286  		// caching-inhibited. See Appendix B.2.2.2 in the ISA 2.07b.
   287  		plwsync := s.Prog(ppc64.ALWSYNC)
   288  		plwsync.To.Type = obj.TYPE_NONE
   289  		// LDAR or LWAR
   290  		p := s.Prog(ld)
   291  		p.From.Type = obj.TYPE_MEM
   292  		p.From.Reg = r0
   293  		p.To.Type = obj.TYPE_REG
   294  		p.To.Reg = out
   295  		// STDCCC or STWCCC
   296  		p1 := s.Prog(st)
   297  		p1.From.Type = obj.TYPE_REG
   298  		p1.From.Reg = r1
   299  		p1.To.Type = obj.TYPE_MEM
   300  		p1.To.Reg = r0
   301  		// BNE retry
   302  		p2 := s.Prog(ppc64.ABNE)
   303  		p2.To.Type = obj.TYPE_BRANCH
   304  		p2.To.SetTarget(p)
   305  		// ISYNC
   306  		pisync := s.Prog(ppc64.AISYNC)
   307  		pisync.To.Type = obj.TYPE_NONE
   308  
   309  	case ssa.OpPPC64LoweredAtomicLoad8,
   310  		ssa.OpPPC64LoweredAtomicLoad32,
   311  		ssa.OpPPC64LoweredAtomicLoad64,
   312  		ssa.OpPPC64LoweredAtomicLoadPtr:
   313  		// SYNC
   314  		// MOVB/MOVD/MOVW (Rarg0), Rout
   315  		// CMP Rout,Rout
   316  		// BNE 1(PC)
   317  		// ISYNC
   318  		ld := ppc64.AMOVD
   319  		cmp := ppc64.ACMP
   320  		switch v.Op {
   321  		case ssa.OpPPC64LoweredAtomicLoad8:
   322  			ld = ppc64.AMOVBZ
   323  		case ssa.OpPPC64LoweredAtomicLoad32:
   324  			ld = ppc64.AMOVWZ
   325  			cmp = ppc64.ACMPW
   326  		}
   327  		arg0 := v.Args[0].Reg()
   328  		out := v.Reg0()
   329  		// SYNC when AuxInt == 1; otherwise, load-acquire
   330  		if v.AuxInt == 1 {
   331  			psync := s.Prog(ppc64.ASYNC)
   332  			psync.To.Type = obj.TYPE_NONE
   333  		}
   334  		// Load
   335  		p := s.Prog(ld)
   336  		p.From.Type = obj.TYPE_MEM
   337  		p.From.Reg = arg0
   338  		p.To.Type = obj.TYPE_REG
   339  		p.To.Reg = out
   340  		// CMP
   341  		p1 := s.Prog(cmp)
   342  		p1.From.Type = obj.TYPE_REG
   343  		p1.From.Reg = out
   344  		p1.To.Type = obj.TYPE_REG
   345  		p1.To.Reg = out
   346  		// BNE
   347  		p2 := s.Prog(ppc64.ABNE)
   348  		p2.To.Type = obj.TYPE_BRANCH
   349  		// ISYNC
   350  		pisync := s.Prog(ppc64.AISYNC)
   351  		pisync.To.Type = obj.TYPE_NONE
   352  		p2.To.SetTarget(pisync)
   353  
   354  	case ssa.OpPPC64LoweredAtomicStore8,
   355  		ssa.OpPPC64LoweredAtomicStore32,
   356  		ssa.OpPPC64LoweredAtomicStore64:
   357  		// SYNC or LWSYNC
   358  		// MOVB/MOVW/MOVD arg1,(arg0)
   359  		st := ppc64.AMOVD
   360  		switch v.Op {
   361  		case ssa.OpPPC64LoweredAtomicStore8:
   362  			st = ppc64.AMOVB
   363  		case ssa.OpPPC64LoweredAtomicStore32:
   364  			st = ppc64.AMOVW
   365  		}
   366  		arg0 := v.Args[0].Reg()
   367  		arg1 := v.Args[1].Reg()
   368  		// If AuxInt == 0, LWSYNC (Store-Release), else SYNC
   369  		// SYNC
   370  		syncOp := ppc64.ASYNC
   371  		if v.AuxInt == 0 {
   372  			syncOp = ppc64.ALWSYNC
   373  		}
   374  		psync := s.Prog(syncOp)
   375  		psync.To.Type = obj.TYPE_NONE
   376  		// Store
   377  		p := s.Prog(st)
   378  		p.To.Type = obj.TYPE_MEM
   379  		p.To.Reg = arg0
   380  		p.From.Type = obj.TYPE_REG
   381  		p.From.Reg = arg1
   382  
   383  	case ssa.OpPPC64LoweredAtomicCas64,
   384  		ssa.OpPPC64LoweredAtomicCas32:
   385  		// LWSYNC
   386  		// loop:
   387  		// LDAR        (Rarg0), MutexHint, Rtmp
   388  		// CMP         Rarg1, Rtmp
   389  		// BNE         fail
   390  		// STDCCC      Rarg2, (Rarg0)
   391  		// BNE         loop
   392  		// LWSYNC      // Only for sequential consistency; not required in CasRel.
   393  		// MOVD        $1, Rout
   394  		// BR          end
   395  		// fail:
   396  		// MOVD        $0, Rout
   397  		// end:
   398  		ld := ppc64.ALDAR
   399  		st := ppc64.ASTDCCC
   400  		cmp := ppc64.ACMP
   401  		if v.Op == ssa.OpPPC64LoweredAtomicCas32 {
   402  			ld = ppc64.ALWAR
   403  			st = ppc64.ASTWCCC
   404  			cmp = ppc64.ACMPW
   405  		}
   406  		r0 := v.Args[0].Reg()
   407  		r1 := v.Args[1].Reg()
   408  		r2 := v.Args[2].Reg()
   409  		out := v.Reg0()
   410  		// LWSYNC - Assuming shared data not write-through-required nor
   411  		// caching-inhibited. See Appendix B.2.2.2 in the ISA 2.07b.
   412  		plwsync1 := s.Prog(ppc64.ALWSYNC)
   413  		plwsync1.To.Type = obj.TYPE_NONE
   414  		// LDAR or LWAR
   415  		p := s.Prog(ld)
   416  		p.From.Type = obj.TYPE_MEM
   417  		p.From.Reg = r0
   418  		p.To.Type = obj.TYPE_REG
   419  		p.To.Reg = ppc64.REGTMP
   420  		// If it is a Compare-and-Swap-Release operation, set the EH field with
   421  		// the release hint.
   422  		if v.AuxInt == 0 {
   423  			p.SetFrom3Const(0)
   424  		}
   425  		// CMP reg1,reg2
   426  		p1 := s.Prog(cmp)
   427  		p1.From.Type = obj.TYPE_REG
   428  		p1.From.Reg = r1
   429  		p1.To.Reg = ppc64.REGTMP
   430  		p1.To.Type = obj.TYPE_REG
   431  		// BNE cas_fail
   432  		p2 := s.Prog(ppc64.ABNE)
   433  		p2.To.Type = obj.TYPE_BRANCH
   434  		// STDCCC or STWCCC
   435  		p3 := s.Prog(st)
   436  		p3.From.Type = obj.TYPE_REG
   437  		p3.From.Reg = r2
   438  		p3.To.Type = obj.TYPE_MEM
   439  		p3.To.Reg = r0
   440  		// BNE retry
   441  		p4 := s.Prog(ppc64.ABNE)
   442  		p4.To.Type = obj.TYPE_BRANCH
   443  		p4.To.SetTarget(p)
   444  		// LWSYNC - Assuming shared data not write-through-required nor
   445  		// caching-inhibited. See Appendix B.2.1.1 in the ISA 2.07b.
   446  		// If the operation is a CAS-Release, then synchronization is not necessary.
   447  		if v.AuxInt != 0 {
   448  			plwsync2 := s.Prog(ppc64.ALWSYNC)
   449  			plwsync2.To.Type = obj.TYPE_NONE
   450  		}
   451  		// return true
   452  		p5 := s.Prog(ppc64.AMOVD)
   453  		p5.From.Type = obj.TYPE_CONST
   454  		p5.From.Offset = 1
   455  		p5.To.Type = obj.TYPE_REG
   456  		p5.To.Reg = out
   457  		// BR done
   458  		p6 := s.Prog(obj.AJMP)
   459  		p6.To.Type = obj.TYPE_BRANCH
   460  		// return false
   461  		p7 := s.Prog(ppc64.AMOVD)
   462  		p7.From.Type = obj.TYPE_CONST
   463  		p7.From.Offset = 0
   464  		p7.To.Type = obj.TYPE_REG
   465  		p7.To.Reg = out
   466  		p2.To.SetTarget(p7)
   467  		// done (label)
   468  		p8 := s.Prog(obj.ANOP)
   469  		p6.To.SetTarget(p8)
   470  
   471  	case ssa.OpPPC64LoweredGetClosurePtr:
   472  		// Closure pointer is R11 (already)
   473  		ssagen.CheckLoweredGetClosurePtr(v)
   474  
   475  	case ssa.OpPPC64LoweredGetCallerSP:
   476  		// caller's SP is FixedFrameSize below the address of the first arg
   477  		p := s.Prog(ppc64.AMOVD)
   478  		p.From.Type = obj.TYPE_ADDR
   479  		p.From.Offset = -base.Ctxt.FixedFrameSize()
   480  		p.From.Name = obj.NAME_PARAM
   481  		p.To.Type = obj.TYPE_REG
   482  		p.To.Reg = v.Reg()
   483  
   484  	case ssa.OpPPC64LoweredGetCallerPC:
   485  		p := s.Prog(obj.AGETCALLERPC)
   486  		p.To.Type = obj.TYPE_REG
   487  		p.To.Reg = v.Reg()
   488  
   489  	case ssa.OpPPC64LoweredRound32F, ssa.OpPPC64LoweredRound64F:
   490  		// input is already rounded
   491  
   492  	case ssa.OpLoadReg:
   493  		loadOp := loadByType(v.Type)
   494  		p := s.Prog(loadOp)
   495  		ssagen.AddrAuto(&p.From, v.Args[0])
   496  		p.To.Type = obj.TYPE_REG
   497  		p.To.Reg = v.Reg()
   498  
   499  	case ssa.OpStoreReg:
   500  		storeOp := storeByType(v.Type)
   501  		p := s.Prog(storeOp)
   502  		p.From.Type = obj.TYPE_REG
   503  		p.From.Reg = v.Args[0].Reg()
   504  		ssagen.AddrAuto(&p.To, v)
   505  
   506  	case ssa.OpArgIntReg, ssa.OpArgFloatReg:
   507  		// The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill
   508  		// The loop only runs once.
   509  		for _, a := range v.Block.Func.RegArgs {
   510  			// Pass the spill/unspill information along to the assembler, offset by size of
   511  			// the saved LR slot.
   512  			addr := ssagen.SpillSlotAddr(a, ppc64.REGSP, base.Ctxt.FixedFrameSize())
   513  			s.FuncInfo().AddSpill(
   514  				obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)})
   515  		}
   516  		v.Block.Func.RegArgs = nil
   517  
   518  		ssagen.CheckArgReg(v)
   519  
   520  	case ssa.OpPPC64DIVD:
   521  		// For now,
   522  		//
   523  		// cmp arg1, -1
   524  		// be  ahead
   525  		// v = arg0 / arg1
   526  		// b over
   527  		// ahead: v = - arg0
   528  		// over: nop
   529  		r := v.Reg()
   530  		r0 := v.Args[0].Reg()
   531  		r1 := v.Args[1].Reg()
   532  
   533  		p := s.Prog(ppc64.ACMP)
   534  		p.From.Type = obj.TYPE_REG
   535  		p.From.Reg = r1
   536  		p.To.Type = obj.TYPE_CONST
   537  		p.To.Offset = -1
   538  
   539  		pbahead := s.Prog(ppc64.ABEQ)
   540  		pbahead.To.Type = obj.TYPE_BRANCH
   541  
   542  		p = s.Prog(v.Op.Asm())
   543  		p.From.Type = obj.TYPE_REG
   544  		p.From.Reg = r1
   545  		p.Reg = r0
   546  		p.To.Type = obj.TYPE_REG
   547  		p.To.Reg = r
   548  
   549  		pbover := s.Prog(obj.AJMP)
   550  		pbover.To.Type = obj.TYPE_BRANCH
   551  
   552  		p = s.Prog(ppc64.ANEG)
   553  		p.To.Type = obj.TYPE_REG
   554  		p.To.Reg = r
   555  		p.From.Type = obj.TYPE_REG
   556  		p.From.Reg = r0
   557  		pbahead.To.SetTarget(p)
   558  
   559  		p = s.Prog(obj.ANOP)
   560  		pbover.To.SetTarget(p)
   561  
   562  	case ssa.OpPPC64DIVW:
   563  		// word-width version of above
   564  		r := v.Reg()
   565  		r0 := v.Args[0].Reg()
   566  		r1 := v.Args[1].Reg()
   567  
   568  		p := s.Prog(ppc64.ACMPW)
   569  		p.From.Type = obj.TYPE_REG
   570  		p.From.Reg = r1
   571  		p.To.Type = obj.TYPE_CONST
   572  		p.To.Offset = -1
   573  
   574  		pbahead := s.Prog(ppc64.ABEQ)
   575  		pbahead.To.Type = obj.TYPE_BRANCH
   576  
   577  		p = s.Prog(v.Op.Asm())
   578  		p.From.Type = obj.TYPE_REG
   579  		p.From.Reg = r1
   580  		p.Reg = r0
   581  		p.To.Type = obj.TYPE_REG
   582  		p.To.Reg = r
   583  
   584  		pbover := s.Prog(obj.AJMP)
   585  		pbover.To.Type = obj.TYPE_BRANCH
   586  
   587  		p = s.Prog(ppc64.ANEG)
   588  		p.To.Type = obj.TYPE_REG
   589  		p.To.Reg = r
   590  		p.From.Type = obj.TYPE_REG
   591  		p.From.Reg = r0
   592  		pbahead.To.SetTarget(p)
   593  
   594  		p = s.Prog(obj.ANOP)
   595  		pbover.To.SetTarget(p)
   596  
   597  	case ssa.OpPPC64CLRLSLWI:
   598  		r := v.Reg()
   599  		r1 := v.Args[0].Reg()
   600  		shifts := v.AuxInt
   601  		p := s.Prog(v.Op.Asm())
   602  		// clrlslwi ra,rs,mb,sh will become rlwinm ra,rs,sh,mb-sh,31-sh as described in ISA
   603  		p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)}
   604  		p.SetFrom3Const(ssa.GetPPC64Shiftsh(shifts))
   605  		p.Reg = r1
   606  		p.To.Type = obj.TYPE_REG
   607  		p.To.Reg = r
   608  
   609  	case ssa.OpPPC64CLRLSLDI:
   610  		r := v.Reg()
   611  		r1 := v.Args[0].Reg()
   612  		shifts := v.AuxInt
   613  		p := s.Prog(v.Op.Asm())
   614  		// clrlsldi ra,rs,mb,sh will become rldic ra,rs,sh,mb-sh
   615  		p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)}
   616  		p.SetFrom3Const(ssa.GetPPC64Shiftsh(shifts))
   617  		p.Reg = r1
   618  		p.To.Type = obj.TYPE_REG
   619  		p.To.Reg = r
   620  
   621  		// Mask has been set as sh
   622  	case ssa.OpPPC64RLDICL:
   623  		r := v.Reg()
   624  		r1 := v.Args[0].Reg()
   625  		shifts := v.AuxInt
   626  		p := s.Prog(v.Op.Asm())
   627  		p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)}
   628  		p.SetFrom3Const(ssa.GetPPC64Shiftmb(shifts))
   629  		p.Reg = r1
   630  		p.To.Type = obj.TYPE_REG
   631  		p.To.Reg = r
   632  
   633  	case ssa.OpPPC64ADD, ssa.OpPPC64FADD, ssa.OpPPC64FADDS, ssa.OpPPC64SUB, ssa.OpPPC64FSUB, ssa.OpPPC64FSUBS,
   634  		ssa.OpPPC64MULLD, ssa.OpPPC64MULLW, ssa.OpPPC64DIVDU, ssa.OpPPC64DIVWU,
   635  		ssa.OpPPC64SRAD, ssa.OpPPC64SRAW, ssa.OpPPC64SRD, ssa.OpPPC64SRW, ssa.OpPPC64SLD, ssa.OpPPC64SLW,
   636  		ssa.OpPPC64ROTL, ssa.OpPPC64ROTLW,
   637  		ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU,
   638  		ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS, ssa.OpPPC64FCPSGN,
   639  		ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64EQV,
   640  		ssa.OpPPC64MODUD, ssa.OpPPC64MODSD, ssa.OpPPC64MODUW, ssa.OpPPC64MODSW:
   641  		r := v.Reg()
   642  		r1 := v.Args[0].Reg()
   643  		r2 := v.Args[1].Reg()
   644  		p := s.Prog(v.Op.Asm())
   645  		p.From.Type = obj.TYPE_REG
   646  		p.From.Reg = r2
   647  		p.Reg = r1
   648  		p.To.Type = obj.TYPE_REG
   649  		p.To.Reg = r
   650  
   651  	case ssa.OpPPC64ANDCC, ssa.OpPPC64ORCC, ssa.OpPPC64XORCC:
   652  		r1 := v.Args[0].Reg()
   653  		r2 := v.Args[1].Reg()
   654  		p := s.Prog(v.Op.Asm())
   655  		p.From.Type = obj.TYPE_REG
   656  		p.From.Reg = r2
   657  		p.Reg = r1
   658  		p.To.Type = obj.TYPE_REG
   659  		p.To.Reg = ppc64.REGTMP // result is not needed
   660  
   661  	case ssa.OpPPC64ROTLconst, ssa.OpPPC64ROTLWconst:
   662  		p := s.Prog(v.Op.Asm())
   663  		p.From.Type = obj.TYPE_CONST
   664  		p.From.Offset = v.AuxInt
   665  		p.Reg = v.Args[0].Reg()
   666  		p.To.Type = obj.TYPE_REG
   667  		p.To.Reg = v.Reg()
   668  
   669  		// Auxint holds encoded rotate + mask
   670  	case ssa.OpPPC64RLWINM, ssa.OpPPC64RLWMI:
   671  		rot, mb, me, _ := ssa.DecodePPC64RotateMask(v.AuxInt)
   672  		p := s.Prog(v.Op.Asm())
   673  		p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()}
   674  		p.Reg = v.Args[0].Reg()
   675  		p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(rot)}
   676  		p.SetRestArgs([]obj.Addr{{Type: obj.TYPE_CONST, Offset: mb}, {Type: obj.TYPE_CONST, Offset: me}})
   677  
   678  		// Auxint holds mask
   679  	case ssa.OpPPC64RLWNM:
   680  		_, mb, me, _ := ssa.DecodePPC64RotateMask(v.AuxInt)
   681  		p := s.Prog(v.Op.Asm())
   682  		p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()}
   683  		p.Reg = v.Args[0].Reg()
   684  		p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[1].Reg()}
   685  		p.SetRestArgs([]obj.Addr{{Type: obj.TYPE_CONST, Offset: mb}, {Type: obj.TYPE_CONST, Offset: me}})
   686  
   687  	case ssa.OpPPC64MADDLD:
   688  		r := v.Reg()
   689  		r1 := v.Args[0].Reg()
   690  		r2 := v.Args[1].Reg()
   691  		r3 := v.Args[2].Reg()
   692  		// r = r1*r2 ± r3
   693  		p := s.Prog(v.Op.Asm())
   694  		p.From.Type = obj.TYPE_REG
   695  		p.From.Reg = r1
   696  		p.Reg = r2
   697  		p.SetFrom3Reg(r3)
   698  		p.To.Type = obj.TYPE_REG
   699  		p.To.Reg = r
   700  
   701  	case ssa.OpPPC64FMADD, ssa.OpPPC64FMADDS, ssa.OpPPC64FMSUB, ssa.OpPPC64FMSUBS:
   702  		r := v.Reg()
   703  		r1 := v.Args[0].Reg()
   704  		r2 := v.Args[1].Reg()
   705  		r3 := v.Args[2].Reg()
   706  		// r = r1*r2 ± r3
   707  		p := s.Prog(v.Op.Asm())
   708  		p.From.Type = obj.TYPE_REG
   709  		p.From.Reg = r1
   710  		p.Reg = r3
   711  		p.SetFrom3Reg(r2)
   712  		p.To.Type = obj.TYPE_REG
   713  		p.To.Reg = r
   714  
   715  	case ssa.OpPPC64NEG, ssa.OpPPC64FNEG, ssa.OpPPC64FSQRT, ssa.OpPPC64FSQRTS, ssa.OpPPC64FFLOOR, ssa.OpPPC64FTRUNC, ssa.OpPPC64FCEIL,
   716  		ssa.OpPPC64FCTIDZ, ssa.OpPPC64FCTIWZ, ssa.OpPPC64FCFID, ssa.OpPPC64FCFIDS, ssa.OpPPC64FRSP, ssa.OpPPC64CNTLZD, ssa.OpPPC64CNTLZW,
   717  		ssa.OpPPC64POPCNTD, ssa.OpPPC64POPCNTW, ssa.OpPPC64POPCNTB, ssa.OpPPC64MFVSRD, ssa.OpPPC64MTVSRD, ssa.OpPPC64FABS, ssa.OpPPC64FNABS,
   718  		ssa.OpPPC64FROUND, ssa.OpPPC64CNTTZW, ssa.OpPPC64CNTTZD:
   719  		r := v.Reg()
   720  		p := s.Prog(v.Op.Asm())
   721  		p.To.Type = obj.TYPE_REG
   722  		p.To.Reg = r
   723  		p.From.Type = obj.TYPE_REG
   724  		p.From.Reg = v.Args[0].Reg()
   725  
   726  	case ssa.OpPPC64ADDconst, ssa.OpPPC64ANDconst, ssa.OpPPC64ORconst, ssa.OpPPC64XORconst,
   727  		ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst,
   728  		ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst, ssa.OpPPC64EXTSWSLconst, ssa.OpPPC64MULLWconst, ssa.OpPPC64MULLDconst:
   729  		p := s.Prog(v.Op.Asm())
   730  		p.Reg = v.Args[0].Reg()
   731  		p.From.Type = obj.TYPE_CONST
   732  		p.From.Offset = v.AuxInt
   733  		p.To.Type = obj.TYPE_REG
   734  		p.To.Reg = v.Reg()
   735  
   736  	case ssa.OpPPC64SUBFCconst:
   737  		p := s.Prog(v.Op.Asm())
   738  		p.SetFrom3Const(v.AuxInt)
   739  		p.From.Type = obj.TYPE_REG
   740  		p.From.Reg = v.Args[0].Reg()
   741  		p.To.Type = obj.TYPE_REG
   742  		p.To.Reg = v.Reg()
   743  
   744  	case ssa.OpPPC64ANDCCconst:
   745  		p := s.Prog(v.Op.Asm())
   746  		p.Reg = v.Args[0].Reg()
   747  		p.From.Type = obj.TYPE_CONST
   748  		p.From.Offset = v.AuxInt
   749  		p.To.Type = obj.TYPE_REG
   750  		p.To.Reg = ppc64.REGTMP // discard result
   751  
   752  	case ssa.OpPPC64MOVDaddr:
   753  		switch v.Aux.(type) {
   754  		default:
   755  			v.Fatalf("aux in MOVDaddr is of unknown type %T", v.Aux)
   756  		case nil:
   757  			// If aux offset and aux int are both 0, and the same
   758  			// input and output regs are used, no instruction
   759  			// needs to be generated, since it would just be
   760  			// addi rx, rx, 0.
   761  			if v.AuxInt != 0 || v.Args[0].Reg() != v.Reg() {
   762  				p := s.Prog(ppc64.AMOVD)
   763  				p.From.Type = obj.TYPE_ADDR
   764  				p.From.Reg = v.Args[0].Reg()
   765  				p.From.Offset = v.AuxInt
   766  				p.To.Type = obj.TYPE_REG
   767  				p.To.Reg = v.Reg()
   768  			}
   769  
   770  		case *obj.LSym, ir.Node:
   771  			p := s.Prog(ppc64.AMOVD)
   772  			p.From.Type = obj.TYPE_ADDR
   773  			p.From.Reg = v.Args[0].Reg()
   774  			p.To.Type = obj.TYPE_REG
   775  			p.To.Reg = v.Reg()
   776  			ssagen.AddAux(&p.From, v)
   777  
   778  		}
   779  
   780  	case ssa.OpPPC64MOVDconst:
   781  		p := s.Prog(v.Op.Asm())
   782  		p.From.Type = obj.TYPE_CONST
   783  		p.From.Offset = v.AuxInt
   784  		p.To.Type = obj.TYPE_REG
   785  		p.To.Reg = v.Reg()
   786  
   787  	case ssa.OpPPC64FMOVDconst, ssa.OpPPC64FMOVSconst:
   788  		p := s.Prog(v.Op.Asm())
   789  		p.From.Type = obj.TYPE_FCONST
   790  		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
   791  		p.To.Type = obj.TYPE_REG
   792  		p.To.Reg = v.Reg()
   793  
   794  	case ssa.OpPPC64FCMPU, ssa.OpPPC64CMP, ssa.OpPPC64CMPW, ssa.OpPPC64CMPU, ssa.OpPPC64CMPWU:
   795  		p := s.Prog(v.Op.Asm())
   796  		p.From.Type = obj.TYPE_REG
   797  		p.From.Reg = v.Args[0].Reg()
   798  		p.To.Type = obj.TYPE_REG
   799  		p.To.Reg = v.Args[1].Reg()
   800  
   801  	case ssa.OpPPC64CMPconst, ssa.OpPPC64CMPUconst, ssa.OpPPC64CMPWconst, ssa.OpPPC64CMPWUconst:
   802  		p := s.Prog(v.Op.Asm())
   803  		p.From.Type = obj.TYPE_REG
   804  		p.From.Reg = v.Args[0].Reg()
   805  		p.To.Type = obj.TYPE_CONST
   806  		p.To.Offset = v.AuxInt
   807  
   808  	case ssa.OpPPC64MOVBreg, ssa.OpPPC64MOVBZreg, ssa.OpPPC64MOVHreg, ssa.OpPPC64MOVHZreg, ssa.OpPPC64MOVWreg, ssa.OpPPC64MOVWZreg:
   809  		// Shift in register to required size
   810  		p := s.Prog(v.Op.Asm())
   811  		p.From.Type = obj.TYPE_REG
   812  		p.From.Reg = v.Args[0].Reg()
   813  		p.To.Reg = v.Reg()
   814  		p.To.Type = obj.TYPE_REG
   815  
   816  	case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload:
   817  
   818  		// MOVDload and MOVWload are DS form instructions that are restricted to
   819  		// offsets that are a multiple of 4. If the offset is not a multple of 4,
   820  		// then the address of the symbol to be loaded is computed (base + offset)
   821  		// and used as the new base register and the offset field in the instruction
   822  		// can be set to zero.
   823  
   824  		// This same problem can happen with gostrings since the final offset is not
   825  		// known yet, but could be unaligned after the relocation is resolved.
   826  		// So gostrings are handled the same way.
   827  
   828  		// This allows the MOVDload and MOVWload to be generated in more cases and
   829  		// eliminates some offset and alignment checking in the rules file.
   830  
   831  		fromAddr := obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[0].Reg()}
   832  		ssagen.AddAux(&fromAddr, v)
   833  
   834  		genAddr := false
   835  
   836  		switch fromAddr.Name {
   837  		case obj.NAME_EXTERN, obj.NAME_STATIC:
   838  			// Special case for a rule combines the bytes of gostring.
   839  			// The v alignment might seem OK, but we don't want to load it
   840  			// using an offset because relocation comes later.
   841  			genAddr = strings.HasPrefix(fromAddr.Sym.Name, "go.string") || v.Type.Alignment()%4 != 0 || fromAddr.Offset%4 != 0
   842  		default:
   843  			genAddr = fromAddr.Offset%4 != 0
   844  		}
   845  		if genAddr {
   846  			// Load full address into the temp register.
   847  			p := s.Prog(ppc64.AMOVD)
   848  			p.From.Type = obj.TYPE_ADDR
   849  			p.From.Reg = v.Args[0].Reg()
   850  			ssagen.AddAux(&p.From, v)
   851  			// Load target using temp as base register
   852  			// and offset zero. Setting NAME_NONE
   853  			// prevents any extra offsets from being
   854  			// added.
   855  			p.To.Type = obj.TYPE_REG
   856  			p.To.Reg = ppc64.REGTMP
   857  			fromAddr.Reg = ppc64.REGTMP
   858  			// Clear the offset field and other
   859  			// information that might be used
   860  			// by the assembler to add to the
   861  			// final offset value.
   862  			fromAddr.Offset = 0
   863  			fromAddr.Name = obj.NAME_NONE
   864  			fromAddr.Sym = nil
   865  		}
   866  		p := s.Prog(v.Op.Asm())
   867  		p.From = fromAddr
   868  		p.To.Type = obj.TYPE_REG
   869  		p.To.Reg = v.Reg()
   870  		break
   871  
   872  	case ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload, ssa.OpPPC64FMOVDload, ssa.OpPPC64FMOVSload:
   873  		p := s.Prog(v.Op.Asm())
   874  		p.From.Type = obj.TYPE_MEM
   875  		p.From.Reg = v.Args[0].Reg()
   876  		ssagen.AddAux(&p.From, v)
   877  		p.To.Type = obj.TYPE_REG
   878  		p.To.Reg = v.Reg()
   879  
   880  	case ssa.OpPPC64MOVDBRload, ssa.OpPPC64MOVWBRload, ssa.OpPPC64MOVHBRload:
   881  		p := s.Prog(v.Op.Asm())
   882  		p.From.Type = obj.TYPE_MEM
   883  		p.From.Reg = v.Args[0].Reg()
   884  		p.To.Type = obj.TYPE_REG
   885  		p.To.Reg = v.Reg()
   886  
   887  	case ssa.OpPPC64MOVDBRstore, ssa.OpPPC64MOVWBRstore, ssa.OpPPC64MOVHBRstore:
   888  		p := s.Prog(v.Op.Asm())
   889  		p.To.Type = obj.TYPE_MEM
   890  		p.To.Reg = v.Args[0].Reg()
   891  		p.From.Type = obj.TYPE_REG
   892  		p.From.Reg = v.Args[1].Reg()
   893  
   894  	case ssa.OpPPC64MOVDloadidx, ssa.OpPPC64MOVWloadidx, ssa.OpPPC64MOVHloadidx, ssa.OpPPC64MOVWZloadidx,
   895  		ssa.OpPPC64MOVBZloadidx, ssa.OpPPC64MOVHZloadidx, ssa.OpPPC64FMOVDloadidx, ssa.OpPPC64FMOVSloadidx,
   896  		ssa.OpPPC64MOVDBRloadidx, ssa.OpPPC64MOVWBRloadidx, ssa.OpPPC64MOVHBRloadidx:
   897  		p := s.Prog(v.Op.Asm())
   898  		p.From.Type = obj.TYPE_MEM
   899  		p.From.Reg = v.Args[0].Reg()
   900  		p.From.Index = v.Args[1].Reg()
   901  		p.To.Type = obj.TYPE_REG
   902  		p.To.Reg = v.Reg()
   903  
   904  	case ssa.OpPPC64DCBT:
   905  		p := s.Prog(v.Op.Asm())
   906  		p.From.Type = obj.TYPE_MEM
   907  		p.From.Reg = v.Args[0].Reg()
   908  		p.To.Type = obj.TYPE_CONST
   909  		p.To.Offset = v.AuxInt
   910  
   911  	case ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero:
   912  		p := s.Prog(v.Op.Asm())
   913  		p.From.Type = obj.TYPE_REG
   914  		p.From.Reg = ppc64.REGZERO
   915  		p.To.Type = obj.TYPE_MEM
   916  		p.To.Reg = v.Args[0].Reg()
   917  		ssagen.AddAux(&p.To, v)
   918  
   919  	case ssa.OpPPC64MOVDstore, ssa.OpPPC64MOVDstorezero:
   920  
   921  		// MOVDstore and MOVDstorezero become DS form instructions that are restricted
   922  		// to offset values that are a multple of 4. If the offset field is not a
   923  		// multiple of 4, then the full address of the store target is computed (base +
   924  		// offset) and used as the new base register and the offset in the instruction
   925  		// is set to 0.
   926  
   927  		// This allows the MOVDstore and MOVDstorezero to be generated in more cases,
   928  		// and prevents checking of the offset value and alignment in the rules.
   929  
   930  		toAddr := obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[0].Reg()}
   931  		ssagen.AddAux(&toAddr, v)
   932  
   933  		if toAddr.Offset%4 != 0 {
   934  			p := s.Prog(ppc64.AMOVD)
   935  			p.From.Type = obj.TYPE_ADDR
   936  			p.From.Reg = v.Args[0].Reg()
   937  			ssagen.AddAux(&p.From, v)
   938  			p.To.Type = obj.TYPE_REG
   939  			p.To.Reg = ppc64.REGTMP
   940  			toAddr.Reg = ppc64.REGTMP
   941  			// Clear the offset field and other
   942  			// information that might be used
   943  			// by the assembler to add to the
   944  			// final offset value.
   945  			toAddr.Offset = 0
   946  			toAddr.Name = obj.NAME_NONE
   947  			toAddr.Sym = nil
   948  		}
   949  		p := s.Prog(v.Op.Asm())
   950  		p.To = toAddr
   951  		p.From.Type = obj.TYPE_REG
   952  		if v.Op == ssa.OpPPC64MOVDstorezero {
   953  			p.From.Reg = ppc64.REGZERO
   954  		} else {
   955  			p.From.Reg = v.Args[1].Reg()
   956  		}
   957  
   958  	case ssa.OpPPC64MOVWstore, ssa.OpPPC64MOVHstore, ssa.OpPPC64MOVBstore, ssa.OpPPC64FMOVDstore, ssa.OpPPC64FMOVSstore:
   959  		p := s.Prog(v.Op.Asm())
   960  		p.From.Type = obj.TYPE_REG
   961  		p.From.Reg = v.Args[1].Reg()
   962  		p.To.Type = obj.TYPE_MEM
   963  		p.To.Reg = v.Args[0].Reg()
   964  		ssagen.AddAux(&p.To, v)
   965  
   966  	case ssa.OpPPC64MOVDstoreidx, ssa.OpPPC64MOVWstoreidx, ssa.OpPPC64MOVHstoreidx, ssa.OpPPC64MOVBstoreidx,
   967  		ssa.OpPPC64FMOVDstoreidx, ssa.OpPPC64FMOVSstoreidx, ssa.OpPPC64MOVDBRstoreidx, ssa.OpPPC64MOVWBRstoreidx,
   968  		ssa.OpPPC64MOVHBRstoreidx:
   969  		p := s.Prog(v.Op.Asm())
   970  		p.From.Type = obj.TYPE_REG
   971  		p.From.Reg = v.Args[2].Reg()
   972  		p.To.Index = v.Args[1].Reg()
   973  		p.To.Type = obj.TYPE_MEM
   974  		p.To.Reg = v.Args[0].Reg()
   975  
   976  	case ssa.OpPPC64ISEL, ssa.OpPPC64ISELB:
   977  		// ISEL, ISELB
   978  		// AuxInt value indicates condition: 0=LT 1=GT 2=EQ 4=GE 5=LE 6=NE
   979  		// ISEL only accepts 0, 1, 2 condition values but the others can be
   980  		// achieved by swapping operand order.
   981  		// arg0 ? arg1 : arg2 with conditions LT, GT, EQ
   982  		// arg0 ? arg2 : arg1 for conditions GE, LE, NE
   983  		// ISELB is used when a boolean result is needed, returning 0 or 1
   984  		p := s.Prog(ppc64.AISEL)
   985  		p.To.Type = obj.TYPE_REG
   986  		p.To.Reg = v.Reg()
   987  		// For ISELB, boolean result 0 or 1. Use R0 for 0 operand to avoid load.
   988  		r := obj.Addr{Type: obj.TYPE_REG, Reg: ppc64.REG_R0}
   989  		if v.Op == ssa.OpPPC64ISEL {
   990  			r.Reg = v.Args[1].Reg()
   991  		}
   992  		// AuxInt values 4,5,6 implemented with reverse operand order from 0,1,2
   993  		if v.AuxInt > 3 {
   994  			p.Reg = r.Reg
   995  			p.SetFrom3Reg(v.Args[0].Reg())
   996  		} else {
   997  			p.Reg = v.Args[0].Reg()
   998  			p.SetFrom3(r)
   999  		}
  1000  		p.From.Type = obj.TYPE_CONST
  1001  		p.From.Offset = v.AuxInt & 3
  1002  
  1003  	case ssa.OpPPC64LoweredQuadZero, ssa.OpPPC64LoweredQuadZeroShort:
  1004  		// The LoweredQuad code generation
  1005  		// generates STXV instructions on
  1006  		// power9. The Short variation is used
  1007  		// if no loop is generated.
  1008  
  1009  		// sizes >= 64 generate a loop as follows:
  1010  
  1011  		// Set up loop counter in CTR, used by BC
  1012  		// XXLXOR clears VS32
  1013  		//       XXLXOR VS32,VS32,VS32
  1014  		//       MOVD len/64,REG_TMP
  1015  		//       MOVD REG_TMP,CTR
  1016  		//       loop:
  1017  		//       STXV VS32,0(R20)
  1018  		//       STXV VS32,16(R20)
  1019  		//       STXV VS32,32(R20)
  1020  		//       STXV VS32,48(R20)
  1021  		//       ADD  $64,R20
  1022  		//       BC   16, 0, loop
  1023  
  1024  		// Bytes per iteration
  1025  		ctr := v.AuxInt / 64
  1026  
  1027  		// Remainder bytes
  1028  		rem := v.AuxInt % 64
  1029  
  1030  		// Only generate a loop if there is more
  1031  		// than 1 iteration.
  1032  		if ctr > 1 {
  1033  			// Set up VS32 (V0) to hold 0s
  1034  			p := s.Prog(ppc64.AXXLXOR)
  1035  			p.From.Type = obj.TYPE_REG
  1036  			p.From.Reg = ppc64.REG_VS32
  1037  			p.To.Type = obj.TYPE_REG
  1038  			p.To.Reg = ppc64.REG_VS32
  1039  			p.Reg = ppc64.REG_VS32
  1040  
  1041  			// Set up CTR loop counter
  1042  			p = s.Prog(ppc64.AMOVD)
  1043  			p.From.Type = obj.TYPE_CONST
  1044  			p.From.Offset = ctr
  1045  			p.To.Type = obj.TYPE_REG
  1046  			p.To.Reg = ppc64.REGTMP
  1047  
  1048  			p = s.Prog(ppc64.AMOVD)
  1049  			p.From.Type = obj.TYPE_REG
  1050  			p.From.Reg = ppc64.REGTMP
  1051  			p.To.Type = obj.TYPE_REG
  1052  			p.To.Reg = ppc64.REG_CTR
  1053  
  1054  			// Don't generate padding for
  1055  			// loops with few iterations.
  1056  			if ctr > 3 {
  1057  				p = s.Prog(obj.APCALIGN)
  1058  				p.From.Type = obj.TYPE_CONST
  1059  				p.From.Offset = 16
  1060  			}
  1061  
  1062  			// generate 4 STXVs to zero 64 bytes
  1063  			var top *obj.Prog
  1064  
  1065  			p = s.Prog(ppc64.ASTXV)
  1066  			p.From.Type = obj.TYPE_REG
  1067  			p.From.Reg = ppc64.REG_VS32
  1068  			p.To.Type = obj.TYPE_MEM
  1069  			p.To.Reg = v.Args[0].Reg()
  1070  
  1071  			//  Save the top of loop
  1072  			if top == nil {
  1073  				top = p
  1074  			}
  1075  			p = s.Prog(ppc64.ASTXV)
  1076  			p.From.Type = obj.TYPE_REG
  1077  			p.From.Reg = ppc64.REG_VS32
  1078  			p.To.Type = obj.TYPE_MEM
  1079  			p.To.Reg = v.Args[0].Reg()
  1080  			p.To.Offset = 16
  1081  
  1082  			p = s.Prog(ppc64.ASTXV)
  1083  			p.From.Type = obj.TYPE_REG
  1084  			p.From.Reg = ppc64.REG_VS32
  1085  			p.To.Type = obj.TYPE_MEM
  1086  			p.To.Reg = v.Args[0].Reg()
  1087  			p.To.Offset = 32
  1088  
  1089  			p = s.Prog(ppc64.ASTXV)
  1090  			p.From.Type = obj.TYPE_REG
  1091  			p.From.Reg = ppc64.REG_VS32
  1092  			p.To.Type = obj.TYPE_MEM
  1093  			p.To.Reg = v.Args[0].Reg()
  1094  			p.To.Offset = 48
  1095  
  1096  			// Increment address for the
  1097  			// 64 bytes just zeroed.
  1098  			p = s.Prog(ppc64.AADD)
  1099  			p.Reg = v.Args[0].Reg()
  1100  			p.From.Type = obj.TYPE_CONST
  1101  			p.From.Offset = 64
  1102  			p.To.Type = obj.TYPE_REG
  1103  			p.To.Reg = v.Args[0].Reg()
  1104  
  1105  			// Branch back to top of loop
  1106  			// based on CTR
  1107  			// BC with BO_BCTR generates bdnz
  1108  			p = s.Prog(ppc64.ABC)
  1109  			p.From.Type = obj.TYPE_CONST
  1110  			p.From.Offset = ppc64.BO_BCTR
  1111  			p.Reg = ppc64.REG_R0
  1112  			p.To.Type = obj.TYPE_BRANCH
  1113  			p.To.SetTarget(top)
  1114  		}
  1115  		// When ctr == 1 the loop was not generated but
  1116  		// there are at least 64 bytes to clear, so add
  1117  		// that to the remainder to generate the code
  1118  		// to clear those doublewords
  1119  		if ctr == 1 {
  1120  			rem += 64
  1121  		}
  1122  
  1123  		// Clear the remainder starting at offset zero
  1124  		offset := int64(0)
  1125  
  1126  		if rem >= 16 && ctr <= 1 {
  1127  			// If the XXLXOR hasn't already been
  1128  			// generated, do it here to initialize
  1129  			// VS32 (V0) to 0.
  1130  			p := s.Prog(ppc64.AXXLXOR)
  1131  			p.From.Type = obj.TYPE_REG
  1132  			p.From.Reg = ppc64.REG_VS32
  1133  			p.To.Type = obj.TYPE_REG
  1134  			p.To.Reg = ppc64.REG_VS32
  1135  			p.Reg = ppc64.REG_VS32
  1136  		}
  1137  		// Generate STXV for 32 or 64
  1138  		// bytes.
  1139  		for rem >= 32 {
  1140  			p := s.Prog(ppc64.ASTXV)
  1141  			p.From.Type = obj.TYPE_REG
  1142  			p.From.Reg = ppc64.REG_VS32
  1143  			p.To.Type = obj.TYPE_MEM
  1144  			p.To.Reg = v.Args[0].Reg()
  1145  			p.To.Offset = offset
  1146  
  1147  			p = s.Prog(ppc64.ASTXV)
  1148  			p.From.Type = obj.TYPE_REG
  1149  			p.From.Reg = ppc64.REG_VS32
  1150  			p.To.Type = obj.TYPE_MEM
  1151  			p.To.Reg = v.Args[0].Reg()
  1152  			p.To.Offset = offset + 16
  1153  			offset += 32
  1154  			rem -= 32
  1155  		}
  1156  		// Generate 16 bytes
  1157  		if rem >= 16 {
  1158  			p := s.Prog(ppc64.ASTXV)
  1159  			p.From.Type = obj.TYPE_REG
  1160  			p.From.Reg = ppc64.REG_VS32
  1161  			p.To.Type = obj.TYPE_MEM
  1162  			p.To.Reg = v.Args[0].Reg()
  1163  			p.To.Offset = offset
  1164  			offset += 16
  1165  			rem -= 16
  1166  		}
  1167  
  1168  		// first clear as many doublewords as possible
  1169  		// then clear remaining sizes as available
  1170  		for rem > 0 {
  1171  			op, size := ppc64.AMOVB, int64(1)
  1172  			switch {
  1173  			case rem >= 8:
  1174  				op, size = ppc64.AMOVD, 8
  1175  			case rem >= 4:
  1176  				op, size = ppc64.AMOVW, 4
  1177  			case rem >= 2:
  1178  				op, size = ppc64.AMOVH, 2
  1179  			}
  1180  			p := s.Prog(op)
  1181  			p.From.Type = obj.TYPE_REG
  1182  			p.From.Reg = ppc64.REG_R0
  1183  			p.To.Type = obj.TYPE_MEM
  1184  			p.To.Reg = v.Args[0].Reg()
  1185  			p.To.Offset = offset
  1186  			rem -= size
  1187  			offset += size
  1188  		}
  1189  
  1190  	case ssa.OpPPC64LoweredZero, ssa.OpPPC64LoweredZeroShort:
  1191  
  1192  		// Unaligned data doesn't hurt performance
  1193  		// for these instructions on power8.
  1194  
  1195  		// For sizes >= 64 generate a loop as follows:
  1196  
  1197  		// Set up loop counter in CTR, used by BC
  1198  		//       XXLXOR VS32,VS32,VS32
  1199  		//	 MOVD len/32,REG_TMP
  1200  		//	 MOVD REG_TMP,CTR
  1201  		//       MOVD $16,REG_TMP
  1202  		//	 loop:
  1203  		//	 STXVD2X VS32,(R0)(R20)
  1204  		//	 STXVD2X VS32,(R31)(R20)
  1205  		//	 ADD  $32,R20
  1206  		//	 BC   16, 0, loop
  1207  		//
  1208  		// any remainder is done as described below
  1209  
  1210  		// for sizes < 64 bytes, first clear as many doublewords as possible,
  1211  		// then handle the remainder
  1212  		//	MOVD R0,(R20)
  1213  		//	MOVD R0,8(R20)
  1214  		// .... etc.
  1215  		//
  1216  		// the remainder bytes are cleared using one or more
  1217  		// of the following instructions with the appropriate
  1218  		// offsets depending which instructions are needed
  1219  		//
  1220  		//	MOVW R0,n1(R20)	4 bytes
  1221  		//	MOVH R0,n2(R20)	2 bytes
  1222  		//	MOVB R0,n3(R20)	1 byte
  1223  		//
  1224  		// 7 bytes: MOVW, MOVH, MOVB
  1225  		// 6 bytes: MOVW, MOVH
  1226  		// 5 bytes: MOVW, MOVB
  1227  		// 3 bytes: MOVH, MOVB
  1228  
  1229  		// each loop iteration does 32 bytes
  1230  		ctr := v.AuxInt / 32
  1231  
  1232  		// remainder bytes
  1233  		rem := v.AuxInt % 32
  1234  
  1235  		// only generate a loop if there is more
  1236  		// than 1 iteration.
  1237  		if ctr > 1 {
  1238  			// Set up VS32 (V0) to hold 0s
  1239  			p := s.Prog(ppc64.AXXLXOR)
  1240  			p.From.Type = obj.TYPE_REG
  1241  			p.From.Reg = ppc64.REG_VS32
  1242  			p.To.Type = obj.TYPE_REG
  1243  			p.To.Reg = ppc64.REG_VS32
  1244  			p.Reg = ppc64.REG_VS32
  1245  
  1246  			// Set up CTR loop counter
  1247  			p = s.Prog(ppc64.AMOVD)
  1248  			p.From.Type = obj.TYPE_CONST
  1249  			p.From.Offset = ctr
  1250  			p.To.Type = obj.TYPE_REG
  1251  			p.To.Reg = ppc64.REGTMP
  1252  
  1253  			p = s.Prog(ppc64.AMOVD)
  1254  			p.From.Type = obj.TYPE_REG
  1255  			p.From.Reg = ppc64.REGTMP
  1256  			p.To.Type = obj.TYPE_REG
  1257  			p.To.Reg = ppc64.REG_CTR
  1258  
  1259  			// Set up R31 to hold index value 16
  1260  			p = s.Prog(ppc64.AMOVD)
  1261  			p.From.Type = obj.TYPE_CONST
  1262  			p.From.Offset = 16
  1263  			p.To.Type = obj.TYPE_REG
  1264  			p.To.Reg = ppc64.REGTMP
  1265  
  1266  			// Don't add padding for alignment
  1267  			// with few loop iterations.
  1268  			if ctr > 3 {
  1269  				p = s.Prog(obj.APCALIGN)
  1270  				p.From.Type = obj.TYPE_CONST
  1271  				p.From.Offset = 16
  1272  			}
  1273  
  1274  			// generate 2 STXVD2Xs to store 16 bytes
  1275  			// when this is a loop then the top must be saved
  1276  			var top *obj.Prog
  1277  			// This is the top of loop
  1278  
  1279  			p = s.Prog(ppc64.ASTXVD2X)
  1280  			p.From.Type = obj.TYPE_REG
  1281  			p.From.Reg = ppc64.REG_VS32
  1282  			p.To.Type = obj.TYPE_MEM
  1283  			p.To.Reg = v.Args[0].Reg()
  1284  			p.To.Index = ppc64.REGZERO
  1285  			// Save the top of loop
  1286  			if top == nil {
  1287  				top = p
  1288  			}
  1289  			p = s.Prog(ppc64.ASTXVD2X)
  1290  			p.From.Type = obj.TYPE_REG
  1291  			p.From.Reg = ppc64.REG_VS32
  1292  			p.To.Type = obj.TYPE_MEM
  1293  			p.To.Reg = v.Args[0].Reg()
  1294  			p.To.Index = ppc64.REGTMP
  1295  
  1296  			// Increment address for the
  1297  			// 4 doublewords just zeroed.
  1298  			p = s.Prog(ppc64.AADD)
  1299  			p.Reg = v.Args[0].Reg()
  1300  			p.From.Type = obj.TYPE_CONST
  1301  			p.From.Offset = 32
  1302  			p.To.Type = obj.TYPE_REG
  1303  			p.To.Reg = v.Args[0].Reg()
  1304  
  1305  			// Branch back to top of loop
  1306  			// based on CTR
  1307  			// BC with BO_BCTR generates bdnz
  1308  			p = s.Prog(ppc64.ABC)
  1309  			p.From.Type = obj.TYPE_CONST
  1310  			p.From.Offset = ppc64.BO_BCTR
  1311  			p.Reg = ppc64.REG_R0
  1312  			p.To.Type = obj.TYPE_BRANCH
  1313  			p.To.SetTarget(top)
  1314  		}
  1315  
  1316  		// when ctr == 1 the loop was not generated but
  1317  		// there are at least 32 bytes to clear, so add
  1318  		// that to the remainder to generate the code
  1319  		// to clear those doublewords
  1320  		if ctr == 1 {
  1321  			rem += 32
  1322  		}
  1323  
  1324  		// clear the remainder starting at offset zero
  1325  		offset := int64(0)
  1326  
  1327  		// first clear as many doublewords as possible
  1328  		// then clear remaining sizes as available
  1329  		for rem > 0 {
  1330  			op, size := ppc64.AMOVB, int64(1)
  1331  			switch {
  1332  			case rem >= 8:
  1333  				op, size = ppc64.AMOVD, 8
  1334  			case rem >= 4:
  1335  				op, size = ppc64.AMOVW, 4
  1336  			case rem >= 2:
  1337  				op, size = ppc64.AMOVH, 2
  1338  			}
  1339  			p := s.Prog(op)
  1340  			p.From.Type = obj.TYPE_REG
  1341  			p.From.Reg = ppc64.REG_R0
  1342  			p.To.Type = obj.TYPE_MEM
  1343  			p.To.Reg = v.Args[0].Reg()
  1344  			p.To.Offset = offset
  1345  			rem -= size
  1346  			offset += size
  1347  		}
  1348  
  1349  	case ssa.OpPPC64LoweredMove, ssa.OpPPC64LoweredMoveShort:
  1350  
  1351  		bytesPerLoop := int64(32)
  1352  		// This will be used when moving more
  1353  		// than 8 bytes.  Moves start with
  1354  		// as many 8 byte moves as possible, then
  1355  		// 4, 2, or 1 byte(s) as remaining.  This will
  1356  		// work and be efficient for power8 or later.
  1357  		// If there are 64 or more bytes, then a
  1358  		// loop is generated to move 32 bytes and
  1359  		// update the src and dst addresses on each
  1360  		// iteration. When < 64 bytes, the appropriate
  1361  		// number of moves are generated based on the
  1362  		// size.
  1363  		// When moving >= 64 bytes a loop is used
  1364  		//	MOVD len/32,REG_TMP
  1365  		//	MOVD REG_TMP,CTR
  1366  		//	MOVD $16,REG_TMP
  1367  		// top:
  1368  		//	LXVD2X (R0)(R21),VS32
  1369  		//	LXVD2X (R31)(R21),VS33
  1370  		//	ADD $32,R21
  1371  		//	STXVD2X VS32,(R0)(R20)
  1372  		//	STXVD2X VS33,(R31)(R20)
  1373  		//	ADD $32,R20
  1374  		//	BC 16,0,top
  1375  		// Bytes not moved by this loop are moved
  1376  		// with a combination of the following instructions,
  1377  		// starting with the largest sizes and generating as
  1378  		// many as needed, using the appropriate offset value.
  1379  		//	MOVD  n(R21),R31
  1380  		//	MOVD  R31,n(R20)
  1381  		//	MOVW  n1(R21),R31
  1382  		//	MOVW  R31,n1(R20)
  1383  		//	MOVH  n2(R21),R31
  1384  		//	MOVH  R31,n2(R20)
  1385  		//	MOVB  n3(R21),R31
  1386  		//	MOVB  R31,n3(R20)
  1387  
  1388  		// Each loop iteration moves 32 bytes
  1389  		ctr := v.AuxInt / bytesPerLoop
  1390  
  1391  		// Remainder after the loop
  1392  		rem := v.AuxInt % bytesPerLoop
  1393  
  1394  		dstReg := v.Args[0].Reg()
  1395  		srcReg := v.Args[1].Reg()
  1396  
  1397  		// The set of registers used here, must match the clobbered reg list
  1398  		// in PPC64Ops.go.
  1399  		offset := int64(0)
  1400  
  1401  		// top of the loop
  1402  		var top *obj.Prog
  1403  		// Only generate looping code when loop counter is > 1 for >= 64 bytes
  1404  		if ctr > 1 {
  1405  			// Set up the CTR
  1406  			p := s.Prog(ppc64.AMOVD)
  1407  			p.From.Type = obj.TYPE_CONST
  1408  			p.From.Offset = ctr
  1409  			p.To.Type = obj.TYPE_REG
  1410  			p.To.Reg = ppc64.REGTMP
  1411  
  1412  			p = s.Prog(ppc64.AMOVD)
  1413  			p.From.Type = obj.TYPE_REG
  1414  			p.From.Reg = ppc64.REGTMP
  1415  			p.To.Type = obj.TYPE_REG
  1416  			p.To.Reg = ppc64.REG_CTR
  1417  
  1418  			// Use REGTMP as index reg
  1419  			p = s.Prog(ppc64.AMOVD)
  1420  			p.From.Type = obj.TYPE_CONST
  1421  			p.From.Offset = 16
  1422  			p.To.Type = obj.TYPE_REG
  1423  			p.To.Reg = ppc64.REGTMP
  1424  
  1425  			// Don't adding padding for
  1426  			// alignment with small iteration
  1427  			// counts.
  1428  			if ctr > 3 {
  1429  				p = s.Prog(obj.APCALIGN)
  1430  				p.From.Type = obj.TYPE_CONST
  1431  				p.From.Offset = 16
  1432  			}
  1433  
  1434  			// Generate 16 byte loads and stores.
  1435  			// Use temp register for index (16)
  1436  			// on the second one.
  1437  
  1438  			p = s.Prog(ppc64.ALXVD2X)
  1439  			p.From.Type = obj.TYPE_MEM
  1440  			p.From.Reg = srcReg
  1441  			p.From.Index = ppc64.REGZERO
  1442  			p.To.Type = obj.TYPE_REG
  1443  			p.To.Reg = ppc64.REG_VS32
  1444  			if top == nil {
  1445  				top = p
  1446  			}
  1447  			p = s.Prog(ppc64.ALXVD2X)
  1448  			p.From.Type = obj.TYPE_MEM
  1449  			p.From.Reg = srcReg
  1450  			p.From.Index = ppc64.REGTMP
  1451  			p.To.Type = obj.TYPE_REG
  1452  			p.To.Reg = ppc64.REG_VS33
  1453  
  1454  			// increment the src reg for next iteration
  1455  			p = s.Prog(ppc64.AADD)
  1456  			p.Reg = srcReg
  1457  			p.From.Type = obj.TYPE_CONST
  1458  			p.From.Offset = bytesPerLoop
  1459  			p.To.Type = obj.TYPE_REG
  1460  			p.To.Reg = srcReg
  1461  
  1462  			// generate 16 byte stores
  1463  			p = s.Prog(ppc64.ASTXVD2X)
  1464  			p.From.Type = obj.TYPE_REG
  1465  			p.From.Reg = ppc64.REG_VS32
  1466  			p.To.Type = obj.TYPE_MEM
  1467  			p.To.Reg = dstReg
  1468  			p.To.Index = ppc64.REGZERO
  1469  
  1470  			p = s.Prog(ppc64.ASTXVD2X)
  1471  			p.From.Type = obj.TYPE_REG
  1472  			p.From.Reg = ppc64.REG_VS33
  1473  			p.To.Type = obj.TYPE_MEM
  1474  			p.To.Reg = dstReg
  1475  			p.To.Index = ppc64.REGTMP
  1476  
  1477  			// increment the dst reg for next iteration
  1478  			p = s.Prog(ppc64.AADD)
  1479  			p.Reg = dstReg
  1480  			p.From.Type = obj.TYPE_CONST
  1481  			p.From.Offset = bytesPerLoop
  1482  			p.To.Type = obj.TYPE_REG
  1483  			p.To.Reg = dstReg
  1484  
  1485  			// BC with BO_BCTR generates bdnz to branch on nonzero CTR
  1486  			// to loop top.
  1487  			p = s.Prog(ppc64.ABC)
  1488  			p.From.Type = obj.TYPE_CONST
  1489  			p.From.Offset = ppc64.BO_BCTR
  1490  			p.Reg = ppc64.REG_R0
  1491  			p.To.Type = obj.TYPE_BRANCH
  1492  			p.To.SetTarget(top)
  1493  
  1494  			// srcReg and dstReg were incremented in the loop, so
  1495  			// later instructions start with offset 0.
  1496  			offset = int64(0)
  1497  		}
  1498  
  1499  		// No loop was generated for one iteration, so
  1500  		// add 32 bytes to the remainder to move those bytes.
  1501  		if ctr == 1 {
  1502  			rem += bytesPerLoop
  1503  		}
  1504  
  1505  		if rem >= 16 {
  1506  			// Generate 16 byte loads and stores.
  1507  			// Use temp register for index (value 16)
  1508  			// on the second one.
  1509  			p := s.Prog(ppc64.ALXVD2X)
  1510  			p.From.Type = obj.TYPE_MEM
  1511  			p.From.Reg = srcReg
  1512  			p.From.Index = ppc64.REGZERO
  1513  			p.To.Type = obj.TYPE_REG
  1514  			p.To.Reg = ppc64.REG_VS32
  1515  
  1516  			p = s.Prog(ppc64.ASTXVD2X)
  1517  			p.From.Type = obj.TYPE_REG
  1518  			p.From.Reg = ppc64.REG_VS32
  1519  			p.To.Type = obj.TYPE_MEM
  1520  			p.To.Reg = dstReg
  1521  			p.To.Index = ppc64.REGZERO
  1522  
  1523  			offset = 16
  1524  			rem -= 16
  1525  
  1526  			if rem >= 16 {
  1527  				// Use REGTMP as index reg
  1528  				p := s.Prog(ppc64.AMOVD)
  1529  				p.From.Type = obj.TYPE_CONST
  1530  				p.From.Offset = 16
  1531  				p.To.Type = obj.TYPE_REG
  1532  				p.To.Reg = ppc64.REGTMP
  1533  
  1534  				p = s.Prog(ppc64.ALXVD2X)
  1535  				p.From.Type = obj.TYPE_MEM
  1536  				p.From.Reg = srcReg
  1537  				p.From.Index = ppc64.REGTMP
  1538  				p.To.Type = obj.TYPE_REG
  1539  				p.To.Reg = ppc64.REG_VS32
  1540  
  1541  				p = s.Prog(ppc64.ASTXVD2X)
  1542  				p.From.Type = obj.TYPE_REG
  1543  				p.From.Reg = ppc64.REG_VS32
  1544  				p.To.Type = obj.TYPE_MEM
  1545  				p.To.Reg = dstReg
  1546  				p.To.Index = ppc64.REGTMP
  1547  
  1548  				offset = 32
  1549  				rem -= 16
  1550  			}
  1551  		}
  1552  
  1553  		// Generate all the remaining load and store pairs, starting with
  1554  		// as many 8 byte moves as possible, then 4, 2, 1.
  1555  		for rem > 0 {
  1556  			op, size := ppc64.AMOVB, int64(1)
  1557  			switch {
  1558  			case rem >= 8:
  1559  				op, size = ppc64.AMOVD, 8
  1560  			case rem >= 4:
  1561  				op, size = ppc64.AMOVWZ, 4
  1562  			case rem >= 2:
  1563  				op, size = ppc64.AMOVH, 2
  1564  			}
  1565  			// Load
  1566  			p := s.Prog(op)
  1567  			p.To.Type = obj.TYPE_REG
  1568  			p.To.Reg = ppc64.REGTMP
  1569  			p.From.Type = obj.TYPE_MEM
  1570  			p.From.Reg = srcReg
  1571  			p.From.Offset = offset
  1572  
  1573  			// Store
  1574  			p = s.Prog(op)
  1575  			p.From.Type = obj.TYPE_REG
  1576  			p.From.Reg = ppc64.REGTMP
  1577  			p.To.Type = obj.TYPE_MEM
  1578  			p.To.Reg = dstReg
  1579  			p.To.Offset = offset
  1580  			rem -= size
  1581  			offset += size
  1582  		}
  1583  
  1584  	case ssa.OpPPC64LoweredQuadMove, ssa.OpPPC64LoweredQuadMoveShort:
  1585  		bytesPerLoop := int64(64)
  1586  		// This is used when moving more
  1587  		// than 8 bytes on power9.  Moves start with
  1588  		// as many 8 byte moves as possible, then
  1589  		// 4, 2, or 1 byte(s) as remaining.  This will
  1590  		// work and be efficient for power8 or later.
  1591  		// If there are 64 or more bytes, then a
  1592  		// loop is generated to move 32 bytes and
  1593  		// update the src and dst addresses on each
  1594  		// iteration. When < 64 bytes, the appropriate
  1595  		// number of moves are generated based on the
  1596  		// size.
  1597  		// When moving >= 64 bytes a loop is used
  1598  		//      MOVD len/32,REG_TMP
  1599  		//      MOVD REG_TMP,CTR
  1600  		// top:
  1601  		//      LXV 0(R21),VS32
  1602  		//      LXV 16(R21),VS33
  1603  		//      ADD $32,R21
  1604  		//      STXV VS32,0(R20)
  1605  		//      STXV VS33,16(R20)
  1606  		//      ADD $32,R20
  1607  		//      BC 16,0,top
  1608  		// Bytes not moved by this loop are moved
  1609  		// with a combination of the following instructions,
  1610  		// starting with the largest sizes and generating as
  1611  		// many as needed, using the appropriate offset value.
  1612  		//      MOVD  n(R21),R31
  1613  		//      MOVD  R31,n(R20)
  1614  		//      MOVW  n1(R21),R31
  1615  		//      MOVW  R31,n1(R20)
  1616  		//      MOVH  n2(R21),R31
  1617  		//      MOVH  R31,n2(R20)
  1618  		//      MOVB  n3(R21),R31
  1619  		//      MOVB  R31,n3(R20)
  1620  
  1621  		// Each loop iteration moves 32 bytes
  1622  		ctr := v.AuxInt / bytesPerLoop
  1623  
  1624  		// Remainder after the loop
  1625  		rem := v.AuxInt % bytesPerLoop
  1626  
  1627  		dstReg := v.Args[0].Reg()
  1628  		srcReg := v.Args[1].Reg()
  1629  
  1630  		offset := int64(0)
  1631  
  1632  		// top of the loop
  1633  		var top *obj.Prog
  1634  
  1635  		// Only generate looping code when loop counter is > 1 for >= 64 bytes
  1636  		if ctr > 1 {
  1637  			// Set up the CTR
  1638  			p := s.Prog(ppc64.AMOVD)
  1639  			p.From.Type = obj.TYPE_CONST
  1640  			p.From.Offset = ctr
  1641  			p.To.Type = obj.TYPE_REG
  1642  			p.To.Reg = ppc64.REGTMP
  1643  
  1644  			p = s.Prog(ppc64.AMOVD)
  1645  			p.From.Type = obj.TYPE_REG
  1646  			p.From.Reg = ppc64.REGTMP
  1647  			p.To.Type = obj.TYPE_REG
  1648  			p.To.Reg = ppc64.REG_CTR
  1649  
  1650  			p = s.Prog(obj.APCALIGN)
  1651  			p.From.Type = obj.TYPE_CONST
  1652  			p.From.Offset = 16
  1653  
  1654  			// Generate 16 byte loads and stores.
  1655  			p = s.Prog(ppc64.ALXV)
  1656  			p.From.Type = obj.TYPE_MEM
  1657  			p.From.Reg = srcReg
  1658  			p.From.Offset = offset
  1659  			p.To.Type = obj.TYPE_REG
  1660  			p.To.Reg = ppc64.REG_VS32
  1661  			if top == nil {
  1662  				top = p
  1663  			}
  1664  			p = s.Prog(ppc64.ALXV)
  1665  			p.From.Type = obj.TYPE_MEM
  1666  			p.From.Reg = srcReg
  1667  			p.From.Offset = offset + 16
  1668  			p.To.Type = obj.TYPE_REG
  1669  			p.To.Reg = ppc64.REG_VS33
  1670  
  1671  			// generate 16 byte stores
  1672  			p = s.Prog(ppc64.ASTXV)
  1673  			p.From.Type = obj.TYPE_REG
  1674  			p.From.Reg = ppc64.REG_VS32
  1675  			p.To.Type = obj.TYPE_MEM
  1676  			p.To.Reg = dstReg
  1677  			p.To.Offset = offset
  1678  
  1679  			p = s.Prog(ppc64.ASTXV)
  1680  			p.From.Type = obj.TYPE_REG
  1681  			p.From.Reg = ppc64.REG_VS33
  1682  			p.To.Type = obj.TYPE_MEM
  1683  			p.To.Reg = dstReg
  1684  			p.To.Offset = offset + 16
  1685  
  1686  			// Generate 16 byte loads and stores.
  1687  			p = s.Prog(ppc64.ALXV)
  1688  			p.From.Type = obj.TYPE_MEM
  1689  			p.From.Reg = srcReg
  1690  			p.From.Offset = offset + 32
  1691  			p.To.Type = obj.TYPE_REG
  1692  			p.To.Reg = ppc64.REG_VS32
  1693  
  1694  			p = s.Prog(ppc64.ALXV)
  1695  			p.From.Type = obj.TYPE_MEM
  1696  			p.From.Reg = srcReg
  1697  			p.From.Offset = offset + 48
  1698  			p.To.Type = obj.TYPE_REG
  1699  			p.To.Reg = ppc64.REG_VS33
  1700  
  1701  			// generate 16 byte stores
  1702  			p = s.Prog(ppc64.ASTXV)
  1703  			p.From.Type = obj.TYPE_REG
  1704  			p.From.Reg = ppc64.REG_VS32
  1705  			p.To.Type = obj.TYPE_MEM
  1706  			p.To.Reg = dstReg
  1707  			p.To.Offset = offset + 32
  1708  
  1709  			p = s.Prog(ppc64.ASTXV)
  1710  			p.From.Type = obj.TYPE_REG
  1711  			p.From.Reg = ppc64.REG_VS33
  1712  			p.To.Type = obj.TYPE_MEM
  1713  			p.To.Reg = dstReg
  1714  			p.To.Offset = offset + 48
  1715  
  1716  			// increment the src reg for next iteration
  1717  			p = s.Prog(ppc64.AADD)
  1718  			p.Reg = srcReg
  1719  			p.From.Type = obj.TYPE_CONST
  1720  			p.From.Offset = bytesPerLoop
  1721  			p.To.Type = obj.TYPE_REG
  1722  			p.To.Reg = srcReg
  1723  
  1724  			// increment the dst reg for next iteration
  1725  			p = s.Prog(ppc64.AADD)
  1726  			p.Reg = dstReg
  1727  			p.From.Type = obj.TYPE_CONST
  1728  			p.From.Offset = bytesPerLoop
  1729  			p.To.Type = obj.TYPE_REG
  1730  			p.To.Reg = dstReg
  1731  
  1732  			// BC with BO_BCTR generates bdnz to branch on nonzero CTR
  1733  			// to loop top.
  1734  			p = s.Prog(ppc64.ABC)
  1735  			p.From.Type = obj.TYPE_CONST
  1736  			p.From.Offset = ppc64.BO_BCTR
  1737  			p.Reg = ppc64.REG_R0
  1738  			p.To.Type = obj.TYPE_BRANCH
  1739  			p.To.SetTarget(top)
  1740  
  1741  			// srcReg and dstReg were incremented in the loop, so
  1742  			// later instructions start with offset 0.
  1743  			offset = int64(0)
  1744  		}
  1745  
  1746  		// No loop was generated for one iteration, so
  1747  		// add 32 bytes to the remainder to move those bytes.
  1748  		if ctr == 1 {
  1749  			rem += bytesPerLoop
  1750  		}
  1751  		if rem >= 32 {
  1752  			p := s.Prog(ppc64.ALXV)
  1753  			p.From.Type = obj.TYPE_MEM
  1754  			p.From.Reg = srcReg
  1755  			p.To.Type = obj.TYPE_REG
  1756  			p.To.Reg = ppc64.REG_VS32
  1757  
  1758  			p = s.Prog(ppc64.ALXV)
  1759  			p.From.Type = obj.TYPE_MEM
  1760  			p.From.Reg = srcReg
  1761  			p.From.Offset = 16
  1762  			p.To.Type = obj.TYPE_REG
  1763  			p.To.Reg = ppc64.REG_VS33
  1764  
  1765  			p = s.Prog(ppc64.ASTXV)
  1766  			p.From.Type = obj.TYPE_REG
  1767  			p.From.Reg = ppc64.REG_VS32
  1768  			p.To.Type = obj.TYPE_MEM
  1769  			p.To.Reg = dstReg
  1770  
  1771  			p = s.Prog(ppc64.ASTXV)
  1772  			p.From.Type = obj.TYPE_REG
  1773  			p.From.Reg = ppc64.REG_VS33
  1774  			p.To.Type = obj.TYPE_MEM
  1775  			p.To.Reg = dstReg
  1776  			p.To.Offset = 16
  1777  
  1778  			offset = 32
  1779  			rem -= 32
  1780  		}
  1781  
  1782  		if rem >= 16 {
  1783  			// Generate 16 byte loads and stores.
  1784  			p := s.Prog(ppc64.ALXV)
  1785  			p.From.Type = obj.TYPE_MEM
  1786  			p.From.Reg = srcReg
  1787  			p.From.Offset = offset
  1788  			p.To.Type = obj.TYPE_REG
  1789  			p.To.Reg = ppc64.REG_VS32
  1790  
  1791  			p = s.Prog(ppc64.ASTXV)
  1792  			p.From.Type = obj.TYPE_REG
  1793  			p.From.Reg = ppc64.REG_VS32
  1794  			p.To.Type = obj.TYPE_MEM
  1795  			p.To.Reg = dstReg
  1796  			p.To.Offset = offset
  1797  
  1798  			offset += 16
  1799  			rem -= 16
  1800  
  1801  			if rem >= 16 {
  1802  				p := s.Prog(ppc64.ALXV)
  1803  				p.From.Type = obj.TYPE_MEM
  1804  				p.From.Reg = srcReg
  1805  				p.From.Offset = offset
  1806  				p.To.Type = obj.TYPE_REG
  1807  				p.To.Reg = ppc64.REG_VS32
  1808  
  1809  				p = s.Prog(ppc64.ASTXV)
  1810  				p.From.Type = obj.TYPE_REG
  1811  				p.From.Reg = ppc64.REG_VS32
  1812  				p.To.Type = obj.TYPE_MEM
  1813  				p.To.Reg = dstReg
  1814  				p.To.Offset = offset
  1815  
  1816  				offset += 16
  1817  				rem -= 16
  1818  			}
  1819  		}
  1820  		// Generate all the remaining load and store pairs, starting with
  1821  		// as many 8 byte moves as possible, then 4, 2, 1.
  1822  		for rem > 0 {
  1823  			op, size := ppc64.AMOVB, int64(1)
  1824  			switch {
  1825  			case rem >= 8:
  1826  				op, size = ppc64.AMOVD, 8
  1827  			case rem >= 4:
  1828  				op, size = ppc64.AMOVWZ, 4
  1829  			case rem >= 2:
  1830  				op, size = ppc64.AMOVH, 2
  1831  			}
  1832  			// Load
  1833  			p := s.Prog(op)
  1834  			p.To.Type = obj.TYPE_REG
  1835  			p.To.Reg = ppc64.REGTMP
  1836  			p.From.Type = obj.TYPE_MEM
  1837  			p.From.Reg = srcReg
  1838  			p.From.Offset = offset
  1839  
  1840  			// Store
  1841  			p = s.Prog(op)
  1842  			p.From.Type = obj.TYPE_REG
  1843  			p.From.Reg = ppc64.REGTMP
  1844  			p.To.Type = obj.TYPE_MEM
  1845  			p.To.Reg = dstReg
  1846  			p.To.Offset = offset
  1847  			rem -= size
  1848  			offset += size
  1849  		}
  1850  
  1851  	case ssa.OpPPC64CALLstatic:
  1852  		s.Call(v)
  1853  
  1854  	case ssa.OpPPC64CALLtail:
  1855  		s.TailCall(v)
  1856  
  1857  	case ssa.OpPPC64CALLclosure, ssa.OpPPC64CALLinter:
  1858  		p := s.Prog(ppc64.AMOVD)
  1859  		p.From.Type = obj.TYPE_REG
  1860  		p.From.Reg = v.Args[0].Reg()
  1861  		p.To.Type = obj.TYPE_REG
  1862  		p.To.Reg = ppc64.REG_LR
  1863  
  1864  		if v.Args[0].Reg() != ppc64.REG_R12 {
  1865  			v.Fatalf("Function address for %v should be in R12 %d but is in %d", v.LongString(), ppc64.REG_R12, p.From.Reg)
  1866  		}
  1867  
  1868  		pp := s.Call(v)
  1869  		pp.To.Reg = ppc64.REG_LR
  1870  
  1871  		// Insert a hint this is not a subroutine return.
  1872  		pp.SetFrom3Const(1)
  1873  
  1874  		if base.Ctxt.Flag_shared {
  1875  			// When compiling Go into PIC, the function we just
  1876  			// called via pointer might have been implemented in
  1877  			// a separate module and so overwritten the TOC
  1878  			// pointer in R2; reload it.
  1879  			q := s.Prog(ppc64.AMOVD)
  1880  			q.From.Type = obj.TYPE_MEM
  1881  			q.From.Offset = 24
  1882  			q.From.Reg = ppc64.REGSP
  1883  			q.To.Type = obj.TYPE_REG
  1884  			q.To.Reg = ppc64.REG_R2
  1885  		}
  1886  
  1887  	case ssa.OpPPC64LoweredWB:
  1888  		p := s.Prog(obj.ACALL)
  1889  		p.To.Type = obj.TYPE_MEM
  1890  		p.To.Name = obj.NAME_EXTERN
  1891  		p.To.Sym = v.Aux.(*obj.LSym)
  1892  
  1893  	case ssa.OpPPC64LoweredPanicBoundsA, ssa.OpPPC64LoweredPanicBoundsB, ssa.OpPPC64LoweredPanicBoundsC:
  1894  		p := s.Prog(obj.ACALL)
  1895  		p.To.Type = obj.TYPE_MEM
  1896  		p.To.Name = obj.NAME_EXTERN
  1897  		p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
  1898  		s.UseArgs(16) // space used in callee args area by assembly stubs
  1899  
  1900  	case ssa.OpPPC64LoweredNilCheck:
  1901  		if buildcfg.GOOS == "aix" {
  1902  			// CMP Rarg0, R0
  1903  			// BNE 2(PC)
  1904  			// STW R0, 0(R0)
  1905  			// NOP (so the BNE has somewhere to land)
  1906  
  1907  			// CMP Rarg0, R0
  1908  			p := s.Prog(ppc64.ACMP)
  1909  			p.From.Type = obj.TYPE_REG
  1910  			p.From.Reg = v.Args[0].Reg()
  1911  			p.To.Type = obj.TYPE_REG
  1912  			p.To.Reg = ppc64.REG_R0
  1913  
  1914  			// BNE 2(PC)
  1915  			p2 := s.Prog(ppc64.ABNE)
  1916  			p2.To.Type = obj.TYPE_BRANCH
  1917  
  1918  			// STW R0, 0(R0)
  1919  			// Write at 0 is forbidden and will trigger a SIGSEGV
  1920  			p = s.Prog(ppc64.AMOVW)
  1921  			p.From.Type = obj.TYPE_REG
  1922  			p.From.Reg = ppc64.REG_R0
  1923  			p.To.Type = obj.TYPE_MEM
  1924  			p.To.Reg = ppc64.REG_R0
  1925  
  1926  			// NOP (so the BNE has somewhere to land)
  1927  			nop := s.Prog(obj.ANOP)
  1928  			p2.To.SetTarget(nop)
  1929  
  1930  		} else {
  1931  			// Issue a load which will fault if arg is nil.
  1932  			p := s.Prog(ppc64.AMOVBZ)
  1933  			p.From.Type = obj.TYPE_MEM
  1934  			p.From.Reg = v.Args[0].Reg()
  1935  			ssagen.AddAux(&p.From, v)
  1936  			p.To.Type = obj.TYPE_REG
  1937  			p.To.Reg = ppc64.REGTMP
  1938  		}
  1939  		if logopt.Enabled() {
  1940  			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
  1941  		}
  1942  		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
  1943  			base.WarnfAt(v.Pos, "generated nil check")
  1944  		}
  1945  
  1946  	// These should be resolved by rules and not make it here.
  1947  	case ssa.OpPPC64Equal, ssa.OpPPC64NotEqual, ssa.OpPPC64LessThan, ssa.OpPPC64FLessThan,
  1948  		ssa.OpPPC64LessEqual, ssa.OpPPC64GreaterThan, ssa.OpPPC64FGreaterThan, ssa.OpPPC64GreaterEqual,
  1949  		ssa.OpPPC64FLessEqual, ssa.OpPPC64FGreaterEqual:
  1950  		v.Fatalf("Pseudo-op should not make it to codegen: %s ###\n", v.LongString())
  1951  	case ssa.OpPPC64InvertFlags:
  1952  		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
  1953  	case ssa.OpPPC64FlagEQ, ssa.OpPPC64FlagLT, ssa.OpPPC64FlagGT:
  1954  		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
  1955  	case ssa.OpClobber, ssa.OpClobberReg:
  1956  		// TODO: implement for clobberdead experiment. Nop is ok for now.
  1957  	default:
  1958  		v.Fatalf("genValue not implemented: %s", v.LongString())
  1959  	}
  1960  }
  1961  
  1962  var blockJump = [...]struct {
  1963  	asm, invasm     obj.As
  1964  	asmeq, invasmun bool
  1965  }{
  1966  	ssa.BlockPPC64EQ: {ppc64.ABEQ, ppc64.ABNE, false, false},
  1967  	ssa.BlockPPC64NE: {ppc64.ABNE, ppc64.ABEQ, false, false},
  1968  
  1969  	ssa.BlockPPC64LT: {ppc64.ABLT, ppc64.ABGE, false, false},
  1970  	ssa.BlockPPC64GE: {ppc64.ABGE, ppc64.ABLT, false, false},
  1971  	ssa.BlockPPC64LE: {ppc64.ABLE, ppc64.ABGT, false, false},
  1972  	ssa.BlockPPC64GT: {ppc64.ABGT, ppc64.ABLE, false, false},
  1973  
  1974  	// TODO: need to work FP comparisons into block jumps
  1975  	ssa.BlockPPC64FLT: {ppc64.ABLT, ppc64.ABGE, false, false},
  1976  	ssa.BlockPPC64FGE: {ppc64.ABGT, ppc64.ABLT, true, true}, // GE = GT or EQ; !GE = LT or UN
  1977  	ssa.BlockPPC64FLE: {ppc64.ABLT, ppc64.ABGT, true, true}, // LE = LT or EQ; !LE = GT or UN
  1978  	ssa.BlockPPC64FGT: {ppc64.ABGT, ppc64.ABLE, false, false},
  1979  }
  1980  
  1981  func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
  1982  	switch b.Kind {
  1983  	case ssa.BlockDefer:
  1984  		// defer returns in R3:
  1985  		// 0 if we should continue executing
  1986  		// 1 if we should jump to deferreturn call
  1987  		p := s.Prog(ppc64.ACMP)
  1988  		p.From.Type = obj.TYPE_REG
  1989  		p.From.Reg = ppc64.REG_R3
  1990  		p.To.Type = obj.TYPE_REG
  1991  		p.To.Reg = ppc64.REG_R0
  1992  
  1993  		p = s.Prog(ppc64.ABNE)
  1994  		p.To.Type = obj.TYPE_BRANCH
  1995  		s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()})
  1996  		if b.Succs[0].Block() != next {
  1997  			p := s.Prog(obj.AJMP)
  1998  			p.To.Type = obj.TYPE_BRANCH
  1999  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
  2000  		}
  2001  
  2002  	case ssa.BlockPlain:
  2003  		if b.Succs[0].Block() != next {
  2004  			p := s.Prog(obj.AJMP)
  2005  			p.To.Type = obj.TYPE_BRANCH
  2006  			s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
  2007  		}
  2008  	case ssa.BlockExit, ssa.BlockRetJmp:
  2009  	case ssa.BlockRet:
  2010  		s.Prog(obj.ARET)
  2011  
  2012  	case ssa.BlockPPC64EQ, ssa.BlockPPC64NE,
  2013  		ssa.BlockPPC64LT, ssa.BlockPPC64GE,
  2014  		ssa.BlockPPC64LE, ssa.BlockPPC64GT,
  2015  		ssa.BlockPPC64FLT, ssa.BlockPPC64FGE,
  2016  		ssa.BlockPPC64FLE, ssa.BlockPPC64FGT:
  2017  		jmp := blockJump[b.Kind]
  2018  		switch next {
  2019  		case b.Succs[0].Block():
  2020  			s.Br(jmp.invasm, b.Succs[1].Block())
  2021  			if jmp.invasmun {
  2022  				// TODO: The second branch is probably predict-not-taken since it is for FP unordered
  2023  				s.Br(ppc64.ABVS, b.Succs[1].Block())
  2024  			}
  2025  		case b.Succs[1].Block():
  2026  			s.Br(jmp.asm, b.Succs[0].Block())
  2027  			if jmp.asmeq {
  2028  				s.Br(ppc64.ABEQ, b.Succs[0].Block())
  2029  			}
  2030  		default:
  2031  			if b.Likely != ssa.BranchUnlikely {
  2032  				s.Br(jmp.asm, b.Succs[0].Block())
  2033  				if jmp.asmeq {
  2034  					s.Br(ppc64.ABEQ, b.Succs[0].Block())
  2035  				}
  2036  				s.Br(obj.AJMP, b.Succs[1].Block())
  2037  			} else {
  2038  				s.Br(jmp.invasm, b.Succs[1].Block())
  2039  				if jmp.invasmun {
  2040  					// TODO: The second branch is probably predict-not-taken since it is for FP unordered
  2041  					s.Br(ppc64.ABVS, b.Succs[1].Block())
  2042  				}
  2043  				s.Br(obj.AJMP, b.Succs[0].Block())
  2044  			}
  2045  		}
  2046  	default:
  2047  		b.Fatalf("branch not implemented: %s", b.LongString())
  2048  	}
  2049  }
  2050  
  2051  func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
  2052  	p := s.Prog(loadByType(t))
  2053  	p.From.Type = obj.TYPE_MEM
  2054  	p.From.Name = obj.NAME_AUTO
  2055  	p.From.Sym = n.Linksym()
  2056  	p.From.Offset = n.FrameOffset() + off
  2057  	p.To.Type = obj.TYPE_REG
  2058  	p.To.Reg = reg
  2059  	return p
  2060  }
  2061  
  2062  func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
  2063  	p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off)
  2064  	p.To.Name = obj.NAME_PARAM
  2065  	p.To.Sym = n.Linksym()
  2066  	p.Pos = p.Pos.WithNotStmt()
  2067  	return p
  2068  }
  2069  

View as plain text