Home | History | Annotate | Download | only in ppc64
      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/gc"
      9 	"cmd/compile/internal/ssa"
     10 	"cmd/internal/obj"
     11 	"cmd/internal/obj/ppc64"
     12 	"math"
     13 )
     14 
     15 var condOps = map[ssa.Op]obj.As{
     16 	ssa.OpPPC64Equal:        ppc64.ABEQ,
     17 	ssa.OpPPC64NotEqual:     ppc64.ABNE,
     18 	ssa.OpPPC64LessThan:     ppc64.ABLT,
     19 	ssa.OpPPC64GreaterEqual: ppc64.ABGE,
     20 	ssa.OpPPC64GreaterThan:  ppc64.ABGT,
     21 	ssa.OpPPC64LessEqual:    ppc64.ABLE,
     22 
     23 	ssa.OpPPC64FLessThan:     ppc64.ABLT, // 1 branch for FCMP
     24 	ssa.OpPPC64FGreaterThan:  ppc64.ABGT, // 1 branch for FCMP
     25 	ssa.OpPPC64FLessEqual:    ppc64.ABLT, // 2 branches for FCMP <=, second is BEQ
     26 	ssa.OpPPC64FGreaterEqual: ppc64.ABGT, // 2 branches for FCMP >=, second is BEQ
     27 }
     28 
     29 // iselOp encodes mapping of comparison operations onto ISEL operands
     30 type iselOp struct {
     31 	cond        int64
     32 	valueIfCond int // if cond is true, the value to return (0 or 1)
     33 }
     34 
     35 // Input registers to ISEL used for comparison. Index 0 is zero, 1 is (will be) 1
     36 var iselRegs = [2]int16{ppc64.REG_R0, ppc64.REGTMP}
     37 
     38 var iselOps = map[ssa.Op]iselOp{
     39 	ssa.OpPPC64Equal:         iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 1},
     40 	ssa.OpPPC64NotEqual:      iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 0},
     41 	ssa.OpPPC64LessThan:      iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
     42 	ssa.OpPPC64GreaterEqual:  iselOp{cond: ppc64.C_COND_LT, valueIfCond: 0},
     43 	ssa.OpPPC64GreaterThan:   iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
     44 	ssa.OpPPC64LessEqual:     iselOp{cond: ppc64.C_COND_GT, valueIfCond: 0},
     45 	ssa.OpPPC64FLessThan:     iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
     46 	ssa.OpPPC64FGreaterThan:  iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
     47 	ssa.OpPPC64FLessEqual:    iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
     48 	ssa.OpPPC64FGreaterEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
     49 }
     50 
     51 // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
     52 func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
     53 	//	flive := b.FlagsLiveAtEnd
     54 	//	if b.Control != nil && b.Control.Type.IsFlags() {
     55 	//		flive = true
     56 	//	}
     57 	//	for i := len(b.Values) - 1; i >= 0; i-- {
     58 	//		v := b.Values[i]
     59 	//		if flive && (v.Op == v.Op == ssa.OpPPC64MOVDconst) {
     60 	//			// The "mark" is any non-nil Aux value.
     61 	//			v.Aux = v
     62 	//		}
     63 	//		if v.Type.IsFlags() {
     64 	//			flive = false
     65 	//		}
     66 	//		for _, a := range v.Args {
     67 	//			if a.Type.IsFlags() {
     68 	//				flive = true
     69 	//			}
     70 	//		}
     71 	//	}
     72 }
     73 
     74 // loadByType returns the load instruction of the given type.
     75 func loadByType(t ssa.Type) obj.As {
     76 	if t.IsFloat() {
     77 		switch t.Size() {
     78 		case 4:
     79 			return ppc64.AFMOVS
     80 		case 8:
     81 			return ppc64.AFMOVD
     82 		}
     83 	} else {
     84 		switch t.Size() {
     85 		case 1:
     86 			if t.IsSigned() {
     87 				return ppc64.AMOVB
     88 			} else {
     89 				return ppc64.AMOVBZ
     90 			}
     91 		case 2:
     92 			if t.IsSigned() {
     93 				return ppc64.AMOVH
     94 			} else {
     95 				return ppc64.AMOVHZ
     96 			}
     97 		case 4:
     98 			if t.IsSigned() {
     99 				return ppc64.AMOVW
    100 			} else {
    101 				return ppc64.AMOVWZ
    102 			}
    103 		case 8:
    104 			return ppc64.AMOVD
    105 		}
    106 	}
    107 	panic("bad load type")
    108 }
    109 
    110 // storeByType returns the store instruction of the given type.
    111 func storeByType(t ssa.Type) obj.As {
    112 	if t.IsFloat() {
    113 		switch t.Size() {
    114 		case 4:
    115 			return ppc64.AFMOVS
    116 		case 8:
    117 			return ppc64.AFMOVD
    118 		}
    119 	} else {
    120 		switch t.Size() {
    121 		case 1:
    122 			return ppc64.AMOVB
    123 		case 2:
    124 			return ppc64.AMOVH
    125 		case 4:
    126 			return ppc64.AMOVW
    127 		case 8:
    128 			return ppc64.AMOVD
    129 		}
    130 	}
    131 	panic("bad store type")
    132 }
    133 
    134 func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
    135 	r := v.Reg()
    136 	p := gc.Prog(ppc64.AISEL)
    137 	p.To.Type = obj.TYPE_REG
    138 	p.To.Reg = r
    139 	p.Reg = r1
    140 	p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r2}
    141 	p.From.Type = obj.TYPE_CONST
    142 	p.From.Offset = cr
    143 }
    144 
    145 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
    146 	s.SetLineno(v.Line)
    147 	switch v.Op {
    148 	case ssa.OpInitMem:
    149 		// memory arg needs no code
    150 	case ssa.OpArg:
    151 		// input args need no code
    152 	case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
    153 		// nothing to do
    154 
    155 	case ssa.OpCopy, ssa.OpPPC64MOVDconvert:
    156 		t := v.Type
    157 		if t.IsMemory() {
    158 			return
    159 		}
    160 		x := v.Args[0].Reg()
    161 		y := v.Reg()
    162 		if x != y {
    163 			rt := obj.TYPE_REG
    164 			op := ppc64.AMOVD
    165 
    166 			if t.IsFloat() {
    167 				op = ppc64.AFMOVD
    168 			}
    169 			p := gc.Prog(op)
    170 			p.From.Type = rt
    171 			p.From.Reg = x
    172 			p.To.Type = rt
    173 			p.To.Reg = y
    174 		}
    175 
    176 	case ssa.OpPPC64Xf2i64:
    177 		{
    178 			x := v.Args[0].Reg()
    179 			y := v.Reg()
    180 			p := gc.Prog(ppc64.AFMOVD)
    181 			p.From.Type = obj.TYPE_REG
    182 			p.From.Reg = x
    183 			s.AddrScratch(&p.To)
    184 			p = gc.Prog(ppc64.AMOVD)
    185 			p.To.Type = obj.TYPE_REG
    186 			p.To.Reg = y
    187 			s.AddrScratch(&p.From)
    188 		}
    189 	case ssa.OpPPC64Xi2f64:
    190 		{
    191 			x := v.Args[0].Reg()
    192 			y := v.Reg()
    193 			p := gc.Prog(ppc64.AMOVD)
    194 			p.From.Type = obj.TYPE_REG
    195 			p.From.Reg = x
    196 			s.AddrScratch(&p.To)
    197 			p = gc.Prog(ppc64.AFMOVD)
    198 			p.To.Type = obj.TYPE_REG
    199 			p.To.Reg = y
    200 			s.AddrScratch(&p.From)
    201 		}
    202 
    203 	case ssa.OpPPC64LoweredGetClosurePtr:
    204 		// Closure pointer is R11 (already)
    205 		gc.CheckLoweredGetClosurePtr(v)
    206 
    207 	case ssa.OpLoadReg:
    208 		loadOp := loadByType(v.Type)
    209 		p := gc.Prog(loadOp)
    210 		gc.AddrAuto(&p.From, v.Args[0])
    211 		p.To.Type = obj.TYPE_REG
    212 		p.To.Reg = v.Reg()
    213 
    214 	case ssa.OpStoreReg:
    215 		storeOp := storeByType(v.Type)
    216 		p := gc.Prog(storeOp)
    217 		p.From.Type = obj.TYPE_REG
    218 		p.From.Reg = v.Args[0].Reg()
    219 		gc.AddrAuto(&p.To, v)
    220 
    221 	case ssa.OpPPC64DIVD:
    222 		// For now,
    223 		//
    224 		// cmp arg1, -1
    225 		// be  ahead
    226 		// v = arg0 / arg1
    227 		// b over
    228 		// ahead: v = - arg0
    229 		// over: nop
    230 		r := v.Reg()
    231 		r0 := v.Args[0].Reg()
    232 		r1 := v.Args[1].Reg()
    233 
    234 		p := gc.Prog(ppc64.ACMP)
    235 		p.From.Type = obj.TYPE_REG
    236 		p.From.Reg = r1
    237 		p.To.Type = obj.TYPE_CONST
    238 		p.To.Offset = -1
    239 
    240 		pbahead := gc.Prog(ppc64.ABEQ)
    241 		pbahead.To.Type = obj.TYPE_BRANCH
    242 
    243 		p = gc.Prog(v.Op.Asm())
    244 		p.From.Type = obj.TYPE_REG
    245 		p.From.Reg = r1
    246 		p.Reg = r0
    247 		p.To.Type = obj.TYPE_REG
    248 		p.To.Reg = r
    249 
    250 		pbover := gc.Prog(obj.AJMP)
    251 		pbover.To.Type = obj.TYPE_BRANCH
    252 
    253 		p = gc.Prog(ppc64.ANEG)
    254 		p.To.Type = obj.TYPE_REG
    255 		p.To.Reg = r
    256 		p.From.Type = obj.TYPE_REG
    257 		p.From.Reg = r0
    258 		gc.Patch(pbahead, p)
    259 
    260 		p = gc.Prog(obj.ANOP)
    261 		gc.Patch(pbover, p)
    262 
    263 	case ssa.OpPPC64DIVW:
    264 		// word-width version of above
    265 		r := v.Reg()
    266 		r0 := v.Args[0].Reg()
    267 		r1 := v.Args[1].Reg()
    268 
    269 		p := gc.Prog(ppc64.ACMPW)
    270 		p.From.Type = obj.TYPE_REG
    271 		p.From.Reg = r1
    272 		p.To.Type = obj.TYPE_CONST
    273 		p.To.Offset = -1
    274 
    275 		pbahead := gc.Prog(ppc64.ABEQ)
    276 		pbahead.To.Type = obj.TYPE_BRANCH
    277 
    278 		p = gc.Prog(v.Op.Asm())
    279 		p.From.Type = obj.TYPE_REG
    280 		p.From.Reg = r1
    281 		p.Reg = r0
    282 		p.To.Type = obj.TYPE_REG
    283 		p.To.Reg = r
    284 
    285 		pbover := gc.Prog(obj.AJMP)
    286 		pbover.To.Type = obj.TYPE_BRANCH
    287 
    288 		p = gc.Prog(ppc64.ANEG)
    289 		p.To.Type = obj.TYPE_REG
    290 		p.To.Reg = r
    291 		p.From.Type = obj.TYPE_REG
    292 		p.From.Reg = r0
    293 		gc.Patch(pbahead, p)
    294 
    295 		p = gc.Prog(obj.ANOP)
    296 		gc.Patch(pbover, p)
    297 
    298 	case ssa.OpPPC64ADD, ssa.OpPPC64FADD, ssa.OpPPC64FADDS, ssa.OpPPC64SUB, ssa.OpPPC64FSUB, ssa.OpPPC64FSUBS,
    299 		ssa.OpPPC64MULLD, ssa.OpPPC64MULLW, ssa.OpPPC64DIVDU, ssa.OpPPC64DIVWU,
    300 		ssa.OpPPC64SRAD, ssa.OpPPC64SRAW, ssa.OpPPC64SRD, ssa.OpPPC64SRW, ssa.OpPPC64SLD, ssa.OpPPC64SLW,
    301 		ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU,
    302 		ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS,
    303 		ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64XOR, ssa.OpPPC64EQV:
    304 		r := v.Reg()
    305 		r1 := v.Args[0].Reg()
    306 		r2 := v.Args[1].Reg()
    307 		p := gc.Prog(v.Op.Asm())
    308 		p.From.Type = obj.TYPE_REG
    309 		p.From.Reg = r2
    310 		p.Reg = r1
    311 		p.To.Type = obj.TYPE_REG
    312 		p.To.Reg = r
    313 
    314 	case ssa.OpPPC64MaskIfNotCarry:
    315 		r := v.Reg()
    316 		p := gc.Prog(v.Op.Asm())
    317 		p.From.Type = obj.TYPE_REG
    318 		p.From.Reg = ppc64.REGZERO
    319 		p.To.Type = obj.TYPE_REG
    320 		p.To.Reg = r
    321 
    322 	case ssa.OpPPC64ADDconstForCarry:
    323 		r1 := v.Args[0].Reg()
    324 		p := gc.Prog(v.Op.Asm())
    325 		p.Reg = r1
    326 		p.From.Type = obj.TYPE_CONST
    327 		p.From.Offset = v.AuxInt
    328 		p.To.Type = obj.TYPE_REG
    329 		p.To.Reg = ppc64.REGTMP // Ignored; this is for the carry effect.
    330 
    331 	case ssa.OpPPC64NEG, ssa.OpPPC64FNEG, ssa.OpPPC64FSQRT, ssa.OpPPC64FSQRTS, ssa.OpPPC64FCTIDZ, ssa.OpPPC64FCTIWZ, ssa.OpPPC64FCFID, ssa.OpPPC64FRSP:
    332 		r := v.Reg()
    333 		p := gc.Prog(v.Op.Asm())
    334 		p.To.Type = obj.TYPE_REG
    335 		p.To.Reg = r
    336 		p.From.Type = obj.TYPE_REG
    337 		p.From.Reg = v.Args[0].Reg()
    338 
    339 	case ssa.OpPPC64ADDconst, ssa.OpPPC64ANDconst, ssa.OpPPC64ORconst, ssa.OpPPC64XORconst,
    340 		ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst, ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst:
    341 		p := gc.Prog(v.Op.Asm())
    342 		p.Reg = v.Args[0].Reg()
    343 
    344 		if v.Aux != nil {
    345 			p.From.Type = obj.TYPE_CONST
    346 			p.From.Offset = gc.AuxOffset(v)
    347 		} else {
    348 			p.From.Type = obj.TYPE_CONST
    349 			p.From.Offset = v.AuxInt
    350 		}
    351 
    352 		p.To.Type = obj.TYPE_REG
    353 		p.To.Reg = v.Reg()
    354 
    355 	case ssa.OpPPC64ANDCCconst:
    356 		p := gc.Prog(v.Op.Asm())
    357 		p.Reg = v.Args[0].Reg()
    358 
    359 		if v.Aux != nil {
    360 			p.From.Type = obj.TYPE_CONST
    361 			p.From.Offset = gc.AuxOffset(v)
    362 		} else {
    363 			p.From.Type = obj.TYPE_CONST
    364 			p.From.Offset = v.AuxInt
    365 		}
    366 
    367 		p.To.Type = obj.TYPE_REG
    368 		p.To.Reg = ppc64.REGTMP // discard result
    369 
    370 	case ssa.OpPPC64MOVDaddr:
    371 		p := gc.Prog(ppc64.AMOVD)
    372 		p.From.Type = obj.TYPE_ADDR
    373 		p.To.Type = obj.TYPE_REG
    374 		p.To.Reg = v.Reg()
    375 
    376 		var wantreg string
    377 		// Suspect comment, copied from ARM code
    378 		// MOVD $sym+off(base), R
    379 		// the assembler expands it as the following:
    380 		// - base is SP: add constant offset to SP
    381 		//               when constant is large, tmp register (R11) may be used
    382 		// - base is SB: load external address from constant pool (use relocation)
    383 		switch v.Aux.(type) {
    384 		default:
    385 			v.Fatalf("aux is of unknown type %T", v.Aux)
    386 		case *ssa.ExternSymbol:
    387 			wantreg = "SB"
    388 			gc.AddAux(&p.From, v)
    389 		case *ssa.ArgSymbol, *ssa.AutoSymbol:
    390 			wantreg = "SP"
    391 			gc.AddAux(&p.From, v)
    392 		case nil:
    393 			// No sym, just MOVD $off(SP), R
    394 			wantreg = "SP"
    395 			p.From.Reg = ppc64.REGSP
    396 			p.From.Offset = v.AuxInt
    397 		}
    398 		if reg := v.Args[0].RegName(); reg != wantreg {
    399 			v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
    400 		}
    401 
    402 	case ssa.OpPPC64MOVDconst:
    403 		p := gc.Prog(v.Op.Asm())
    404 		p.From.Type = obj.TYPE_CONST
    405 		p.From.Offset = v.AuxInt
    406 		p.To.Type = obj.TYPE_REG
    407 		p.To.Reg = v.Reg()
    408 
    409 	case ssa.OpPPC64FMOVDconst, ssa.OpPPC64FMOVSconst:
    410 		p := gc.Prog(v.Op.Asm())
    411 		p.From.Type = obj.TYPE_FCONST
    412 		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
    413 		p.To.Type = obj.TYPE_REG
    414 		p.To.Reg = v.Reg()
    415 
    416 	case ssa.OpPPC64FCMPU, ssa.OpPPC64CMP, ssa.OpPPC64CMPW, ssa.OpPPC64CMPU, ssa.OpPPC64CMPWU:
    417 		p := gc.Prog(v.Op.Asm())
    418 		p.From.Type = obj.TYPE_REG
    419 		p.From.Reg = v.Args[0].Reg()
    420 		p.To.Type = obj.TYPE_REG
    421 		p.To.Reg = v.Args[1].Reg()
    422 
    423 	case ssa.OpPPC64CMPconst, ssa.OpPPC64CMPUconst, ssa.OpPPC64CMPWconst, ssa.OpPPC64CMPWUconst:
    424 		p := gc.Prog(v.Op.Asm())
    425 		p.From.Type = obj.TYPE_REG
    426 		p.From.Reg = v.Args[0].Reg()
    427 		p.To.Type = obj.TYPE_CONST
    428 		p.To.Offset = v.AuxInt
    429 
    430 	case ssa.OpPPC64MOVBreg, ssa.OpPPC64MOVBZreg, ssa.OpPPC64MOVHreg, ssa.OpPPC64MOVHZreg, ssa.OpPPC64MOVWreg, ssa.OpPPC64MOVWZreg:
    431 		// Shift in register to required size
    432 		p := gc.Prog(v.Op.Asm())
    433 		p.From.Type = obj.TYPE_REG
    434 		p.From.Reg = v.Args[0].Reg()
    435 		p.To.Reg = v.Reg()
    436 		p.To.Type = obj.TYPE_REG
    437 
    438 	case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload:
    439 		p := gc.Prog(v.Op.Asm())
    440 		p.From.Type = obj.TYPE_MEM
    441 		p.From.Reg = v.Args[0].Reg()
    442 		gc.AddAux(&p.From, v)
    443 		p.To.Type = obj.TYPE_REG
    444 		p.To.Reg = v.Reg()
    445 
    446 	case ssa.OpPPC64FMOVDload, ssa.OpPPC64FMOVSload:
    447 		p := gc.Prog(v.Op.Asm())
    448 		p.From.Type = obj.TYPE_MEM
    449 		p.From.Reg = v.Args[0].Reg()
    450 		gc.AddAux(&p.From, v)
    451 		p.To.Type = obj.TYPE_REG
    452 		p.To.Reg = v.Reg()
    453 
    454 	case ssa.OpPPC64MOVDstorezero, ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero:
    455 		p := gc.Prog(v.Op.Asm())
    456 		p.From.Type = obj.TYPE_REG
    457 		p.From.Reg = ppc64.REGZERO
    458 		p.To.Type = obj.TYPE_MEM
    459 		p.To.Reg = v.Args[0].Reg()
    460 		gc.AddAux(&p.To, v)
    461 
    462 	case ssa.OpPPC64MOVDstore, ssa.OpPPC64MOVWstore, ssa.OpPPC64MOVHstore, ssa.OpPPC64MOVBstore:
    463 		p := gc.Prog(v.Op.Asm())
    464 		p.From.Type = obj.TYPE_REG
    465 		p.From.Reg = v.Args[1].Reg()
    466 		p.To.Type = obj.TYPE_MEM
    467 		p.To.Reg = v.Args[0].Reg()
    468 		gc.AddAux(&p.To, v)
    469 	case ssa.OpPPC64FMOVDstore, ssa.OpPPC64FMOVSstore:
    470 		p := gc.Prog(v.Op.Asm())
    471 		p.From.Type = obj.TYPE_REG
    472 		p.From.Reg = v.Args[1].Reg()
    473 		p.To.Type = obj.TYPE_MEM
    474 		p.To.Reg = v.Args[0].Reg()
    475 		gc.AddAux(&p.To, v)
    476 
    477 	case ssa.OpPPC64Equal,
    478 		ssa.OpPPC64NotEqual,
    479 		ssa.OpPPC64LessThan,
    480 		ssa.OpPPC64FLessThan,
    481 		ssa.OpPPC64LessEqual,
    482 		ssa.OpPPC64GreaterThan,
    483 		ssa.OpPPC64FGreaterThan,
    484 		ssa.OpPPC64GreaterEqual:
    485 
    486 		// On Power7 or later, can use isel instruction:
    487 		// for a < b, a > b, a = b:
    488 		//   rtmp := 1
    489 		//   isel rt,rtmp,r0,cond // rt is target in ppc asm
    490 
    491 		// for  a >= b, a <= b, a != b:
    492 		//   rtmp := 1
    493 		//   isel rt,0,rtmp,!cond // rt is target in ppc asm
    494 
    495 		if v.Block.Func.Config.OldArch {
    496 			p := gc.Prog(ppc64.AMOVD)
    497 			p.From.Type = obj.TYPE_CONST
    498 			p.From.Offset = 1
    499 			p.To.Type = obj.TYPE_REG
    500 			p.To.Reg = v.Reg()
    501 
    502 			pb := gc.Prog(condOps[v.Op])
    503 			pb.To.Type = obj.TYPE_BRANCH
    504 
    505 			p = gc.Prog(ppc64.AMOVD)
    506 			p.From.Type = obj.TYPE_CONST
    507 			p.From.Offset = 0
    508 			p.To.Type = obj.TYPE_REG
    509 			p.To.Reg = v.Reg()
    510 
    511 			p = gc.Prog(obj.ANOP)
    512 			gc.Patch(pb, p)
    513 			break
    514 		}
    515 		// Modern PPC uses ISEL
    516 		p := gc.Prog(ppc64.AMOVD)
    517 		p.From.Type = obj.TYPE_CONST
    518 		p.From.Offset = 1
    519 		p.To.Type = obj.TYPE_REG
    520 		p.To.Reg = iselRegs[1]
    521 		iop := iselOps[v.Op]
    522 		ssaGenISEL(v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
    523 
    524 	case ssa.OpPPC64FLessEqual, // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion
    525 		ssa.OpPPC64FGreaterEqual:
    526 
    527 		if v.Block.Func.Config.OldArch {
    528 			p := gc.Prog(ppc64.AMOVW)
    529 			p.From.Type = obj.TYPE_CONST
    530 			p.From.Offset = 1
    531 			p.To.Type = obj.TYPE_REG
    532 			p.To.Reg = v.Reg()
    533 
    534 			pb0 := gc.Prog(condOps[v.Op])
    535 			pb0.To.Type = obj.TYPE_BRANCH
    536 			pb1 := gc.Prog(ppc64.ABEQ)
    537 			pb1.To.Type = obj.TYPE_BRANCH
    538 
    539 			p = gc.Prog(ppc64.AMOVW)
    540 			p.From.Type = obj.TYPE_CONST
    541 			p.From.Offset = 0
    542 			p.To.Type = obj.TYPE_REG
    543 			p.To.Reg = v.Reg()
    544 
    545 			p = gc.Prog(obj.ANOP)
    546 			gc.Patch(pb0, p)
    547 			gc.Patch(pb1, p)
    548 			break
    549 		}
    550 		// Modern PPC uses ISEL
    551 		p := gc.Prog(ppc64.AMOVD)
    552 		p.From.Type = obj.TYPE_CONST
    553 		p.From.Offset = 1
    554 		p.To.Type = obj.TYPE_REG
    555 		p.To.Reg = iselRegs[1]
    556 		iop := iselOps[v.Op]
    557 		ssaGenISEL(v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
    558 		ssaGenISEL(v, ppc64.C_COND_EQ, iselRegs[1], v.Reg())
    559 
    560 	case ssa.OpPPC64LoweredZero:
    561 		// Similar to how this is done on ARM,
    562 		// except that PPC MOVDU x,off(y) is *(y+off) = x; y=y+off
    563 		// not store-and-increment.
    564 		// Therefore R3 should be dest-align
    565 		// and arg1 should be dest+size-align
    566 		// HOWEVER, the input dest address cannot be dest-align because
    567 		// that does not necessarily address valid memory and it's not
    568 		// known how that might be optimized.  Therefore, correct it in
    569 		// in the expansion:
    570 		//
    571 		// ADD    -8,R3,R3
    572 		// MOVDU  R0, 8(R3)
    573 		// CMP	  R3, Rarg1
    574 		// BL	  -2(PC)
    575 		// arg1 is the address of the last element to zero
    576 		// auxint is alignment
    577 		var sz int64
    578 		var movu obj.As
    579 		switch {
    580 		case v.AuxInt%8 == 0:
    581 			sz = 8
    582 			movu = ppc64.AMOVDU
    583 		case v.AuxInt%4 == 0:
    584 			sz = 4
    585 			movu = ppc64.AMOVWZU // MOVWU instruction not implemented
    586 		case v.AuxInt%2 == 0:
    587 			sz = 2
    588 			movu = ppc64.AMOVHU
    589 		default:
    590 			sz = 1
    591 			movu = ppc64.AMOVBU
    592 		}
    593 
    594 		p := gc.Prog(ppc64.AADD)
    595 		p.Reg = v.Args[0].Reg()
    596 		p.From.Type = obj.TYPE_CONST
    597 		p.From.Offset = -sz
    598 		p.To.Type = obj.TYPE_REG
    599 		p.To.Reg = v.Args[0].Reg()
    600 
    601 		p = gc.Prog(movu)
    602 		p.From.Type = obj.TYPE_REG
    603 		p.From.Reg = ppc64.REG_R0
    604 		p.To.Type = obj.TYPE_MEM
    605 		p.To.Reg = v.Args[0].Reg()
    606 		p.To.Offset = sz
    607 
    608 		p2 := gc.Prog(ppc64.ACMPU)
    609 		p2.From.Type = obj.TYPE_REG
    610 		p2.From.Reg = v.Args[0].Reg()
    611 		p2.To.Reg = v.Args[1].Reg()
    612 		p2.To.Type = obj.TYPE_REG
    613 
    614 		p3 := gc.Prog(ppc64.ABLT)
    615 		p3.To.Type = obj.TYPE_BRANCH
    616 		gc.Patch(p3, p)
    617 
    618 	case ssa.OpPPC64LoweredMove:
    619 		// Similar to how this is done on ARM,
    620 		// except that PPC MOVDU x,off(y) is *(y+off) = x; y=y+off,
    621 		// not store-and-increment.
    622 		// Inputs must be valid pointers to memory,
    623 		// so adjust arg0 and arg1 as part of the expansion.
    624 		// arg2 should be src+size-align,
    625 		//
    626 		// ADD    -8,R3,R3
    627 		// ADD    -8,R4,R4
    628 		// MOVDU	8(R4), Rtmp
    629 		// MOVDU 	Rtmp, 8(R3)
    630 		// CMP	R4, Rarg2
    631 		// BL	-3(PC)
    632 		// arg2 is the address of the last element of src
    633 		// auxint is alignment
    634 		var sz int64
    635 		var movu obj.As
    636 		switch {
    637 		case v.AuxInt%8 == 0:
    638 			sz = 8
    639 			movu = ppc64.AMOVDU
    640 		case v.AuxInt%4 == 0:
    641 			sz = 4
    642 			movu = ppc64.AMOVWZU // MOVWU instruction not implemented
    643 		case v.AuxInt%2 == 0:
    644 			sz = 2
    645 			movu = ppc64.AMOVHU
    646 		default:
    647 			sz = 1
    648 			movu = ppc64.AMOVBU
    649 		}
    650 
    651 		p := gc.Prog(ppc64.AADD)
    652 		p.Reg = v.Args[0].Reg()
    653 		p.From.Type = obj.TYPE_CONST
    654 		p.From.Offset = -sz
    655 		p.To.Type = obj.TYPE_REG
    656 		p.To.Reg = v.Args[0].Reg()
    657 
    658 		p = gc.Prog(ppc64.AADD)
    659 		p.Reg = v.Args[1].Reg()
    660 		p.From.Type = obj.TYPE_CONST
    661 		p.From.Offset = -sz
    662 		p.To.Type = obj.TYPE_REG
    663 		p.To.Reg = v.Args[1].Reg()
    664 
    665 		p = gc.Prog(movu)
    666 		p.From.Type = obj.TYPE_MEM
    667 		p.From.Reg = v.Args[1].Reg()
    668 		p.From.Offset = sz
    669 		p.To.Type = obj.TYPE_REG
    670 		p.To.Reg = ppc64.REGTMP
    671 
    672 		p2 := gc.Prog(movu)
    673 		p2.From.Type = obj.TYPE_REG
    674 		p2.From.Reg = ppc64.REGTMP
    675 		p2.To.Type = obj.TYPE_MEM
    676 		p2.To.Reg = v.Args[0].Reg()
    677 		p2.To.Offset = sz
    678 
    679 		p3 := gc.Prog(ppc64.ACMPU)
    680 		p3.From.Reg = v.Args[1].Reg()
    681 		p3.From.Type = obj.TYPE_REG
    682 		p3.To.Reg = v.Args[2].Reg()
    683 		p3.To.Type = obj.TYPE_REG
    684 
    685 		p4 := gc.Prog(ppc64.ABLT)
    686 		p4.To.Type = obj.TYPE_BRANCH
    687 		gc.Patch(p4, p)
    688 
    689 	case ssa.OpPPC64CALLstatic:
    690 		if v.Aux.(*gc.Sym) == gc.Deferreturn.Sym {
    691 			// Deferred calls will appear to be returning to
    692 			// the CALL deferreturn(SB) that we are about to emit.
    693 			// However, the stack trace code will show the line
    694 			// of the instruction byte before the return PC.
    695 			// To avoid that being an unrelated instruction,
    696 			// insert two actual hardware NOPs that will have the right line number.
    697 			// This is different from obj.ANOP, which is a virtual no-op
    698 			// that doesn't make it into the instruction stream.
    699 			// PPC64 is unusual because TWO nops are required
    700 			// (see gc/cgen.go, gc/plive.go -- copy of comment below)
    701 			//
    702 			// On ppc64, when compiling Go into position
    703 			// independent code on ppc64le we insert an
    704 			// instruction to reload the TOC pointer from the
    705 			// stack as well. See the long comment near
    706 			// jmpdefer in runtime/asm_ppc64.s for why.
    707 			// If the MOVD is not needed, insert a hardware NOP
    708 			// so that the same number of instructions are used
    709 			// on ppc64 in both shared and non-shared modes.
    710 			ginsnop()
    711 			if gc.Ctxt.Flag_shared {
    712 				p := gc.Prog(ppc64.AMOVD)
    713 				p.From.Type = obj.TYPE_MEM
    714 				p.From.Offset = 24
    715 				p.From.Reg = ppc64.REGSP
    716 				p.To.Type = obj.TYPE_REG
    717 				p.To.Reg = ppc64.REG_R2
    718 			} else {
    719 				ginsnop()
    720 			}
    721 		}
    722 		p := gc.Prog(obj.ACALL)
    723 		p.To.Type = obj.TYPE_MEM
    724 		p.To.Name = obj.NAME_EXTERN
    725 		p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym))
    726 		if gc.Maxarg < v.AuxInt {
    727 			gc.Maxarg = v.AuxInt
    728 		}
    729 
    730 	case ssa.OpPPC64CALLclosure, ssa.OpPPC64CALLinter:
    731 		p := gc.Prog(ppc64.AMOVD)
    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 = ppc64.REG_CTR
    736 
    737 		if gc.Ctxt.Flag_shared && p.From.Reg != ppc64.REG_R12 {
    738 			// Make sure function pointer is in R12 as well when
    739 			// compiling Go into PIC.
    740 			// TODO(mwhudson): it would obviously be better to
    741 			// change the register allocation to put the value in
    742 			// R12 already, but I don't know how to do that.
    743 			// TODO: We have the technology now to implement TODO above.
    744 			q := gc.Prog(ppc64.AMOVD)
    745 			q.From = p.From
    746 			q.To.Type = obj.TYPE_REG
    747 			q.To.Reg = ppc64.REG_R12
    748 		}
    749 
    750 		pp := gc.Prog(obj.ACALL)
    751 		pp.To.Type = obj.TYPE_REG
    752 		pp.To.Reg = ppc64.REG_CTR
    753 
    754 		if gc.Ctxt.Flag_shared {
    755 			// When compiling Go into PIC, the function we just
    756 			// called via pointer might have been implemented in
    757 			// a separate module and so overwritten the TOC
    758 			// pointer in R2; reload it.
    759 			q := gc.Prog(ppc64.AMOVD)
    760 			q.From.Type = obj.TYPE_MEM
    761 			q.From.Offset = 24
    762 			q.From.Reg = ppc64.REGSP
    763 			q.To.Type = obj.TYPE_REG
    764 			q.To.Reg = ppc64.REG_R2
    765 		}
    766 
    767 		if gc.Maxarg < v.AuxInt {
    768 			gc.Maxarg = v.AuxInt
    769 		}
    770 
    771 	case ssa.OpPPC64CALLdefer:
    772 		p := gc.Prog(obj.ACALL)
    773 		p.To.Type = obj.TYPE_MEM
    774 		p.To.Name = obj.NAME_EXTERN
    775 		p.To.Sym = gc.Linksym(gc.Deferproc.Sym)
    776 		if gc.Maxarg < v.AuxInt {
    777 			gc.Maxarg = v.AuxInt
    778 		}
    779 	case ssa.OpPPC64CALLgo:
    780 		p := gc.Prog(obj.ACALL)
    781 		p.To.Type = obj.TYPE_MEM
    782 		p.To.Name = obj.NAME_EXTERN
    783 		p.To.Sym = gc.Linksym(gc.Newproc.Sym)
    784 		if gc.Maxarg < v.AuxInt {
    785 			gc.Maxarg = v.AuxInt
    786 		}
    787 	case ssa.OpVarDef:
    788 		gc.Gvardef(v.Aux.(*gc.Node))
    789 	case ssa.OpVarKill:
    790 		gc.Gvarkill(v.Aux.(*gc.Node))
    791 	case ssa.OpVarLive:
    792 		gc.Gvarlive(v.Aux.(*gc.Node))
    793 	case ssa.OpKeepAlive:
    794 		gc.KeepAlive(v)
    795 	case ssa.OpPhi:
    796 		gc.CheckLoweredPhi(v)
    797 
    798 	case ssa.OpPPC64LoweredNilCheck:
    799 		// Issue a load which will fault if arg is nil.
    800 		p := gc.Prog(ppc64.AMOVBZ)
    801 		p.From.Type = obj.TYPE_MEM
    802 		p.From.Reg = v.Args[0].Reg()
    803 		gc.AddAux(&p.From, v)
    804 		p.To.Type = obj.TYPE_REG
    805 		p.To.Reg = ppc64.REGTMP
    806 		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
    807 			gc.Warnl(v.Line, "generated nil check")
    808 		}
    809 
    810 	case ssa.OpPPC64InvertFlags:
    811 		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
    812 	case ssa.OpPPC64FlagEQ, ssa.OpPPC64FlagLT, ssa.OpPPC64FlagGT:
    813 		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
    814 
    815 	default:
    816 		v.Fatalf("genValue not implemented: %s", v.LongString())
    817 	}
    818 }
    819 
    820 var blockJump = [...]struct {
    821 	asm, invasm     obj.As
    822 	asmeq, invasmun bool
    823 }{
    824 	ssa.BlockPPC64EQ: {ppc64.ABEQ, ppc64.ABNE, false, false},
    825 	ssa.BlockPPC64NE: {ppc64.ABNE, ppc64.ABEQ, false, false},
    826 
    827 	ssa.BlockPPC64LT: {ppc64.ABLT, ppc64.ABGE, false, false},
    828 	ssa.BlockPPC64GE: {ppc64.ABGE, ppc64.ABLT, false, false},
    829 	ssa.BlockPPC64LE: {ppc64.ABLE, ppc64.ABGT, false, false},
    830 	ssa.BlockPPC64GT: {ppc64.ABGT, ppc64.ABLE, false, false},
    831 
    832 	// TODO: need to work FP comparisons into block jumps
    833 	ssa.BlockPPC64FLT: {ppc64.ABLT, ppc64.ABGE, false, false},
    834 	ssa.BlockPPC64FGE: {ppc64.ABGT, ppc64.ABLT, true, true}, // GE = GT or EQ; !GE = LT or UN
    835 	ssa.BlockPPC64FLE: {ppc64.ABLT, ppc64.ABGT, true, true}, // LE = LT or EQ; !LE = GT or UN
    836 	ssa.BlockPPC64FGT: {ppc64.ABGT, ppc64.ABLE, false, false},
    837 }
    838 
    839 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
    840 	s.SetLineno(b.Line)
    841 
    842 	switch b.Kind {
    843 
    844 	case ssa.BlockDefer:
    845 		// defer returns in R3:
    846 		// 0 if we should continue executing
    847 		// 1 if we should jump to deferreturn call
    848 		p := gc.Prog(ppc64.ACMP)
    849 		p.From.Type = obj.TYPE_REG
    850 		p.From.Reg = ppc64.REG_R3
    851 		p.To.Type = obj.TYPE_REG
    852 		p.To.Reg = ppc64.REG_R0
    853 
    854 		p = gc.Prog(ppc64.ABNE)
    855 		p.To.Type = obj.TYPE_BRANCH
    856 		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
    857 		if b.Succs[0].Block() != next {
    858 			p := gc.Prog(obj.AJMP)
    859 			p.To.Type = obj.TYPE_BRANCH
    860 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
    861 		}
    862 
    863 	case ssa.BlockPlain:
    864 		if b.Succs[0].Block() != next {
    865 			p := gc.Prog(obj.AJMP)
    866 			p.To.Type = obj.TYPE_BRANCH
    867 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
    868 		}
    869 	case ssa.BlockExit:
    870 		gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
    871 	case ssa.BlockRet:
    872 		gc.Prog(obj.ARET)
    873 	case ssa.BlockRetJmp:
    874 		p := gc.Prog(obj.AJMP)
    875 		p.To.Type = obj.TYPE_MEM
    876 		p.To.Name = obj.NAME_EXTERN
    877 		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
    878 
    879 	case ssa.BlockPPC64EQ, ssa.BlockPPC64NE,
    880 		ssa.BlockPPC64LT, ssa.BlockPPC64GE,
    881 		ssa.BlockPPC64LE, ssa.BlockPPC64GT,
    882 		ssa.BlockPPC64FLT, ssa.BlockPPC64FGE,
    883 		ssa.BlockPPC64FLE, ssa.BlockPPC64FGT:
    884 		jmp := blockJump[b.Kind]
    885 		likely := b.Likely
    886 		var p *obj.Prog
    887 		switch next {
    888 		case b.Succs[0].Block():
    889 			p = gc.Prog(jmp.invasm)
    890 			likely *= -1
    891 			p.To.Type = obj.TYPE_BRANCH
    892 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
    893 			if jmp.invasmun {
    894 				// TODO: The second branch is probably predict-not-taken since it is for FP unordered
    895 				q := gc.Prog(ppc64.ABVS)
    896 				q.To.Type = obj.TYPE_BRANCH
    897 				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
    898 			}
    899 		case b.Succs[1].Block():
    900 			p = gc.Prog(jmp.asm)
    901 			p.To.Type = obj.TYPE_BRANCH
    902 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
    903 			if jmp.asmeq {
    904 				q := gc.Prog(ppc64.ABEQ)
    905 				q.To.Type = obj.TYPE_BRANCH
    906 				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()})
    907 			}
    908 		default:
    909 			p = gc.Prog(jmp.asm)
    910 			p.To.Type = obj.TYPE_BRANCH
    911 			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
    912 			if jmp.asmeq {
    913 				q := gc.Prog(ppc64.ABEQ)
    914 				q.To.Type = obj.TYPE_BRANCH
    915 				s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()})
    916 			}
    917 			q := gc.Prog(obj.AJMP)
    918 			q.To.Type = obj.TYPE_BRANCH
    919 			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
    920 		}
    921 
    922 		// liblink reorders the instruction stream as it sees fit.
    923 		// Pass along what we know so liblink can make use of it.
    924 		// TODO: Once we've fully switched to SSA,
    925 		// make liblink leave our output alone.
    926 		//switch likely {
    927 		//case ssa.BranchUnlikely:
    928 		//	p.From.Type = obj.TYPE_CONST
    929 		//	p.From.Offset = 0
    930 		//case ssa.BranchLikely:
    931 		//	p.From.Type = obj.TYPE_CONST
    932 		//	p.From.Offset = 1
    933 		//}
    934 
    935 	default:
    936 		b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
    937 	}
    938 }
    939