Skip to content

Commit 3e4ad6c

Browse files
committed
cmd/compile: fix long RMW bit operations on AMD64
Under certain circumstances, the existing rules for bit operations can produce code that writes beyond its intended bounds. For example, consider the following code: func repro(b []byte, addr, bit int32) { _ = b[3] v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 | 1<<(bit&31) b[0] = byte(v) b[1] = byte(v >> 8) b[2] = byte(v >> 16) b[3] = byte(v >> 24) } Roughly speaking: 1. The expression `1 << (bit & 31)` is rewritten into `(SHLL 1 bit)` 2. The expression `uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24` is rewritten into `(MOVLload &b[0])` 3. The statements `b[0] = byte(v) ... b[3] = byte(v >> 24)` are rewritten into `(MOVLstore &b[0], v)` 4. `(ORL (SHLL 1, bit) (MOVLload &b[0]))` is rewritten into `(BTSL (MOVLload &b[0]) bit)`. This is a valid transformation because the destination is a register: in this case, the bit offset is masked by the number of bits in the destination register. This is identical to the masking performed by `SHL`. 5. `(MOVLstore &b[0] (BTSL (MOVLload &b[0]) bit))` is rewritten into `(BTSLmodify &b[0] bit)`. This is an invalid transformation because the destination is memory: in this case, the bit offset is not masked, and the chosen instruction may write outside its intended 32-bit location. These changes fix the invalid rewrite performed in step (5) by adding an `AuxInt` field to `S(H|A)(L|R)(L|Q)` and `BT(S|R|C)(L|Q)` that indicates whether or not the shift amount/bit offset is known to be bounded and using that field to decide whether or not the bit offset operand to `BT(S|R|C)(L|Q)modify` must be masked. Applying the adjusted rules to the example above changes the rewrite performed in step (5) s.t. it produces `(BTSLmodify &b[0] (ANDLconst [31] bit))`. These changes also add several new rules to rewrite bit sets, toggles, and clears that are rooted at `(OR|XOR|AND)(L|Q)modify` operators into appropriate `BT(S|R|C)(L|Q)modify` operators. These rules catch cases where `MOV(L|Q)store ((OR|XOR|AND)(L|Q) ...)` is rewritten to `(OR|XOR|AND)(L|Q)modify` before the `(OR|XOR|AND)(L|Q) ...` can be rewritten to `BT(S|R|C)(L|Q) ...`. Overall, compilecmp reports small improvements in code size on darwin/amd64 when the changes to the compiler itself are exlcuded: file before after Δ % math.s 35557 35563 +6 +0.017% runtime.s 536464 536413 -51 -0.010% bytes.s 32629 32593 -36 -0.110% strings.s 44565 44529 -36 -0.081% cmd/vendor/golang.org/x/sys/unix.s 81686 81678 -8 -0.010% os/signal.s 7967 7959 -8 -0.100% math/big.s 188235 188253 +18 +0.010% cmd/link/internal/loader.s 89295 89056 -239 -0.268% cmd/link/internal/ld.s 633551 633232 -319 -0.050% cmd/link/internal/arm.s 18934 18928 -6 -0.032% cmd/link/internal/arm64.s 31814 31801 -13 -0.041% cmd/link/internal/riscv64.s 7347 7345 -2 -0.027% cmd/compile/internal/ssa.s 4029173 4041251 +12078 +0.300% total 21298280 21309664 +11384 +0.053%
1 parent 2887ef4 commit 3e4ad6c

File tree

5 files changed

+782
-125
lines changed

5 files changed

+782
-125
lines changed

src/cmd/compile/internal/ssa/gen/AMD64.rules

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -169,20 +169,20 @@
169169
(Lsh16x(64|32|16|8) <t> x y) && !shiftIsBounded(v) => (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMP(Q|L|W|B)const y [32])))
170170
(Lsh8x(64|32|16|8) <t> x y) && !shiftIsBounded(v) => (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMP(Q|L|W|B)const y [32])))
171171

172-
(Lsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SHLQ x y)
173-
(Lsh32x(64|32|16|8) x y) && shiftIsBounded(v) => (SHLL x y)
174-
(Lsh16x(64|32|16|8) x y) && shiftIsBounded(v) => (SHLL x y)
175-
(Lsh8x(64|32|16|8) x y) && shiftIsBounded(v) => (SHLL x y)
172+
(Lsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SHLQ [true] x y)
173+
(Lsh32x(64|32|16|8) x y) && shiftIsBounded(v) => (SHLL [true] x y)
174+
(Lsh16x(64|32|16|8) x y) && shiftIsBounded(v) => (SHLL [true] x y)
175+
(Lsh8x(64|32|16|8) x y) && shiftIsBounded(v) => (SHLL [true] x y)
176176

177177
(Rsh64Ux(64|32|16|8) <t> x y) && !shiftIsBounded(v) => (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMP(Q|L|W|B)const y [64])))
178178
(Rsh32Ux(64|32|16|8) <t> x y) && !shiftIsBounded(v) => (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMP(Q|L|W|B)const y [32])))
179179
(Rsh16Ux(64|32|16|8) <t> x y) && !shiftIsBounded(v) => (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMP(Q|L|W|B)const y [16])))
180180
(Rsh8Ux(64|32|16|8) <t> x y) && !shiftIsBounded(v) => (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMP(Q|L|W|B)const y [8])))
181181

182-
(Rsh64Ux(64|32|16|8) x y) && shiftIsBounded(v) => (SHRQ x y)
183-
(Rsh32Ux(64|32|16|8) x y) && shiftIsBounded(v) => (SHRL x y)
184-
(Rsh16Ux(64|32|16|8) x y) && shiftIsBounded(v) => (SHRW x y)
185-
(Rsh8Ux(64|32|16|8) x y) && shiftIsBounded(v) => (SHRB x y)
182+
(Rsh64Ux(64|32|16|8) x y) && shiftIsBounded(v) => (SHRQ [true] x y)
183+
(Rsh32Ux(64|32|16|8) x y) && shiftIsBounded(v) => (SHRL [true] x y)
184+
(Rsh16Ux(64|32|16|8) x y) && shiftIsBounded(v) => (SHRW [true] x y)
185+
(Rsh8Ux(64|32|16|8) x y) && shiftIsBounded(v) => (SHRB [true] x y)
186186

187187
// Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
188188
// We implement this by setting the shift value to -1 (all ones) if the shift value is >= width.
@@ -191,10 +191,10 @@
191191
(Rsh16x(64|32|16|8) <t> x y) && !shiftIsBounded(v) => (SARW <t> x (OR(Q|L|L|L) <y.Type> y (NOT(Q|L|L|L) <y.Type> (SBB(Q|L|L|L)carrymask <y.Type> (CMP(Q|L|W|B)const y [16])))))
192192
(Rsh8x(64|32|16|8) <t> x y) && !shiftIsBounded(v) => (SARB <t> x (OR(Q|L|L|L) <y.Type> y (NOT(Q|L|L|L) <y.Type> (SBB(Q|L|L|L)carrymask <y.Type> (CMP(Q|L|W|B)const y [8])))))
193193

194-
(Rsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SARQ x y)
195-
(Rsh32x(64|32|16|8) x y) && shiftIsBounded(v) => (SARL x y)
196-
(Rsh16x(64|32|16|8) x y) && shiftIsBounded(v) => (SARW x y)
197-
(Rsh8x(64|32|16|8) x y) && shiftIsBounded(v) => (SARB x y)
194+
(Rsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SARQ [true] x y)
195+
(Rsh32x(64|32|16|8) x y) && shiftIsBounded(v) => (SARL [true] x y)
196+
(Rsh16x(64|32|16|8) x y) && shiftIsBounded(v) => (SARW [true] x y)
197+
(Rsh8x(64|32|16|8) x y) && shiftIsBounded(v) => (SARB [true] x y)
198198

199199
// Lowering integer comparisons
200200
(Less(64|32|16|8) x y) => (SETL (CMP(Q|L|W|B) x y))
@@ -609,10 +609,10 @@
609609
// and further combining shifts.
610610
(BT(Q|L)const [c] (SHRQconst [d] x)) && (c+d)<64 => (BTQconst [c+d] x)
611611
(BT(Q|L)const [c] (SHLQconst [d] x)) && c>d => (BT(Q|L)const [c-d] x)
612-
(BT(Q|L)const [0] s:(SHRQ x y)) => (BTQ y x)
612+
(BT(Q|L)const [0] s:(SHRQ [a] x y)) => (BTQ [a] y x)
613613
(BTLconst [c] (SHRLconst [d] x)) && (c+d)<32 => (BTLconst [c+d] x)
614614
(BTLconst [c] (SHLLconst [d] x)) && c>d => (BTLconst [c-d] x)
615-
(BTLconst [0] s:(SHRL x y)) => (BTL y x)
615+
(BTLconst [0] s:(SHRL [a] x y)) => (BTL [a] y x)
616616

617617
// Rewrite a & 1 != 1 into a & 1 == 0.
618618
// Among other things, this lets us turn (a>>b)&1 != 1 into a bit test.
@@ -622,8 +622,24 @@
622622
(SET(NE|EQ)store [off] {sym} ptr (CMPQconst [1] s:(ANDQconst [1] _)) mem) => (SET(EQ|NE)store [off] {sym} ptr (CMPQconst [0] s) mem)
623623

624624
// Recognize bit setting (a |= 1<<b) and toggling (a ^= 1<<b)
625-
(OR(Q|L) (SHL(Q|L) (MOV(Q|L)const [1]) y) x) => (BTS(Q|L) x y)
626-
(XOR(Q|L) (SHL(Q|L) (MOV(Q|L)const [1]) y) x) => (BTC(Q|L) x y)
625+
(OR(Q|L) (SHL(Q|L) [a] (MOV(Q|L)const [1]) y) x) => (BTS(Q|L) [a] x y)
626+
(XOR(Q|L) (SHL(Q|L) [a] (MOV(Q|L)const [1]) y) x) => (BTC(Q|L) [a] x y)
627+
(ORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem) && !shiftIsBounded(s) =>
628+
(BTSLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
629+
(ORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) x) mem) && shiftIsBounded(s) =>
630+
(BTSLmodify [off] {sym} ptr x mem)
631+
(ORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem) && !shiftIsBounded(s) =>
632+
(BTSQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
633+
(ORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) x) mem) && shiftIsBounded(s) =>
634+
(BTSQmodify [off] {sym} ptr x mem)
635+
(XORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) <t> x) mem) && !shiftIsBounded(s) =>
636+
(BTCLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
637+
(XORLmodify [off] {sym} ptr s:(SHLL (MOVLconst [1]) x) mem) && shiftIsBounded(s) =>
638+
(BTCLmodify [off] {sym} ptr x mem)
639+
(XORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) <t> x) mem) && !shiftIsBounded(s) =>
640+
(BTCQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
641+
(XORQmodify [off] {sym} ptr s:(SHLQ (MOVQconst [1]) x) mem) && shiftIsBounded(s) =>
642+
(BTCQmodify [off] {sym} ptr x mem)
627643

628644
// Convert ORconst into BTS, if the code gets smaller, with boundary being
629645
// (ORL $40,AX is 3 bytes, ORL $80,AX is 6 bytes).
@@ -637,7 +653,7 @@
637653
=> (BT(S|C)Lconst [int8(log32(c))] x)
638654

639655
// Recognize bit clearing: a &^= 1<<b
640-
(AND(Q|L) (NOT(Q|L) (SHL(Q|L) (MOV(Q|L)const [1]) y)) x) => (BTR(Q|L) x y)
656+
(AND(Q|L) (NOT(Q|L) (SHL(Q|L) [a] (MOV(Q|L)const [1]) y)) x) => (BTR(Q|L) [a] x y)
641657
(ANDQconst [c] x) && isUint64PowerOfTwo(int64(^c)) && uint64(^c) >= 128
642658
=> (BTRQconst [int8(log32(^c))] x)
643659
(ANDLconst [c] x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
@@ -646,6 +662,14 @@
646662
=> (BTRQconst [int8(log64(^c))] x)
647663
(ANDL (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
648664
=> (BTRLconst [int8(log32(^c))] x)
665+
(ANDLmodify [off] {sym} ptr (NOTL s:(SHLL (MOVLconst [1]) <t> x)) mem) && !shiftIsBounded(s) =>
666+
(BTRLmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
667+
(ANDLmodify [off] {sym} ptr (NOTL s:(SHLL (MOVLconst [1]) x)) mem) && shiftIsBounded(s) =>
668+
(BTRLmodify [off] {sym} ptr x mem)
669+
(ANDQmodify [off] {sym} ptr (NOTQ s:(SHLQ (MOVQconst [1]) <t> x)) mem) && !shiftIsBounded(s) =>
670+
(BTRQmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
671+
(ANDQmodify [off] {sym} ptr (NOTQ s:(SHLQ (MOVQconst [1]) x)) mem) && shiftIsBounded(s) =>
672+
(BTRQmodify [off] {sym} ptr x mem)
649673

650674
// Special-case bit patterns on first/last bit.
651675
// generic.rules changes ANDs of high-part/low-part masks into a couple of shifts,
@@ -2064,11 +2088,19 @@
20642088
((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
20652089
((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
20662090
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) => ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
2067-
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
2068-
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off] {sym} ptr x mem)
2091+
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
2092+
((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
2093+
(MOVLstore {sym} [off] ptr y:((BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) <t> x) mem) && !shiftIsBounded(y) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
2094+
((BTC|BTR|BTS)Lmodify [off] {sym} ptr (ANDLconst <t> [31] x) mem)
2095+
(MOVLstore {sym} [off] ptr y:((BTC|BTR|BTS)L l:(MOVLload [off] {sym} ptr mem) x) mem) && shiftIsBounded(y) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
2096+
((BTC|BTR|BTS)Lmodify [off] {sym} ptr x mem)
20692097
(MOVQstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Qload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) => ((ADD|AND|OR|XOR)Qmodify [off] {sym} ptr x mem)
2070-
(MOVQstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Q l:(MOVQload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
2071-
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Qmodify [off] {sym} ptr x mem)
2098+
(MOVQstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)Q l:(MOVQload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
2099+
((ADD|SUB|AND|OR|XOR)Qmodify [off] {sym} ptr x mem)
2100+
(MOVQstore {sym} [off] ptr y:((BTC|BTR|BTS)Q l:(MOVQload [off] {sym} ptr mem) <t> x) mem) && !shiftIsBounded(y) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
2101+
((BTC|BTR|BTS)Qmodify [off] {sym} ptr (ANDQconst <t> [63] x) mem)
2102+
(MOVQstore {sym} [off] ptr y:((BTC|BTR|BTS)Q l:(MOVQload [off] {sym} ptr mem) x) mem) && shiftIsBounded(y) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
2103+
((BTC|BTR|BTS)Qmodify [off] {sym} ptr x mem)
20722104

20732105
// Merge ADDQconst and LEAQ into atomic loads.
20742106
(MOV(Q|L|B)atomicload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>

src/cmd/compile/internal/ssa/gen/AMD64Ops.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -345,14 +345,14 @@ func init() {
345345
{name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32
346346
{name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64
347347

348-
{name: "BTL", argLength: 2, reg: gp2flags, asm: "BTL", typ: "Flags"}, // test whether bit arg0%32 in arg1 is set
349-
{name: "BTQ", argLength: 2, reg: gp2flags, asm: "BTQ", typ: "Flags"}, // test whether bit arg0%64 in arg1 is set
350-
{name: "BTCL", argLength: 2, reg: gp21, asm: "BTCL", resultInArg0: true, clobberFlags: true}, // complement bit arg1%32 in arg0
351-
{name: "BTCQ", argLength: 2, reg: gp21, asm: "BTCQ", resultInArg0: true, clobberFlags: true}, // complement bit arg1%64 in arg0
352-
{name: "BTRL", argLength: 2, reg: gp21, asm: "BTRL", resultInArg0: true, clobberFlags: true}, // reset bit arg1%32 in arg0
353-
{name: "BTRQ", argLength: 2, reg: gp21, asm: "BTRQ", resultInArg0: true, clobberFlags: true}, // reset bit arg1%64 in arg0
354-
{name: "BTSL", argLength: 2, reg: gp21, asm: "BTSL", resultInArg0: true, clobberFlags: true}, // set bit arg1%32 in arg0
355-
{name: "BTSQ", argLength: 2, reg: gp21, asm: "BTSQ", resultInArg0: true, clobberFlags: true}, // set bit arg1%64 in arg0
348+
{name: "BTL", argLength: 2, reg: gp2flags, aux: "Bool", asm: "BTL", typ: "Flags"}, // test whether bit arg0%32 in arg1 is set
349+
{name: "BTQ", argLength: 2, reg: gp2flags, aux: "Bool", asm: "BTQ", typ: "Flags"}, // test whether bit arg0%64 in arg1 is set
350+
{name: "BTCL", argLength: 2, reg: gp21, asm: "BTCL", aux: "Bool", resultInArg0: true, clobberFlags: true}, // complement bit arg1%32 in arg0
351+
{name: "BTCQ", argLength: 2, reg: gp21, asm: "BTCQ", aux: "Bool", resultInArg0: true, clobberFlags: true}, // complement bit arg1%64 in arg0
352+
{name: "BTRL", argLength: 2, reg: gp21, asm: "BTRL", aux: "Bool", resultInArg0: true, clobberFlags: true}, // reset bit arg1%32 in arg0
353+
{name: "BTRQ", argLength: 2, reg: gp21, asm: "BTRQ", aux: "Bool", resultInArg0: true, clobberFlags: true}, // reset bit arg1%64 in arg0
354+
{name: "BTSL", argLength: 2, reg: gp21, asm: "BTSL", aux: "Bool", resultInArg0: true, clobberFlags: true}, // set bit arg1%32 in arg0
355+
{name: "BTSQ", argLength: 2, reg: gp21, asm: "BTSQ", aux: "Bool", resultInArg0: true, clobberFlags: true}, // set bit arg1%64 in arg0
356356
{name: "BTLconst", argLength: 1, reg: gp1flags, asm: "BTL", typ: "Flags", aux: "Int8"}, // test whether bit auxint in arg0 is set, 0 <= auxint < 32
357357
{name: "BTQconst", argLength: 1, reg: gp1flags, asm: "BTQ", typ: "Flags", aux: "Int8"}, // test whether bit auxint in arg0 is set, 0 <= auxint < 64
358358
{name: "BTCLconst", argLength: 1, reg: gp11, asm: "BTCL", resultInArg0: true, clobberFlags: true, aux: "Int8"}, // complement bit auxint in arg0, 0 <= auxint < 32
@@ -385,25 +385,25 @@ func init() {
385385
{name: "TESTWconst", argLength: 1, reg: gp1flags, asm: "TESTW", typ: "Flags", aux: "Int16"}, // (arg0 & auxint) compare to 0
386386
{name: "TESTBconst", argLength: 1, reg: gp1flags, asm: "TESTB", typ: "Flags", aux: "Int8"}, // (arg0 & auxint) compare to 0
387387

388-
{name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ", resultInArg0: true, clobberFlags: true}, // arg0 << arg1, shift amount is mod 64
389-
{name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true, clobberFlags: true}, // arg0 << arg1, shift amount is mod 32
388+
{name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ", aux: "Bool", resultInArg0: true, clobberFlags: true}, // arg0 << arg1, shift amount is mod 64
389+
{name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", aux: "Bool", resultInArg0: true, clobberFlags: true}, // arg0 << arg1, shift amount is mod 32
390390
{name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 << auxint, shift amount 0-63
391391
{name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 << auxint, shift amount 0-31
392392
// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
393393

394-
{name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 64
395-
{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32
396-
{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> arg1, shift amount is mod 32
397-
{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> arg1, shift amount is mod 32
394+
{name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", aux: "Bool", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 64
395+
{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", aux: "Bool", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32
396+
{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", aux: "Bool", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> arg1, shift amount is mod 32
397+
{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", aux: "Bool", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> arg1, shift amount is mod 32
398398
{name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-63
399399
{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> auxint, shift amount 0-31
400400
{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> auxint, shift amount 0-15
401401
{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> auxint, shift amount 0-7
402402

403-
{name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64
404-
{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32
405-
{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> arg1, shift amount is mod 32
406-
{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> arg1, shift amount is mod 32
403+
{name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", aux: "Bool", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64
404+
{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", aux: "Bool", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32
405+
{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", aux: "Bool", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> arg1, shift amount is mod 32
406+
{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", aux: "Bool", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> arg1, shift amount is mod 32
407407
{name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
408408
{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31
409409
{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> auxint, shift amount 0-15

0 commit comments

Comments
 (0)