From 5e492f531bb4e55d60d1bfde948b7e01b609ece0 Mon Sep 17 00:00:00 2001 From: mxr <> Date: Sat, 11 Apr 2026 01:08:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(mir)=E5=A4=84=E7=90=86=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E7=AB=8B=E5=8D=B3=E6=95=B0=E8=B6=85=E5=87=BA=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mir/AsmPrinter.cpp | 88 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 11 deletions(-) diff --git a/src/mir/AsmPrinter.cpp b/src/mir/AsmPrinter.cpp index f30f6d7..aaf9825 100644 --- a/src/mir/AsmPrinter.cpp +++ b/src/mir/AsmPrinter.cpp @@ -102,6 +102,39 @@ void PrintOperand(std::ostream& os, const Operand& op) { } } +// 判断立即数是否可作为 AArch64 ADD/SUB 指令的 12 位立即数(可左移 0 或 12 位) +static bool IsLegalAddSubImm(int64_t imm) { + if (imm < 0) imm = -imm; // 取绝对值,因为移位规则对称 + if (imm <= 4095) return true; // 0-4095 直接合法 + if ((imm & 0xFFF) == 0 && imm <= 4095 * 4096) return true; // 4096 的倍数且 ≤ 16773120 + return false; +} + +// 在匿名命名空间添加辅助函数 +static void PrintLoadImm64(std::ostream& os, PhysReg reg, uint64_t imm) { + // 输出 movz + movk 序列 + uint16_t part0 = imm & 0xFFFF; + uint16_t part1 = (imm >> 16) & 0xFFFF; + uint16_t part2 = (imm >> 32) & 0xFFFF; + uint16_t part3 = (imm >> 48) & 0xFFFF; + + os << " movz " << PhysRegName(reg) << ", #" << part0; + if (part1 != 0 || part2 != 0 || part3 != 0) { + os << ", lsl #0"; + } + os << "\n"; + + if (part1 != 0) { + os << " movk " << PhysRegName(reg) << ", #" << part1 << ", lsl #16\n"; + } + if (part2 != 0) { + os << " movk " << PhysRegName(reg) << ", #" << part2 << ", lsl #32\n"; + } + if (part3 != 0) { + os << " movk " << PhysRegName(reg) << ", #" << part3 << ", lsl #48\n"; + } +} + // 打印单条指令 void PrintInstruction(std::ostream& os, const MachineInstr& instr, const MachineFunction& function) { @@ -112,15 +145,27 @@ void PrintInstruction(std::ostream& os, const MachineInstr& instr, os << " stp x29, x30, [sp, #-16]!\n"; os << " mov x29, sp\n"; if (function.GetFrameSize() > 0) { - os << " sub sp, sp, #" << function.GetFrameSize() << "\n"; + int64_t size = function.GetFrameSize(); + if (IsLegalAddSubImm(size)) { + os << " sub sp, sp, #" << size << "\n"; + } else { + PrintLoadImm64(os, PhysReg::X16, size); + os << " sub sp, sp, x16\n"; + } } break; case Opcode::Epilogue: - if (function.GetFrameSize() > 0) { - os << " add sp, sp, #" << function.GetFrameSize() << "\n"; + if (function.GetFrameSize() > 0) { + int64_t size = function.GetFrameSize(); + if (IsLegalAddSubImm(size)) { + os << " add sp, sp, #" << size << "\n"; + } else { + PrintLoadImm64(os, PhysReg::X16, size); + os << " add sp, sp, x16\n"; } - os << " ldp x29, x30, [sp], #16\n"; - break; + } + os << " ldp x29, x30, [sp], #16\n"; + break; case Opcode::MovImm: os << " mov " << PhysRegName(ops.at(0).GetReg()) << ", #" << ops.at(1).GetImm() << "\n"; @@ -321,12 +366,33 @@ void PrintInstruction(std::ostream& os, const MachineInstr& instr, << ops.at(1).GetImm() << ", lsl #" << ops.at(2).GetImm() << "\n"; break; case Opcode::LoadStackAddr: { - // 格式:add xd, sp, #offset - const FrameSlot& slot = GetFrameSlot(function, ops.at(1)); - // 注意:FrameSlot.offset 是相对于栈底(函数入口 sp)的偏移,在 prologue 中 sp 已经下移 - // 因此这里直接使用 slot.offset 即可 - os << " add " << PhysRegName(ops.at(0).GetReg()) << ", sp, #" << slot.offset << "\n"; - break; + const FrameSlot& slot = GetFrameSlot(function, ops.at(1)); + int64_t offset = slot.offset; // 偏移可能为正或负 + PhysReg dst = ops.at(0).GetReg(); + + // 尝试生成简单的 add/sub 立即数指令 + auto tryEmitSimple = [&]() -> bool { + if (offset >= 0 && offset <= 4095) { + os << " add " << PhysRegName(dst) << ", sp, #" << offset << "\n"; + return true; + } else if (offset < 0 && offset >= -4095) { + os << " sub " << PhysRegName(dst) << ", sp, #" << (-offset) << "\n"; + return true; + } + return false; + }; + + if (tryEmitSimple()) break; + + // 复杂情况:偏移绝对值 > 4095,使用 x16 临时寄存器 + uint64_t absOffset = (offset >= 0) ? offset : -offset; + PrintLoadImm64(os, PhysReg::X16, absOffset); + if (offset >= 0) { + os << " add " << PhysRegName(dst) << ", sp, x16\n"; + } else { + os << " sub " << PhysRegName(dst) << ", sp, x16\n"; + } + break; } default: os << " // unknown instruction\n";