feat(mir)处理指令立即数超出范围

feature/mir
mxr 1 day ago
parent c9f73980ea
commit 5e492f531b

@ -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";

Loading…
Cancel
Save