You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1187 lines
47 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "mir/MIR.h"
#include <cstring>
#include <stdexcept>
#include <unordered_map>
#include <set>
#include "ir/IR.h"
#include "utils/Log.h"
//#define DEBUG_Lower
#ifdef DEBUG_Lower
#include <iostream>
#define DEBUG_MSG(msg) std::cerr << "[Lower Debug] " << msg << std::endl
#else
#define DEBUG_MSG(msg) ((void)0)
#endif
namespace mir {
namespace {
// ========== VReg 类型 ==========
enum class VRegType { kInt32, kInt64, kFloat32 };
// ========== VReg 上下文:管理虚拟寄存器分配和 IR Value 映射 ==========
struct VRegContext {
int next_vreg = 1;
std::unordered_map<const ir::Value*, int> value_to_vreg;
std::unordered_map<int, VRegType> vreg_types;
int NewVReg(VRegType type) {
int id = next_vreg++;
vreg_types[id] = type;
return id;
}
VRegType GetType(int vreg) const {
auto it = vreg_types.find(vreg);
return it != vreg_types.end() ? it->second : VRegType::kInt32;
}
bool IsFloat(int vreg) const {
auto it = vreg_types.find(vreg);
return it != vreg_types.end() && it->second == VRegType::kFloat32;
}
bool IsPointer(int vreg) const {
auto it = vreg_types.find(vreg);
return it != vreg_types.end() && it->second == VRegType::kInt64;
}
void SetVReg(const ir::Value* value, int vreg) {
value_to_vreg[value] = vreg;
}
int GetVReg(const ir::Value* value) const {
auto it = value_to_vreg.find(value);
return it != value_to_vreg.end() ? it->second : -1;
}
bool HasVReg(const ir::Value* value) const {
return value_to_vreg.count(value) > 0;
}
};
// ========== 辅助:判断类型 ==========
inline bool IsInt32Type(const ir::Type* type) {
return type && type->IsInt32() && type->Size() == 4;
}
static uint32_t FloatToBits(float f) {
uint32_t bits;
memcpy(&bits, &f, sizeof(bits));
return bits;
}
int GetTypeSize(const ir::Type* type) {
if (!type) return 4;
size_t size = type->Size();
return size > 0 ? static_cast<int>(size) : 4;
}
VRegType GetVRegTypeForIRType(const ir::Type* type) {
if (!type) return VRegType::kInt32;
if (type->IsFloat()) return VRegType::kFloat32;
if (type->IsPtrInt32() || type->IsPtrFloat() || type->IsPtrInt1() || type->IsArray())
return VRegType::kInt64;
return VRegType::kInt32;
}
// ========== 辅助:记录 MachineInstr 的 def/use ==========
void RecordDefUse(MachineInstr& instr, int def, std::initializer_list<int> uses) {
if (def > 0) instr.AddDef(def);
for (int u : uses) {
if (u > 0) instr.AddUse(u);
}
}
void RecordDefUseVec(MachineInstr& instr, const std::vector<int>& defs,
const std::vector<int>& uses) {
for (int d : defs) instr.AddDef(d);
for (int u : uses) instr.AddUse(u);
}
// ========== 辅助:发射立即数到虚拟寄存器 ==========
void EmitMovImm(int vreg, uint32_t imm, MachineBasicBlock& block) {
auto isLegalMovImm = [](uint32_t v) -> bool {
return (v & 0xFFFF) == v || (v & 0xFFFF0000) == v;
};
if (isLegalMovImm(imm)) {
auto& instr = block.Append(Opcode::MovImm,
{Operand::VReg(vreg), Operand::Imm(static_cast<int64_t>(imm))});
instr.AddDef(vreg);
} else {
uint16_t low = imm & 0xFFFF;
uint16_t high = (imm >> 16) & 0xFFFF;
auto& i1 = block.Append(Opcode::MovImm,
{Operand::VReg(vreg), Operand::Imm(low)});
i1.AddDef(vreg);
if (high != 0) {
auto& i2 = block.Append(Opcode::Movk,
{Operand::VReg(vreg), Operand::Imm(high), Operand::Imm(16)});
i2.AddDef(vreg);
i2.AddUse(vreg);
}
}
}
void EmitMovImm64(int vreg, uint64_t imm, MachineBasicBlock& block) {
uint16_t part0 = imm & 0xFFFF;
uint16_t part1 = (imm >> 16) & 0xFFFF;
uint16_t part2 = (imm >> 32) & 0xFFFF;
uint16_t part3 = (imm >> 48) & 0xFFFF;
auto& i1 = block.Append(Opcode::MovImm,
{Operand::VReg(vreg), Operand::Imm(part0)});
i1.AddDef(vreg);
if (part1 != 0) {
auto& i2 = block.Append(Opcode::Movk,
{Operand::VReg(vreg), Operand::Imm(part1), Operand::Imm(16)});
i2.AddDef(vreg);
i2.AddUse(vreg);
}
if (part2 != 0) {
auto& i3 = block.Append(Opcode::Movk,
{Operand::VReg(vreg), Operand::Imm(part2), Operand::Imm(32)});
i3.AddDef(vreg);
i3.AddUse(vreg);
}
if (part3 != 0) {
auto& i4 = block.Append(Opcode::Movk,
{Operand::VReg(vreg), Operand::Imm(part3), Operand::Imm(48)});
i4.AddDef(vreg);
i4.AddUse(vreg);
}
}
// ========== 核心:将 IR Value 转换为虚拟寄存器 ==========
int EmitValueToVReg(const ir::Value* value, VRegContext& ctx,
MachineBasicBlock& block, MachineFunction& function) {
// 整数常量:每次都生成新的 MovImm不缓存
// 缓存会导致常量在某个条件块中定义,但其他控制流路径上的使用
// 可能不经过该定义,导致寄存器残留过期值。
if (auto* constant = dynamic_cast<const ir::ConstantInt*>(value)) {
uint32_t imm = static_cast<uint32_t>(constant->GetValue());
int vreg = ctx.NewVReg(VRegType::kInt32);
EmitMovImm(vreg, imm, block);
return vreg;
}
// 浮点常量:每次都走栈槽加载(不缓存)
if (auto* fconstant = dynamic_cast<const ir::ConstantFloat*>(value)) {
float fval = fconstant->GetValue();
uint32_t bits = FloatToBits(fval);
int slot = function.CreateFrameIndex(4);
int tmp = ctx.NewVReg(VRegType::kInt32);
EmitMovImm(tmp, bits, block);
auto& s = block.Append(Opcode::StoreStack,
{Operand::VReg(tmp), Operand::FrameIndex(slot)});
s.AddUse(tmp);
int fvreg = ctx.NewVReg(VRegType::kFloat32);
auto& l = block.Append(Opcode::LoadStack,
{Operand::VReg(fvreg), Operand::FrameIndex(slot)});
l.AddDef(fvreg);
return fvreg;
}
// 零常量 / 聚合零:每次都生成新 MovImm不缓存
if (dynamic_cast<const ir::ConstantZero*>(value) ||
dynamic_cast<const ir::ConstantAggregateZero*>(value)) {
int vreg = ctx.NewVReg(VRegType::kInt32);
auto& instr = block.Append(Opcode::MovImm,
{Operand::VReg(vreg), Operand::Imm(0)});
instr.AddDef(vreg);
return vreg;
}
// 全局变量:每次都生成新的 adrp+add不缓存
// 与常量同理:缓存会导致全局变量在某条件块中定义,但其他控制流路径
// 上的使用可能不经过该定义,导致寄存器残留过期值。
if (auto* global = dynamic_cast<const ir::GlobalValue*>(value)) {
int vreg = ctx.NewVReg(VRegType::kInt64);
auto& i1 = block.Append(Opcode::Adrp,
{Operand::VReg(vreg), Operand::Label(global->GetName())});
i1.AddDef(vreg);
auto& i2 = block.Append(Opcode::AddLabel,
{Operand::VReg(vreg), Operand::VReg(vreg), Operand::Label(global->GetName())});
i2.AddDef(vreg);
i2.AddUse(vreg);
return vreg;
}
// 非常量值:检查是否已有映射
if (ctx.HasVReg(value)) {
return ctx.GetVReg(value);
}
// 未找到
std::string name = value->GetName();
if (name.empty()) name = "(anonymous)";
throw std::runtime_error(
FormatError("mir", "EmitValueToVReg: 找不到值对应的 vreg: " + name));
}
// ========== IR 比较谓词 → ARMv8 条件码 ==========
CondCode IcmpToCondCode(ir::IcmpInst::Predicate pred) {
switch (pred) {
case ir::IcmpInst::Predicate::EQ: return CondCode::EQ;
case ir::IcmpInst::Predicate::NE: return CondCode::NE;
case ir::IcmpInst::Predicate::LT: return CondCode::LT;
case ir::IcmpInst::Predicate::GT: return CondCode::GT;
case ir::IcmpInst::Predicate::LE: return CondCode::LE;
case ir::IcmpInst::Predicate::GE: return CondCode::GE;
default: return CondCode::AL;
}
}
CondCode FcmpToCondCode(ir::FcmpInst::Predicate pred, bool& isOrdered) {
isOrdered = true;
switch (pred) {
case ir::FcmpInst::Predicate::OEQ: return CondCode::EQ;
case ir::FcmpInst::Predicate::ONE: return CondCode::NE;
case ir::FcmpInst::Predicate::OLT: return CondCode::LT;
case ir::FcmpInst::Predicate::OGT: return CondCode::GT;
case ir::FcmpInst::Predicate::OLE: return CondCode::LE;
case ir::FcmpInst::Predicate::OGE: return CondCode::GE;
case ir::FcmpInst::Predicate::UEQ: isOrdered = false; return CondCode::EQ;
case ir::FcmpInst::Predicate::UNE: isOrdered = false; return CondCode::NE;
case ir::FcmpInst::Predicate::ULT: isOrdered = false; return CondCode::LT;
case ir::FcmpInst::Predicate::UGT: isOrdered = false; return CondCode::GT;
case ir::FcmpInst::Predicate::ULE: isOrdered = false; return CondCode::LE;
case ir::FcmpInst::Predicate::UGE: isOrdered = false; return CondCode::GE;
default: return CondCode::AL;
}
}
std::string GetBlockLabel(const ir::BasicBlock* bb) {
if (!bb || !bb->GetParent()) return ".Lunknown";
std::string funcName = bb->GetParent()->GetName();
std::string blockName = bb->GetName();
if (blockName.empty())
blockName = std::to_string(reinterpret_cast<uintptr_t>(bb));
return ".L" + funcName + "_" + blockName;
}
// ========== LowerInstruction将单条 IR 指令转换为 MIR 指令 ==========
void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
VRegContext& ctx, MachineBasicBlock& block,
std::unordered_map<const ir::BasicBlock*,
MachineBasicBlock*>& blockMap) {
DEBUG_MSG("Processing instruction: " << inst.GetName()
<< " (opcode: " << static_cast<int>(inst.GetOpcode()) << ")");
switch (inst.GetOpcode()) {
// ---- Alloca在栈上分配空间返回指针 ----
case ir::Opcode::Alloca: {
int arraySlot = function.CreateFrameIndex(GetTypeSize(inst.GetType().get()));
int ptrVreg = ctx.NewVReg(VRegType::kInt64);
auto& instr = block.Append(Opcode::LoadStackAddr,
{Operand::VReg(ptrVreg), Operand::FrameIndex(arraySlot)});
instr.AddDef(ptrVreg);
ctx.SetVReg(&inst, ptrVreg);
return;
}
// ---- Store将值存储到指针指向的地址 ----
case ir::Opcode::Store: {
auto& store = static_cast<const ir::StoreInst&>(inst);
const ir::Value* ptr = store.GetPtr();
const ir::Value* val = store.GetValue();
int ptrVreg = EmitValueToVReg(ptr, ctx, block, function);
int valVreg = EmitValueToVReg(val, ctx, block, function);
auto& instr = block.Append(Opcode::StoreStack,
{Operand::VReg(valVreg), Operand::VReg(ptrVreg)});
instr.AddUse(valVreg);
instr.AddUse(ptrVreg);
return;
}
// ---- Load从指针指向的地址加载值 ----
case ir::Opcode::Load: {
auto& load = static_cast<const ir::LoadInst&>(inst);
const ir::Value* ptr = load.GetPtr();
int ptrVreg = EmitValueToVReg(ptr, ctx, block, function);
VRegType resultType = GetVRegTypeForIRType(inst.GetType().get());
int dstVreg = ctx.NewVReg(resultType);
auto& instr = block.Append(Opcode::LoadStack,
{Operand::VReg(dstVreg), Operand::VReg(ptrVreg)});
instr.AddDef(dstVreg);
instr.AddUse(ptrVreg);
ctx.SetVReg(&inst, dstVreg);
return;
}
// ---- Add ----
case ir::Opcode::Add: {
auto& bin = static_cast<const ir::BinaryInst&>(inst);
const ir::Type* lhsTy = bin.GetLhs()->GetType().get();
const ir::Type* rhsTy = bin.GetRhs()->GetType().get();
const ir::Type* resultTy = inst.GetType().get();
bool isPointer = (lhsTy->IsPtrInt32() || lhsTy->IsPtrFloat() || lhsTy->IsPtrInt1() || lhsTy->IsArray()) ||
(rhsTy->IsPtrInt32() || rhsTy->IsPtrFloat() || rhsTy->IsPtrInt1() || rhsTy->IsArray()) ||
resultTy->IsPtrInt32() || resultTy->IsPtrFloat() || resultTy->IsPtrInt1() || resultTy->IsArray();
bool isI32 = !isPointer && IsInt32Type(lhsTy) && IsInt32Type(rhsTy) && IsInt32Type(resultTy);
if (isI32) {
// i32 加法:用 64 位运算避免溢出
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vxl = ctx.NewVReg(VRegType::kInt64);
int vxr = ctx.NewVReg(VRegType::kInt64);
int vxd = ctx.NewVReg(VRegType::kInt64);
auto& s1 = block.Append(Opcode::Sxtw, {Operand::VReg(vxl), Operand::VReg(vl)});
s1.AddDef(vxl); s1.AddUse(vl);
auto& s2 = block.Append(Opcode::Sxtw, {Operand::VReg(vxr), Operand::VReg(vr)});
s2.AddDef(vxr); s2.AddUse(vr);
auto& a = block.Append(Opcode::AddRR, {Operand::VReg(vxd), Operand::VReg(vxl), Operand::VReg(vxr)});
a.AddDef(vxd); a.AddUse(vxl); a.AddUse(vxr);
// 结果用 32 位 vreg低 32 位正确)
int vd = ctx.NewVReg(VRegType::kInt32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(vd), Operand::VReg(vxd)});
mv.AddDef(vd); mv.AddUse(vxd);
ctx.SetVReg(&inst, vd);
} else {
VRegType ty = isPointer ? VRegType::kInt64 : VRegType::kInt32;
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(ty);
auto& a = block.Append(Opcode::AddRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
}
return;
}
// ---- Sub ----
case ir::Opcode::Sub: {
auto& bin = static_cast<const ir::BinaryInst&>(inst);
// 浮点减法
if (bin.GetLhs()->GetType()->IsFloat() && bin.GetRhs()->GetType()->IsFloat()) {
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(VRegType::kFloat32);
auto& a = block.Append(Opcode::FSubRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
return;
}
const ir::Type* lhsTy = bin.GetLhs()->GetType().get();
const ir::Type* rhsTy = bin.GetRhs()->GetType().get();
const ir::Type* resultTy = inst.GetType().get();
bool isPointer = (lhsTy->IsPtrInt32() || lhsTy->IsPtrFloat() || lhsTy->IsPtrInt1() || lhsTy->IsArray()) ||
(rhsTy->IsPtrInt32() || rhsTy->IsPtrFloat() || rhsTy->IsPtrInt1() || rhsTy->IsArray()) ||
resultTy->IsPtrInt32() || resultTy->IsPtrFloat() || resultTy->IsPtrInt1() || resultTy->IsArray();
bool isI32 = !isPointer && IsInt32Type(lhsTy) && IsInt32Type(rhsTy) && IsInt32Type(resultTy);
if (isI32) {
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vxl = ctx.NewVReg(VRegType::kInt64);
int vxr = ctx.NewVReg(VRegType::kInt64);
int vxd = ctx.NewVReg(VRegType::kInt64);
auto& s1 = block.Append(Opcode::Sxtw, {Operand::VReg(vxl), Operand::VReg(vl)});
s1.AddDef(vxl); s1.AddUse(vl);
auto& s2 = block.Append(Opcode::Sxtw, {Operand::VReg(vxr), Operand::VReg(vr)});
s2.AddDef(vxr); s2.AddUse(vr);
auto& a = block.Append(Opcode::SubRR, {Operand::VReg(vxd), Operand::VReg(vxl), Operand::VReg(vxr)});
a.AddDef(vxd); a.AddUse(vxl); a.AddUse(vxr);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(vd), Operand::VReg(vxd)});
mv.AddDef(vd); mv.AddUse(vxd);
ctx.SetVReg(&inst, vd);
} else {
VRegType ty = isPointer ? VRegType::kInt64 : VRegType::kInt32;
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(ty);
auto& a = block.Append(Opcode::SubRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
}
return;
}
// ---- Mul ----
case ir::Opcode::Mul: {
auto& bin = static_cast<const ir::BinaryInst&>(inst);
const ir::Type* lhsTy = bin.GetLhs()->GetType().get();
const ir::Type* rhsTy = bin.GetRhs()->GetType().get();
const ir::Type* resultTy = inst.GetType().get();
bool isPointer = (lhsTy->IsPtrInt32() || lhsTy->IsPtrFloat() || lhsTy->IsPtrInt1()) ||
(rhsTy->IsPtrInt32() || rhsTy->IsPtrFloat() || rhsTy->IsPtrInt1()) ||
resultTy->IsPtrInt32() || resultTy->IsPtrFloat() || resultTy->IsPtrInt1();
bool isI32 = !isPointer && IsInt32Type(lhsTy) && IsInt32Type(rhsTy) && IsInt32Type(resultTy);
if (isI32) {
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vxl = ctx.NewVReg(VRegType::kInt64);
int vxr = ctx.NewVReg(VRegType::kInt64);
int vxd = ctx.NewVReg(VRegType::kInt64);
auto& s1 = block.Append(Opcode::Sxtw, {Operand::VReg(vxl), Operand::VReg(vl)});
s1.AddDef(vxl); s1.AddUse(vl);
auto& s2 = block.Append(Opcode::Sxtw, {Operand::VReg(vxr), Operand::VReg(vr)});
s2.AddDef(vxr); s2.AddUse(vr);
auto& a = block.Append(Opcode::MulRR, {Operand::VReg(vxd), Operand::VReg(vxl), Operand::VReg(vxr)});
a.AddDef(vxd); a.AddUse(vxl); a.AddUse(vxr);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(vd), Operand::VReg(vxd)});
mv.AddDef(vd); mv.AddUse(vxd);
ctx.SetVReg(&inst, vd);
} else {
VRegType ty = isPointer ? VRegType::kInt64 : VRegType::kInt32;
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(ty);
auto& a = block.Append(Opcode::MulRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
}
return;
}
// ---- Div ----
case ir::Opcode::Div: {
auto& bin = static_cast<const ir::BinaryInst&>(inst);
const ir::Type* lhsTy = bin.GetLhs()->GetType().get();
const ir::Type* rhsTy = bin.GetRhs()->GetType().get();
const ir::Type* resultTy = inst.GetType().get();
bool isPointer = (lhsTy->IsPtrInt32() || lhsTy->IsPtrFloat() || lhsTy->IsPtrInt1()) ||
(rhsTy->IsPtrInt32() || rhsTy->IsPtrFloat() || rhsTy->IsPtrInt1()) ||
resultTy->IsPtrInt32() || resultTy->IsPtrFloat() || resultTy->IsPtrInt1();
bool isI32 = !isPointer && IsInt32Type(lhsTy) && IsInt32Type(rhsTy) && IsInt32Type(resultTy);
if (isI32) {
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vxl = ctx.NewVReg(VRegType::kInt64);
int vxr = ctx.NewVReg(VRegType::kInt64);
int vxd = ctx.NewVReg(VRegType::kInt64);
auto& s1 = block.Append(Opcode::Sxtw, {Operand::VReg(vxl), Operand::VReg(vl)});
s1.AddDef(vxl); s1.AddUse(vl);
auto& s2 = block.Append(Opcode::Sxtw, {Operand::VReg(vxr), Operand::VReg(vr)});
s2.AddDef(vxr); s2.AddUse(vr);
auto& a = block.Append(Opcode::SDivRR, {Operand::VReg(vxd), Operand::VReg(vxl), Operand::VReg(vxr)});
a.AddDef(vxd); a.AddUse(vxl); a.AddUse(vxr);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(vd), Operand::VReg(vxd)});
mv.AddDef(vd); mv.AddUse(vxd);
ctx.SetVReg(&inst, vd);
} else {
VRegType ty = isPointer ? VRegType::kInt64 : VRegType::kInt32;
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(ty);
auto& a = block.Append(Opcode::SDivRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
}
return;
}
// ---- Mod: a % b = a - (a / b) * b ----
case ir::Opcode::Mod: {
const ir::Value* lhs = inst.GetOperand(0);
const ir::Value* rhs = inst.GetOperand(1);
const ir::Type* lhsTy = lhs->GetType().get();
const ir::Type* rhsTy = rhs->GetType().get();
const ir::Type* resultTy = inst.GetType().get();
bool isI32 = IsInt32Type(lhsTy) && IsInt32Type(rhsTy) && IsInt32Type(resultTy);
if (isI32) {
int vl = EmitValueToVReg(lhs, ctx, block, function);
int vr = EmitValueToVReg(rhs, ctx, block, function);
int vxl = ctx.NewVReg(VRegType::kInt64);
int vxr = ctx.NewVReg(VRegType::kInt64);
auto& s1 = block.Append(Opcode::Sxtw, {Operand::VReg(vxl), Operand::VReg(vl)});
s1.AddDef(vxl); s1.AddUse(vl);
auto& s2 = block.Append(Opcode::Sxtw, {Operand::VReg(vxr), Operand::VReg(vr)});
s2.AddDef(vxr); s2.AddUse(vr);
int vxdiv = ctx.NewVReg(VRegType::kInt64);
int vxtmp = ctx.NewVReg(VRegType::kInt64);
int vxd = ctx.NewVReg(VRegType::kInt64);
auto& d = block.Append(Opcode::SDivRR, {Operand::VReg(vxdiv), Operand::VReg(vxl), Operand::VReg(vxr)});
d.AddDef(vxdiv); d.AddUse(vxl); d.AddUse(vxr);
auto& m = block.Append(Opcode::MulRR, {Operand::VReg(vxtmp), Operand::VReg(vxdiv), Operand::VReg(vxr)});
m.AddDef(vxtmp); m.AddUse(vxdiv); m.AddUse(vxr);
auto& sub = block.Append(Opcode::SubRR, {Operand::VReg(vxd), Operand::VReg(vxl), Operand::VReg(vxtmp)});
sub.AddDef(vxd); sub.AddUse(vxl); sub.AddUse(vxtmp);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(vd), Operand::VReg(vxd)});
mv.AddDef(vd); mv.AddUse(vxd);
ctx.SetVReg(&inst, vd);
} else {
int vl = EmitValueToVReg(lhs, ctx, block, function);
int vr = EmitValueToVReg(rhs, ctx, block, function);
int vdiv = ctx.NewVReg(VRegType::kInt32);
int vtmp = ctx.NewVReg(VRegType::kInt32);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& d = block.Append(Opcode::SDivRR, {Operand::VReg(vdiv), Operand::VReg(vl), Operand::VReg(vr)});
d.AddDef(vdiv); d.AddUse(vl); d.AddUse(vr);
auto& m = block.Append(Opcode::MulRR, {Operand::VReg(vtmp), Operand::VReg(vdiv), Operand::VReg(vr)});
m.AddDef(vtmp); m.AddUse(vdiv); m.AddUse(vr);
auto& s = block.Append(Opcode::SubRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vtmp)});
s.AddDef(vd); s.AddUse(vl); s.AddUse(vtmp);
ctx.SetVReg(&inst, vd);
}
return;
}
// ---- Ret ----
case ir::Opcode::Ret: {
auto& ret = static_cast<const ir::ReturnInst&>(inst);
const ir::Value* retVal = ret.GetValue();
if (retVal != nullptr) {
const ir::Type* retType = retVal->GetType().get();
int valVreg = EmitValueToVReg(retVal, ctx, block, function);
PhysReg retReg = PhysReg::W0;
if (retType->IsFloat()) retReg = PhysReg::S0;
else if (retType->IsPtrInt32() || retType->IsPtrFloat() || retType->IsPtrInt1())
retReg = PhysReg::X0;
auto& mv = block.Append(Opcode::MovReg,
{Operand::Reg(retReg), Operand::VReg(valVreg)});
mv.AddUse(valVreg);
}
auto& r = block.Append(Opcode::Ret);
return;
}
// ---- FAdd ----
case ir::Opcode::FAdd: {
auto& bin = static_cast<const ir::BinaryInst&>(inst);
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(VRegType::kFloat32);
auto& a = block.Append(Opcode::FAddRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
return;
}
case ir::Opcode::FSub: {
auto& bin = static_cast<const ir::BinaryInst&>(inst);
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(VRegType::kFloat32);
auto& a = block.Append(Opcode::FSubRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
return;
}
case ir::Opcode::FMul: {
auto& bin = static_cast<const ir::BinaryInst&>(inst);
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(VRegType::kFloat32);
auto& a = block.Append(Opcode::FMulRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
return;
}
case ir::Opcode::FDiv: {
auto& bin = static_cast<const ir::BinaryInst&>(inst);
int vl = EmitValueToVReg(bin.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(bin.GetRhs(), ctx, block, function);
int vd = ctx.NewVReg(VRegType::kFloat32);
auto& a = block.Append(Opcode::FDivRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
return;
}
// ---- Icmp整数比较 ----
case ir::Opcode::Icmp: {
auto& icmp = static_cast<const ir::IcmpInst&>(inst);
int vl = EmitValueToVReg(icmp.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(icmp.GetRhs(), ctx, block, function);
CondCode cc = IcmpToCondCode(icmp.GetPredicate());
auto& cmp = block.Append(Opcode::CmpRR, {Operand::VReg(vl), Operand::VReg(vr)});
cmp.AddUse(vl); cmp.AddUse(vr);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& set1 = block.Append(Opcode::MovImm, {Operand::VReg(vd), Operand::Imm(1)});
set1.AddDef(vd);
std::string trueLabel = ".L_cset_true_" + std::to_string(reinterpret_cast<uintptr_t>(&icmp));
std::string endLabel = ".L_cset_end_" + std::to_string(reinterpret_cast<uintptr_t>(&icmp));
auto& bc = block.Append(Opcode::BCond, {Operand::Cond(cc), Operand::Label(trueLabel)});
auto& mv0 = block.Append(Opcode::MovImm, {Operand::VReg(vd), Operand::Imm(0)});
mv0.AddDef(vd);
auto& b = block.Append(Opcode::B, {Operand::Label(endLabel)});
auto& lt = block.Append(Opcode::Label, {Operand::Label(trueLabel)});
auto& le = block.Append(Opcode::Label, {Operand::Label(endLabel)});
ctx.SetVReg(&inst, vd);
return;
}
// ---- FCmp浮点比较 ----
case ir::Opcode::FCmp: {
auto& fcmp = static_cast<const ir::FcmpInst&>(inst);
int vl = EmitValueToVReg(fcmp.GetLhs(), ctx, block, function);
int vr = EmitValueToVReg(fcmp.GetRhs(), ctx, block, function);
bool isOrdered;
CondCode cc = FcmpToCondCode(fcmp.GetPredicate(), isOrdered);
auto& cmp = block.Append(Opcode::FCmpRR, {Operand::VReg(vl), Operand::VReg(vr)});
cmp.AddUse(vl); cmp.AddUse(vr);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& zero = block.Append(Opcode::MovImm, {Operand::VReg(vd), Operand::Imm(0)});
zero.AddDef(vd);
std::string set1Label = ".L_fcset_true_" + std::to_string(reinterpret_cast<uintptr_t>(&fcmp));
std::string endLabel = ".L_fcset_end_" + std::to_string(reinterpret_cast<uintptr_t>(&fcmp));
if (isOrdered) {
auto& bc_vs = block.Append(Opcode::BCond, {Operand::Cond(CondCode::VS), Operand::Label(endLabel)});
} else {
auto& bc_vs = block.Append(Opcode::BCond, {Operand::Cond(CondCode::VS), Operand::Label(set1Label)});
}
auto& bc = block.Append(Opcode::BCond, {Operand::Cond(cc), Operand::Label(set1Label)});
auto& b = block.Append(Opcode::B, {Operand::Label(endLabel)});
auto& lt = block.Append(Opcode::Label, {Operand::Label(set1Label)});
auto& s1 = block.Append(Opcode::MovImm, {Operand::VReg(vd), Operand::Imm(1)});
s1.AddDef(vd);
auto& le = block.Append(Opcode::Label, {Operand::Label(endLabel)});
ctx.SetVReg(&inst, vd);
return;
}
// ---- Br / CondBr ----
case ir::Opcode::Br:
case ir::Opcode::CondBr: {
auto& br = static_cast<const ir::BranchInst&>(inst);
if (br.IsConditional()) {
int condVreg = EmitValueToVReg(br.GetCondition(), ctx, block, function);
auto& cmp = block.Append(Opcode::CmpRI, {Operand::VReg(condVreg), Operand::Imm(0)});
cmp.AddUse(condVreg);
std::string trueLabel = GetBlockLabel(br.GetTrueTarget());
std::string falseLabel = GetBlockLabel(br.GetFalseTarget());
auto& bc = block.Append(Opcode::BCond, {Operand::Cond(CondCode::NE), Operand::Label(trueLabel)});
auto& b = block.Append(Opcode::B, {Operand::Label(falseLabel)});
} else {
std::string targetLabel = GetBlockLabel(br.GetTarget());
auto& b = block.Append(Opcode::B, {Operand::Label(targetLabel)});
}
return;
}
// ---- Call ----
case ir::Opcode::Call: {
auto& call = static_cast<const ir::CallInst&>(inst);
const ir::Function* callee = call.GetCallee();
const std::string& calleeName = callee->GetName();
// 传递参数vreg → 物理寄存器)
const auto& args = call.GetArgs();
size_t intArgCount = 0;
size_t fpArgCount = 0;
for (size_t i = 0; i < args.size(); ++i) {
const auto* arg = args[i];
const ir::Type* argType = arg->GetType().get();
int argVreg = EmitValueToVReg(arg, ctx, block, function);
if (argType->IsFloat()) {
PhysReg reg = static_cast<PhysReg>(static_cast<int>(PhysReg::S0) + fpArgCount);
auto& mv = block.Append(Opcode::MovReg, {Operand::Reg(reg), Operand::VReg(argVreg)});
mv.AddUse(argVreg);
fpArgCount++;
} else if (argType->IsPtrInt32() || argType->IsPtrFloat() || argType->IsPtrInt1()) {
PhysReg reg = static_cast<PhysReg>(static_cast<int>(PhysReg::X0) + intArgCount);
auto& mv = block.Append(Opcode::MovReg, {Operand::Reg(reg), Operand::VReg(argVreg)});
mv.AddUse(argVreg);
intArgCount++;
} else {
PhysReg reg = static_cast<PhysReg>(static_cast<int>(PhysReg::W0) + intArgCount);
auto& mv = block.Append(Opcode::MovReg, {Operand::Reg(reg), Operand::VReg(argVreg)});
mv.AddUse(argVreg);
intArgCount++;
}
}
auto& callInst = block.Append(Opcode::Call, {Operand::Label(calleeName)});
// 返回值:物理寄存器 → vreg
if (!inst.GetType()->IsVoid()) {
const ir::Type* retType = inst.GetType().get();
VRegType vtype = GetVRegTypeForIRType(retType);
int dstVreg = ctx.NewVReg(vtype);
PhysReg srcReg = PhysReg::W0;
if (retType->IsFloat()) srcReg = PhysReg::S0;
else if (retType->IsPtrInt32() || retType->IsPtrFloat() || retType->IsPtrInt1())
srcReg = PhysReg::X0;
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(dstVreg), Operand::Reg(srcReg)});
mv.AddDef(dstVreg);
ctx.SetVReg(&inst, dstVreg);
}
return;
}
// ---- ZExt (i1 → i32) ----
case ir::Opcode::ZExt: {
auto& zext = static_cast<const ir::ZExtInst&>(inst);
int src = EmitValueToVReg(zext.GetValue(), ctx, block, function);
int dst = ctx.NewVReg(VRegType::kInt32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(dst), Operand::VReg(src)});
mv.AddDef(dst); mv.AddUse(src);
ctx.SetVReg(&inst, dst);
return;
}
// ---- SIToFP ----
case ir::Opcode::SIToFP: {
auto& sitofp = static_cast<const ir::SIToFPInst&>(inst);
int src = EmitValueToVReg(sitofp.GetValue(), ctx, block, function);
int dst = ctx.NewVReg(VRegType::kFloat32);
auto& cvt = block.Append(Opcode::SIToFP, {Operand::VReg(dst), Operand::VReg(src)});
cvt.AddDef(dst); cvt.AddUse(src);
ctx.SetVReg(&inst, dst);
return;
}
// ---- FPToSI ----
case ir::Opcode::FPToSI: {
auto& fptosi = static_cast<const ir::FPToSIInst&>(inst);
int src = EmitValueToVReg(fptosi.GetValue(), ctx, block, function);
int dst = ctx.NewVReg(VRegType::kInt32);
auto& cvt = block.Append(Opcode::FPToSI, {Operand::VReg(dst), Operand::VReg(src)});
cvt.AddDef(dst); cvt.AddUse(src);
ctx.SetVReg(&inst, dst);
return;
}
// ---- Trunc ----
case ir::Opcode::Trunc: {
const ir::Value* srcVal = inst.GetNumOperands() > 0 ? inst.GetOperand(0) : nullptr;
if (srcVal) {
int src = EmitValueToVReg(srcVal, ctx, block, function);
int dst = ctx.NewVReg(VRegType::kInt32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(dst), Operand::VReg(src)});
mv.AddDef(dst); mv.AddUse(src);
ctx.SetVReg(&inst, dst);
}
return;
}
// ---- And ----
case ir::Opcode::And: {
const ir::Value* lhs = inst.GetNumOperands() >= 2 ? inst.GetOperand(0) : nullptr;
const ir::Value* rhs = inst.GetNumOperands() >= 2 ? inst.GetOperand(1) : nullptr;
if (lhs && rhs) {
int vl = EmitValueToVReg(lhs, ctx, block, function);
int vr = EmitValueToVReg(rhs, ctx, block, function);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& a = block.Append(Opcode::AndRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
}
return;
}
// ---- Or ----
case ir::Opcode::Or: {
const ir::Value* lhs = inst.GetNumOperands() >= 2 ? inst.GetOperand(0) : nullptr;
const ir::Value* rhs = inst.GetNumOperands() >= 2 ? inst.GetOperand(1) : nullptr;
if (lhs && rhs) {
int vl = EmitValueToVReg(lhs, ctx, block, function);
int vr = EmitValueToVReg(rhs, ctx, block, function);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& a = block.Append(Opcode::OrRR, {Operand::VReg(vd), Operand::VReg(vl), Operand::VReg(vr)});
a.AddDef(vd); a.AddUse(vl); a.AddUse(vr);
ctx.SetVReg(&inst, vd);
}
return;
}
// ---- Not ----
case ir::Opcode::Not: {
const ir::Value* srcVal = inst.GetNumOperands() > 0 ? inst.GetOperand(0) : nullptr;
if (srcVal) {
int src = EmitValueToVReg(srcVal, ctx, block, function);
int m1 = ctx.NewVReg(VRegType::kInt32);
auto& mv1 = block.Append(Opcode::MovImm, {Operand::VReg(m1), Operand::Imm(-1)});
mv1.AddDef(m1);
int vd = ctx.NewVReg(VRegType::kInt32);
auto& eor = block.Append(Opcode::EorRR, {Operand::VReg(vd), Operand::VReg(src), Operand::VReg(m1)});
eor.AddDef(vd); eor.AddUse(src); eor.AddUse(m1);
ctx.SetVReg(&inst, vd);
}
return;
}
// ---- FPExt ----
case ir::Opcode::FPExt: {
const ir::Value* srcVal = inst.GetNumOperands() > 0 ? inst.GetOperand(0) : nullptr;
if (srcVal) {
int src = EmitValueToVReg(srcVal, ctx, block, function);
int dst = ctx.NewVReg(VRegType::kFloat32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(dst), Operand::VReg(src)});
mv.AddDef(dst); mv.AddUse(src);
ctx.SetVReg(&inst, dst);
}
return;
}
// ---- FPTrunc ----
case ir::Opcode::FPTrunc: {
const ir::Value* srcVal = inst.GetNumOperands() > 0 ? inst.GetOperand(0) : nullptr;
if (srcVal) {
int src = EmitValueToVReg(srcVal, ctx, block, function);
int dst = ctx.NewVReg(VRegType::kFloat32);
auto& mv = block.Append(Opcode::MovReg, {Operand::VReg(dst), Operand::VReg(src)});
mv.AddDef(dst); mv.AddUse(src);
ctx.SetVReg(&inst, dst);
}
return;
}
// ---- GEP ----
case ir::Opcode::GEP: {
auto& gep = static_cast<const ir::GEPInst&>(inst);
ir::Value* base = gep.GetBase();
const auto& indices = gep.GetIndices();
int baseVreg = EmitValueToVReg(base, ctx, block, function);
if (indices.empty()) {
ctx.SetVReg(&inst, baseVreg);
return;
}
const ir::Type* baseType = base->GetType().get();
size_t startIndex = 0;
if (baseType->IsArray()) {
startIndex = 1; // 跳过数组解码的第一个索引
}
if (baseType->IsArray() && indices.size() > startIndex) {
const ir::ArrayType* arrayType = static_cast<const ir::ArrayType*>(baseType);
const std::vector<int>& dims = arrayType->GetDimensions();
std::vector<int> strides(dims.size());
int elementSize = 4;
for (int i = static_cast<int>(dims.size()) - 1; i >= 0; --i) {
if (i == static_cast<int>(dims.size()) - 1)
strides[i] = elementSize;
else
strides[i] = strides[i + 1] * dims[i + 1];
}
size_t numIndices = indices.size();
size_t effectiveIndices = numIndices - startIndex;
if (effectiveIndices > dims.size()) effectiveIndices = dims.size();
// 偏移累加器初始化为 0
int offsetVreg = ctx.NewVReg(VRegType::kInt64);
auto& zero = block.Append(Opcode::MovImm, {Operand::VReg(offsetVreg), Operand::Imm(0)});
zero.AddDef(offsetVreg);
for (size_t i = 0; i < effectiveIndices; ++i) {
size_t idxPos = startIndex + i;
int idxVreg = EmitValueToVReg(indices[idxPos], ctx, block, function);
// 确保索引是 Int64地址计算必须是 64 位)
if (ctx.GetType(idxVreg) == VRegType::kInt32) {
int idxVreg64 = ctx.NewVReg(VRegType::kInt64);
auto& sxt = block.Append(Opcode::Sxtw,
{Operand::VReg(idxVreg64), Operand::VReg(idxVreg)});
sxt.AddDef(idxVreg64); sxt.AddUse(idxVreg);
idxVreg = idxVreg64;
}
int strideVreg = ctx.NewVReg(VRegType::kInt64);
auto& stride = block.Append(Opcode::MovImm,
{Operand::VReg(strideVreg), Operand::Imm(strides[i])});
stride.AddDef(strideVreg);
int prodVreg = ctx.NewVReg(VRegType::kInt64);
auto& mul = block.Append(Opcode::MulRR,
{Operand::VReg(prodVreg), Operand::VReg(idxVreg), Operand::VReg(strideVreg)});
mul.AddDef(prodVreg); mul.AddUse(idxVreg); mul.AddUse(strideVreg);
int newOff = ctx.NewVReg(VRegType::kInt64);
auto& add = block.Append(Opcode::AddRR,
{Operand::VReg(newOff), Operand::VReg(offsetVreg), Operand::VReg(prodVreg)});
add.AddDef(newOff); add.AddUse(offsetVreg); add.AddUse(prodVreg);
offsetVreg = newOff;
}
int resultVreg = ctx.NewVReg(VRegType::kInt64);
auto& finalAdd = block.Append(Opcode::AddRR,
{Operand::VReg(resultVreg), Operand::VReg(baseVreg), Operand::VReg(offsetVreg)});
finalAdd.AddDef(resultVreg); finalAdd.AddUse(baseVreg); finalAdd.AddUse(offsetVreg);
ctx.SetVReg(&inst, resultVreg);
} else if (indices.size() >= 1) {
// 简单指针运算
int idxVreg = EmitValueToVReg(indices[0], ctx, block, function);
if (ctx.GetType(idxVreg) == VRegType::kInt32) {
int idxVreg64 = ctx.NewVReg(VRegType::kInt64);
auto& sxt = block.Append(Opcode::Sxtw,
{Operand::VReg(idxVreg64), Operand::VReg(idxVreg)});
sxt.AddDef(idxVreg64); sxt.AddUse(idxVreg);
idxVreg = idxVreg64;
}
int strideVreg = ctx.NewVReg(VRegType::kInt64);
int elemSize = 4;
if (baseType->IsArray()) {
const ir::ArrayType* arrType = static_cast<const ir::ArrayType*>(baseType);
elemSize = GetTypeSize(arrType->GetElementType().get());
}
auto& stride = block.Append(Opcode::MovImm, {Operand::VReg(strideVreg), Operand::Imm(elemSize)});
stride.AddDef(strideVreg);
int prodVreg = ctx.NewVReg(VRegType::kInt64);
auto& mul = block.Append(Opcode::MulRR,
{Operand::VReg(prodVreg), Operand::VReg(idxVreg), Operand::VReg(strideVreg)});
mul.AddDef(prodVreg); mul.AddUse(idxVreg); mul.AddUse(strideVreg);
int resultVreg = ctx.NewVReg(VRegType::kInt64);
auto& add = block.Append(Opcode::AddRR,
{Operand::VReg(resultVreg), Operand::VReg(baseVreg), Operand::VReg(prodVreg)});
add.AddDef(resultVreg); add.AddUse(baseVreg); add.AddUse(prodVreg);
ctx.SetVReg(&inst, resultVreg);
}
return;
}
default:
throw std::runtime_error(FormatError("mir", "暂不支持该 IR 指令opcode: "
+ std::to_string(static_cast<int>(inst.GetOpcode()))));
}
}
// ========== LowerFunction将 IR 函数转换为 MachineFunction ==========
std::unique_ptr<MachineFunction> LowerFunction(const ir::Function& func) {
auto machineFunc = std::make_unique<MachineFunction>(func.GetName());
VRegContext ctx;
// 为函数参数分配 vreg
struct ParamInfo {
const ir::Value* arg;
int vreg;
bool isFloat;
bool isPointer;
};
std::vector<ParamInfo> paramInfos;
for (const auto& arg : func.GetArguments()) {
bool isFloat = arg->GetType()->IsFloat();
bool isPointer = arg->GetType()->IsPtrInt32() || arg->GetType()->IsPtrFloat()
|| arg->GetType()->IsPtrInt1();
VRegType ty = isFloat ? VRegType::kFloat32
: (isPointer ? VRegType::kInt64 : VRegType::kInt32);
int vreg = ctx.NewVReg(ty);
ctx.SetVReg(arg.get(), vreg);
paramInfos.push_back({arg.get(), vreg, isFloat, isPointer});
}
// IR 基本块 → MIR 基本块 映射
std::unordered_map<const ir::BasicBlock*, MachineBasicBlock*> blockMap;
std::string funcName = func.GetName();
for (const auto& bb : func.GetBlocks()) {
auto mirBB = std::make_unique<MachineBasicBlock>(".L" + funcName + "_" + bb->GetName());
blockMap[bb.get()] = mirBB.get();
machineFunc->AddBasicBlock(std::move(mirBB));
}
// 在入口基本块开头:从物理参数寄存器加载参数到 vreg
if (!func.GetBlocks().empty()) {
MachineBasicBlock* entryBB = blockMap[func.GetEntry()];
if (entryBB) {
size_t intArgIdx = 0;
size_t fpArgIdx = 0;
for (const auto& param : paramInfos) {
if (param.isFloat) {
if (fpArgIdx < 8) {
PhysReg reg = static_cast<PhysReg>(
static_cast<int>(PhysReg::S0) + fpArgIdx);
auto& mv = entryBB->Append(Opcode::MovReg,
{Operand::VReg(param.vreg), Operand::Reg(reg)});
mv.AddDef(param.vreg);
}
fpArgIdx++;
} else if (param.isPointer) {
if (intArgIdx < 8) {
PhysReg reg = static_cast<PhysReg>(
static_cast<int>(PhysReg::X0) + intArgIdx);
auto& mv = entryBB->Append(Opcode::MovReg,
{Operand::VReg(param.vreg), Operand::Reg(reg)});
mv.AddDef(param.vreg);
}
intArgIdx++;
} else {
if (intArgIdx < 8) {
PhysReg reg = static_cast<PhysReg>(
static_cast<int>(PhysReg::W0) + intArgIdx);
auto& mv = entryBB->Append(Opcode::MovReg,
{Operand::VReg(param.vreg), Operand::Reg(reg)});
mv.AddDef(param.vreg);
}
intArgIdx++;
}
}
}
}
// 转换每个基本块的指令
for (const auto& bb : func.GetBlocks()) {
MachineBasicBlock* mirBB = blockMap[bb.get()];
if (!mirBB)
throw std::runtime_error(FormatError("mir", "找不到基本块对应的 MIR 基本块"));
for (const auto& inst : bb->GetInstructions()) {
LowerInstruction(*inst, *machineFunc, ctx, *mirBB, blockMap);
}
}
// 将 vreg 类型信息存入 MachineFunctionRA 阶段使用)
for (const auto& [vreg, type] : ctx.vreg_types) {
switch (type) {
case VRegType::kInt32:
machineFunc->SetVRegType(vreg, MachineFunction::VRegType::kInt32);
break;
case VRegType::kInt64:
machineFunc->SetVRegType(vreg, MachineFunction::VRegType::kInt64);
break;
case VRegType::kFloat32:
machineFunc->SetVRegType(vreg, MachineFunction::VRegType::kFloat32);
break;
}
}
// 构建 CFG 边(解析 B/BCond 中的 Label 目标)
for (const auto& bb : func.GetBlocks()) {
MachineBasicBlock* mirBB = blockMap[bb.get()];
auto& insts = mirBB->GetInstructions();
if (insts.empty()) continue;
// 辅助:从指令中提取 Label 操作数并添加边
auto addLabelSuccessors = [&](const MachineInstr& inst) {
for (const auto& op : inst.GetOperands()) {
if (op.GetKind() == Operand::Kind::Label) {
MachineBasicBlock* target = machineFunc->GetBlockByName(op.GetLabel());
if (target) {
mirBB->AddSuccessor(target);
target->AddPredecessor(mirBB);
}
}
}
};
// 辅助:添加 fallthrough 到下一个 IR 基本块
auto addFallthrough = [&]() {
for (size_t i = 0; i + 1 < func.GetBlocks().size(); ++i) {
if (func.GetBlocks()[i].get() == bb.get()) {
const auto* nextBB = func.GetBlocks()[i + 1].get();
MachineBasicBlock* nextMIR = blockMap[nextBB];
if (nextMIR) {
mirBB->AddSuccessor(nextMIR);
nextMIR->AddPredecessor(mirBB);
}
break;
}
}
};
const auto& last = insts.back();
if (last.GetOpcode() == Opcode::B) {
// B 为最后一条指令:添加 B 的目标
addLabelSuccessors(last);
// 若倒数第二条是 BCond则 BCond 的目标也是后继BCond; B 模式)
if (insts.size() >= 2) {
const auto& prev = insts[insts.size() - 2];
if (prev.GetOpcode() == Opcode::BCond) {
addLabelSuccessors(prev);
}
}
} else if (last.GetOpcode() == Opcode::BCond) {
// BCond 为最后一条指令:添加 BCond 目标 + fallthrough
addLabelSuccessors(last);
// 若倒数第二条是 B罕见B; BCond也添加 B 目标
if (insts.size() >= 2) {
const auto& prev = insts[insts.size() - 2];
if (prev.GetOpcode() == Opcode::B) {
addLabelSuccessors(prev);
}
}
// BCond 之后无 B则 false 分支 fallthrough
addFallthrough();
} else if (last.GetOpcode() == Opcode::Ret) {
// Ret 无后继
} else {
// 非终结指令fall-through 到下一个基本块
addFallthrough();
}
}
return machineFunc;
}
} // namespace
// ========== LowerToMIR入口函数 ==========
std::unique_ptr<MachineModule> LowerToMIR(const ir::Module& module) {
DefaultContext();
auto machineModule = std::make_unique<MachineModule>();
// 收集全局变量信息
for (const auto& global : module.GetGlobals()) {
int size = GetTypeSize(global->GetType().get());
int alignment = global->GetType()->Alignment();
bool isZeroInit = !global->HasInitializer();
bool hasInitData = false;
uint64_t initData = 0;
if (!isZeroInit) {
const auto& init = global->GetInitializer();
if (init.size() == 1) {
if (auto* cf = dynamic_cast<const ir::ConstantFloat*>(init[0])) {
float fval = cf->GetValue();
uint32_t bits;
memcpy(&bits, &fval, sizeof(bits));
initData = bits;
hasInitData = true;
} else if (auto* ci = dynamic_cast<const ir::ConstantInt*>(init[0])) {
initData = static_cast<uint64_t>(ci->GetValue());
hasInitData = true;
}
}
}
machineModule->AddGlobal(global->GetName(), size, alignment,
isZeroInit, hasInitData, initData);
}
// 转换所有函数
for (const auto& func : module.GetFunctions()) {
try {
auto machineFunc = LowerFunction(*func);
machineModule->AddFunction(std::move(machineFunc));
} catch (const std::runtime_error& e) {
throw std::runtime_error(
FormatError("mir", "转换函数失败: " + func->GetName() + " - " + e.what()));
}
}
if (machineModule->GetFunctions().empty()) {
throw std::runtime_error(FormatError("mir", "模块中没有成功转换的函数"));
}
return machineModule;
}
} // namespace mir