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