Skip to content

Commit 2183135

Browse files
committed
cmd/compile: recognize bit test patterns on amd64
Updates #18943 Change-Id: If3080d6133bb6d2710b57294da24c90251ab4e08 Reviewed-on: https://go-review.googlesource.com/36329 Run-TryBot: Josh Bleecher Snyder <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent ac7761e commit 2183135

File tree

7 files changed

+852
-2
lines changed

7 files changed

+852
-2
lines changed

src/cmd/compile/internal/amd64/prog.go

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ var progtable = [x86.ALAST & obj.AMask]gc.ProgInfo{
7272
x86.ACMOVWEQ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.UseCarry},
7373
x86.ACMOVWNE & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.UseCarry},
7474

75+
x86.ABTL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
76+
x86.ABTQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry},
7577
x86.ACMPB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
7678
x86.ACMPL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
7779
x86.ACMPQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry},

src/cmd/compile/internal/amd64/ssa.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
471471
p.To.Type = obj.TYPE_REG
472472
p.To.Reg = v.Reg()
473473
case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
474-
ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
474+
ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB,
475+
ssa.OpAMD64BTL, ssa.OpAMD64BTQ:
475476
opregreg(v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
476477
case ssa.OpAMD64UCOMISS, ssa.OpAMD64UCOMISD:
477478
// Go assembler has swapped operands for UCOMISx relative to CMP,
@@ -483,7 +484,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
483484
p.From.Reg = v.Args[0].Reg()
484485
p.To.Type = obj.TYPE_CONST
485486
p.To.Offset = v.AuxInt
486-
case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst:
487+
case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst,
488+
ssa.OpAMD64BTLconst, ssa.OpAMD64BTQconst:
487489
p := gc.Prog(v.Op.Asm())
488490
p.From.Type = obj.TYPE_CONST
489491
p.From.Offset = v.AuxInt

src/cmd/compile/internal/gc/asm_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,45 @@ var linuxAMD64Tests = []*asmTest{
504504
`,
505505
[]string{"\"abc\""},
506506
},
507+
// Bit test ops on amd64, issue 18943.
508+
{
509+
`
510+
func f37(a, b uint64) int {
511+
if a&(1<<(b&63)) != 0 {
512+
return 1
513+
}
514+
return -1
515+
}
516+
`,
517+
[]string{"\tBTQ\t"},
518+
},
519+
{
520+
`
521+
func f38(a, b uint64) bool {
522+
return a&(1<<(b&63)) != 0
523+
}
524+
`,
525+
[]string{"\tBTQ\t"},
526+
},
527+
{
528+
`
529+
func f39(a uint64) int {
530+
if a&(1<<60) != 0 {
531+
return 1
532+
}
533+
return -1
534+
}
535+
`,
536+
[]string{"\tBTQ\t\\$60"},
537+
},
538+
{
539+
`
540+
func f40(a uint64) bool {
541+
return a&(1<<60) != 0
542+
}
543+
`,
544+
[]string{"\tBTQ\t\\$60"},
545+
},
507546
}
508547

509548
var linux386Tests = []*asmTest{

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

+41
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,37 @@
518518
(NE (TESTB (SETA cmp) (SETA cmp)) yes no) -> (UGT cmp yes no)
519519
(NE (TESTB (SETAE cmp) (SETAE cmp)) yes no) -> (UGE cmp yes no)
520520

521+
// Normalize TESTx argument order for BTx rewrites below.
522+
(TESTQ y x:(SHLQ _ _)) && y.Op != OpAMD64SHLQ -> (TESTQ x y)
523+
(TESTL y x:(SHLL _ _)) && y.Op != OpAMD64SHLL -> (TESTL x y)
524+
525+
// Recognize bit tests: a&(1<<b) != 0 for b suitably bounded
526+
// Note that ULT and SETB check the carry flag; they are identical to CS and SETCS.
527+
// Same, mutatis mutandis, for UGE and SETAE, and CC and SETCC.
528+
(NE (TESTL (SHLL (MOVLconst [1]) x) y)) && !config.nacl -> (ULT (BTL x y))
529+
(EQ (TESTL (SHLL (MOVLconst [1]) x) y)) && !config.nacl -> (UGE (BTL x y))
530+
(NE (TESTQ (SHLQ (MOVQconst [1]) x) y)) && !config.nacl -> (ULT (BTQ x y))
531+
(EQ (TESTQ (SHLQ (MOVQconst [1]) x) y)) && !config.nacl -> (UGE (BTQ x y))
532+
(NE (TESTLconst [c] x)) && isPowerOfTwo(c) && log2(c) < 32 && !config.nacl -> (ULT (BTLconst [log2(c)] x))
533+
(EQ (TESTLconst [c] x)) && isPowerOfTwo(c) && log2(c) < 32 && !config.nacl -> (UGE (BTLconst [log2(c)] x))
534+
(NE (TESTQconst [c] x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (ULT (BTQconst [log2(c)] x))
535+
(EQ (TESTQconst [c] x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (UGE (BTQconst [log2(c)] x))
536+
(NE (TESTQ (MOVQconst [c]) x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (ULT (BTQconst [log2(c)] x))
537+
(EQ (TESTQ (MOVQconst [c]) x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (UGE (BTQconst [log2(c)] x))
538+
(SETNE (TESTL (SHLL (MOVLconst [1]) x) y)) && !config.nacl -> (SETB (BTL x y))
539+
(SETEQ (TESTL (SHLL (MOVLconst [1]) x) y)) && !config.nacl -> (SETAE (BTL x y))
540+
(SETNE (TESTQ (SHLQ (MOVQconst [1]) x) y)) && !config.nacl -> (SETB (BTQ x y))
541+
(SETEQ (TESTQ (SHLQ (MOVQconst [1]) x) y)) && !config.nacl -> (SETAE (BTQ x y))
542+
(SETNE (TESTLconst [c] x)) && isPowerOfTwo(c) && log2(c) < 32 && !config.nacl -> (SETB (BTLconst [log2(c)] x))
543+
(SETEQ (TESTLconst [c] x)) && isPowerOfTwo(c) && log2(c) < 32 && !config.nacl -> (SETAE (BTLconst [log2(c)] x))
544+
(SETNE (TESTQconst [c] x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (SETB (BTQconst [log2(c)] x))
545+
(SETEQ (TESTQconst [c] x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (SETAE (BTQconst [log2(c)] x))
546+
(SETNE (TESTQ (MOVQconst [c]) x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (SETB (BTQconst [log2(c)] x))
547+
(SETEQ (TESTQ (MOVQconst [c]) x)) && isPowerOfTwo(c) && log2(c) < 64 && !config.nacl -> (SETAE (BTQconst [log2(c)] x))
548+
549+
// Convert BTQconst to BTLconst if possible. It has a shorter encoding.
550+
(BTQconst [c] x) && c < 32 -> (BTLconst [c] x)
551+
521552
// Special case for floating point - LF/LEF not generated
522553
(NE (TESTB (SETGF cmp) (SETGF cmp)) yes no) -> (UGT cmp yes no)
523554
(NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no) -> (UGE cmp yes no)
@@ -1380,6 +1411,16 @@
13801411
(CMPWconst (ANDLconst [c] x) [0]) -> (TESTWconst [int64(int16(c))] x)
13811412
(CMPBconst (ANDLconst [c] x) [0]) -> (TESTBconst [int64(int8(c))] x)
13821413

1414+
// Convert TESTx to TESTxconst if possible.
1415+
(TESTQ (MOVQconst [c]) x) && c < 1<<31 -> (TESTQconst [c] x)
1416+
(TESTL (MOVLconst [c]) x) -> (TESTLconst [c] x)
1417+
(TESTW (MOVLconst [c]) x) -> (TESTWconst [c] x)
1418+
(TESTB (MOVLconst [c]) x) -> (TESTBconst [c] x)
1419+
(TESTQ x (MOVQconst [c])) && c < 1<<31 -> (TESTQconst [c] x)
1420+
(TESTL x (MOVLconst [c])) -> (TESTLconst [c] x)
1421+
(TESTW x (MOVLconst [c])) -> (TESTWconst [c] x)
1422+
(TESTB x (MOVLconst [c])) -> (TESTBconst [c] x)
1423+
13831424
// TEST %reg,%reg is shorter than CMP
13841425
(CMPQconst x [0]) -> (TESTQ x x)
13851426
(CMPLconst x [0]) -> (TESTL x x)

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

+5
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ func init() {
250250
{name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32
251251
{name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64
252252

253+
{name: "BTL", argLength: 2, reg: gp2flags, asm: "BTL", typ: "Flags"}, // test whether bit arg0 % 32 in arg1 is set
254+
{name: "BTQ", argLength: 2, reg: gp2flags, asm: "BTQ", typ: "Flags"}, // test whether bit arg0 % 64 in arg1 is set
255+
{name: "BTLconst", argLength: 1, reg: gp1flags, asm: "BTL", typ: "Flags", aux: "Int8"}, // test whether bit auxint in arg0 is set, 0 <= auxint < 32
256+
{name: "BTQconst", argLength: 1, reg: gp1flags, asm: "BTQ", typ: "Flags", aux: "Int8"}, // test whether bit auxint in arg0 is set, 0 <= auxint < 64
257+
253258
{name: "TESTQ", argLength: 2, reg: gp2flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & arg1) compare to 0
254259
{name: "TESTL", argLength: 2, reg: gp2flags, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0
255260
{name: "TESTW", argLength: 2, reg: gp2flags, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0

src/cmd/compile/internal/ssa/opGen.go

+48
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,10 @@ const (
491491
OpAMD64CMPBconst
492492
OpAMD64UCOMISS
493493
OpAMD64UCOMISD
494+
OpAMD64BTL
495+
OpAMD64BTQ
496+
OpAMD64BTLconst
497+
OpAMD64BTQconst
494498
OpAMD64TESTQ
495499
OpAMD64TESTL
496500
OpAMD64TESTW
@@ -5550,6 +5554,50 @@ var opcodeTable = [...]opInfo{
55505554
},
55515555
},
55525556
},
5557+
{
5558+
name: "BTL",
5559+
argLen: 2,
5560+
asm: x86.ABTL,
5561+
reg: regInfo{
5562+
inputs: []inputInfo{
5563+
{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
5564+
{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
5565+
},
5566+
},
5567+
},
5568+
{
5569+
name: "BTQ",
5570+
argLen: 2,
5571+
asm: x86.ABTQ,
5572+
reg: regInfo{
5573+
inputs: []inputInfo{
5574+
{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
5575+
{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
5576+
},
5577+
},
5578+
},
5579+
{
5580+
name: "BTLconst",
5581+
auxType: auxInt8,
5582+
argLen: 1,
5583+
asm: x86.ABTL,
5584+
reg: regInfo{
5585+
inputs: []inputInfo{
5586+
{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
5587+
},
5588+
},
5589+
},
5590+
{
5591+
name: "BTQconst",
5592+
auxType: auxInt8,
5593+
argLen: 1,
5594+
asm: x86.ABTQ,
5595+
reg: regInfo{
5596+
inputs: []inputInfo{
5597+
{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
5598+
},
5599+
},
5600+
},
55535601
{
55545602
name: "TESTQ",
55555603
argLen: 2,

0 commit comments

Comments
 (0)