feat(backend): AsmPrinter 帧基址缓存,避免连续栈访问重复计算地址

新增 g_frame_base_offset/g_frame_base_valid 缓存机制:
- PrintStackAccess 尝试复用 x13 中已计算的帧地址
- 相邻访问偏移差在 ldur/stur ±256 或 ldr/str 0~32760 范围内时免重算
- x13 被覆写时(ADRP/EmitAddressFromBase/EmitStackAdjust)自动失效
- 为后续 MIR 层 spill 排序优化提供基础架构
lzk
lzkk 5 days ago
parent 3ab88232f7
commit 535ab08d32

@ -260,6 +260,15 @@ namespace mir
std::string g_cached_adrp_symbol;
bool g_adrp_cache_valid = false;
// 帧基址缓存——x13 持有 x29 + g_frame_base_offset避免重复计算地址
int g_frame_base_offset = 0;
bool g_frame_base_valid = false;
void InvalidateFrameBase()
{
g_frame_base_valid = false;
}
void InvalidateAdrpCache()
{
g_adrp_cache_valid = false;
@ -270,6 +279,7 @@ namespace mir
if (amount > 12285)
{
InvalidateAdrpCache();
InvalidateFrameBase();
os << " movz x13, #" << (amount & 0xFFFF) << "\n";
if ((amount >> 16) != 0)
os << " movk x13, #" << ((amount >> 16) & 0xFFFF) << ", lsl #16\n";
@ -295,9 +305,17 @@ namespace mir
void EmitAddressFromBase(PhysReg target_xreg, PhysReg base_reg, int offset,
std::ostream &os)
{
if (offset > 12285)
// 使用 x13 时ADRP 和帧基址缓存同时失效
if (target_xreg == PrinterScratchXReg())
{
InvalidateAdrpCache();
InvalidateFrameBase();
}
if (offset > 12285)
{
if (target_xreg != PrinterScratchXReg())
InvalidateAdrpCache();
os << " movz x13, #" << (offset & 0xFFFF) << "\n";
if ((offset >> 16) != 0)
os << " movk x13, #" << ((offset >> 16) & 0xFFFF) << ", lsl #16\n";
@ -308,7 +326,8 @@ namespace mir
if (offset < -12285)
{
int abs_off = -offset;
InvalidateAdrpCache();
if (target_xreg != PrinterScratchXReg())
InvalidateAdrpCache();
os << " movz x13, #" << (abs_off & 0xFFFF) << "\n";
if ((abs_off >> 16) != 0)
os << " movk x13, #" << ((abs_off >> 16) & 0xFFFF) << ", lsl #16\n";
@ -341,6 +360,7 @@ namespace mir
const char *narrow_op = (opcode == Opcode::LoadStack) ? "ldur" : "stur";
const char *wide_op = (opcode == Opcode::LoadStack) ? "ldr" : "str";
// x29 可达的窄范围直接用 ldur/stur
if (offset >= -256 && offset <= 255)
{
os << " " << narrow_op << " ";
@ -350,7 +370,41 @@ namespace mir
}
const PhysReg scratch_xreg = PrinterScratchXReg();
bool is_32bit = IsWReg(reg.GetReg()) || IsSReg(reg.GetReg());
// 尝试帧基址缓存——x13 已持有之前的地址
if (g_frame_base_valid)
{
int diff = offset - g_frame_base_offset;
// ldur/stur范围 ±256
if (diff >= -256 && diff <= 255)
{
os << " " << narrow_op << " ";
PrintOperand(reg, os);
os << ", [" << PhysRegName(scratch_xreg) << ", #" << diff << "]\n";
return;
}
// ldr/str 无符号立即数(正偏移)
if (diff >= 0)
{
int max_imm = is_32bit ? 16380 : 32760;
int align = is_32bit ? 4 : 8;
if (diff <= max_imm && diff % align == 0)
{
os << " " << wide_op << " ";
PrintOperand(reg, os);
os << ", [" << PhysRegName(scratch_xreg) << ", #" << diff << "]\n";
return;
}
}
}
// 缓存未命中——完整计算地址到 x13
EmitAddressFromBase(scratch_xreg, PhysReg::X29, offset, os);
g_frame_base_offset = offset;
g_frame_base_valid = true;
os << " " << wide_op << " ";
PrintOperand(reg, os);
@ -386,6 +440,7 @@ namespace mir
os << " adrp " << PhysRegName(scratch_xreg) << ", " << asm_symbol << "\n";
g_cached_adrp_symbol = asm_symbol;
g_adrp_cache_valid = true;
InvalidateFrameBase();
}
os << " " << (opcode == Opcode::LoadGlobal ? "ldr " : "str ");
@ -944,6 +999,7 @@ namespace mir
void PrintAsm(const MachineFunction &function, std::ostream &os)
{
g_adrp_cache_valid = false;
g_frame_base_valid = false;
const std::string asm_name = NormalizeAsmSymbol(function.GetName());
os << " .text\n";
@ -959,8 +1015,9 @@ namespace mir
}
const auto &block = *block_ptr;
// 每个基本块重置 ADRP 缓存——跨块时 x13 可能已被 call/clobber 破坏
// 每个基本块重置缓存——跨块时 x13 可能已被 call/clobber 破坏
g_adrp_cache_valid = false;
g_frame_base_valid = false;
PrintBlockLabelRef(function, block.GetLabelId(), os);
os << ":\n";

Loading…
Cancel
Save