forked from p4jyxwm3q/nudt-compiler-cpp
parent
29b7bf7357
commit
f56f9772a3
File diff suppressed because it is too large
Load Diff
@ -1,45 +1,40 @@
|
||||
#include "mir/MIR.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/Log.h"
|
||||
#include <string>
|
||||
|
||||
namespace mir {
|
||||
namespace {
|
||||
|
||||
int AlignTo(int value, int align) {
|
||||
if (align <= 1) {
|
||||
return value;
|
||||
}
|
||||
return ((value + align - 1) / align) * align;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void RunFrameLowering(MachineFunction& function) {
|
||||
int cursor = 0;
|
||||
for (const auto& slot : function.GetFrameSlots()) {
|
||||
cursor += slot.size;
|
||||
if (-cursor < -256) {
|
||||
throw std::runtime_error(FormatError("mir", "暂不支持过大的栈帧"));
|
||||
void RunFrameLowering(MachineModule& module) {
|
||||
for (auto& function : module.GetFunctions()) {
|
||||
for (int reg : function->GetUsedCalleeSavedGPRs()) {
|
||||
function->CreateStackObject(8, 8, StackObjectKind::SavedGPR,
|
||||
"save.x" + std::to_string(reg));
|
||||
}
|
||||
for (int reg : function->GetUsedCalleeSavedFPRs()) {
|
||||
function->CreateStackObject(8, 8, StackObjectKind::SavedFPR,
|
||||
"save.v" + std::to_string(reg));
|
||||
}
|
||||
}
|
||||
|
||||
cursor = 0;
|
||||
for (const auto& slot : function.GetFrameSlots()) {
|
||||
cursor += slot.size;
|
||||
function.GetFrameSlot(slot.index).offset = -cursor;
|
||||
}
|
||||
function.SetFrameSize(AlignTo(cursor, 16));
|
||||
|
||||
auto& insts = function.GetEntry().GetInstructions();
|
||||
std::vector<MachineInstr> lowered;
|
||||
lowered.emplace_back(Opcode::Prologue);
|
||||
for (const auto& inst : insts) {
|
||||
if (inst.GetOpcode() == Opcode::Ret) {
|
||||
lowered.emplace_back(Opcode::Epilogue);
|
||||
int cursor = 0;
|
||||
const int object_count = static_cast<int>(function->GetStackObjects().size());
|
||||
for (int i = 0; i < object_count; ++i) {
|
||||
auto& object = function->GetStackObject(i);
|
||||
cursor = AlignTo(cursor, object.align);
|
||||
cursor += object.size;
|
||||
object.offset = -cursor;
|
||||
}
|
||||
lowered.push_back(inst);
|
||||
function->SetFrameSize(AlignTo(cursor, 16));
|
||||
}
|
||||
insts = std::move(lowered);
|
||||
}
|
||||
|
||||
} // namespace mir
|
||||
|
||||
@ -1,33 +1,106 @@
|
||||
#include "mir/MIR.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace mir {
|
||||
|
||||
MachineFunction::MachineFunction(std::string name)
|
||||
: name_(std::move(name)), entry_("entry") {}
|
||||
MachineFunction::MachineFunction(std::string name, ValueType return_type,
|
||||
std::vector<ValueType> param_types)
|
||||
: name_(std::move(name)),
|
||||
return_type_(return_type),
|
||||
param_types_(std::move(param_types)) {}
|
||||
|
||||
MachineBasicBlock* MachineFunction::CreateBlock(const std::string& name) {
|
||||
auto block = std::make_unique<MachineBasicBlock>(name);
|
||||
auto* ptr = block.get();
|
||||
blocks_.push_back(std::move(block));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int MachineFunction::NewVReg(ValueType type) {
|
||||
const int id = static_cast<int>(vregs_.size());
|
||||
vregs_.push_back({id, type});
|
||||
allocations_.push_back({});
|
||||
return id;
|
||||
}
|
||||
|
||||
const VRegInfo& MachineFunction::GetVRegInfo(int id) const {
|
||||
if (id < 0 || id >= static_cast<int>(vregs_.size())) {
|
||||
throw std::out_of_range("virtual register index out of range");
|
||||
}
|
||||
return vregs_[static_cast<size_t>(id)];
|
||||
}
|
||||
|
||||
VRegInfo& MachineFunction::GetVRegInfo(int id) {
|
||||
if (id < 0 || id >= static_cast<int>(vregs_.size())) {
|
||||
throw std::out_of_range("virtual register index out of range");
|
||||
}
|
||||
return vregs_[static_cast<size_t>(id)];
|
||||
}
|
||||
|
||||
int MachineFunction::CreateFrameIndex(int size) {
|
||||
int index = static_cast<int>(frame_slots_.size());
|
||||
frame_slots_.push_back(FrameSlot{index, size, 0});
|
||||
int MachineFunction::CreateStackObject(int size, int align, StackObjectKind kind,
|
||||
const std::string& name) {
|
||||
const int index = static_cast<int>(stack_objects_.size());
|
||||
stack_objects_.push_back({index, kind, size, align, 0, name});
|
||||
return index;
|
||||
}
|
||||
|
||||
FrameSlot& MachineFunction::GetFrameSlot(int index) {
|
||||
if (index < 0 || index >= static_cast<int>(frame_slots_.size())) {
|
||||
throw std::runtime_error(FormatError("mir", "非法 FrameIndex"));
|
||||
StackObject& MachineFunction::GetStackObject(int index) {
|
||||
if (index < 0 || index >= static_cast<int>(stack_objects_.size())) {
|
||||
throw std::out_of_range("stack object index out of range");
|
||||
}
|
||||
return stack_objects_[static_cast<size_t>(index)];
|
||||
}
|
||||
|
||||
const StackObject& MachineFunction::GetStackObject(int index) const {
|
||||
if (index < 0 || index >= static_cast<int>(stack_objects_.size())) {
|
||||
throw std::out_of_range("stack object index out of range");
|
||||
}
|
||||
return frame_slots_[index];
|
||||
return stack_objects_[static_cast<size_t>(index)];
|
||||
}
|
||||
|
||||
const FrameSlot& MachineFunction::GetFrameSlot(int index) const {
|
||||
if (index < 0 || index >= static_cast<int>(frame_slots_.size())) {
|
||||
throw std::runtime_error(FormatError("mir", "非法 FrameIndex"));
|
||||
void MachineFunction::SetAllocation(int vreg, Allocation allocation) {
|
||||
if (vreg < 0 || vreg >= static_cast<int>(allocations_.size())) {
|
||||
throw std::out_of_range("allocation index out of range");
|
||||
}
|
||||
return frame_slots_[index];
|
||||
allocations_[static_cast<size_t>(vreg)] = allocation;
|
||||
}
|
||||
|
||||
const Allocation& MachineFunction::GetAllocation(int vreg) const {
|
||||
if (vreg < 0 || vreg >= static_cast<int>(allocations_.size())) {
|
||||
throw std::out_of_range("allocation index out of range");
|
||||
}
|
||||
return allocations_[static_cast<size_t>(vreg)];
|
||||
}
|
||||
|
||||
Allocation& MachineFunction::GetAllocation(int vreg) {
|
||||
if (vreg < 0 || vreg >= static_cast<int>(allocations_.size())) {
|
||||
throw std::out_of_range("allocation index out of range");
|
||||
}
|
||||
return allocations_[static_cast<size_t>(vreg)];
|
||||
}
|
||||
|
||||
void MachineFunction::AddUsedCalleeSavedGPR(int reg_index) {
|
||||
if (std::find(used_callee_saved_gprs_.begin(), used_callee_saved_gprs_.end(),
|
||||
reg_index) == used_callee_saved_gprs_.end()) {
|
||||
used_callee_saved_gprs_.push_back(reg_index);
|
||||
}
|
||||
}
|
||||
|
||||
void MachineFunction::AddUsedCalleeSavedFPR(int reg_index) {
|
||||
if (std::find(used_callee_saved_fprs_.begin(), used_callee_saved_fprs_.end(),
|
||||
reg_index) == used_callee_saved_fprs_.end()) {
|
||||
used_callee_saved_fprs_.push_back(reg_index);
|
||||
}
|
||||
}
|
||||
|
||||
MachineFunction* MachineModule::AddFunction(
|
||||
std::unique_ptr<MachineFunction> function) {
|
||||
auto* ptr = function.get();
|
||||
functions_.push_back(std::move(function));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
} // namespace mir
|
||||
|
||||
@ -1,23 +1,178 @@
|
||||
#include "mir/MIR.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace mir {
|
||||
|
||||
Operand::Operand(Kind kind, PhysReg reg, int imm)
|
||||
: kind_(kind), reg_(reg), imm_(imm) {}
|
||||
MachineOperand::MachineOperand(OperandKind kind, int vreg, std::int64_t imm,
|
||||
std::string text)
|
||||
: kind_(kind), vreg_(vreg), imm_(imm), text_(std::move(text)) {}
|
||||
|
||||
MachineOperand MachineOperand::VReg(int reg) {
|
||||
return MachineOperand(OperandKind::VReg, reg, 0, "");
|
||||
}
|
||||
|
||||
Operand Operand::Reg(PhysReg reg) { return Operand(Kind::Reg, reg, 0); }
|
||||
MachineOperand MachineOperand::Imm(std::int64_t value) {
|
||||
return MachineOperand(OperandKind::Imm, -1, value, "");
|
||||
}
|
||||
|
||||
Operand Operand::Imm(int value) {
|
||||
return Operand(Kind::Imm, PhysReg::W0, value);
|
||||
MachineOperand MachineOperand::Block(std::string name) {
|
||||
return MachineOperand(OperandKind::Block, -1, 0, std::move(name));
|
||||
}
|
||||
|
||||
Operand Operand::FrameIndex(int index) {
|
||||
return Operand(Kind::FrameIndex, PhysReg::W0, index);
|
||||
MachineOperand MachineOperand::Symbol(std::string name) {
|
||||
return MachineOperand(OperandKind::Symbol, -1, 0, std::move(name));
|
||||
}
|
||||
|
||||
MachineInstr::MachineInstr(Opcode opcode, std::vector<Operand> operands)
|
||||
MachineInstr::MachineInstr(Opcode opcode, std::vector<MachineOperand> operands)
|
||||
: opcode_(opcode), operands_(std::move(operands)) {}
|
||||
|
||||
bool MachineInstr::IsTerminator() const {
|
||||
return opcode_ == Opcode::Br || opcode_ == Opcode::CondBr ||
|
||||
opcode_ == Opcode::Ret || opcode_ == Opcode::Unreachable;
|
||||
}
|
||||
|
||||
std::vector<int> MachineInstr::GetDefs() const {
|
||||
switch (opcode_) {
|
||||
case Opcode::Arg:
|
||||
case Opcode::Copy:
|
||||
case Opcode::Load:
|
||||
case Opcode::Lea:
|
||||
case Opcode::Add:
|
||||
case Opcode::Sub:
|
||||
case Opcode::Mul:
|
||||
case Opcode::Div:
|
||||
case Opcode::Rem:
|
||||
case Opcode::And:
|
||||
case Opcode::Or:
|
||||
case Opcode::Xor:
|
||||
case Opcode::Shl:
|
||||
case Opcode::AShr:
|
||||
case Opcode::LShr:
|
||||
case Opcode::FAdd:
|
||||
case Opcode::FSub:
|
||||
case Opcode::FMul:
|
||||
case Opcode::FDiv:
|
||||
case Opcode::FNeg:
|
||||
case Opcode::ICmp:
|
||||
case Opcode::FCmp:
|
||||
case Opcode::ZExt:
|
||||
case Opcode::ItoF:
|
||||
case Opcode::FtoI:
|
||||
if (!operands_.empty() && operands_[0].GetKind() == OperandKind::VReg) {
|
||||
return {operands_[0].GetVReg()};
|
||||
}
|
||||
return {};
|
||||
case Opcode::Call:
|
||||
if (call_return_type_ != ValueType::Void && !operands_.empty() &&
|
||||
operands_[0].GetKind() == OperandKind::VReg) {
|
||||
return {operands_[0].GetVReg()};
|
||||
}
|
||||
return {};
|
||||
case Opcode::Store:
|
||||
case Opcode::Br:
|
||||
case Opcode::CondBr:
|
||||
case Opcode::Ret:
|
||||
case Opcode::Memset:
|
||||
case Opcode::Unreachable:
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<int> MachineInstr::GetUses() const {
|
||||
std::vector<int> uses;
|
||||
auto push_vreg = [&](const MachineOperand& operand) {
|
||||
if (operand.GetKind() == OperandKind::VReg) {
|
||||
uses.push_back(operand.GetVReg());
|
||||
}
|
||||
};
|
||||
auto push_addr_uses = [&]() {
|
||||
if (!has_address_) {
|
||||
return;
|
||||
}
|
||||
if (address_.base_kind == AddrBaseKind::VReg && address_.base_index >= 0) {
|
||||
uses.push_back(address_.base_index);
|
||||
}
|
||||
for (const auto& term : address_.scaled_vregs) {
|
||||
uses.push_back(term.first);
|
||||
}
|
||||
};
|
||||
|
||||
switch (opcode_) {
|
||||
case Opcode::Arg:
|
||||
case Opcode::Br:
|
||||
case Opcode::Unreachable:
|
||||
break;
|
||||
case Opcode::Copy:
|
||||
case Opcode::ZExt:
|
||||
case Opcode::ItoF:
|
||||
case Opcode::FtoI:
|
||||
case Opcode::FNeg:
|
||||
if (operands_.size() >= 2) {
|
||||
push_vreg(operands_[1]);
|
||||
}
|
||||
break;
|
||||
case Opcode::Load:
|
||||
case Opcode::Lea:
|
||||
push_addr_uses();
|
||||
break;
|
||||
case Opcode::Store:
|
||||
if (!operands_.empty()) {
|
||||
push_vreg(operands_[0]);
|
||||
}
|
||||
push_addr_uses();
|
||||
break;
|
||||
case Opcode::Add:
|
||||
case Opcode::Sub:
|
||||
case Opcode::Mul:
|
||||
case Opcode::Div:
|
||||
case Opcode::Rem:
|
||||
case Opcode::And:
|
||||
case Opcode::Or:
|
||||
case Opcode::Xor:
|
||||
case Opcode::Shl:
|
||||
case Opcode::AShr:
|
||||
case Opcode::LShr:
|
||||
case Opcode::FAdd:
|
||||
case Opcode::FSub:
|
||||
case Opcode::FMul:
|
||||
case Opcode::FDiv:
|
||||
case Opcode::ICmp:
|
||||
case Opcode::FCmp:
|
||||
if (operands_.size() >= 2) {
|
||||
push_vreg(operands_[1]);
|
||||
}
|
||||
if (operands_.size() >= 3) {
|
||||
push_vreg(operands_[2]);
|
||||
}
|
||||
break;
|
||||
case Opcode::CondBr:
|
||||
if (!operands_.empty()) {
|
||||
push_vreg(operands_[0]);
|
||||
}
|
||||
break;
|
||||
case Opcode::Call: {
|
||||
size_t arg_begin = call_return_type_ == ValueType::Void ? 0 : 1;
|
||||
for (size_t i = arg_begin; i < operands_.size(); ++i) {
|
||||
push_vreg(operands_[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Opcode::Ret:
|
||||
if (!operands_.empty()) {
|
||||
push_vreg(operands_[0]);
|
||||
}
|
||||
break;
|
||||
case Opcode::Memset:
|
||||
if (!operands_.empty()) {
|
||||
push_vreg(operands_[0]);
|
||||
}
|
||||
if (operands_.size() >= 2) {
|
||||
push_vreg(operands_[1]);
|
||||
}
|
||||
push_addr_uses();
|
||||
break;
|
||||
}
|
||||
return uses;
|
||||
}
|
||||
|
||||
} // namespace mir
|
||||
|
||||
Loading…
Reference in new issue