forked from NUDT-compiler/nudt-compiler-cpp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
12 KiB
284 lines
12 KiB
#include "ir/IR.h"
|
|
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
#include "utils/Log.h"
|
|
|
|
namespace ir {
|
|
|
|
// ─── User ─────────────────────────────────────────────────────────────────────
|
|
User::User(std::shared_ptr<Type> ty, std::string name)
|
|
: Value(std::move(ty), std::move(name)) {}
|
|
|
|
size_t User::GetNumOperands() const { return operands_.size(); }
|
|
|
|
Value* User::GetOperand(size_t index) const {
|
|
if (index >= operands_.size()) {
|
|
throw std::out_of_range("User operand index out of range");
|
|
}
|
|
return operands_[index];
|
|
}
|
|
|
|
void User::SetOperand(size_t index, Value* value) {
|
|
if (index >= operands_.size()) {
|
|
throw std::out_of_range("User operand index out of range");
|
|
}
|
|
auto* old = operands_[index];
|
|
if (old == value) return;
|
|
if (old) old->RemoveUse(this, index);
|
|
operands_[index] = value;
|
|
if (value) value->AddUse(this, index);
|
|
}
|
|
|
|
void User::AddOperand(Value* value) {
|
|
size_t idx = operands_.size();
|
|
operands_.push_back(value);
|
|
if (value) value->AddUse(this, idx);
|
|
}
|
|
|
|
// ─── Instruction ──────────────────────────────────────────────────────────────
|
|
Instruction::Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name)
|
|
: User(std::move(ty), std::move(name)), opcode_(op) {}
|
|
|
|
Opcode Instruction::GetOpcode() const { return opcode_; }
|
|
|
|
bool Instruction::IsTerminator() const {
|
|
return opcode_ == Opcode::Ret || opcode_ == Opcode::Br ||
|
|
opcode_ == Opcode::CondBr;
|
|
}
|
|
|
|
BasicBlock* Instruction::GetParent() const { return parent_; }
|
|
void Instruction::SetParent(BasicBlock* parent) { parent_ = parent; }
|
|
|
|
// ─── BinaryInst ───────────────────────────────────────────────────────────────
|
|
BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
|
|
Value* rhs, std::string name)
|
|
: Instruction(op, std::move(ty), std::move(name)) {
|
|
if (op != Opcode::Add && op != Opcode::Sub && op != Opcode::Mul &&
|
|
op != Opcode::Div && op != Opcode::Mod && op != Opcode::FAdd &&
|
|
op != Opcode::FSub && op != Opcode::FMul && op != Opcode::FDiv) {
|
|
throw std::runtime_error(
|
|
FormatError("ir", "BinaryInst: 不支持的操作码"));
|
|
}
|
|
if (!lhs || !rhs) {
|
|
throw std::runtime_error(FormatError("ir", "BinaryInst 缺少操作数"));
|
|
}
|
|
AddOperand(lhs);
|
|
AddOperand(rhs);
|
|
}
|
|
|
|
Value* BinaryInst::GetLhs() const { return GetOperand(0); }
|
|
Value* BinaryInst::GetRhs() const { return GetOperand(1); }
|
|
|
|
// ─── ICmpInst ─────────────────────────────────────────────────────────────────
|
|
ICmpInst::ICmpInst(ICmpPredicate pred, Value* lhs, Value* rhs, std::string name)
|
|
: Instruction(Opcode::ICmp, Type::GetInt1Type(), std::move(name)),
|
|
pred_(pred) {
|
|
if (!lhs || !rhs) {
|
|
throw std::runtime_error(FormatError("ir", "ICmpInst 缺少操作数"));
|
|
}
|
|
AddOperand(lhs);
|
|
AddOperand(rhs);
|
|
}
|
|
|
|
Value* ICmpInst::GetLhs() const { return GetOperand(0); }
|
|
Value* ICmpInst::GetRhs() const { return GetOperand(1); }
|
|
|
|
// ─── FCmpInst ─────────────────────────────────────────────────────────────────
|
|
FCmpInst::FCmpInst(FCmpPredicate pred, Value* lhs, Value* rhs, std::string name)
|
|
: Instruction(Opcode::FCmp, Type::GetInt1Type(), std::move(name)),
|
|
pred_(pred) {
|
|
if (!lhs || !rhs) {
|
|
throw std::runtime_error(FormatError("ir", "FCmpInst 缺少操作数"));
|
|
}
|
|
AddOperand(lhs);
|
|
AddOperand(rhs);
|
|
}
|
|
|
|
Value* FCmpInst::GetLhs() const { return GetOperand(0); }
|
|
Value* FCmpInst::GetRhs() const { return GetOperand(1); }
|
|
|
|
// ─── BrInst ───────────────────────────────────────────────────────────────────
|
|
BrInst::BrInst(BasicBlock* target)
|
|
: Instruction(Opcode::Br, Type::GetVoidType(), "") {
|
|
if (!target) {
|
|
throw std::runtime_error(FormatError("ir", "BrInst 缺少目标"));
|
|
}
|
|
AddOperand(target);
|
|
}
|
|
|
|
BasicBlock* BrInst::GetTarget() const {
|
|
return static_cast<BasicBlock*>(GetOperand(0));
|
|
}
|
|
|
|
// ─── CondBrInst ───────────────────────────────────────────────────────────────
|
|
CondBrInst::CondBrInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb)
|
|
: Instruction(Opcode::CondBr, Type::GetVoidType(), "") {
|
|
if (!cond || !true_bb || !false_bb) {
|
|
throw std::runtime_error(FormatError("ir", "CondBrInst 缺少操作数"));
|
|
}
|
|
AddOperand(cond);
|
|
AddOperand(true_bb);
|
|
AddOperand(false_bb);
|
|
}
|
|
|
|
Value* CondBrInst::GetCond() const { return GetOperand(0); }
|
|
BasicBlock* CondBrInst::GetTrueBB() const {
|
|
return static_cast<BasicBlock*>(GetOperand(1));
|
|
}
|
|
BasicBlock* CondBrInst::GetFalseBB() const {
|
|
return static_cast<BasicBlock*>(GetOperand(2));
|
|
}
|
|
|
|
// ─── CallInst ─────────────────────────────────────────────────────────────────
|
|
CallInst::CallInst(Function* callee, std::vector<Value*> args, std::string name)
|
|
: Instruction(Opcode::Call,
|
|
callee ? callee->GetType() : Type::GetVoidType(),
|
|
std::move(name)),
|
|
callee_(callee) {
|
|
if (!callee) {
|
|
throw std::runtime_error(FormatError("ir", "CallInst: callee 为空"));
|
|
}
|
|
callee_name_ = callee->GetName();
|
|
for (auto* arg : args) {
|
|
AddOperand(arg);
|
|
}
|
|
}
|
|
|
|
CallInst::CallInst(std::string callee_name, std::shared_ptr<Type> ret_type,
|
|
std::vector<Value*> args, std::string name)
|
|
: Instruction(Opcode::Call, std::move(ret_type), std::move(name)),
|
|
callee_(nullptr),
|
|
callee_name_(std::move(callee_name)) {
|
|
for (auto* arg : args) {
|
|
AddOperand(arg);
|
|
}
|
|
}
|
|
|
|
// ─── ZExtInst ─────────────────────────────────────────────────────────────────
|
|
ZExtInst::ZExtInst(Value* val, std::string name)
|
|
: Instruction(Opcode::ZExt, Type::GetInt32Type(), std::move(name)) {
|
|
if (!val) {
|
|
throw std::runtime_error(FormatError("ir", "ZExtInst 缺少操作数"));
|
|
}
|
|
AddOperand(val);
|
|
}
|
|
|
|
Value* ZExtInst::GetSrc() const { return GetOperand(0); }
|
|
|
|
// ─── SIToFPInst ───────────────────────────────────────────────────────────────
|
|
SIToFPInst::SIToFPInst(Value* val, std::string name)
|
|
: Instruction(Opcode::SIToFP, Type::GetFloat32Type(), std::move(name)) {
|
|
if (!val) {
|
|
throw std::runtime_error(FormatError("ir", "SIToFPInst 缺少操作数"));
|
|
}
|
|
AddOperand(val);
|
|
}
|
|
|
|
Value* SIToFPInst::GetSrc() const { return GetOperand(0); }
|
|
|
|
// ─── FPToSIInst ───────────────────────────────────────────────────────────────
|
|
FPToSIInst::FPToSIInst(Value* val, std::string name)
|
|
: Instruction(Opcode::FPToSI, Type::GetInt32Type(), std::move(name)) {
|
|
if (!val) {
|
|
throw std::runtime_error(FormatError("ir", "FPToSIInst 缺少操作数"));
|
|
}
|
|
AddOperand(val);
|
|
}
|
|
|
|
Value* FPToSIInst::GetSrc() const { return GetOperand(0); }
|
|
|
|
// ─── ReturnInst ───────────────────────────────────────────────────────────────
|
|
ReturnInst::ReturnInst(Value* val)
|
|
: Instruction(Opcode::Ret, Type::GetVoidType(), "") {
|
|
if (val) {
|
|
AddOperand(val);
|
|
}
|
|
}
|
|
|
|
ReturnInst::ReturnInst()
|
|
: Instruction(Opcode::Ret, Type::GetVoidType(), "") {}
|
|
|
|
Value* ReturnInst::GetValue() const {
|
|
return HasValue() ? GetOperand(0) : nullptr;
|
|
}
|
|
|
|
// ─── AllocaInst ───────────────────────────────────────────────────────────────
|
|
AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name)
|
|
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)),
|
|
num_elements_(1) {
|
|
if (!type_->IsPtrInt32() && !type_->IsPtrFloat32()) {
|
|
throw std::runtime_error(FormatError("ir", "AllocaInst 只支持 i32* 和 f32*"));
|
|
}
|
|
}
|
|
|
|
AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, int num_elements,
|
|
std::string name)
|
|
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)),
|
|
num_elements_(num_elements) {
|
|
if (!type_->IsPtrInt32() && !type_->IsPtrFloat32()) {
|
|
throw std::runtime_error(FormatError("ir", "AllocaInst 只支持 i32* 和 f32*"));
|
|
}
|
|
}
|
|
|
|
// ─── GepInst ──────────────────────────────────────────────────────────────────
|
|
GepInst::GepInst(Value* base_ptr, Value* index, std::string name)
|
|
: Instruction(Opcode::Gep,
|
|
(base_ptr && base_ptr->GetType()->IsPtrFloat32())
|
|
? Type::GetPtrFloat32Type()
|
|
: Type::GetPtrInt32Type(),
|
|
std::move(name)) {
|
|
if (!base_ptr || !index) {
|
|
throw std::runtime_error(FormatError("ir", "GepInst 缺少操作数"));
|
|
}
|
|
AddOperand(base_ptr);
|
|
AddOperand(index);
|
|
}
|
|
|
|
Value* GepInst::GetBasePtr() const { return GetOperand(0); }
|
|
Value* GepInst::GetIndex() const { return GetOperand(1); }
|
|
|
|
// ─── LoadInst ─────────────────────────────────────────────────────────────────
|
|
LoadInst::LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name)
|
|
: Instruction(Opcode::Load, std::move(val_ty), std::move(name)) {
|
|
if (!ptr) {
|
|
throw std::runtime_error(FormatError("ir", "LoadInst 缺少 ptr"));
|
|
}
|
|
AddOperand(ptr);
|
|
}
|
|
|
|
Value* LoadInst::GetPtr() const { return GetOperand(0); }
|
|
|
|
// ─── StoreInst ────────────────────────────────────────────────────────────────
|
|
StoreInst::StoreInst(Value* val, Value* ptr)
|
|
: Instruction(Opcode::Store, Type::GetVoidType(), "") {
|
|
if (!val || !ptr) {
|
|
throw std::runtime_error(FormatError("ir", "StoreInst 缺少操作数"));
|
|
}
|
|
AddOperand(val);
|
|
AddOperand(ptr);
|
|
}
|
|
|
|
Value* StoreInst::GetValue() const { return GetOperand(0); }
|
|
Value* StoreInst::GetPtr() const { return GetOperand(1); }
|
|
|
|
// ─── GlobalValue (占位) ────────────────────────────────────────────────────────
|
|
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name)
|
|
: User(std::move(ty), std::move(name)) {}
|
|
|
|
// ─── GlobalVariable ────────────────────────────────────────────────────────────
|
|
GlobalVariable::GlobalVariable(std::string name, bool is_const, int init_val,
|
|
int num_elements, bool is_array_decl,
|
|
bool is_float)
|
|
: Value(is_float ? Type::GetPtrFloat32Type() : Type::GetPtrInt32Type(),
|
|
std::move(name)),
|
|
is_const_(is_const),
|
|
is_float_(is_float),
|
|
init_val_(init_val),
|
|
init_val_f_(0.0f),
|
|
num_elements_(num_elements),
|
|
is_array_decl_(is_array_decl) {}
|
|
|
|
} // namespace ir
|