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

View as plain text