#include "mir/MIR.h" #include #include #include #include "ir/IR.h" #include "utils/Log.h" namespace mir { namespace { using ValueSlotMap = std::unordered_map; int AlignTo(int value, int align) { return ((value + align - 1) / align) * align; } bool IsPointerLike(const ir::Type& ty) { return ty.IsPointer() || ty.IsPtrInt32() || ty.IsPtrFloat(); } bool IsFloatLike(const ir::Type& ty) { return ty.IsFloat(); } PhysReg ToXReg(PhysReg reg) { if ((int)reg >= (int)PhysReg::W0 && (int)reg <= (int)PhysReg::W15) { return static_cast((int)reg - (int)PhysReg::W0 + (int)PhysReg::X0); } return reg; } PhysReg ToSReg(PhysReg reg) { if ((int)reg >= (int)PhysReg::W0 && (int)reg <= (int)PhysReg::W15) { return static_cast((int)reg - (int)PhysReg::W0 + (int)PhysReg::S0); } return reg; } struct ArgLoc { bool in_reg = false; PhysReg reg = PhysReg::W0; int stack_offset = 0; // bytes from stack-args base }; ArgLoc GetFunctionArgLoc(const ir::Function& func, size_t arg_no) { int gpr_idx = 0; int fpr_idx = 0; int stack_slots = 0; const auto& args = func.GetArgs(); for (size_t i = 0; i < args.size(); ++i) { const auto& ty = *args[i]->GetType(); const bool is_float = IsFloatLike(ty); const bool is_ptr = IsPointerLike(ty); ArgLoc loc; if (is_float && fpr_idx < 8) { loc.in_reg = true; loc.reg = static_cast((int)PhysReg::S0 + fpr_idx); ++fpr_idx; } else if (!is_float && gpr_idx < 8) { loc.in_reg = true; loc.reg = is_ptr ? static_cast((int)PhysReg::X0 + gpr_idx) : static_cast((int)PhysReg::W0 + gpr_idx); ++gpr_idx; } else { loc.in_reg = false; loc.stack_offset = stack_slots * 8; ++stack_slots; } if (i == arg_no) return loc; } throw std::runtime_error( FormatError("mir", "函数参数索引越界: " + std::to_string(arg_no))); } void EmitValueToReg(const ir::Value* value, PhysReg target, const ValueSlotMap& slots, MachineBasicBlock& block) { bool is_ptr = IsPointerLike(*value->GetType()); bool is_float = IsFloatLike(*value->GetType()); if (is_ptr) { target = ToXReg(target); } else if (is_float) { target = ToSReg(target); } if (auto* constant = dynamic_cast(value)) { block.Append(Opcode::MovImm, {Operand::Reg(target), Operand::Imm(constant->GetValue())}); return; } if (auto* cf = dynamic_cast(value)) { float f = cf->GetValue(); uint32_t bits; std::memcpy(&bits, &f, 4); // mov w10, #bits; fmov target, w10 block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::W10), Operand::Imm((int)bits)}); block.Append(Opcode::MovRR, {Operand::Reg(target), Operand::Reg(PhysReg::W10)}); return; } if (auto* gv = dynamic_cast(value)) { // This loads the VALUE of the global, not its address block.Append(Opcode::LoadGlobal, {Operand::Reg(target), Operand::Global(gv->GetName())}); return; } if (auto* arg = dynamic_cast(value)) { const auto* parent = arg->GetParent(); if (!parent) { throw std::runtime_error(FormatError("mir", "参数未绑定到函数")); } const ArgLoc loc = GetFunctionArgLoc(*parent, arg->GetArgNo()); if (loc.in_reg) { block.Append(Opcode::MovRR, {Operand::Reg(target), Operand::Reg(loc.reg)}); } else { // Incoming stack args are at [old_sp + offset]. After prologue: // x29 = old_sp - 16, so address is [x29 + 16 + offset]. const int fp_offset = 16 + loc.stack_offset; if (fp_offset <= 4095) { block.Append(Opcode::AddRRI, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X29), Operand::Imm(fp_offset)}); } else { block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::X11), Operand::Imm(fp_offset)}); block.Append(Opcode::AddRR, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X29), Operand::Reg(PhysReg::X11)}); } block.Append(Opcode::LoadR, {Operand::Reg(target), Operand::Reg(PhysReg::X10)}); } return; } auto it = slots.find(value); if (it == slots.end()) { throw std::runtime_error( FormatError("mir", "找不到值对应的栈槽: " + value->GetName())); } block.Append(Opcode::LoadStack, {Operand::Reg(target), Operand::FrameIndex(it->second)}); } void EmitAddrToReg(const ir::Value* value, PhysReg target, const MachineFunction& function, const ValueSlotMap& slots, MachineBasicBlock& block) { if (auto* gv = dynamic_cast(value)) { // adrp x10, gv; add x10, x10, :lo12:gv block.Append(Opcode::MovImm, {Operand::Reg(target), Operand::Global(gv->GetName())}); // Special case for address return; } if (auto* arg = dynamic_cast(value)) { // Argument is already an address (pointer) EmitValueToReg(arg, target, slots, block); return; } auto it = slots.find(value); if (it != slots.end()) { // Check if it's an alloca (frame index) or a stored address // For alloca, we want the address: add x10, x29, #offset // For stored address, we want to load it: ldr x10, [x29, #offset] // In our simple lowering, alloca's value in 'slots' is the frame index. // If 'value' is an AllocaInst, we compute its address. if (dynamic_cast(value)) { block.Append(Opcode::AddrStack, {Operand::Reg(target), Operand::FrameIndex(it->second)}); return; } // Otherwise it's a stored address (from a GEP) block.Append(Opcode::LoadStack, {Operand::Reg(target), Operand::FrameIndex(it->second)}); return; } throw std::runtime_error(FormatError("mir", "无法获取地址: " + value->GetName())); } size_t GetTypeSize(const ir::Type& ty) { if (ty.IsInt32() || ty.IsFloat()) return 4; if (ty.IsPointer() || ty.IsPtrInt32() || ty.IsPtrFloat()) return 8; if (ty.IsArray()) { return ty.GetNumElements() * GetTypeSize(*ty.GetElementType()); } return 0; } void LowerInstruction(const ir::Instruction& inst, MachineFunction& function, MachineBasicBlock& block, ValueSlotMap& slots) { switch (inst.GetOpcode()) { case ir::Opcode::Alloca: { auto& alloca = static_cast(inst); // AllocaInst's type is PointerType. We want the size of the pointed type. size_t size = GetTypeSize(*alloca.GetType()->GetPointedType()); slots.emplace(&inst, function.CreateFrameIndex(static_cast(size))); return; } case ir::Opcode::Store: { auto& store = static_cast(inst); PhysReg val_reg = PhysReg::W8; EmitValueToReg(store.GetValue(), val_reg, slots, block); if (IsPointerLike(*store.GetValue()->GetType())) { val_reg = ToXReg(val_reg); } else if (IsFloatLike(*store.GetValue()->GetType())) { val_reg = ToSReg(val_reg); } // If ptr is a global or stored address (GEP result), we use LoadR/StoreR logic if (auto* gv = dynamic_cast(store.GetPtr())) { block.Append(Opcode::StoreGlobal, {Operand::Reg(val_reg), Operand::Global(gv->GetName())}); } else if (auto* alloca = dynamic_cast(store.GetPtr())) { auto it = slots.find(alloca); if (it == slots.end()) throw std::runtime_error("Alloca not found"); block.Append(Opcode::StoreStack, {Operand::Reg(val_reg), Operand::FrameIndex(it->second)}); } else { // Pointer is in a register (from GEP) EmitAddrToReg(store.GetPtr(), PhysReg::X10, function, slots, block); block.Append(Opcode::StoreR, {Operand::Reg(val_reg), Operand::Reg(PhysReg::X10)}); } return; } case ir::Opcode::Load: { auto& load = static_cast(inst); int dst_slot = function.CreateFrameIndex(static_cast(GetTypeSize(*load.GetType()))); PhysReg dst_reg = PhysReg::W8; if (IsPointerLike(*load.GetType())) { dst_reg = ToXReg(dst_reg); } else if (IsFloatLike(*load.GetType())) { dst_reg = ToSReg(dst_reg); } if (auto* gv = dynamic_cast(load.GetPtr())) { block.Append(Opcode::LoadGlobal, {Operand::Reg(dst_reg), Operand::Global(gv->GetName())}); } else if (auto* alloca = dynamic_cast(load.GetPtr())) { auto it = slots.find(alloca); if (it == slots.end()) throw std::runtime_error("Alloca not found"); block.Append(Opcode::LoadStack, {Operand::Reg(dst_reg), Operand::FrameIndex(it->second)}); } else { // Pointer is in a register (from GEP) EmitAddrToReg(load.GetPtr(), PhysReg::X10, function, slots, block); block.Append(Opcode::LoadR, {Operand::Reg(dst_reg), Operand::Reg(PhysReg::X10)}); } block.Append(Opcode::StoreStack, {Operand::Reg(dst_reg), Operand::FrameIndex(dst_slot)}); slots.emplace(&inst, dst_slot); return; } case ir::Opcode::GEP: { auto& gep = static_cast(inst); int dst_slot = function.CreateFrameIndex(8); // Address is 8 bytes EmitAddrToReg(gep.GetPtr(), PhysReg::X10, function, slots, block); // Initial type is the pointed type of the base pointer std::shared_ptr cur_ty = gep.GetPtr()->GetType()->GetPointedType(); for (size_t i = 0; i < gep.GetIndices().size(); ++i) { ir::Value* index_val = gep.GetIndices()[i]; // Skip index 0 if it's the first index and we're starting from a pointer if (i == 0) { if (auto* ci = dynamic_cast(index_val)) { if (ci->GetValue() == 0) { continue; } } EmitValueToReg(index_val, PhysReg::W8, slots, block); size_t element_size = GetTypeSize(*cur_ty); // Use X8 for 64-bit multiplication if element_size is large, // but for simple cases we can use AddRRR_LSL with W8 for auto sxtw if (element_size == 4) { block.Append(Opcode::AddRRR_LSL, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::W8), Operand::Imm(2)}); } else if (element_size == 8) { block.Append(Opcode::AddRRR_LSL, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::W8), Operand::Imm(3)}); } else { block.Append(Opcode::Sxtw, {Operand::Reg(PhysReg::X8), Operand::Reg(PhysReg::W8)}); block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::X9), Operand::Imm(static_cast(element_size))}); block.Append(Opcode::MulRR, {Operand::Reg(PhysReg::X8), Operand::Reg(PhysReg::X8), Operand::Reg(PhysReg::X9)}); block.Append(Opcode::AddRR, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X8)}); } continue; } if (cur_ty->IsArray()) { size_t element_size = GetTypeSize(*cur_ty->GetElementType()); EmitValueToReg(index_val, PhysReg::W8, slots, block); if (element_size == 4) { block.Append(Opcode::AddRRR_LSL, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::W8), Operand::Imm(2)}); } else if (element_size == 8) { block.Append(Opcode::AddRRR_LSL, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::W8), Operand::Imm(3)}); } else { block.Append(Opcode::Sxtw, {Operand::Reg(PhysReg::X8), Operand::Reg(PhysReg::W8)}); block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::X9), Operand::Imm(static_cast(element_size))}); block.Append(Opcode::MulRR, {Operand::Reg(PhysReg::X8), Operand::Reg(PhysReg::X8), Operand::Reg(PhysReg::X9)}); block.Append(Opcode::AddRR, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::X8)}); } cur_ty = cur_ty->GetElementType(); } else { throw std::runtime_error(FormatError("mir", "GEP 索引超出范围或类型不是数组")); } } block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::X10), Operand::FrameIndex(dst_slot)}); slots.emplace(&inst, dst_slot); return; } case ir::Opcode::Call: { auto& call = static_cast(inst); const auto& args = call.GetArgs(); std::vector arg_locs(args.size()); int gpr_idx = 0; int fpr_idx = 0; int stack_slots = 0; for (size_t i = 0; i < args.size(); ++i) { const auto& ty = *args[i]->GetType(); const bool is_float = IsFloatLike(ty); const bool is_ptr = IsPointerLike(ty); if (is_float && fpr_idx < 8) { arg_locs[i] = ArgLoc{true, static_cast((int)PhysReg::S0 + fpr_idx), 0}; ++fpr_idx; } else if (!is_float && gpr_idx < 8) { arg_locs[i] = ArgLoc{ true, is_ptr ? static_cast((int)PhysReg::X0 + gpr_idx) : static_cast((int)PhysReg::W0 + gpr_idx), 0}; ++gpr_idx; } else { arg_locs[i] = ArgLoc{false, PhysReg::W0, stack_slots * 8}; ++stack_slots; } } int stack_arg_size = 0; if (stack_slots > 0) { stack_arg_size = AlignTo(stack_slots * 8, 16); block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::X11), Operand::Imm(stack_arg_size)}); block.Append(Opcode::SubRR, {Operand::Reg(PhysReg::SP), Operand::Reg(PhysReg::SP), Operand::Reg(PhysReg::X11)}); } for (size_t i = 0; i < args.size(); ++i) { const ArgLoc& loc = arg_locs[i]; if (loc.in_reg) { EmitValueToReg(args[i], loc.reg, slots, block); continue; } PhysReg val_reg = PhysReg::W8; if (IsPointerLike(*args[i]->GetType())) { val_reg = ToXReg(val_reg); } else if (IsFloatLike(*args[i]->GetType())) { val_reg = ToSReg(val_reg); } EmitValueToReg(args[i], val_reg, slots, block); if (loc.stack_offset == 0) { block.Append(Opcode::MovRR, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::SP)}); } else if (loc.stack_offset <= 4095) { block.Append(Opcode::AddRRI, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::SP), Operand::Imm(loc.stack_offset)}); } else { block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::X11), Operand::Imm(loc.stack_offset)}); block.Append(Opcode::AddRR, {Operand::Reg(PhysReg::X10), Operand::Reg(PhysReg::SP), Operand::Reg(PhysReg::X11)}); } block.Append(Opcode::StoreR, {Operand::Reg(val_reg), Operand::Reg(PhysReg::X10)}); } block.Append(Opcode::Call, {Operand::Label(call.GetFunc()->GetName())}); if (stack_arg_size > 0) { block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::X11), Operand::Imm(stack_arg_size)}); block.Append(Opcode::AddRR, {Operand::Reg(PhysReg::SP), Operand::Reg(PhysReg::SP), Operand::Reg(PhysReg::X11)}); } if (!call.GetType()->IsVoid()) { int dst_slot = function.CreateFrameIndex(static_cast(GetTypeSize(*call.GetType()))); PhysReg ret_reg = PhysReg::W0; if (IsFloatLike(*call.GetType())) { ret_reg = ToSReg(ret_reg); } else if (IsPointerLike(*call.GetType())) { ret_reg = ToXReg(ret_reg); } block.Append(Opcode::StoreStack, {Operand::Reg(ret_reg), Operand::FrameIndex(dst_slot)}); slots.emplace(&inst, dst_slot); } return; } case ir::Opcode::Add: case ir::Opcode::Sub: case ir::Opcode::Mul: case ir::Opcode::Div: case ir::Opcode::Mod: { auto& bin = static_cast(inst); int dst_slot = function.CreateFrameIndex(); if (bin.GetType()->IsFloat()) { PhysReg lhs_reg = PhysReg::W8; PhysReg rhs_reg = PhysReg::W9; EmitValueToReg(bin.GetLhs(), lhs_reg, slots, block); EmitValueToReg(bin.GetRhs(), rhs_reg, slots, block); lhs_reg = ToSReg(lhs_reg); rhs_reg = ToSReg(rhs_reg); Opcode op; if (inst.GetOpcode() == ir::Opcode::Add) op = Opcode::FAdd; else if (inst.GetOpcode() == ir::Opcode::Sub) op = Opcode::FSub; else if (inst.GetOpcode() == ir::Opcode::Mul) op = Opcode::FMUL; else if (inst.GetOpcode() == ir::Opcode::Div) op = Opcode::FDiv; else throw std::runtime_error("Float mod not supported"); block.Append(op, {Operand::Reg(PhysReg::S0), Operand::Reg(lhs_reg), Operand::Reg(rhs_reg)}); block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::S0), Operand::FrameIndex(dst_slot)}); } else { EmitValueToReg(bin.GetLhs(), PhysReg::W8, slots, block); EmitValueToReg(bin.GetRhs(), PhysReg::W9, slots, block); if (inst.GetOpcode() == ir::Opcode::Add) { block.Append(Opcode::AddRR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W9)}); } else if (inst.GetOpcode() == ir::Opcode::Sub) { block.Append(Opcode::SubRR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W9)}); } else if (inst.GetOpcode() == ir::Opcode::Mul) { block.Append(Opcode::MulRR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W9)}); } else if (inst.GetOpcode() == ir::Opcode::Div) { block.Append(Opcode::SDivRR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W9)}); } else if (inst.GetOpcode() == ir::Opcode::Mod) { // srem w10, w8, w9 => sdiv w10, w8, w9; msub w8, w10, w9, w8 block.Append(Opcode::SDivRR, {Operand::Reg(PhysReg::W10), Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W9)}); block.Append(Opcode::MSubRRR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W10), Operand::Reg(PhysReg::W9), Operand::Reg(PhysReg::W8)}); } block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)}); } slots.emplace(&inst, dst_slot); return; } case ir::Opcode::SIToFP: { auto& fcvt = static_cast(inst); int dst_slot = function.CreateFrameIndex(); EmitValueToReg(fcvt.GetUnaryOperand(), PhysReg::W8, slots, block); block.Append(Opcode::FCvtSI2FP, {Operand::Reg(PhysReg::S0), Operand::Reg(PhysReg::W8)}); block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::S0), Operand::FrameIndex(dst_slot)}); slots.emplace(&inst, dst_slot); return; } case ir::Opcode::FPToSI: { auto& fcvt = static_cast(inst); int dst_slot = function.CreateFrameIndex(); EmitValueToReg(fcvt.GetUnaryOperand(), PhysReg::W8, slots, block); block.Append(Opcode::FCvtFP2SI, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::S8)}); block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)}); slots.emplace(&inst, dst_slot); return; } case ir::Opcode::Cmp: case ir::Opcode::FCmp: { int dst_slot = function.CreateFrameIndex(); ir::CmpOp ir_cc; if (inst.GetOpcode() == ir::Opcode::Cmp) { auto& cmp = static_cast(inst); EmitValueToReg(cmp.GetLhs(), PhysReg::W8, slots, block); EmitValueToReg(cmp.GetRhs(), PhysReg::W9, slots, block); block.Append(Opcode::CmpRR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W9)}); ir_cc = cmp.GetCmpOp(); } else { auto& cmp = static_cast(inst); EmitValueToReg(cmp.GetLhs(), PhysReg::W8, slots, block); EmitValueToReg(cmp.GetRhs(), PhysReg::W9, slots, block); block.Append(Opcode::FCmp, {Operand::Reg(PhysReg::S8), Operand::Reg(PhysReg::S9)}); ir_cc = cmp.GetCmpOp(); } CondCode cc = CondCode::EQ; switch (ir_cc) { case ir::CmpOp::Eq: cc = CondCode::EQ; break; case ir::CmpOp::Ne: cc = CondCode::NE; break; case ir::CmpOp::Lt: cc = CondCode::LT; break; case ir::CmpOp::Le: cc = CondCode::LE; break; case ir::CmpOp::Gt: cc = CondCode::GT; break; case ir::CmpOp::Ge: cc = CondCode::GE; break; } block.Append(Opcode::CSet, {Operand::Reg(PhysReg::W8), Operand::Cond(cc)}); block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)}); slots.emplace(&inst, dst_slot); return; } case ir::Opcode::Zext: { auto& zext = static_cast(inst); int dst_slot = function.CreateFrameIndex(); EmitValueToReg(zext.GetValue(), PhysReg::W8, slots, block); block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)}); slots.emplace(&inst, dst_slot); return; } case ir::Opcode::Neg: { auto& unary = static_cast(inst); int dst_slot = function.CreateFrameIndex(); if (unary.GetType()->IsFloat()) { EmitValueToReg(unary.GetUnaryOperand(), PhysReg::W8, slots, block); block.Append(Opcode::FNeg, {Operand::Reg(PhysReg::S0), Operand::Reg(PhysReg::S8)}); block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::S0), Operand::FrameIndex(dst_slot)}); } else { EmitValueToReg(unary.GetUnaryOperand(), PhysReg::W8, slots, block); block.Append(Opcode::NegR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W8)}); block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)}); } slots.emplace(&inst, dst_slot); return; } case ir::Opcode::Br: { auto& br = static_cast(inst); block.Append(Opcode::B, {Operand::Label(br.GetDest()->GetName())}); return; } case ir::Opcode::CondBr: { auto& cbr = static_cast(inst); EmitValueToReg(cbr.GetCond(), PhysReg::W8, slots, block); // SysY IR CondBr uses i1. In MIR, we compare with 0. block.Append(Opcode::BCond, {Operand::Cond(CondCode::NE), Operand::Reg(PhysReg::W8), Operand::Label(cbr.GetTrueBlock()->GetName())}); block.Append(Opcode::B, {Operand::Label(cbr.GetFalseBlock()->GetName())}); return; } case ir::Opcode::Ret: { auto& ret = static_cast(inst); if (auto* val = ret.GetValue()) { EmitValueToReg(val, PhysReg::W0, slots, block); } block.Append(Opcode::Ret); return; } default: throw std::runtime_error(FormatError("mir", "暂不支持该 IR 指令: " + std::to_string((int)inst.GetOpcode()))); } } } // namespace std::unique_ptr LowerToMIR(const ir::Module& module) { DefaultContext(); auto machine_module = std::make_unique(); // Lower global variables for (const auto& gv : module.GetGlobalVariables()) { GlobalVariable mir_gv; mir_gv.name = gv->GetName(); mir_gv.size = GetTypeSize(*gv->GetType()->GetPointedType()); if (auto* init = gv->GetInitializer()) { if (auto* ci = dynamic_cast(init)) { mir_gv.init_value = ci->GetValue(); } else if (auto* cf = dynamic_cast(init)) { float f = cf->GetValue(); uint32_t bits; std::memcpy(&bits, &f, 4); mir_gv.init_value = static_cast(bits); } } machine_module->GetGlobals().push_back(mir_gv); } // Lower functions for (const auto& ir_func : module.GetFunctions()) { if (ir_func->GetBlocks().empty()) continue; // Skip declarations auto machine_func = std::make_unique(ir_func->GetName()); ValueSlotMap slots; // Create all blocks first to handle forward references in branches std::unordered_map block_map; for (const auto& ir_bb : ir_func->GetBlocks()) { block_map[ir_bb.get()] = &machine_func->CreateBlock(ir_bb->GetName()); } // Lower instructions in each block for (const auto& ir_bb : ir_func->GetBlocks()) { auto& machine_bb = *block_map.at(ir_bb.get()); for (const auto& inst : ir_bb->GetInstructions()) { LowerInstruction(*inst, *machine_func, machine_bb, slots); } } machine_module->GetFunctions().push_back(std::move(machine_func)); } return machine_module; } } // namespace mir