Skip to content

Commit cba8fe8

Browse files
committed
cmd/compile: fold single-bit TST; CSET NE into UBFX on arm64
A boolean materialized from a single-bit test compiles to TST $(1<<k); CSET NE. The bit is a bitfield extract: rewrite the NotEqual of a one-bit TSTconst/TSTWconst to UBFX #k, #1, the value form of the existing single-bit TBZ/TBNZ branch rules. The flags producer remains for any other reader, and a shared bool's branch then tests the extracted bit directly, so the TST disappears there too. Measured with armlint on darwin/arm64: cmd/go: 166 TST; CSET pairs eliminated, __text -672 bytes. gofmt: 35 pairs eliminated, __text -192 bytes.
1 parent 31525e9 commit cba8fe8

3 files changed

Lines changed: 56 additions & 0 deletions

File tree

src/cmd/compile/internal/ssa/_gen/ARM64.rules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,12 @@
570570
((Equal|NotEqual|LessThan|LessEqual|GreaterThan|GreaterEqual) (CMPconst [0] x:(ANDconst [c] y))) && x.Uses == 1 =>
571571
((Equal|NotEqual|LessThan|LessEqual|GreaterThan|GreaterEqual) (TSTconst [c] y))
572572

573+
// A single-bit test materialized as a boolean is a bitfield extract:
574+
// TST $(1<<k); CSET NE is UBFX #k, #1. The flags stay for any other
575+
// reader; the branch form is handled by the TBZ/TBNZ rules below.
576+
(NotEqual (TSTconst [c] x)) && oneBit(c) => (UBFX [armBFAuxInt(int64(ntz64(c)), 1)] x)
577+
(NotEqual (TSTWconst [c] x)) && oneBit(int64(uint32(c))) => (UBFX [armBFAuxInt(int64(ntz64(int64(uint32(c)))), 1)] x)
578+
573579
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => ((EQ|NE|LTnoov|LEnoov|GTnoov|GEnoov) (CMNconst [c] y) yes no)
574580
((EQ|NE|LT|LE|GT|GE) (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => ((EQ|NE|LTnoov|LEnoov|GTnoov|GEnoov) (CMNWconst [int32(c)] y) yes no)
575581
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => ((EQ|NE|LTnoov|LEnoov|GTnoov|GEnoov) (CMN x y) yes no)

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

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/codegen/bitfield.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,22 @@ func ubfx16(x uint64) uint64 {
327327
return ((x >> 3) & 0xfff) >> 1 & 0x3f
328328
}
329329

330+
// materialize a single-bit test as ubfx instead of TST + CSET.
331+
func ubfx17(x uint64) bool {
332+
// arm64:"UBFX [$]3, R[0-9]+, [$]1" -"TST" -"CSET"
333+
return x&8 != 0
334+
}
335+
336+
func ubfx18(x uint64) bool {
337+
// arm64:"UBFX [$]63, R[0-9]+, [$]1" -"TST" -"CSET"
338+
return x&(1<<63) != 0
339+
}
340+
341+
func ubfx19(x uint32) bool {
342+
// arm64:"UBFX [$]31, R[0-9]+, [$]1" -"TST" -"CSET"
343+
return x&(1<<31) != 0
344+
}
345+
330346
// Check that we don't emit comparisons for constant shifts.
331347
//
332348
//go:nosplit

0 commit comments

Comments
 (0)