[go] cmd/internal/obj/arm: use single BIC for AND with negative-rotated immediate

0 views
Skip to first unread message

Brad Fitzpatrick (Gerrit)

unread,
May 11, 2026, 1:45:04 PM (10 hours ago) May 11
to Brad Fitzpatrick, goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, Nicholas Husin, Keith Randall, Cherry Mui, Gopher Robot, golang...@luci-project-accounts.iam.gserviceaccount.com, golang-co...@googlegroups.com

Brad Fitzpatrick submitted the change

Change information

Commit message:
cmd/internal/obj/arm: use single BIC for AND with negative-rotated immediate

When AND $imm, Rn, Rd is given a constant whose bitwise complement
fits in a rotated 8-bit ARM immediate (i.e. classified as C_NCON),
the assembler synthesized the operation as MVN $~imm, R11 followed
by AND R11, Rn, Rd. This silently clobbered REGTMP (R11) for an
operation that has a one-instruction encoding: BIC $~imm, Rn, Rd.

Within Go's internal ABI this synthesis is technically legal: R11
is documented REGTMP, reserved for assembler and linker scratch,
and Go-compiled callers do not assume its value is preserved across
arbitrary instructions. So this is a quality-of-implementation
improvement, not a correctness bug fix for first-party Go code.

The rewrite is unconditional within the C_NCON path: the class is
only assigned when immrot(^imm) succeeds, which is exactly the
condition for BIC to encode the immediate directly. AND.S maps to
BIC.S; both set N from bit 31 and Z from result==0, leave V
unchanged, and the C flag from a rotated immediate is the same in
either form. Constants that fall through to C_LCON (literal pool)
are unaffected.

It also stops surprising hand-written assembly ported in from other
toolchains. Outside Go's ABI, on the standard ARM ABI used by
GAS/GCC/clang/etc., R11 is fp -- an ordinary callee-saved register
that hand-written code routinely keeps live across instructions.
Code ported from those toolchains (e.g. CryptoGAMS, OpenSSL) reads
as plain AND but, with the old synthesis, silently expands to two
instructions and trashes R11 in between. After this change a single
AND in Plan 9 syntax encodes as a single ARM instruction, matching
what GAS produces for the same source.

The Go compiler does not currently emit AND with a C_NCON immediate
on ARM, so this only affects hand-written .s files. Building cmd/go
for GOARCH=arm hits exactly three call sites:

internal/bytealg/compare_arm.s:52 AND $0xfffffffc, R6, R8 -> BIC $3, R6, R8
internal/bytealg/equal_arm.s:61 AND $0xfffffffc, R1, R6 -> BIC $3, R1, R6
runtime/asm_arm.s:105 AND $~7, R13 -> BIC $7, R13
Change-Id: I0194961917c8a5b3fb5075f787bf8d1e4020ab40
TryBot-Bypass: Brad Fitzpatrick <brad...@golang.org>
Reviewed-by: Nicholas Husin <hu...@google.com>
Reviewed-by: Cherry Mui <cher...@google.com>
Files:
  • M src/cmd/asm/internal/asm/testdata/arm.s
  • M src/cmd/internal/obj/arm/asm5.go
Change size: S
Delta: 2 files changed, 34 insertions(+), 6 deletions(-)
Branch: refs/heads/master
Submit Requirements:
Open in Gerrit
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: merged
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I0194961917c8a5b3fb5075f787bf8d1e4020ab40
Gerrit-Change-Number: 774862
Gerrit-PatchSet: 2
Gerrit-Owner: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Reviewer: Cherry Mui <cher...@google.com>
Gerrit-Reviewer: Nicholas Husin <hu...@google.com>
Gerrit-CC: Gopher Robot <go...@golang.org>
Gerrit-CC: Keith Randall <k...@golang.org>
open
diffy
satisfied_requirement
Reply all
Reply to author
Forward
0 new messages