MOVD $2199090364416, R5 // 60058001
// Hex constant 0xFFFFFE0004000000
MOVD $-2198956146688, R5 // 38a08001
+ // TODO: On GOPPC64={power8,power9}, this is preprocessed into MOVD $-1, R5; RLDC R5, $33, $63, R5.
+ // This only captures the MOVD. Should the RLDC be appended to the encoding by the test?
+ // Hex constant 0xFFFFFFFE00000001
+ MOVD $-8589934591, R5 // 38a0ffff or 0602000038a00001
MOVD 8(R3), R4 // e8830008
MOVD (R3)(R4), R5 // 7ca4182a
RLDIMI $0, R4, $7, R6 // 788601cc
RLDIMICC $0, R4, $7, R6 // 788601cd
RLDC $0, R4, $15, R6 // 78860728
+ RLDC R3, $32, $12, R4 // 7864030a
+ RLDC R3, $8, $32, R4 // 78644028
+ RLDCCC R3, $32, $12, R4 // 7864030b
+ RLDCCC R3, $8, $32, R4 // 78644029
RLDCCC $0, R4, $15, R6 // 78860729
RLDCL $0, R4, $7, R6 // 78860770
RLDCLCC $0, R4, $15, R6 // 78860721
{as: ACLRLSLWI, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 62, size: 4},
{as: ARLDMI, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 30, size: 4},
{as: ARLDC, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 29, size: 4},
+ {as: ARLDC, a1: C_REG, a3: C_U8CON, a4: C_U8CON, a6: C_REG, type_: 9, size: 4},
{as: ARLDCL, a1: C_SCON, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 29, size: 4},
{as: ARLDCL, a1: C_REG, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 14, size: 4},
{as: ARLDICL, a1: C_REG, a2: C_REG, a3: C_LCON, a6: C_REG, type_: 14, size: 4},
// 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 9: /* RLDC Ra, $sh, $mb, Rb */
+ sh := uint32(p.RestArgs[0].Addr.Offset) & 0x3F
+ mb := uint32(p.RestArgs[1].Addr.Offset) & 0x3F
+ o1 = AOP_RRR(c.opirr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), (uint32(sh) & 0x1F))
+ o1 |= (sh & 0x20) >> 4 // sh[5] is placed in bit 1.
+ o1 |= (mb & 0x1F) << 6 // mb[0:4] is placed in bits 6-10.
+ o1 |= (mb & 0x20) // mb[5] is placed in bit 5
+
case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
r := int(p.Reg)
"math/bits"
)
+// Test if this value can encoded as a mask for
+// li -1, rx; rlic rx,rx,sh,mb.
+// Masks can also extend from the msb and wrap to
+// the lsb too. That is, the valid masks are 32 bit strings
+// of the form: 0..01..10..0 or 1..10..01..1 or 1...1
+func isPPC64DoublewordRotateMask(v64 int64) bool {
+ // Isolate rightmost 1 (if none 0) and add.
+ v := uint64(v64)
+ vp := (v & -v) + v
+ // Likewise, for the wrapping case.
+ vn := ^v
+ vpn := (vn & -vn) + vn
+ return (v&vp == 0 || vn&vpn == 0) && v != 0
+}
+
+// Encode a doubleword rotate mask into mb (mask begin) and
+// me (mask end, inclusive). Note, POWER ISA labels bits in
+// big endian order.
+func encodePPC64RLDCMask(mask int64) (mb, me int) {
+ // Determine boundaries and then decode them
+ mb = bits.LeadingZeros64(uint64(mask))
+ me = 64 - bits.TrailingZeros64(uint64(mask))
+ mbn := bits.LeadingZeros64(^uint64(mask))
+ men := 64 - bits.TrailingZeros64(^uint64(mask))
+ // Check for a wrapping mask (e.g bits at 0 and 63)
+ if mb == 0 && me == 64 {
+ // swap the inverted values
+ mb, me = men, mbn
+ }
+ // Note, me is inclusive.
+ return mb, me - 1
+}
+
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.From.Class = 0
p.To.Class = 0
// Rewrite this value into MOVD $const>>shift, Rto; SLD $shift, Rto
q := obj.Appendp(p, c.newprog)
q.As = ASLD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(shift)
+ q.From.SetConst(int64(shift))
q.To = p.To
p.From.Offset >>= shift
p = q
+ // Is this constant a mask value? If so, generate MOVD $-1, Rto; RLDIC Rto, ^me, mb, Rto
+ } else if isPPC64DoublewordRotateMask(val) {
+ mb, me := encodePPC64RLDCMask(val)
+ q := obj.Appendp(p, c.newprog)
+ q.As = ARLDC
+ q.AddRestSourceConst((^int64(me)) & 0x3F)
+ q.AddRestSourceConst(int64(mb))
+ q.From = p.To
+ q.To = p.To
+ p.From.Offset = -1
+ p = q
} else {
// Load the constant from memory.
p.From.Type = obj.TYPE_MEM
package codegen
+// A uint16 or sint16 constant shifted left.
func shifted16BitConstants(out [64]uint64) {
// ppc64x: "MOVD\t[$]8193,", "SLD\t[$]27,"
out[0] = 0x0000010008000000
out[2] = 0xFFFF000000000000
// ppc64x: "MOVD\t[$]65535", "SLD\t[$]44,"
out[3] = 0x0FFFF00000000000
+}
- // ppc64x: "MOVD\t[$]i64.fffff00000000001[(]SB[)]"
- out[4] = 0xFFFFF00000000001
- // ppc64x: "MOVD\t[$]i64.fffff80000000001[(]SB[)]"
- out[5] = 0xFFFFF80000000001
- // ppc64x: "MOVD\t[$]i64.0ffff80000000000[(]SB[)]"
- out[6] = 0x0FFFF80000000000
+// A contiguous set of 1 bits, potentially wrapping.
+func contiguousMaskConstants(out [64]uint64) {
+ // ppc64x: "MOVD\t[$]-1", "RLDC\tR[0-9]+, [$]44, [$]63,"
+ out[0] = 0xFFFFF00000000001
+ // ppc64x: "MOVD\t[$]-1", "RLDC\tR[0-9]+, [$]43, [$]63,"
+ out[1] = 0xFFFFF80000000001
+ // ppc64x: "MOVD\t[$]-1", "RLDC\tR[0-9]+, [$]43, [$]4,"
+ out[2] = 0x0FFFF80000000000
+ // ppc64x/power8: "MOVD\t[$]-1", "RLDC\tR[0-9]+, [$]33, [$]63,"
+ // ppc64x/power9: "MOVD\t[$]-1", "RLDC\tR[0-9]+, [$]33, [$]63,"
+ // ppc64x/power10: "MOVD\t[$]-8589934591,"
+ out[3] = 0xFFFFFFFE00000001
}