From 596b0ee334432bd9409e498c47836ada52399997 Mon Sep 17 00:00:00 2001 From: mxr <> Date: Fri, 10 Apr 2026 23:16:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(mir)=E6=B7=BB=E5=8A=A0Movk=E6=8C=87?= =?UTF-8?q?=E4=BB=A4=E5=8A=A0=E8=BD=BD=E5=A4=A7=E7=AB=8B=E5=8D=B3=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mir/MIR.h | 3 +++ src/mir/AsmPrinter.cpp | 4 ++++ src/mir/Lowering.cpp | 42 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/include/mir/MIR.h b/include/mir/MIR.h index ff1ce75..6c5f1ea 100644 --- a/include/mir/MIR.h +++ b/include/mir/MIR.h @@ -130,6 +130,9 @@ enum class Opcode { // ---------- 特殊 ---------- Nop, // 空操作: NOP Label, // 内联标签,不生成实际指令,仅输出标签名 + + // 添加 + Movk, // movk Rd, #imm16, lsl #shift }; // ========== 操作数类 ========== diff --git a/src/mir/AsmPrinter.cpp b/src/mir/AsmPrinter.cpp index 07d1452..d8c2fd8 100644 --- a/src/mir/AsmPrinter.cpp +++ b/src/mir/AsmPrinter.cpp @@ -316,6 +316,10 @@ void PrintInstruction(std::ostream& os, const MachineInstr& instr, case Opcode::Label: os << ops.at(0).GetLabel() << ":\n"; break; + case Opcode::Movk: + os << " movk " << PhysRegName(ops.at(0).GetReg()) << ", #" + << ops.at(1).GetImm() << ", lsl #" << ops.at(2).GetImm() << "\n"; + break; default: os << " // unknown instruction\n"; break; diff --git a/src/mir/Lowering.cpp b/src/mir/Lowering.cpp index 013aa26..c05bf35 100644 --- a/src/mir/Lowering.cpp +++ b/src/mir/Lowering.cpp @@ -128,9 +128,34 @@ void EmitValueToReg(const ir::Value* value, PhysReg target, if (value == nullptr) { DEBUG_MSG( "EmitValueToReg called with null value\n"); } + + // 辅助函数:判断32位立即数是否可用单条 movz/movn 编码 + auto isLegalMovImm = [](uint32_t imm) -> bool { + // 检查是否可以通过 movz 或 movn 表示(16位立即数,可左移0/16/32/48位) + // 对于32位寄存器,只考虑 lsl 0 或 16 + if ((imm & 0xFFFF) == imm) return true; // 低16位,lsl #0 + if ((imm & 0xFFFF0000) == imm) return true; // 高16位,lsl #16 + // 可选:检查 movn 情况(~imm 满足上述条件),为了简单可不做,直接返回 false + return false; + }; + if (auto* constant = dynamic_cast(value)) { - block.Append(Opcode::MovImm, - {Operand::Reg(target), Operand::Imm(constant->GetValue())}); + uint32_t imm = static_cast(constant->GetValue()); + if (isLegalMovImm(imm)) { + block.Append(Opcode::MovImm, + {Operand::Reg(target), Operand::Imm(static_cast(imm))}); + } else { + // 分解为 movz (低16位) + movk (高16位) + uint16_t low = imm & 0xFFFF; + uint16_t high = (imm >> 16) & 0xFFFF; + block.Append(Opcode::MovImm, + {Operand::Reg(target), Operand::Imm(low)}); // 先加载低16位 + if (high != 0) { + // 使用 Movk 指令写入高16位 + block.Append(Opcode::Movk, + {Operand::Reg(target), Operand::Imm(high), Operand::Imm(16)}); + } + } return; } // 处理浮点常量 @@ -150,8 +175,17 @@ void EmitValueToReg(const ir::Value* value, PhysReg target, float fval = fconstant->GetValue(); uint32_t int_val = FloatToBits(fval); - // 使用临时寄存器加载常量并存储 - block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::W8), Operand::Imm(static_cast(int_val))}); + // 同样需要对 int_val 进行大立即数分解 + if (isLegalMovImm(int_val)) { + block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::W8), Operand::Imm(static_cast(int_val))}); + } else { + uint16_t low = int_val & 0xFFFF; + uint16_t high = (int_val >> 16) & 0xFFFF; + block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::W8), Operand::Imm(low)}); + if (high != 0) { + block.Append(Opcode::Movk, {Operand::Reg(PhysReg::W8), Operand::Imm(high), Operand::Imm(16)}); + } + } block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::W8), Operand::FrameIndex(slot)}); const_cast(slots).emplace(value, slot); } else {