|
|
|
|
@ -17,6 +17,8 @@
|
|
|
|
|
namespace mir {
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
static void PrintLoadImm64(std::ostream& os, PhysReg reg, uint64_t imm);
|
|
|
|
|
|
|
|
|
|
const FrameSlot& GetFrameSlot(const MachineFunction& function,
|
|
|
|
|
const Operand& operand) {
|
|
|
|
|
if (operand.GetKind() != Operand::Kind::FrameIndex) {
|
|
|
|
|
@ -25,58 +27,33 @@ const FrameSlot& GetFrameSlot(const MachineFunction& function,
|
|
|
|
|
return function.GetFrameSlot(operand.GetFrameIndex());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*void PrintStackAccess(std::ostream& os, const char* mnemonic, PhysReg reg,
|
|
|
|
|
int offset) {
|
|
|
|
|
// 使用 sp 相对寻址
|
|
|
|
|
os << " " << mnemonic << " " << PhysRegName(reg) << ", [sp, #" << offset << "]\n";
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
void PrintStackAccess(std::ostream& os, const char* insn, PhysReg reg, int64_t offset) {
|
|
|
|
|
// 合法范围:-256 到 255
|
|
|
|
|
// offset 通常是负数,例如 -8, -24, -40 等
|
|
|
|
|
if (offset >= -256 && offset <= 255) {
|
|
|
|
|
os << " " << insn << " " << PhysRegName(reg) << ", [sp, #" << offset << "]\n";
|
|
|
|
|
os << " " << insn << " " << PhysRegName(reg) << ", [x29, #" << offset << "]\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 大偏移:使用 x16 计算地址
|
|
|
|
|
os << " mov x16, sp"<< "\n";
|
|
|
|
|
// 大偏移量:用 x16 计算 x29 + offset,然后间接访问
|
|
|
|
|
os << " mov x16, x29\n";
|
|
|
|
|
|
|
|
|
|
// 处理正偏移
|
|
|
|
|
if (offset >= 0) {
|
|
|
|
|
// AArch64 add immediate 范围 0~4095,超过则需要分解
|
|
|
|
|
if (offset <= 4095) {
|
|
|
|
|
int64_t abs_offset = (offset >= 0) ? offset : -offset;
|
|
|
|
|
if (abs_offset <= 4095) {
|
|
|
|
|
if (offset >= 0) {
|
|
|
|
|
os << " add x16, x16, #" << offset << "\n";
|
|
|
|
|
} else {
|
|
|
|
|
// 简单分解:高部分必须是 4096 的倍数?这里为了通用,分两次加
|
|
|
|
|
// 更严谨的做法是循环,但栈帧一般不超过 8192,两次足够
|
|
|
|
|
int64_t low = offset & 0xFFF; // 低12位
|
|
|
|
|
int64_t high = offset - low;
|
|
|
|
|
if (high > 0) {
|
|
|
|
|
os << " add x16, x16, #" << high << "\n";
|
|
|
|
|
}
|
|
|
|
|
if (low > 0) {
|
|
|
|
|
os << " add x16, x16, #" << low << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 处理负偏移
|
|
|
|
|
else {
|
|
|
|
|
int64_t abs_offset = -offset;
|
|
|
|
|
if (abs_offset <= 4095) {
|
|
|
|
|
os << " sub x16, x16, #" << abs_offset << "\n";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 分解大偏移量
|
|
|
|
|
PrintLoadImm64(os, PhysReg::X17, abs_offset);
|
|
|
|
|
if (offset >= 0) {
|
|
|
|
|
os << " add x16, x16, x17\n";
|
|
|
|
|
} else {
|
|
|
|
|
int64_t low = abs_offset & 0xFFF;
|
|
|
|
|
int64_t high = abs_offset - low;
|
|
|
|
|
if (high > 0) {
|
|
|
|
|
os << " sub x16, x16, #" << high << "\n";
|
|
|
|
|
}
|
|
|
|
|
if (low > 0) {
|
|
|
|
|
os << " sub x16, x16, #" << low << "\n";
|
|
|
|
|
}
|
|
|
|
|
os << " sub x16, x16, x17\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 最后使用无偏移的 ldr/str(注意不是 ldur/stur)
|
|
|
|
|
os << " " << insn << " " << PhysRegName(reg) << ", [x16]\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -367,16 +344,15 @@ void PrintInstruction(std::ostream& os, const MachineInstr& instr,
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::LoadStackAddr: {
|
|
|
|
|
const FrameSlot& slot = GetFrameSlot(function, ops.at(1));
|
|
|
|
|
int64_t offset = slot.offset; // 偏移可能为正或负
|
|
|
|
|
int64_t offset = slot.offset; // 负值,如 -8
|
|
|
|
|
PhysReg dst = ops.at(0).GetReg();
|
|
|
|
|
|
|
|
|
|
// 尝试生成简单的 add/sub 立即数指令
|
|
|
|
|
auto tryEmitSimple = [&]() -> bool {
|
|
|
|
|
if (offset >= 0 && offset <= 4095) {
|
|
|
|
|
os << " add " << PhysRegName(dst) << ", sp, #" << offset << "\n";
|
|
|
|
|
os << " add " << PhysRegName(dst) << ", x29, #" << offset << "\n";
|
|
|
|
|
return true;
|
|
|
|
|
} else if (offset < 0 && offset >= -4095) {
|
|
|
|
|
os << " sub " << PhysRegName(dst) << ", sp, #" << (-offset) << "\n";
|
|
|
|
|
os << " sub " << PhysRegName(dst) << ", x29, #" << (-offset) << "\n";
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
@ -384,13 +360,13 @@ void PrintInstruction(std::ostream& os, const MachineInstr& instr,
|
|
|
|
|
|
|
|
|
|
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";
|
|
|
|
|
os << " add " << PhysRegName(dst) << ", x29, x16\n";
|
|
|
|
|
} else {
|
|
|
|
|
os << " sub " << PhysRegName(dst) << ", sp, x16\n";
|
|
|
|
|
os << " sub " << PhysRegName(dst) << ", x29, x16\n";
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|