From 535ab08d3200da3d6a987da0e25f7d3a6605ebe0 Mon Sep 17 00:00:00 2001 From: lzkk <956449176@qq.com> Date: Tue, 26 May 2026 13:10:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(backend):=20AsmPrinter=20=E5=B8=A7?= =?UTF-8?q?=E5=9F=BA=E5=9D=80=E7=BC=93=E5=AD=98=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E8=BF=9E=E7=BB=AD=E6=A0=88=E8=AE=BF=E9=97=AE=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 g_frame_base_offset/g_frame_base_valid 缓存机制: - PrintStackAccess 尝试复用 x13 中已计算的帧地址 - 相邻访问偏移差在 ldur/stur ±256 或 ldr/str 0~32760 范围内时免重算 - x13 被覆写时(ADRP/EmitAddressFromBase/EmitStackAdjust)自动失效 - 为后续 MIR 层 spill 排序优化提供基础架构 --- src/mir/AsmPrinter.cpp | 63 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) 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";