diff --git a/src/mir/AsmPrinter.cpp b/src/mir/AsmPrinter.cpp index 664cb82f..ae06d87a 100644 --- a/src/mir/AsmPrinter.cpp +++ b/src/mir/AsmPrinter.cpp @@ -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";