in src/cmd/internal/obj/ppc64/asm9.go [2459:3768]
func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 := uint32(0)
o2 := uint32(0)
o3 := uint32(0)
o4 := uint32(0)
o5 := uint32(0)
//print("%v => case %d\n", p, o->type);
switch o.type_ {
default:
c.ctxt.Diag("unknown type %d", o.type_)
prasm(p)
case 0: /* pseudo ops */
break
case 2: /* int/cr/fp op Rb,[Ra],Rd */
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
case 3: /* mov $soreg/addcon/andcon/ucon, r ==> addis/oris/addi/ori $i,reg',r */
d := c.vregoff(&p.From)
v := int32(d)
r := int(p.From.Reg)
if r == 0 {
r = c.getimpliedreg(&p.From, p)
}
if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 && (r != 0 || v != 0) {
c.ctxt.Diag("literal operation on R0\n%v", p)
}
a := OP_ADDI
if o.a1 == C_UCON {
if d&0xffff != 0 {
log.Fatalf("invalid handling of %v", p)
}
// For UCON operands the value is right shifted 16, using ADDIS if the
// value should be signed, ORIS if unsigned.
v >>= 16
if r == REGZERO && isuint32(uint64(d)) {
o1 = LOP_IRR(OP_ORIS, uint32(p.To.Reg), REGZERO, uint32(v))
break
}
a = OP_ADDIS
} else if int64(int16(d)) != d {
// Operand is 16 bit value with sign bit set
if o.a1 == C_ANDCON {
// Needs unsigned 16 bit so use ORI
if r == 0 || r == REGZERO {
o1 = LOP_IRR(uint32(OP_ORI), uint32(p.To.Reg), uint32(0), uint32(v))
break
}
// With ADDCON, needs signed 16 bit value, fall through to use ADDI
} else if o.a1 != C_ADDCON {
log.Fatalf("invalid handling of %v", p)
}
}
o1 = AOP_IRR(uint32(a), uint32(p.To.Reg), uint32(r), uint32(v))
case 4: /* add/mul $scon,[r1],r2 */
v := c.regoff(&p.From)
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 {
c.ctxt.Diag("literal operation on R0\n%v", p)
}
if int32(int16(v)) != v {
log.Fatalf("mishandled instruction %v", p)
}
o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
case 5: /* syscall */
o1 = c.oprrr(p.As)
case 6: /* logical op Rb,[Rs,]Ra; no literal */
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
// AROTL and AROTLW are extended mnemonics, which map to RLDCL and RLWNM.
switch p.As {
case AROTL:
o1 = AOP_RLDIC(OP_RLDCL, uint32(p.To.Reg), uint32(r), uint32(p.From.Reg), uint32(0))
case AROTLW:
o1 = OP_RLW(OP_RLWNM, uint32(p.To.Reg), uint32(r), uint32(p.From.Reg), 0, 31)
default:
o1 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
}
case 7: /* mov r, soreg ==> stw o(r) */
r := int(p.To.Reg)
if r == 0 {
r = c.getimpliedreg(&p.To, p)
}
v := c.regoff(&p.To)
if p.To.Type == obj.TYPE_MEM && p.To.Index != 0 {
if v != 0 {
c.ctxt.Diag("illegal indexed instruction\n%v", p)
}
o1 = AOP_RRR(c.opstorex(p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(r))
} else {
if int32(int16(v)) != v {
log.Fatalf("mishandled instruction %v", p)
}
// Offsets in DS form stores must be a multiple of 4
inst := c.opstore(p.As)
if c.opform(inst) == DS_FORM && v&0x3 != 0 {
log.Fatalf("invalid offset for DS form load/store %v", p)
}
o1 = AOP_IRR(inst, uint32(p.From.Reg), uint32(r), uint32(v))
}
case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r), lbz o(r) + extsb r,r */
r := int(p.From.Reg)
if r == 0 {
r = c.getimpliedreg(&p.From, p)
}
v := c.regoff(&p.From)
if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 {
if v != 0 {
c.ctxt.Diag("illegal indexed instruction\n%v", p)
}
o1 = AOP_RRR(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
} else {
if int32(int16(v)) != v {
log.Fatalf("mishandled instruction %v", p)
}
// Offsets in DS form loads must be a multiple of 4
inst := c.opload(p.As)
if c.opform(inst) == DS_FORM && v&0x3 != 0 {
log.Fatalf("invalid offset for DS form load/store %v", p)
}
o1 = AOP_IRR(inst, uint32(p.To.Reg), uint32(r), uint32(v))
}
// Sign extend MOVB operations. This is ignored for other cases (o.size == 4).
o2 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(r))
case 11: /* br/bl lbra */
v := int32(0)
if p.To.Target() != nil {
v = int32(p.To.Target().Pc - p.Pc)
if v&03 != 0 {
c.ctxt.Diag("odd branch target address\n%v", p)
v &^= 03
}
if v < -(1<<25) || v >= 1<<24 {
c.ctxt.Diag("branch too far\n%v", p)
}
}
o1 = OP_BR(c.opirr(p.As), uint32(v), 0)
if p.To.Sym != nil {
rel := obj.Addrel(c.cursym)
rel.Off = int32(c.pc)
rel.Siz = 4
rel.Sym = p.To.Sym
v += int32(p.To.Offset)
if v&03 != 0 {
c.ctxt.Diag("odd branch target address\n%v", p)
v &^= 03
}
rel.Add = int64(v)
rel.Type = objabi.R_CALLPOWER
}
o2 = 0x60000000 // nop, sometimes overwritten by ld r2, 24(r1) when dynamic linking
case 13: /* mov[bhwd]{z,} r,r */
// This needs to handle "MOV* $0, Rx". This shows up because $0 also
// matches C_REG if r0iszero. This happens because C_REG sorts before C_ANDCON
// TODO: fix the above behavior and cleanup this exception.
if p.From.Type == obj.TYPE_CONST {
o1 = LOP_IRR(OP_ADDI, REGZERO, uint32(p.To.Reg), 0)
break
}
if p.To.Type == obj.TYPE_CONST {
c.ctxt.Diag("cannot move into constant 0\n%v", p)
}
switch p.As {
case AMOVB:
o1 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.From.Reg), 0)
case AMOVBZ:
o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.From.Reg), 0, 24, 31)
case AMOVH:
o1 = LOP_RRR(OP_EXTSH, uint32(p.To.Reg), uint32(p.From.Reg), 0)
case AMOVHZ:
o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.From.Reg), 0, 16, 31)
case AMOVW:
o1 = LOP_RRR(OP_EXTSW, uint32(p.To.Reg), uint32(p.From.Reg), 0)
case AMOVWZ:
o1 = OP_RLW(OP_RLDIC, uint32(p.To.Reg), uint32(p.From.Reg), 0, 0, 0) | 1<<5 /* MB=32 */
case AMOVD:
o1 = LOP_RRR(OP_OR, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.From.Reg))
default:
c.ctxt.Diag("internal: bad register move/truncation\n%v", p)
}
case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
d := c.vregoff(p.GetFrom3())
var a int
switch p.As {
// These opcodes expect a mask operand that has to be converted into the
// appropriate operand. The way these were defined, not all valid masks are possible.
// Left here for compatibility in case they were used or generated.
case ARLDCL, ARLDCLCC:
var mask [2]uint8
c.maskgen64(p, mask[:], uint64(d))
a = int(mask[0]) /* MB */
if mask[1] != 63 {
c.ctxt.Diag("invalid mask for rotate: %x (end != bit 63)\n%v", uint64(d), p)
}
o1 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
o1 |= (uint32(a) & 31) << 6
if a&0x20 != 0 {
o1 |= 1 << 5 /* mb[5] is top bit */
}
case ARLDCR, ARLDCRCC:
var mask [2]uint8
c.maskgen64(p, mask[:], uint64(d))
a = int(mask[1]) /* ME */
if mask[0] != 0 {
c.ctxt.Diag("invalid mask for rotate: %x %x (start != 0)\n%v", uint64(d), mask[0], p)
}
o1 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
o1 |= (uint32(a) & 31) << 6
if a&0x20 != 0 {
o1 |= 1 << 5 /* mb[5] is top bit */
}
// These opcodes use a shift count like the ppc64 asm, no mask conversion done
case ARLDICR, ARLDICRCC:
me := int(d)
sh := c.regoff(&p.From)
if me < 0 || me > 63 || sh > 63 {
c.ctxt.Diag("Invalid me or sh for RLDICR: %x %x\n%v", int(d), sh, p)
}
o1 = AOP_RLDIC(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(sh), uint32(me))
case ARLDICL, ARLDICLCC, ARLDIC, ARLDICCC:
mb := int(d)
sh := c.regoff(&p.From)
if mb < 0 || mb > 63 || sh > 63 {
c.ctxt.Diag("Invalid mb or sh for RLDIC, RLDICL: %x %x\n%v", mb, sh, p)
}
o1 = AOP_RLDIC(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(sh), uint32(mb))
case ACLRLSLDI:
// This is an extended mnemonic defined in the ISA section C.8.1
// clrlsldi ra,rs,b,n --> rldic ra,rs,n,b-n
// It maps onto RLDIC so is directly generated here based on the operands from
// the clrlsldi.
n := int32(d)
b := c.regoff(&p.From)
if n > b || b > 63 {
c.ctxt.Diag("Invalid n or b for CLRLSLDI: %x %x\n%v", n, b, p)
}
o1 = AOP_RLDIC(OP_RLDIC, uint32(p.To.Reg), uint32(r), uint32(n), uint32(b)-uint32(n))
default:
c.ctxt.Diag("unexpected op in rldc case\n%v", p)
a = 0
}
case 17, /* bc bo,bi,lbra (same for now) */
16: /* bc bo,bi,sbra */
a := 0
r := int(p.Reg)
if p.From.Type == obj.TYPE_CONST {
a = int(c.regoff(&p.From))
} else if p.From.Type == obj.TYPE_REG {
if r != 0 {
c.ctxt.Diag("unexpected register setting for branch with CR: %d\n", r)
}
// BI values for the CR
switch p.From.Reg {
case REG_CR0:
r = BI_CR0
case REG_CR1:
r = BI_CR1
case REG_CR2:
r = BI_CR2
case REG_CR3:
r = BI_CR3
case REG_CR4:
r = BI_CR4
case REG_CR5:
r = BI_CR5
case REG_CR6:
r = BI_CR6
case REG_CR7:
r = BI_CR7
default:
c.ctxt.Diag("unrecognized register: expecting CR\n")
}
}
v := int32(0)
if p.To.Target() != nil {
v = int32(p.To.Target().Pc - p.Pc)
}
if v&03 != 0 {
c.ctxt.Diag("odd branch target address\n%v", p)
v &^= 03
}
if v < -(1<<16) || v >= 1<<15 {
c.ctxt.Diag("branch too far\n%v", p)
}
o1 = OP_BC(c.opirr(p.As), uint32(a), uint32(r), uint32(v), 0)
case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
var v int32
if p.As == ABC || p.As == ABCL {
v = c.regoff(&p.To) & 31
} else {
v = 20 /* unconditional */
}
o1 = AOP_RRR(OP_MTSPR, uint32(p.To.Reg), 0, 0) | (REG_LR&0x1f)<<16 | ((REG_LR>>5)&0x1f)<<11
o2 = OPVCC(19, 16, 0, 0)
if p.As == ABL || p.As == ABCL {
o2 |= 1
}
o2 = OP_BCR(o2, uint32(v), uint32(p.To.Index))
case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
var v int32
var bh uint32 = 0
if p.As == ABC || p.As == ABCL {
v = c.regoff(&p.From) & 31
} else {
v = 20 /* unconditional */
}
r := int(p.Reg)
if r == 0 {
r = 0
}
switch oclass(&p.To) {
case C_CTR:
o1 = OPVCC(19, 528, 0, 0)
case C_LR:
o1 = OPVCC(19, 16, 0, 0)
default:
c.ctxt.Diag("bad optab entry (18): %d\n%v", p.To.Class, p)
v = 0
}
// Insert optional branch hint for bclr[l]/bcctr[l]
if p.From3Type() != obj.TYPE_NONE {
bh = uint32(p.GetFrom3().Offset)
if bh == 2 || bh > 3 {
log.Fatalf("BH must be 0,1,3 for %v", p)
}
o1 |= bh << 11
}
if p.As == ABL || p.As == ABCL {
o1 |= 1
}
o1 = OP_BCR(o1, uint32(v), uint32(r))
case 19: /* mov $lcon,r ==> cau+or */
d := c.vregoff(&p.From)
o1 = loadu32(int(p.To.Reg), d)
o2 = LOP_IRR(OP_ORI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(int32(d)))
case 20: /* add $ucon,,r | addis $addcon,r,r */
v := c.regoff(&p.From)
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
if p.As == AADD && (r0iszero == 0 /*TypeKind(100016)*/ && p.Reg == 0 || r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0) {
c.ctxt.Diag("literal operation on R0\n%v", p)
}
if p.As == AADDIS {
o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
} else {
o1 = AOP_IRR(c.opirr(AADDIS), uint32(p.To.Reg), uint32(r), uint32(v)>>16)
}
case 22: /* add $lcon/$andcon,r1,r2 ==> oris+ori+add/ori+add */
if p.To.Reg == REGTMP || p.Reg == REGTMP {
c.ctxt.Diag("can't synthesize large constant\n%v", p)
}
d := c.vregoff(&p.From)
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
if p.From.Sym != nil {
c.ctxt.Diag("%v is not supported", p)
}
// If operand is ANDCON, generate 2 instructions using
// ORI for unsigned value; with LCON 3 instructions.
if o.size == 8 {
o1 = LOP_IRR(OP_ORI, REGTMP, REGZERO, uint32(int32(d)))
o2 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
} else {
o1 = loadu32(REGTMP, d)
o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
}
case 23: /* and $lcon/$addcon,r1,r2 ==> oris+ori+and/addi+and */
if p.To.Reg == REGTMP || p.Reg == REGTMP {
c.ctxt.Diag("can't synthesize large constant\n%v", p)
}
d := c.vregoff(&p.From)
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
// With ADDCON operand, generate 2 instructions using ADDI for signed value,
// with LCON operand generate 3 instructions.
if o.size == 8 {
o1 = LOP_IRR(OP_ADDI, REGZERO, REGTMP, uint32(int32(d)))
o2 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
} else {
o1 = loadu32(REGTMP, d)
o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
o3 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
}
if p.From.Sym != nil {
c.ctxt.Diag("%v is not supported", p)
}
case 24: /* lfd fA,float64(0) -> xxlxor xsA,xsaA,xsaA + fneg for -0 */
o1 = AOP_XX3I(c.oprrr(AXXLXOR), uint32(p.To.Reg), uint32(p.To.Reg), uint32(p.To.Reg), uint32(0))
// This is needed for -0.
if o.size == 8 {
o2 = AOP_RRR(c.oprrr(AFNEG), uint32(p.To.Reg), 0, uint32(p.To.Reg))
}
case 25:
/* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
v := c.regoff(&p.From)
if v < 0 {
v = 0
} else if v > 63 {
v = 63
}
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
var a int
op := uint32(0)
switch p.As {
case ASLD, ASLDCC:
a = int(63 - v)
op = OP_RLDICR
case ASRD, ASRDCC:
a = int(v)
v = 64 - v
op = OP_RLDICL
case AROTL:
a = int(0)
op = OP_RLDICL
case AEXTSWSLI:
a = int(v)
default:
c.ctxt.Diag("unexpected op in sldi case\n%v", p)
a = 0
o1 = 0
}
if p.As == AEXTSWSLI || p.As == AEXTSWSLICC {
o1 = AOP_EXTSWSLI(OP_EXTSWSLI, uint32(r), uint32(p.To.Reg), uint32(v))
} else {
o1 = AOP_RLDIC(op, uint32(p.To.Reg), uint32(r), uint32(v), uint32(a))
}
if p.As == ASLDCC || p.As == ASRDCC || p.As == AEXTSWSLICC {
o1 |= 1 // Set the condition code bit
}
case 26: /* mov $lsext/auto/oreg,,r2 ==> addis+addi */
v := c.vregoff(&p.From)
r := int(p.From.Reg)
switch p.From.Name {
case obj.NAME_EXTERN, obj.NAME_STATIC:
// Load a 32 bit constant, or relocation depending on if a symbol is attached
o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI, true)
default:
if r == 0 {
r = c.getimpliedreg(&p.From, p)
}
// Add a 32 bit offset to a register.
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(int32(v))))
o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
}
case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
v := c.regoff(p.GetFrom3())
r := int(p.From.Reg)
o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */
if p.To.Reg == REGTMP || p.From.Reg == REGTMP {
c.ctxt.Diag("can't synthesize large constant\n%v", p)
}
v := c.regoff(p.GetFrom3())
o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(v)>>16)
o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(v))
o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP)
if p.From.Sym != nil {
c.ctxt.Diag("%v is not supported", p)
}
case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
v := c.regoff(&p.From)
d := c.vregoff(p.GetFrom3())
var mask [2]uint8
c.maskgen64(p, mask[:], uint64(d))
var a int
switch p.As {
case ARLDC, ARLDCCC:
a = int(mask[0]) /* MB */
if int32(mask[1]) != (63 - v) {
c.ctxt.Diag("invalid mask for shift: %x %x (shift %d)\n%v", uint64(d), mask[1], v, p)
}
case ARLDCL, ARLDCLCC:
a = int(mask[0]) /* MB */
if mask[1] != 63 {
c.ctxt.Diag("invalid mask for shift: %x %s (shift %d)\n%v", uint64(d), mask[1], v, p)
}
case ARLDCR, ARLDCRCC:
a = int(mask[1]) /* ME */
if mask[0] != 0 {
c.ctxt.Diag("invalid mask for shift: %x %x (shift %d)\n%v", uint64(d), mask[0], v, p)
}
default:
c.ctxt.Diag("unexpected op in rldic case\n%v", p)
a = 0
}
o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
o1 |= (uint32(a) & 31) << 6
if v&0x20 != 0 {
o1 |= 1 << 1
}
if a&0x20 != 0 {
o1 |= 1 << 5 /* mb[5] is top bit */
}
case 30: /* rldimi $sh,s,$mask,a */
v := c.regoff(&p.From)
d := c.vregoff(p.GetFrom3())
// Original opcodes had mask operands which had to be converted to a shift count as expected by
// the ppc64 asm.
switch p.As {
case ARLDMI, ARLDMICC:
var mask [2]uint8
c.maskgen64(p, mask[:], uint64(d))
if int32(mask[1]) != (63 - v) {
c.ctxt.Diag("invalid mask for shift: %x %x (shift %d)\n%v", uint64(d), mask[1], v, p)
}
o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
o1 |= (uint32(mask[0]) & 31) << 6
if v&0x20 != 0 {
o1 |= 1 << 1
}
if mask[0]&0x20 != 0 {
o1 |= 1 << 5 /* mb[5] is top bit */
}
// Opcodes with shift count operands.
case ARLDIMI, ARLDIMICC:
o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
o1 |= (uint32(d) & 31) << 6
if d&0x20 != 0 {
o1 |= 1 << 5
}
if v&0x20 != 0 {
o1 |= 1 << 1
}
}
case 31: /* dword */
d := c.vregoff(&p.From)
if c.ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = uint32(d >> 32)
o2 = uint32(d)
} else {
o1 = uint32(d)
o2 = uint32(d >> 32)
}
if p.From.Sym != nil {
rel := obj.Addrel(c.cursym)
rel.Off = int32(c.pc)
rel.Siz = 8
rel.Sym = p.From.Sym
rel.Add = p.From.Offset
rel.Type = objabi.R_ADDR
o2 = 0
o1 = o2
}
case 32: /* fmul frc,fra,frd */
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), 0) | (uint32(p.From.Reg)&31)<<6
case 33: /* fabs [frb,]frd; fmr. frb,frd */
r := int(p.From.Reg)
if oclass(&p.From) == C_NONE {
r = int(p.To.Reg)
}
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), 0, uint32(r))
case 34: /* FMADDx fra,frb,frc,frt (t=a*c±b) */
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg)) | (uint32(p.GetFrom3().Reg)&31)<<6
case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
v := c.regoff(&p.To)
r := int(p.To.Reg)
if r == 0 {
r = c.getimpliedreg(&p.To, p)
}
// Offsets in DS form stores must be a multiple of 4
inst := c.opstore(p.As)
if c.opform(inst) == DS_FORM && v&0x3 != 0 {
log.Fatalf("invalid offset for DS form load/store %v", p)
}
o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
o2 = AOP_IRR(inst, uint32(p.From.Reg), REGTMP, uint32(v))
case 36: /* mov b/bz/h/hz lext/lauto/lreg,r ==> lbz+extsb/lbz/lha/lhz etc */
v := c.regoff(&p.From)
r := int(p.From.Reg)
if r == 0 {
r = c.getimpliedreg(&p.From, p)
}
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v)))
o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
// Sign extend MOVB if needed
o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
case 40: /* word */
o1 = uint32(c.regoff(&p.From))
case 41: /* stswi */
o1 = AOP_RRR(c.opirr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), 0) | (uint32(c.regoff(p.GetFrom3()))&0x7F)<<11
case 42: /* lswi */
o1 = AOP_RRR(c.opirr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), 0) | (uint32(c.regoff(p.GetFrom3()))&0x7F)<<11
case 43: /* data cache instructions: op (Ra+[Rb]), [th|l] */
/* TH field for dcbt/dcbtst: */
/* 0 = Block access - program will soon access EA. */
/* 8-15 = Stream access - sequence of access (data stream). See section 4.3.2 of the ISA for details. */
/* 16 = Block access - program will soon make a transient access to EA. */
/* 17 = Block access - program will not access EA for a long time. */
/* L field for dcbf: */
/* 0 = invalidates the block containing EA in all processors. */
/* 1 = same as 0, but with limited scope (i.e. block in the current processor will not be reused soon). */
/* 3 = same as 1, but with even more limited scope (i.e. block in the current processor primary cache will not be reused soon). */
if p.To.Type == obj.TYPE_NONE {
o1 = AOP_RRR(c.oprrr(p.As), 0, uint32(p.From.Index), uint32(p.From.Reg))
} else {
th := c.regoff(&p.To)
o1 = AOP_RRR(c.oprrr(p.As), uint32(th), uint32(p.From.Index), uint32(p.From.Reg))
}
case 44: /* indexed store */
o1 = AOP_RRR(c.opstorex(p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))
case 45: /* indexed load */
switch p.As {
/* The assembler accepts a 4-operand l*arx instruction. The fourth operand is an Exclusive Access Hint (EH) */
/* The EH field can be used as a lock acquire/release hint as follows: */
/* 0 = Atomic Update (fetch-and-operate or similar algorithm) */
/* 1 = Exclusive Access (lock acquire and release) */
case ALBAR, ALHAR, ALWAR, ALDAR:
if p.From3Type() != obj.TYPE_NONE {
eh := int(c.regoff(p.GetFrom3()))
if eh > 1 {
c.ctxt.Diag("illegal EH field\n%v", p)
}
o1 = AOP_RRRI(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg), uint32(eh))
} else {
o1 = AOP_RRR(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
}
default:
o1 = AOP_RRR(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
}
case 46: /* plain op */
o1 = c.oprrr(p.As)
case 47: /* op Ra, Rd; also op [Ra,] Rd */
r := int(p.From.Reg)
if r == 0 {
r = int(p.To.Reg)
}
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), 0)
case 48: /* op Rs, Ra */
r := int(p.From.Reg)
if r == 0 {
r = int(p.To.Reg)
}
o1 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), 0)
case 49: /* op Rb; op $n, Rb */
if p.From.Type != obj.TYPE_REG { /* tlbie $L, rB */
v := c.regoff(&p.From) & 1
o1 = AOP_RRR(c.oprrr(p.As), 0, 0, uint32(p.To.Reg)) | uint32(v)<<21
} else {
o1 = AOP_RRR(c.oprrr(p.As), 0, 0, uint32(p.From.Reg))
}
case 50: /* rem[u] r1[,r2],r3 */
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
v := c.oprrr(p.As)
t := v & (1<<10 | 1) /* OE|Rc */
o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg))
o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, uint32(p.From.Reg))
o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r))
if p.As == AREMU {
o4 = o3
/* Clear top 32 bits */
o3 = OP_RLW(OP_RLDIC, REGTMP, REGTMP, 0, 0, 0) | 1<<5
}
case 51: /* remd[u] r1[,r2],r3 */
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
v := c.oprrr(p.As)
t := v & (1<<10 | 1) /* OE|Rc */
o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg))
o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, uint32(p.From.Reg))
o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r))
/* cases 50,51: removed; can be reused. */
/* cases 50,51: removed; can be reused. */
case 52: /* mtfsbNx cr(n) */
v := c.regoff(&p.From) & 31
o1 = AOP_RRR(c.oprrr(p.As), uint32(v), 0, 0)
case 53: /* mffsX ,fr1 */
o1 = AOP_RRR(OP_MFFS, uint32(p.To.Reg), 0, 0)
case 55: /* op Rb, Rd */
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), 0, uint32(p.From.Reg))
case 56: /* sra $sh,[s,]a; srd $sh,[s,]a */
v := c.regoff(&p.From)
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
o1 = AOP_RRR(c.opirr(p.As), uint32(r), uint32(p.To.Reg), uint32(v)&31)
if (p.As == ASRAD || p.As == ASRADCC) && (v&0x20 != 0) {
o1 |= 1 << 1 /* mb[5] */
}
case 57: /* slw $sh,[s,]a -> rlwinm ... */
v := c.regoff(&p.From)
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
/*
* Let user (gs) shoot himself in the foot.
* qc has already complained.
*
if(v < 0 || v > 31)
ctxt->diag("illegal shift %ld\n%v", v, p);
*/
if v < 0 {
v = 0
} else if v > 32 {
v = 32
}
var mask [2]uint8
switch p.As {
case AROTLW:
mask[0], mask[1] = 0, 31
case ASRW, ASRWCC:
mask[0], mask[1] = uint8(v), 31
v = 32 - v
default:
mask[0], mask[1] = 0, uint8(31-v)
}
o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(r), uint32(v), uint32(mask[0]), uint32(mask[1]))
if p.As == ASLWCC || p.As == ASRWCC {
o1 |= 1 // set the condition code
}
case 58: /* logical $andcon,[s],a */
v := c.regoff(&p.From)
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
o1 = LOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
case 59: /* or/xor/and $ucon,,r | oris/xoris/andis $addcon,r,r */
v := c.regoff(&p.From)
r := int(p.Reg)
if r == 0 {
r = int(p.To.Reg)
}
switch p.As {
case AOR:
o1 = LOP_IRR(c.opirr(AORIS), uint32(p.To.Reg), uint32(r), uint32(v)>>16) /* oris, xoris, andis. */
case AXOR:
o1 = LOP_IRR(c.opirr(AXORIS), uint32(p.To.Reg), uint32(r), uint32(v)>>16)
case AANDCC:
o1 = LOP_IRR(c.opirr(AANDISCC), uint32(p.To.Reg), uint32(r), uint32(v)>>16)
default:
o1 = LOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
}
case 60: /* tw to,a,b */
r := int(c.regoff(&p.From) & 31)
o1 = AOP_RRR(c.oprrr(p.As), uint32(r), uint32(p.Reg), uint32(p.To.Reg))
case 61: /* tw to,a,$simm */
r := int(c.regoff(&p.From) & 31)
v := c.regoff(&p.To)
o1 = AOP_IRR(c.opirr(p.As), uint32(r), uint32(p.Reg), uint32(v))
case 62: /* rlwmi $sh,s,$mask,a */
v := c.regoff(&p.From)
switch p.As {
case ACLRLSLWI:
n := c.regoff(p.GetFrom3())
// This is an extended mnemonic described in the ISA C.8.2
// clrlslwi ra,rs,b,n -> rlwinm ra,rs,n,b-n,31-n
// It maps onto rlwinm which is directly generated here.
if n > v || v >= 32 {
c.ctxt.Diag("Invalid n or b for CLRLSLWI: %x %x\n%v", v, n, p)
}
o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.Reg), uint32(n), uint32(v-n), uint32(31-n))
default:
var mask [2]uint8
c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(v))
o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
}
case 63: /* rlwmi b,s,$mask,a */
var mask [2]uint8
c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg))
o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
case 64: /* mtfsf fr[, $m] {,fpcsr} */
var v int32
if p.From3Type() != obj.TYPE_NONE {
v = c.regoff(p.GetFrom3()) & 255
} else {
v = 255
}
o1 = OP_MTFSF | uint32(v)<<17 | uint32(p.From.Reg)<<11
case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
if p.To.Reg == 0 {
c.ctxt.Diag("must specify FPSCR(n)\n%v", p)
}
o1 = OP_MTFSFI | (uint32(p.To.Reg)&15)<<23 | (uint32(c.regoff(&p.From))&31)<<12
case 66: /* mov spr,r1; mov r1,spr */
var r int
var v int32
if REG_R0 <= p.From.Reg && p.From.Reg <= REG_R31 {
r = int(p.From.Reg)
v = int32(p.To.Reg)
o1 = OPVCC(31, 467, 0, 0) /* mtspr */
} else {
r = int(p.To.Reg)
v = int32(p.From.Reg)
o1 = OPVCC(31, 339, 0, 0) /* mfspr */
}
o1 = AOP_RRR(o1, uint32(r), 0, 0) | (uint32(v)&0x1f)<<16 | ((uint32(v)>>5)&0x1f)<<11
case 67: /* mcrf crfD,crfS */
if p.From.Reg == REG_CR || p.To.Reg == REG_CR {
c.ctxt.Diag("CR argument must be a conditional register field (CR0-CR7)\n%v", p)
}
o1 = AOP_RRR(OP_MCRF, ((uint32(p.To.Reg) & 7) << 2), ((uint32(p.From.Reg) & 7) << 2), 0)
case 68: /* mfcr rD; mfocrf CRM,rD */
o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) /* form, whole register */
if p.From.Reg != REG_CR {
v := uint32(1) << uint(7-(p.From.Reg&7)) /* CR(n) */
o1 |= 1<<20 | v<<12 /* new form, mfocrf */
}
case 69: /* mtcrf CRM,rS, mtocrf CRx,rS */
var v uint32
if p.To.Reg == REG_CR {
v = 0xff
} else if p.To.Offset != 0 { // MOVFL gpr, constant
v = uint32(p.To.Offset)
} else { // p.To.Reg == REG_CRx
v = 1 << uint(7-(p.To.Reg&7))
}
// Use mtocrf form if only one CR field moved.
if bits.OnesCount32(v) == 1 {
v |= 1 << 8
}
o1 = AOP_RRR(OP_MTCRF, uint32(p.From.Reg), 0, 0) | uint32(v)<<12
case 70: /* [f]cmp r,r,cr*/
var r int
if p.Reg == 0 {
r = 0
} else {
r = (int(p.Reg) & 7) << 2
}
o1 = AOP_RRR(c.oprrr(p.As), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
case 71: /* cmp[l] r,i,cr*/
var r int
if p.Reg == 0 {
r = 0
} else {
r = (int(p.Reg) & 7) << 2
}
o1 = AOP_RRR(c.opirr(p.As), uint32(r), uint32(p.From.Reg), 0) | uint32(c.regoff(&p.To))&0xffff
case 72: /* slbmte (Rb+Rs -> slb[Rb]) -> Rs, Rb */
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), 0, uint32(p.To.Reg))
case 73: /* mcrfs crfD,crfS */
if p.From.Type != obj.TYPE_REG || p.From.Reg != REG_FPSCR || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
c.ctxt.Diag("illegal FPSCR/CR field number\n%v", p)
}
o1 = AOP_RRR(OP_MCRFS, ((uint32(p.To.Reg) & 7) << 2), ((0 & 7) << 2), 0)
case 77: /* syscall $scon, syscall Rx */
if p.From.Type == obj.TYPE_CONST {
if p.From.Offset > BIG || p.From.Offset < -BIG {
c.ctxt.Diag("illegal syscall, sysnum too large: %v", p)
}
o1 = AOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(p.From.Offset))
} else if p.From.Type == obj.TYPE_REG {
o1 = LOP_RRR(OP_OR, REGZERO, uint32(p.From.Reg), uint32(p.From.Reg))
} else {
c.ctxt.Diag("illegal syscall: %v", p)
o1 = 0x7fe00008 // trap always
}
o2 = c.oprrr(p.As)
o3 = AOP_RRR(c.oprrr(AXOR), REGZERO, REGZERO, REGZERO) // XOR R0, R0
case 78: /* undef */
o1 = 0 /* "An instruction consisting entirely of binary 0s is guaranteed
always to be an illegal instruction." */
/* relocation operations */
case 74:
v := c.vregoff(&p.To)
// Offsets in DS form stores must be a multiple of 4
inst := c.opstore(p.As)
if c.opform(inst) == DS_FORM && v&0x3 != 0 {
log.Fatalf("invalid offset for DS form load/store %v", p)
}
// Can't reuse base for store instructions.
o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst, false)
case 75: // 32 bit offset symbol loads (got/toc/addr)
v := p.From.Offset
// Offsets in DS form loads must be a multiple of 4
inst := c.opload(p.As)
if c.opform(inst) == DS_FORM && v&0x3 != 0 {
log.Fatalf("invalid offset for DS form load/store %v", p)
}
switch p.From.Name {
case obj.NAME_GOTREF, obj.NAME_TOCREF:
if v != 0 {
c.ctxt.Diag("invalid offset for GOT/TOC access %v", p)
}
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
o2 = AOP_IRR(inst, uint32(p.To.Reg), uint32(p.To.Reg), 0)
rel := obj.Addrel(c.cursym)
rel.Off = int32(c.pc)
rel.Siz = 8
rel.Sym = p.From.Sym
switch p.From.Name {
case obj.NAME_GOTREF:
rel.Type = objabi.R_ADDRPOWER_GOT
case obj.NAME_TOCREF:
rel.Type = objabi.R_ADDRPOWER_TOCREL_DS
}
default:
reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS
// Reuse To.Reg as base register if not FP move.
o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg)
}
o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
case 79:
if p.From.Offset != 0 {
c.ctxt.Diag("invalid offset against tls var %v", p)
}
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R13, 0)
o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), uint32(p.To.Reg), 0)
rel := obj.Addrel(c.cursym)
rel.Off = int32(c.pc)
rel.Siz = 8
rel.Sym = p.From.Sym
rel.Type = objabi.R_POWER_TLS_LE
case 80:
if p.From.Offset != 0 {
c.ctxt.Diag("invalid offset against tls var %v", p)
}
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
o2 = AOP_IRR(c.opload(AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
o3 = AOP_RRR(OP_ADD, uint32(p.To.Reg), uint32(p.To.Reg), REG_R13)
rel := obj.Addrel(c.cursym)
rel.Off = int32(c.pc)
rel.Siz = 8
rel.Sym = p.From.Sym
rel.Type = objabi.R_POWER_TLS_IE
rel = obj.Addrel(c.cursym)
rel.Off = int32(c.pc) + 8
rel.Siz = 4
rel.Sym = p.From.Sym
rel.Type = objabi.R_POWER_TLS
case 82: /* vector instructions, VX-form and VC-form */
if p.From.Type == obj.TYPE_REG {
/* reg reg none OR reg reg reg */
/* 3-register operand order: VRA, VRB, VRT */
/* 2-register operand order: VRA, VRT */
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
} else if p.From3Type() == obj.TYPE_CONST {
/* imm imm reg reg */
/* operand order: SIX, VRA, ST, VRT */
six := int(c.regoff(&p.From))
st := int(c.regoff(p.GetFrom3()))
o1 = AOP_IIRR(c.opiirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(st), uint32(six))
} else if p.From3Type() == obj.TYPE_NONE && p.Reg != 0 {
/* imm reg reg */
/* operand order: UIM, VRB, VRT */
uim := int(c.regoff(&p.From))
o1 = AOP_VIRR(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(uim))
} else {
/* imm reg */
/* operand order: SIM, VRT */
sim := int(c.regoff(&p.From))
o1 = AOP_IR(c.opirr(p.As), uint32(p.To.Reg), uint32(sim))
}
case 83: /* vector instructions, VA-form */
if p.From.Type == obj.TYPE_REG {
/* reg reg reg reg */
/* 4-register operand order: VRA, VRB, VRC, VRT */
o1 = AOP_RRRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg))
} else if p.From.Type == obj.TYPE_CONST {
/* imm reg reg reg */
/* operand order: SHB, VRA, VRB, VRT */
shb := int(c.regoff(&p.From))
o1 = AOP_IRRR(c.opirrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg), uint32(shb))
}
case 84: // ISEL BC,RA,RB,RT -> isel rt,ra,rb,bc
bc := c.vregoff(&p.From)
// rt = To.Reg, ra = p.Reg, rb = p.From3.Reg
o1 = AOP_ISEL(OP_ISEL, uint32(p.To.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg), uint32(bc))
case 85: /* vector instructions, VX-form */
/* reg none reg */
/* 2-register operand order: VRB, VRT */
o1 = AOP_RR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg))
case 86: /* VSX indexed store, XX1-form */
/* reg reg reg */
/* 3-register operand order: XT, (RB)(RA*1) */
o1 = AOP_XX1(c.opstorex(p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))
case 87: /* VSX indexed load, XX1-form */
/* reg reg reg */
/* 3-register operand order: (RB)(RA*1), XT */
o1 = AOP_XX1(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
case 88: /* VSX mfvsr* instructions, XX1-form XS,RA */
o1 = AOP_XX1(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
case 89: /* VSX instructions, XX2-form */
/* reg none reg OR reg imm reg */
/* 2-register operand order: XB, XT or XB, UIM, XT*/
uim := int(c.regoff(p.GetFrom3()))
o1 = AOP_XX2(c.oprrr(p.As), uint32(p.To.Reg), uint32(uim), uint32(p.From.Reg))
case 90: /* VSX instructions, XX3-form */
if p.From3Type() == obj.TYPE_NONE {
/* reg reg reg */
/* 3-register operand order: XA, XB, XT */
o1 = AOP_XX3(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
} else if p.From3Type() == obj.TYPE_CONST {
/* reg reg reg imm */
/* operand order: XA, XB, DM, XT */
dm := int(c.regoff(p.GetFrom3()))
o1 = AOP_XX3I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(dm))
}
case 91: /* VSX instructions, XX4-form */
/* reg reg reg reg */
/* 3-register operand order: XA, XB, XC, XT */
o1 = AOP_XX4(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg))
case 92: /* X-form instructions, 3-operands */
if p.To.Type == obj.TYPE_CONST {
/* imm reg reg */
xf := int32(p.From.Reg)
if REG_F0 <= xf && xf <= REG_F31 {
/* operand order: FRA, FRB, BF */
bf := int(c.regoff(&p.To)) << 2
o1 = AOP_RRR(c.opirr(p.As), uint32(bf), uint32(p.From.Reg), uint32(p.Reg))
} else {
/* operand order: RA, RB, L */
l := int(c.regoff(&p.To))
o1 = AOP_RRR(c.opirr(p.As), uint32(l), uint32(p.From.Reg), uint32(p.Reg))
}
} else if p.From3Type() == obj.TYPE_CONST {
/* reg reg imm */
/* operand order: RB, L, RA */
l := int(c.regoff(p.GetFrom3()))
o1 = AOP_RRR(c.opirr(p.As), uint32(l), uint32(p.To.Reg), uint32(p.From.Reg))
} else if p.To.Type == obj.TYPE_REG {
cr := int32(p.To.Reg)
if REG_CR0 <= cr && cr <= REG_CR7 {
/* cr reg reg */
/* operand order: RA, RB, BF */
bf := (int(p.To.Reg) & 7) << 2
o1 = AOP_RRR(c.opirr(p.As), uint32(bf), uint32(p.From.Reg), uint32(p.Reg))
} else if p.From.Type == obj.TYPE_CONST {
/* reg imm */
/* operand order: L, RT */
l := int(c.regoff(&p.From))
o1 = AOP_RRR(c.opirr(p.As), uint32(p.To.Reg), uint32(l), uint32(p.Reg))
} else {
switch p.As {
case ACOPY, APASTECC:
o1 = AOP_RRR(c.opirr(p.As), uint32(1), uint32(p.From.Reg), uint32(p.To.Reg))
default:
/* reg reg reg */
/* operand order: RS, RB, RA */
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
}
}
}
case 93: /* X-form instructions, 2-operands */
if p.To.Type == obj.TYPE_CONST {
/* imm reg */
/* operand order: FRB, BF */
bf := int(c.regoff(&p.To)) << 2
o1 = AOP_RR(c.opirr(p.As), uint32(bf), uint32(p.From.Reg))
} else if p.Reg == 0 {
/* popcnt* r,r, X-form */
/* operand order: RS, RA */
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
}
case 94: /* Z23-form instructions, 4-operands */
/* reg reg reg imm */
/* operand order: RA, RB, CY, RT */
cy := int(c.regoff(p.GetFrom3()))
o1 = AOP_Z23I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(cy))
case 96: /* VSX load, DQ-form */
/* reg imm reg */
/* operand order: (RA)(DQ), XT */
dq := int16(c.regoff(&p.From))
if (dq & 15) != 0 {
c.ctxt.Diag("invalid offset for DQ form load/store %v", dq)
}
o1 = AOP_DQ(c.opload(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(dq))
case 97: /* VSX store, DQ-form */
/* reg imm reg */
/* operand order: XT, (RA)(DQ) */
dq := int16(c.regoff(&p.To))
if (dq & 15) != 0 {
c.ctxt.Diag("invalid offset for DQ form load/store %v", dq)
}
o1 = AOP_DQ(c.opstore(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(dq))
case 98: /* VSX indexed load or load with length (also left-justified), x-form */
/* vsreg, reg, reg */
o1 = AOP_XX1(c.opload(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
case 99: /* VSX store with length (also left-justified) x-form */
/* reg, reg, vsreg */
o1 = AOP_XX1(c.opstore(p.As), uint32(p.From.Reg), uint32(p.Reg), uint32(p.To.Reg))
case 100: /* VSX X-form XXSPLTIB */
if p.From.Type == obj.TYPE_CONST {
/* imm reg */
uim := int(c.regoff(&p.From))
/* imm reg */
/* Use AOP_XX1 form with 0 for one of the registers. */
o1 = AOP_XX1(c.oprrr(p.As), uint32(p.To.Reg), uint32(0), uint32(uim))
} else {
c.ctxt.Diag("invalid ops for %v", p.As)
}
case 101:
o1 = AOP_XX2(c.oprrr(p.As), uint32(p.To.Reg), uint32(0), uint32(p.From.Reg))
case 102: /* RLWMI $sh,rs,$mb,$me,rt (M-form opcode)*/
mb := uint32(c.regoff(&p.RestArgs[0].Addr))
me := uint32(c.regoff(&p.RestArgs[1].Addr))
sh := uint32(c.regoff(&p.From))
o1 = OP_RLW(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), sh, mb, me)
case 103: /* RLWMI rb,rs,$mb,$me,rt (M-form opcode)*/
mb := uint32(c.regoff(&p.RestArgs[0].Addr))
me := uint32(c.regoff(&p.RestArgs[1].Addr))
o1 = OP_RLW(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.From.Reg), mb, me)
case 104: /* VSX mtvsr* instructions, XX1-form RA,RB,XT */
o1 = AOP_XX1(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
case 105: /* PNOP */
o1 = 0x07000000
o2 = 0x00000000
}
out[0] = o1
out[1] = o2
out[2] = o3
out[3] = o4
out[4] = o5
}