|
|
|
|
@ -12,6 +12,16 @@ namespace {
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
@ -26,10 +36,50 @@ PhysReg ToSReg(PhysReg reg) {
|
|
|
|
|
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,
|
|
|
|
|
const ValueSlotMap& slots, MachineBasicBlock& block) {
|
|
|
|
|
bool is_ptr = value->GetType()->IsPointer() || value->GetType()->IsPtrInt32() || value->GetType()->IsPtrFloat();
|
|
|
|
|
bool is_float = value->GetType()->IsFloat();
|
|
|
|
|
bool is_ptr = IsPointerLike(*value->GetType());
|
|
|
|
|
bool is_float = IsFloatLike(*value->GetType());
|
|
|
|
|
|
|
|
|
|
if (is_ptr) {
|
|
|
|
|
target = ToXReg(target);
|
|
|
|
|
@ -61,18 +111,29 @@ void EmitValueToReg(const ir::Value* value, PhysReg target,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto* arg = dynamic_cast<const ir::Argument*>(value)) {
|
|
|
|
|
if (arg->GetArgNo() < 8) {
|
|
|
|
|
PhysReg src;
|
|
|
|
|
if (is_ptr) {
|
|
|
|
|
src = static_cast<PhysReg>((int)PhysReg::X0 + arg->GetArgNo());
|
|
|
|
|
} else if (is_float) {
|
|
|
|
|
src = static_cast<PhysReg>((int)PhysReg::S0 + arg->GetArgNo());
|
|
|
|
|
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 {
|
|
|
|
|
src = static_cast<PhysReg>((int)PhysReg::W0 + arg->GetArgNo());
|
|
|
|
|
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::MovRR, {Operand::Reg(target), Operand::Reg(src)});
|
|
|
|
|
} else {
|
|
|
|
|
throw std::runtime_error(FormatError("mir", "暂不支持超过 8 个参数"));
|
|
|
|
|
block.Append(Opcode::LoadR, {Operand::Reg(target), Operand::Reg(PhysReg::X10)});
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@ -145,9 +206,9 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
|
|
|
|
|
auto& store = static_cast<const ir::StoreInst&>(inst);
|
|
|
|
|
PhysReg val_reg = PhysReg::W8;
|
|
|
|
|
EmitValueToReg(store.GetValue(), val_reg, slots, block);
|
|
|
|
|
if (store.GetValue()->GetType()->IsPointer() || store.GetValue()->GetType()->IsPtrInt32() || store.GetValue()->GetType()->IsPtrFloat()) {
|
|
|
|
|
if (IsPointerLike(*store.GetValue()->GetType())) {
|
|
|
|
|
val_reg = ToXReg(val_reg);
|
|
|
|
|
} else if (store.GetValue()->GetType()->IsFloat()) {
|
|
|
|
|
} else if (IsFloatLike(*store.GetValue()->GetType())) {
|
|
|
|
|
val_reg = ToSReg(val_reg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -169,9 +230,9 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
|
|
|
|
|
auto& load = static_cast<const ir::LoadInst&>(inst);
|
|
|
|
|
int dst_slot = function.CreateFrameIndex(static_cast<int>(GetTypeSize(*load.GetType())));
|
|
|
|
|
PhysReg dst_reg = PhysReg::W8;
|
|
|
|
|
if (load.GetType()->IsPointer() || load.GetType()->IsPtrInt32() || load.GetType()->IsPtrFloat()) {
|
|
|
|
|
if (IsPointerLike(*load.GetType())) {
|
|
|
|
|
dst_reg = ToXReg(dst_reg);
|
|
|
|
|
} else if (load.GetType()->IsFloat()) {
|
|
|
|
|
} else if (IsFloatLike(*load.GetType())) {
|
|
|
|
|
dst_reg = ToSReg(dst_reg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -253,25 +314,90 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
|
|
|
|
|
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) {
|
|
|
|
|
if (i < 8) {
|
|
|
|
|
// Determine if arg is a pointer
|
|
|
|
|
bool is_ptr = args[i]->GetType()->IsPointer() || args[i]->GetType()->IsPtrInt32() || args[i]->GetType()->IsPtrFloat();
|
|
|
|
|
PhysReg target = is_ptr ? static_cast<PhysReg>((int)PhysReg::X0 + i)
|
|
|
|
|
: static_cast<PhysReg>((int)PhysReg::W0 + i);
|
|
|
|
|
EmitValueToReg(args[i], target, slots, block);
|
|
|
|
|
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 {
|
|
|
|
|
throw std::runtime_error("Only up to 8 arguments supported for now");
|
|
|
|
|
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 (call.GetType()->IsFloat()) {
|
|
|
|
|
if (IsFloatLike(*call.GetType())) {
|
|
|
|
|
ret_reg = ToSReg(ret_reg);
|
|
|
|
|
} else if (call.GetType()->IsPointer() || call.GetType()->IsPtrInt32() || call.GetType()->IsPtrFloat()) {
|
|
|
|
|
} else if (IsPointerLike(*call.GetType())) {
|
|
|
|
|
ret_reg = ToXReg(ret_reg);
|
|
|
|
|
}
|
|
|
|
|
block.Append(Opcode::StoreStack, {Operand::Reg(ret_reg), Operand::FrameIndex(dst_slot)});
|
|
|
|
|
|