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

View as plain text