feat(asm): encode the arm64 register-offset addressing forms
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
a344399b81
commit
458cdd2066
4 files changed
+221
-1
No files matched your search
+80
-1
@@ -2008,6 +2008,14 @@ func encodeARM64MemOp(mnem string, mem *ast.Operand, reg int, load bool, fi arm6
|
||||
lt = a64LoadTable["MOVD"]
|
||||
}
|
||||
|
||||
// Register-offset addressing: (Rn)(Rm), (Rn)(Rm<<k), (Rn)(Rm.UXTW) and
|
||||
// friends. The toolchain accepts the LSL (UXTX), UXTW, SXTW and SXTX
|
||||
// options with a shift amount of either zero or the access size's log2,
|
||||
// rejects every other spelling, and rejects the whole form on FMOVQ.
|
||||
if mem.Addr.Index != "" {
|
||||
return encodeARM64RegOffset(mnem, mem, rn, reg, load, lt, wb)
|
||||
}
|
||||
|
||||
scale := a64LSScale(lt)
|
||||
storeOpc := a64StoreOpc(lt)
|
||||
var opc int
|
||||
@@ -2094,7 +2102,78 @@ func arm64PoolAccess(mnem string, lt a64LSType, opc int, off int64, rn, reg, pc
|
||||
// option the toolchain's register-offset accesses use:
|
||||
// size<<30 | 0x38<<24 | V<<26 | opc<<22 | 1<<21 | Rm<<16 | 011<<13 | 10<<10 | Rn<<5 | Rt.
|
||||
func a64LSReg(size, V, opc, rm, rn, rt uint32) uint32 {
|
||||
return size<<30 | 0x38<<24 | V<<26 | opc<<22 | 1<<21 | rm<<16 | 3<<13 | 2<<10 | rn<<5 | rt
|
||||
return a64LSRegExt(size, V, opc, rm, rn, rt, 3, 0)
|
||||
}
|
||||
|
||||
// a64LSRegExt encodes the extended-register-offset load/store:
|
||||
// size<<30 | 0x38<<24 | V<<26 | opc<<22 | 1<<21 | Rm<<16 | option<<13 |
|
||||
// S<<12 | 10<<10 | Rn<<5 | Rt, with S meaning "scale by the access size".
|
||||
func a64LSRegExt(size, V, opc, rm, rn, rt, option, s uint32) uint32 {
|
||||
return size<<30 | 0x38<<24 | V<<26 | opc<<22 | 1<<21 | rm<<16 | option<<13 | s<<12 | 2<<10 | rn<<5 | rt
|
||||
}
|
||||
|
||||
// encodeARM64RegOffset encodes the register-offset addressing forms of the
|
||||
// MOV family: (Rn)(Rm), (Rn)(Rm*1), (Rn)(Rm<<k) and the extend spellings
|
||||
// (Rn)(Rm.UXTW<<k), (Rn)(Rm.SXTW), (Rn)(Rm.SXTX<<k). The toolchain's
|
||||
// contract, probed against `go tool asm`: the four options UXTX/LSL, UXTW,
|
||||
// SXTW and SXTX exist (the spellings UXTX, UXTB, SXTH and friends are
|
||||
// rejected), the shift amount is either zero or the access size's log2, FMOVQ
|
||||
// carries no register-offset form at all, and writeback does not combine with
|
||||
// an index.
|
||||
func encodeARM64RegOffset(mnem string, mem *ast.Operand, rn, reg int, load bool, lt a64LSType, wb string) ([]byte, error) {
|
||||
if wb != "" {
|
||||
return nil, fmt.Errorf("%s: writeback does not combine with a register offset", mnem)
|
||||
}
|
||||
if mnem == "FMOVQ" {
|
||||
return nil, fmt.Errorf("%s: illegal combination: the register offset form does not exist", mnem)
|
||||
}
|
||||
if mem.Addr.Scale > 1 {
|
||||
return nil, fmt.Errorf("%s: the register offset addressing mode takes no scale factor", mnem)
|
||||
}
|
||||
name, ext, _ := strings.Cut(mem.Addr.Index, ".")
|
||||
var option uint32
|
||||
switch strings.ToUpper(ext) {
|
||||
case "":
|
||||
option = 3 // UXTX / LSL
|
||||
case "UXTW":
|
||||
option = 2
|
||||
case "SXTW":
|
||||
option = 6
|
||||
case "SXTX":
|
||||
option = 7
|
||||
default:
|
||||
return nil, fmt.Errorf("%s: invalid shift for the register offset addressing mode: %s", mnem, ext)
|
||||
}
|
||||
rm := arm64RegNum(name)
|
||||
if rm < 0 {
|
||||
return nil, fmt.Errorf("%s: invalid index register %q", mnem, name)
|
||||
}
|
||||
amount := 0
|
||||
shift := strings.Join(strings.Fields(mem.Addr.Shift), "")
|
||||
shift = strings.TrimSuffix(shift, ")")
|
||||
if shift != "" {
|
||||
if !strings.HasPrefix(shift, "<<") {
|
||||
return nil, fmt.Errorf("%s: invalid shift for the register offset addressing mode: %s", mnem, shift)
|
||||
}
|
||||
v, err := strconv.Atoi(strings.TrimPrefix(shift, "<<"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: invalid shift for the register offset addressing mode: %s", mnem, shift)
|
||||
}
|
||||
amount = v
|
||||
}
|
||||
log2 := bits.TrailingZeros64(uint64(a64LSScale(lt)))
|
||||
if amount != 0 && amount != log2 {
|
||||
return nil, fmt.Errorf("%s: invalid index shift amount %d", mnem, amount)
|
||||
}
|
||||
s := uint32(0)
|
||||
if amount == log2 && log2 > 0 {
|
||||
s = 1
|
||||
}
|
||||
opc := lt.opc
|
||||
if !load {
|
||||
opc = a64StoreOpc(lt)
|
||||
}
|
||||
return a64wordLE(a64LSRegExt(uint32(lt.size), uint32(lt.V), uint32(opc), uint32(rm), uint32(rn), uint32(reg), option, s)), nil
|
||||
}
|
||||
|
||||
// arm64OffsetSplitReach reports whether an offset stays within the band the
|
||||
|
||||
Reference in new issue
Block a user