fix(asm): reject the arm64 REGTMP spellings the toolchain refuses

Assisted-by: GLM 5.3
This commit is contained in:
petrbalvin committed 2026-10-07 13:49:49 +02:00
1 parent 2385bb7069
commit 7a69be8b59
3 files changed
+88 -14

No files matched your search

+42 -7
View File
@@ -980,9 +980,13 @@ func encodeARM64DPSR(mnem string, baseOp uint32, ops []*ast.Operand) ([]byte, er
}
// Beyond the bitmask immediates, and for the ZR destinations, the
// toolchain materialises the constant into REGTMP and uses the
// register form (asm7.go cases 62 and 13). BIC/ORN/EON read the
// written value, so the materialisation uses v before any
// inversion.
// register form (asm7.go cases 62 and 13). A REGTMP source
// register is refused, the materialisation clobbering it before
// the register form reads it. BIC/ORN/EON read the written
// value, so the materialisation uses v before any inversion.
if rn == 27 {
return nil, fmt.Errorf("%s: cannot use REGTMP as source", mnem)
}
written := v
if inverted {
written = ^v
@@ -1515,7 +1519,12 @@ func arm64AddSubImmWords(mnem string, v int64, rn, rd int, ext bool) ([]uint32,
// Constant into REGTMP (R27), then the register form. The first word
// mirrors omovconst (asm7.go case 62): MOVZ for a movcon value, MOVN for
// the complement form, the bitmask ORR otherwise, and the full
// omovlconst sequence when no single word carries the value.
// omovlconst sequence when no single word carries the value. A REGTMP
// source register is refused: the materialisation would clobber it
// before the register form reads it (asm7.go cases 13 and 62).
if rn == 27 {
return nil, fmt.Errorf("%s: cannot use REGTMP as source", mnem)
}
var seq []uint32
switch s := arm64Movcon(d); {
case s >= 0:
@@ -2284,7 +2293,7 @@ func encodeARM64MemOp(mnem string, mem *ast.Operand, reg int, load bool, fi arm6
// ADD offsets from the operand's own base register, [SP] and [Rn]
// alike; beyond the split band the offset reaches the literal pool.
if !arm64OffsetSplitReach(off, lt) {
return arm64PoolAccess(mnem, lt, opc, off, rn, reg, pc, pool, poolBase)
return arm64PoolAccess(mnem, lt, opc, off, rn, reg, pc, pool, poolBase, load)
}
hi, lo, ok := arm64SplitImm24(off, bits.TrailingZeros64(uint64(scale)))
if !ok {
@@ -2301,7 +2310,16 @@ func encodeARM64MemOp(mnem string, mem *ast.Operand, reg int, load bool, fi arm6
// into REGTMP, then the access against the register pair (asm7.go cases
// 30/31 and omovlit). The pooled words sit at poolBase plus the entry's
// offset, both function-relative, so the imm19 distance resolves here.
func arm64PoolAccess(mnem string, lt a64LSType, opc int, off int64, rn, reg, pc int, pool *arm64Pool, poolBase int) ([]byte, error) {
func arm64PoolAccess(mnem string, lt a64LSType, opc int, off int64, rn, reg, pc int, pool *arm64Pool, poolBase int, load bool) ([]byte, error) {
// The toolchain refuses a REGTMP data register or base on the pool path
// (asm7.go cases 30/31): the literal load itself rides REGTMP.
if reg == 27 || rn == 27 {
kind := "load"
if !load {
kind = "store"
}
return nil, fmt.Errorf("%s: REGTMP used in large offset %s", mnem, kind)
}
if pool == nil {
return nil, fmt.Errorf("%s: offset %d out of range (literal pool not supported)", mnem, off)
}
@@ -3904,7 +3922,12 @@ func encodeARM64Pair(mnem string, baseOp uint32, ops []*ast.Operand, pc int, fi
}
// Offsets within ±4095 the imm7 field cannot carry move the whole
// distance into REGTMP first (asm7.go cases 74/76: add/sub + ldp/stp).
// A store refuses a REGTMP pair member here (case 76: the add would
// clobber it before the store reads it); a load allows one.
if off >= -4095 && off <= 4095 {
if !load && (rt1 == 27 || rt2 == 27) {
return nil, fmt.Errorf("%s: cannot use REGTMP as source", mnem)
}
op, v := uint32(0), off // ADD
if v < 0 {
op, v = 1, -v // SUB
@@ -3916,8 +3939,20 @@ func encodeARM64Pair(mnem string, baseOp uint32, ops []*ast.Operand, pc int, fi
}
// Positive offsets up to 16 MiB split into two ADDs: the low imm12 bits
// from the base register into REGTMP, the high multiple of 0x1000 on top
// (asm7.go cases 75/77). Beyond the band the offset reaches the pool.
// (asm7.go cases 75/77). Beyond the band the offset reaches the pool,
// which refuses a REGTMP base outright and, for the stores, a REGTMP
// pair member as well.
if off < 0 || off > 0xffffff {
if rn == 27 {
kind := "load"
if !load {
kind = "store"
}
return nil, fmt.Errorf("%s: REGTMP used in large offset %s", mnem, kind)
}
if !load && (rt1 == 27 || rt2 == 27) {
return nil, fmt.Errorf("%s: REGTMP used in large offset store", mnem)
}
if pool == nil {
return nil, fmt.Errorf("%s: offset %d out of range (literal pool not supported)", mnem, off)
}