|
|
#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 类型信息存入 MachineFunction(RA 阶段使用)
|
|
|
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
|