fix(asm): size the arm64 logical-immediate materialisation exactly
Assisted-by: GLM 5.3
This commit is contained in:
1 parent
4ccd3bb4c6
commit
4fc96decc4
2 files changed
+45
-4
No files matched your search
+11
-4
@@ -313,22 +313,26 @@ func arm64InstrSize(instr *ast.Instr, fi arm64FrameInfo, pos int) int {
|
|||||||
return arm64MovSize(mnem, ops, fi)
|
return arm64MovSize(mnem, ops, fi)
|
||||||
}
|
}
|
||||||
// The logical-immediate family: one word on the bitmask fast path (a
|
// The logical-immediate family: one word on the bitmask fast path (a
|
||||||
// real destination, or the flags-only TST spellings), two words for the
|
// real destination, or the flags-only TST spellings), otherwise the
|
||||||
// materialisation the ZR destinations and the non-bitmask immediates
|
// constant materialisation into REGTMP plus the register-form tail.
|
||||||
// take. Mirrors encodeARM64DPSR's decision exactly.
|
// Mirrors encodeARM64DPSR's decision exactly, the materialisation word
|
||||||
|
// count included: a MOVZ plus up to three MOVKs makes five words.
|
||||||
if len(ops) >= 2 && len(ops) <= 3 && isImmOperand(ops[0]) {
|
if len(ops) >= 2 && len(ops) <= 3 && isImmOperand(ops[0]) {
|
||||||
switch mnem {
|
switch mnem {
|
||||||
case "AND", "ANDW", "ANDS", "ANDSW", "ORR", "ORRW", "EOR", "EORW",
|
case "AND", "ANDW", "ANDS", "ANDSW", "ORR", "ORRW", "EOR", "EORW",
|
||||||
"BIC", "BICW", "BICS", "BICSW", "ORN", "ORNW", "EON", "EONW",
|
"BIC", "BICW", "BICS", "BICSW", "ORN", "ORNW", "EON", "EONW",
|
||||||
"TST", "TSTW":
|
"TST", "TSTW":
|
||||||
if v, ok := arm64ImmOperandValue(ops[0]); ok {
|
if v, ok := arm64ImmOperandValue(ops[0]); ok {
|
||||||
|
written := v
|
||||||
switch mnem {
|
switch mnem {
|
||||||
case "BIC", "BICW", "BICS", "BICSW", "ORN", "ORNW", "EON", "EONW":
|
case "BIC", "BICW", "BICS", "BICSW", "ORN", "ORNW", "EON", "EONW":
|
||||||
v = ^v
|
v = ^v
|
||||||
}
|
}
|
||||||
width := 64
|
width := 64
|
||||||
|
mwMnem := "MOVD"
|
||||||
if strings.HasSuffix(mnem, "W") {
|
if strings.HasSuffix(mnem, "W") {
|
||||||
width = 32
|
width = 32
|
||||||
|
mwMnem = "MOVW"
|
||||||
}
|
}
|
||||||
zrDest := false
|
zrDest := false
|
||||||
if mnem != "TST" && mnem != "TSTW" {
|
if mnem != "TST" && mnem != "TSTW" {
|
||||||
@@ -337,7 +341,10 @@ func arm64InstrSize(instr *ast.Instr, fi arm64FrameInfo, pos int) int {
|
|||||||
if _, _, _, bc := a64LogicalImm(v, width); bc && (mnem == "TST" || mnem == "TSTW" || !zrDest) {
|
if _, _, _, bc := a64LogicalImm(v, width); bc && (mnem == "TST" || mnem == "TSTW" || !zrDest) {
|
||||||
return 4
|
return 4
|
||||||
}
|
}
|
||||||
return 8
|
if mw, err := encodeARM64LoadImm(27, written, mwMnem); err == nil {
|
||||||
|
return len(mw) + 4
|
||||||
|
}
|
||||||
|
return 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2070,6 +2070,40 @@ func TestArm64ConRnRejections(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestArm64LogicalMaterialisationBranch pins a forward branch over the
|
||||||
|
// three-word logical materialisation against `go tool asm -S` (Go 1.27,
|
||||||
|
// arm64): the size pass must count the MOVZ/MOVK pair the encoder lays down,
|
||||||
|
// or the label offsets desynchronise from the bytes and the branch lands a
|
||||||
|
// word early.
|
||||||
|
func TestArm64LogicalMaterialisationBranch(t *testing.T) {
|
||||||
|
// The body closes with its own RET under the end label, so the file is
|
||||||
|
// parsed as written rather than through arm64Words' appended RET.
|
||||||
|
f, errs := parser.Parse("test_arm64.s", "#include \"textflag.h\"\n\nTEXT ·f(SB), NOSPLIT, $0-0\n\tCBZ\tR2, end\n\tTST\t$0x4900000049, R0\nend:\tRET\n")
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatalf("parse: %v", errs)
|
||||||
|
}
|
||||||
|
img, err := AssembleFileARM64(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("AssembleFileARM64: %v", err)
|
||||||
|
}
|
||||||
|
got := leWords(img.Code)
|
||||||
|
want := []uint32{
|
||||||
|
0xb4000082, // CBZ R2, +16 (four words ahead)
|
||||||
|
0xd280093b, // MOVZ $0x49, R27
|
||||||
|
0xf2c0093b, // MOVK $(0x49<<32), R27
|
||||||
|
0xea1b001f, // TST R27, R0
|
||||||
|
0xd65f03c0, // RET
|
||||||
|
}
|
||||||
|
if len(got) != len(want) {
|
||||||
|
t.Fatalf("word count = %d, want %d", len(got), len(want))
|
||||||
|
}
|
||||||
|
for i := range want {
|
||||||
|
if got[i] != want[i] {
|
||||||
|
t.Errorf("word %d = %08x, want %08x", i, got[i], want[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestArm64FPImmediate pins the FP immediate moves against `go tool asm`
|
// TestArm64FPImmediate pins the FP immediate moves against `go tool asm`
|
||||||
// words: the FMOV (immediate) instruction for the 8-bit encodable values and
|
// words: the FMOV (immediate) instruction for the 8-bit encodable values and
|
||||||
// the FMOV-from-ZR move for zero, plus the rejections the toolchain raises
|
// the FMOV-from-ZR move for zero, plus the rejections the toolchain raises
|
||||||
|
|||||||
Reference in new issue
Block a user