|
|
|
@ -1,6 +1,5 @@
|
|
|
|
#include "mir/MIR.h"
|
|
|
|
#include "mir/MIR.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
|
|
|
|
@ -12,600 +11,113 @@ namespace {
|
|
|
|
|
|
|
|
|
|
|
|
using ValueSlotMap = std::unordered_map<const ir::Value*, int>;
|
|
|
|
using ValueSlotMap = std::unordered_map<const ir::Value*, int>;
|
|
|
|
|
|
|
|
|
|
|
|
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<PhysReg>((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<PhysReg>((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<PhysReg>((int)PhysReg::S0 + fpr_idx);
|
|
|
|
|
|
|
|
++fpr_idx;
|
|
|
|
|
|
|
|
} else if (!is_float && gpr_idx < 8) {
|
|
|
|
|
|
|
|
loc.in_reg = true;
|
|
|
|
|
|
|
|
loc.reg = is_ptr ? static_cast<PhysReg>((int)PhysReg::X0 + gpr_idx)
|
|
|
|
|
|
|
|
: static_cast<PhysReg>((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,
|
|
|
|
void EmitValueToReg(const ir::Value* value, PhysReg target,
|
|
|
|
const ValueSlotMap& slots, MachineBasicBlock& block) {
|
|
|
|
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<const ir::ConstantInt*>(value)) {
|
|
|
|
if (auto* constant = dynamic_cast<const ir::ConstantInt*>(value)) {
|
|
|
|
block.Append(Opcode::MovImm,
|
|
|
|
block.Append(Opcode::MovImm,
|
|
|
|
{Operand::Reg(target), Operand::Imm(constant->GetValue())});
|
|
|
|
{Operand::Reg(target), Operand::Imm(constant->GetValue())});
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (auto* cf = dynamic_cast<const ir::ConstantFloat*>(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<const ir::GlobalVariable*>(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<const ir::Argument*>(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);
|
|
|
|
auto it = slots.find(value);
|
|
|
|
if (it == slots.end()) {
|
|
|
|
if (it == slots.end()) {
|
|
|
|
throw std::runtime_error(
|
|
|
|
throw std::runtime_error(
|
|
|
|
FormatError("mir", "找不到值对应的栈槽: " + value->GetName()));
|
|
|
|
FormatError("mir", "找不到值对应的栈槽: " + value->GetName()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
block.Append(Opcode::LoadStack, {Operand::Reg(target), Operand::FrameIndex(it->second)});
|
|
|
|
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<const ir::GlobalVariable*>(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<const ir::Argument*>(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<const ir::AllocaInst*>(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,
|
|
|
|
void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
|
|
|
|
MachineBasicBlock& block, ValueSlotMap& slots) {
|
|
|
|
ValueSlotMap& slots) {
|
|
|
|
|
|
|
|
auto& block = function.GetEntry();
|
|
|
|
|
|
|
|
|
|
|
|
switch (inst.GetOpcode()) {
|
|
|
|
switch (inst.GetOpcode()) {
|
|
|
|
case ir::Opcode::Alloca: {
|
|
|
|
case ir::Opcode::Alloca: {
|
|
|
|
auto& alloca = static_cast<const ir::AllocaInst&>(inst);
|
|
|
|
slots.emplace(&inst, function.CreateFrameIndex());
|
|
|
|
// 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<int>(size)));
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ir::Opcode::Store: {
|
|
|
|
case ir::Opcode::Store: {
|
|
|
|
auto& store = static_cast<const ir::StoreInst&>(inst);
|
|
|
|
auto& store = static_cast<const ir::StoreInst&>(inst);
|
|
|
|
PhysReg val_reg = PhysReg::W8;
|
|
|
|
auto dst = slots.find(store.GetPtr());
|
|
|
|
EmitValueToReg(store.GetValue(), val_reg, slots, block);
|
|
|
|
if (dst == slots.end()) {
|
|
|
|
if (IsPointerLike(*store.GetValue()->GetType())) {
|
|
|
|
throw std::runtime_error(
|
|
|
|
val_reg = ToXReg(val_reg);
|
|
|
|
FormatError("mir", "暂不支持对非栈变量地址进行写入"));
|
|
|
|
} 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<const ir::GlobalVariable*>(store.GetPtr())) {
|
|
|
|
|
|
|
|
block.Append(Opcode::StoreGlobal, {Operand::Reg(val_reg), Operand::Global(gv->GetName())});
|
|
|
|
|
|
|
|
} else if (auto* alloca = dynamic_cast<const ir::AllocaInst*>(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)});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EmitValueToReg(store.GetValue(), PhysReg::W8, slots, block);
|
|
|
|
|
|
|
|
block.Append(Opcode::StoreStack,
|
|
|
|
|
|
|
|
{Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst->second)});
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ir::Opcode::Load: {
|
|
|
|
case ir::Opcode::Load: {
|
|
|
|
auto& load = static_cast<const ir::LoadInst&>(inst);
|
|
|
|
auto& load = static_cast<const ir::LoadInst&>(inst);
|
|
|
|
int dst_slot = function.CreateFrameIndex(static_cast<int>(GetTypeSize(*load.GetType())));
|
|
|
|
auto src = slots.find(load.GetPtr());
|
|
|
|
PhysReg dst_reg = PhysReg::W8;
|
|
|
|
if (src == slots.end()) {
|
|
|
|
if (IsPointerLike(*load.GetType())) {
|
|
|
|
throw std::runtime_error(
|
|
|
|
dst_reg = ToXReg(dst_reg);
|
|
|
|
FormatError("mir", "暂不支持对非栈变量地址进行读取"));
|
|
|
|
} else if (IsFloatLike(*load.GetType())) {
|
|
|
|
|
|
|
|
dst_reg = ToSReg(dst_reg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (auto* gv = dynamic_cast<const ir::GlobalVariable*>(load.GetPtr())) {
|
|
|
|
|
|
|
|
block.Append(Opcode::LoadGlobal, {Operand::Reg(dst_reg), Operand::Global(gv->GetName())});
|
|
|
|
|
|
|
|
} else if (auto* alloca = dynamic_cast<const ir::AllocaInst*>(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<const ir::GEPInst&>(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<ir::Type> 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<ir::ConstantInt*>(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<int>(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<int>(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<const ir::CallInst&>(inst);
|
|
|
|
|
|
|
|
const auto& args = call.GetArgs();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<ArgLoc> 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<PhysReg>((int)PhysReg::S0 + fpr_idx), 0};
|
|
|
|
|
|
|
|
++fpr_idx;
|
|
|
|
|
|
|
|
} else if (!is_float && gpr_idx < 8) {
|
|
|
|
|
|
|
|
arg_locs[i] = ArgLoc{
|
|
|
|
|
|
|
|
true,
|
|
|
|
|
|
|
|
is_ptr ? static_cast<PhysReg>((int)PhysReg::X0 + gpr_idx)
|
|
|
|
|
|
|
|
: static_cast<PhysReg>((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<int>(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<const ir::BinaryInst&>(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<const ir::UnaryInst&>(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<const ir::UnaryInst&>(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();
|
|
|
|
int dst_slot = function.CreateFrameIndex();
|
|
|
|
ir::CmpOp ir_cc;
|
|
|
|
block.Append(Opcode::LoadStack,
|
|
|
|
if (inst.GetOpcode() == ir::Opcode::Cmp) {
|
|
|
|
{Operand::Reg(PhysReg::W8), Operand::FrameIndex(src->second)});
|
|
|
|
auto& cmp = static_cast<const ir::CmpInst&>(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<const ir::FCmpInst&>(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,
|
|
|
|
block.Append(Opcode::StoreStack,
|
|
|
|
{Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)});
|
|
|
|
{Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)});
|
|
|
|
slots.emplace(&inst, dst_slot);
|
|
|
|
slots.emplace(&inst, dst_slot);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ir::Opcode::Zext: {
|
|
|
|
case ir::Opcode::Add: {
|
|
|
|
auto& zext = static_cast<const ir::ZextInst&>(inst);
|
|
|
|
auto& bin = static_cast<const ir::BinaryInst&>(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<const ir::UnaryInst&>(inst);
|
|
|
|
|
|
|
|
int dst_slot = function.CreateFrameIndex();
|
|
|
|
int dst_slot = function.CreateFrameIndex();
|
|
|
|
if (unary.GetType()->IsFloat()) {
|
|
|
|
EmitValueToReg(bin.GetLhs(), PhysReg::W8, slots, block);
|
|
|
|
EmitValueToReg(unary.GetUnaryOperand(), PhysReg::W8, slots, block);
|
|
|
|
EmitValueToReg(bin.GetRhs(), PhysReg::W9, slots, block);
|
|
|
|
block.Append(Opcode::FNeg, {Operand::Reg(PhysReg::S0), Operand::Reg(PhysReg::S8)});
|
|
|
|
block.Append(Opcode::AddRR, {Operand::Reg(PhysReg::W8),
|
|
|
|
block.Append(Opcode::StoreStack, {Operand::Reg(PhysReg::S0), Operand::FrameIndex(dst_slot)});
|
|
|
|
Operand::Reg(PhysReg::W8),
|
|
|
|
} else {
|
|
|
|
Operand::Reg(PhysReg::W9)});
|
|
|
|
EmitValueToReg(unary.GetUnaryOperand(), PhysReg::W8, slots, block);
|
|
|
|
|
|
|
|
block.Append(Opcode::NegR, {Operand::Reg(PhysReg::W8), Operand::Reg(PhysReg::W8)});
|
|
|
|
|
|
|
|
block.Append(Opcode::StoreStack,
|
|
|
|
block.Append(Opcode::StoreStack,
|
|
|
|
{Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)});
|
|
|
|
{Operand::Reg(PhysReg::W8), Operand::FrameIndex(dst_slot)});
|
|
|
|
}
|
|
|
|
|
|
|
|
slots.emplace(&inst, dst_slot);
|
|
|
|
slots.emplace(&inst, dst_slot);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ir::Opcode::Br: {
|
|
|
|
|
|
|
|
auto& br = static_cast<const ir::BranchInst&>(inst);
|
|
|
|
|
|
|
|
block.Append(Opcode::B, {Operand::Label(br.GetDest()->GetName())});
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case ir::Opcode::CondBr: {
|
|
|
|
|
|
|
|
auto& cbr = static_cast<const ir::CondBranchInst&>(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: {
|
|
|
|
case ir::Opcode::Ret: {
|
|
|
|
auto& ret = static_cast<const ir::ReturnInst&>(inst);
|
|
|
|
auto& ret = static_cast<const ir::ReturnInst&>(inst);
|
|
|
|
if (auto* val = ret.GetValue()) {
|
|
|
|
EmitValueToReg(ret.GetValue(), PhysReg::W0, slots, block);
|
|
|
|
EmitValueToReg(val, PhysReg::W0, slots, block);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
block.Append(Opcode::Ret);
|
|
|
|
block.Append(Opcode::Ret);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
case ir::Opcode::Sub:
|
|
|
|
throw std::runtime_error(FormatError("mir", "暂不支持该 IR 指令: " + std::to_string((int)inst.GetOpcode())));
|
|
|
|
case ir::Opcode::Mul:
|
|
|
|
|
|
|
|
throw std::runtime_error(FormatError("mir", "暂不支持该二元运算"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
throw std::runtime_error(FormatError("mir", "暂不支持该 IR 指令"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<MachineModule> LowerToMIR(const ir::Module& module) {
|
|
|
|
std::unique_ptr<MachineFunction> LowerToMIR(const ir::Module& module) {
|
|
|
|
DefaultContext();
|
|
|
|
DefaultContext();
|
|
|
|
auto machine_module = std::make_unique<MachineModule>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Lower global variables
|
|
|
|
if (module.GetFunctions().size() != 1) {
|
|
|
|
for (const auto& gv : module.GetGlobalVariables()) {
|
|
|
|
throw std::runtime_error(FormatError("mir", "暂不支持多个函数"));
|
|
|
|
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<ir::ConstantInt*>(init)) {
|
|
|
|
|
|
|
|
mir_gv.init_value = ci->GetValue();
|
|
|
|
|
|
|
|
} else if (auto* cf = dynamic_cast<ir::ConstantFloat*>(init)) {
|
|
|
|
|
|
|
|
float f = cf->GetValue();
|
|
|
|
|
|
|
|
uint32_t bits;
|
|
|
|
|
|
|
|
std::memcpy(&bits, &f, 4);
|
|
|
|
|
|
|
|
mir_gv.init_value = static_cast<int>(bits);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
machine_module->GetGlobals().push_back(mir_gv);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Lower functions
|
|
|
|
const auto& func = *module.GetFunctions().front();
|
|
|
|
for (const auto& ir_func : module.GetFunctions()) {
|
|
|
|
if (func.GetName() != "main") {
|
|
|
|
if (ir_func->GetBlocks().empty()) continue; // Skip declarations
|
|
|
|
throw std::runtime_error(FormatError("mir", "暂不支持非 main 函数"));
|
|
|
|
|
|
|
|
|
|
|
|
auto machine_func = std::make_unique<MachineFunction>(ir_func->GetName());
|
|
|
|
|
|
|
|
ValueSlotMap slots;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create all blocks first to handle forward references in branches
|
|
|
|
|
|
|
|
std::unordered_map<const ir::BasicBlock*, MachineBasicBlock*> 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
|
|
|
|
auto machine_func = std::make_unique<MachineFunction>(func.GetName());
|
|
|
|
for (const auto& ir_bb : ir_func->GetBlocks()) {
|
|
|
|
ValueSlotMap slots;
|
|
|
|
auto& machine_bb = *block_map.at(ir_bb.get());
|
|
|
|
const auto* entry = func.GetEntry();
|
|
|
|
for (const auto& inst : ir_bb->GetInstructions()) {
|
|
|
|
if (!entry) {
|
|
|
|
LowerInstruction(*inst, *machine_func, machine_bb, slots);
|
|
|
|
throw std::runtime_error(FormatError("mir", "IR 函数缺少入口基本块"));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
machine_module->GetFunctions().push_back(std::move(machine_func));
|
|
|
|
for (const auto& inst : entry->GetInstructions()) {
|
|
|
|
|
|
|
|
LowerInstruction(*inst, *machine_func, slots);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return machine_module;
|
|
|
|
return machine_func;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace mir
|
|
|
|
} // namespace mir
|
|
|
|
|