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.
327 lines
11 KiB
327 lines
11 KiB
// IR 构建工具:
|
|
// - 管理插入点(当前基本块/位置)
|
|
// - 提供创建各类指令的便捷接口,降低 IRGen 复杂度
|
|
|
|
#include "ir/IR.h"
|
|
|
|
#include <stdexcept>
|
|
|
|
#include "utils/Log.h"
|
|
|
|
namespace ir {
|
|
|
|
static std::string TypeToString(const Type& ty) {
|
|
switch (ty.GetKind()) {
|
|
case Type::Kind::Void:
|
|
return "void";
|
|
case Type::Kind::Int1:
|
|
return "i1";
|
|
case Type::Kind::Int32:
|
|
return "i32";
|
|
case Type::Kind::Float:
|
|
return "float";
|
|
case Type::Kind::Label:
|
|
return "label";
|
|
case Type::Kind::Pointer:
|
|
return TypeToString(*ty.GetElementType()) + "*";
|
|
case Type::Kind::Array: {
|
|
return "[" + std::to_string(ty.GetArraySize()) + " x " +
|
|
TypeToString(*ty.GetElementType()) + "]";
|
|
}
|
|
case Type::Kind::Function: {
|
|
std::string out = TypeToString(*ty.GetReturnType()) + " (";
|
|
const auto& params = ty.GetParamTypes();
|
|
for (size_t i = 0; i < params.size(); ++i) {
|
|
if (i > 0) out += ", ";
|
|
out += TypeToString(*params[i]);
|
|
}
|
|
if (ty.IsVarArg()) {
|
|
if (!params.empty()) out += ", ";
|
|
out += "...";
|
|
}
|
|
out += ")";
|
|
return out;
|
|
}
|
|
}
|
|
return "?";
|
|
}
|
|
IRBuilder::IRBuilder(Context& ctx, BasicBlock* bb)
|
|
: ctx_(ctx), insert_block_(bb) {}
|
|
|
|
void IRBuilder::SetInsertPoint(BasicBlock* bb) { insert_block_ = bb; }
|
|
|
|
BasicBlock* IRBuilder::GetInsertBlock() const { return insert_block_; }
|
|
|
|
ConstantInt* IRBuilder::CreateConstInt(int v) {
|
|
// 常量不需要挂在基本块里,由 Context 负责去重与生命周期。
|
|
return ctx_.GetConstInt(v);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
if (!lhs) {
|
|
throw std::runtime_error(
|
|
FormatError("ir", "IRBuilder::CreateBinary 缺少 lhs"));
|
|
}
|
|
if (!rhs) {
|
|
throw std::runtime_error(
|
|
FormatError("ir", "IRBuilder::CreateBinary 缺少 rhs"));
|
|
}
|
|
return insert_block_->Append<BinaryInst>(op, lhs->GetType(), lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateAdd(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::Add, lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateSub(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::Sub, lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateMul(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::Mul, lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateSDiv(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::SDiv, lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateSRem(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::SRem, lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateFAdd(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::FAdd, lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateFSub(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::FSub, lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateFMul(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::FMul, lhs, rhs, name);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateFDiv(Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
return CreateBinary(Opcode::FDiv, lhs, rhs, name);
|
|
}
|
|
|
|
ICmpInst* IRBuilder::CreateICmp(ICmpPredicate pred, Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<ICmpInst>(pred, lhs, rhs, name);
|
|
}
|
|
|
|
FCmpInst* IRBuilder::CreateFCmp(FCmpPredicate pred, Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<FCmpInst>(pred, lhs, rhs, name);
|
|
}
|
|
|
|
CastInst* IRBuilder::CreateSIToFP(Value* src, std::shared_ptr<Type> dst_ty,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<CastInst>(Opcode::SIToFP, std::move(dst_ty), src,
|
|
name);
|
|
}
|
|
|
|
CastInst* IRBuilder::CreateFPToSI(Value* src, std::shared_ptr<Type> dst_ty,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<CastInst>(Opcode::FPToSI, std::move(dst_ty), src,
|
|
name);
|
|
}
|
|
|
|
CastInst* IRBuilder::CreateZExt(Value* src, std::shared_ptr<Type> dst_ty,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<CastInst>(Opcode::ZExt, std::move(dst_ty), src,
|
|
name);
|
|
}
|
|
|
|
ConstantInt* IRBuilder::CreateConstBool(bool v) {
|
|
return ctx_.GetConstBool(v);
|
|
}
|
|
|
|
ConstantFloat* IRBuilder::CreateConstFloat(float v) {
|
|
return ctx_.GetConstFloat(v);
|
|
}
|
|
|
|
AllocaInst* IRBuilder::CreateAlloca(std::shared_ptr<Type> ty,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<AllocaInst>(std::move(ty), name);
|
|
}
|
|
|
|
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
|
|
return CreateAlloca(Type::GetInt32Type(), name);
|
|
}
|
|
|
|
LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
if (!ptr) {
|
|
throw std::runtime_error(
|
|
FormatError("ir", "IRBuilder::CreateLoad 缺少 ptr"));
|
|
}
|
|
if (!ptr->GetType() || !ptr->GetType()->IsPointer()) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateLoad ptr 不是指针"));
|
|
}
|
|
auto val_ty = ptr->GetType()->GetElementType();
|
|
return insert_block_->Append<LoadInst>(val_ty, ptr, name);
|
|
}
|
|
|
|
StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
if (!val) {
|
|
throw std::runtime_error(
|
|
FormatError("ir", "IRBuilder::CreateStore 缺少 val"));
|
|
}
|
|
if (!ptr) {
|
|
throw std::runtime_error(
|
|
FormatError("ir", "IRBuilder::CreateStore 缺少 ptr"));
|
|
}
|
|
return insert_block_->Append<StoreInst>(Type::GetVoidType(), val, ptr);
|
|
}
|
|
|
|
static std::shared_ptr<Type> ResolveGepResultType(const std::shared_ptr<Type>& base_ptr_ty,
|
|
size_t index_count) {
|
|
if (!base_ptr_ty || !base_ptr_ty->IsPointer()) {
|
|
throw std::runtime_error("GEP base type 必须是指针");
|
|
}
|
|
auto cur = base_ptr_ty->GetElementType();
|
|
for (size_t i = 0; i < index_count; ++i) {
|
|
// LLVM GEP 的第一个索引只是在当前 pointee 对象上做寻址,
|
|
// 不会立刻深入到数组元素类型;真正进入聚合类型从第二个索引开始。
|
|
if (i == 0) {
|
|
continue;
|
|
}
|
|
if (cur->IsArray()) {
|
|
cur = cur->GetElementType();
|
|
continue;
|
|
}
|
|
if (cur->IsPointer()) {
|
|
cur = cur->GetElementType();
|
|
continue;
|
|
}
|
|
}
|
|
return Type::GetPointerType(cur);
|
|
}
|
|
|
|
GepInst* IRBuilder::CreateGep(Value* base_ptr, std::vector<Value*> indices,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
if (!base_ptr || !base_ptr->GetType() || !base_ptr->GetType()->IsPointer()) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateGep base_ptr 非指针"));
|
|
}
|
|
auto result_ty = ResolveGepResultType(base_ptr->GetType(), indices.size());
|
|
return insert_block_->Append<GepInst>(result_ty, base_ptr, std::move(indices),
|
|
name);
|
|
}
|
|
|
|
CallInst* IRBuilder::CreateCall(Value* callee, std::vector<Value*> args,
|
|
const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
if (!callee || !callee->GetType()) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCall 缺少 callee"));
|
|
}
|
|
std::shared_ptr<Type> func_ty;
|
|
if (callee->GetType()->IsFunction()) {
|
|
func_ty = callee->GetType();
|
|
} else if (callee->GetType()->IsPointer() &&
|
|
callee->GetType()->GetElementType()->IsFunction()) {
|
|
func_ty = callee->GetType()->GetElementType();
|
|
} else {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCall callee 非函数"));
|
|
}
|
|
const auto& params = func_ty->GetParamTypes();
|
|
if (!func_ty->IsVarArg() && params.size() != args.size()) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCall 参数数量不匹配"));
|
|
}
|
|
for (size_t i = 0; i < params.size() && i < args.size(); ++i) {
|
|
if (!args[i] || !args[i]->GetType() ||
|
|
!args[i]->GetType()->Equals(*params[i])) {
|
|
std::string msg = "IRBuilder::CreateCall 参数类型不匹配: arg" +
|
|
std::to_string(i) + " got " +
|
|
TypeToString(*args[i]->GetType()) + ", expect " +
|
|
TypeToString(*params[i]);
|
|
throw std::runtime_error(FormatError("ir", msg));
|
|
}
|
|
}
|
|
auto ret_ty = func_ty->GetReturnType();
|
|
return insert_block_->Append<CallInst>(ret_ty, callee, std::move(args), name);
|
|
}
|
|
|
|
PhiInst* IRBuilder::CreatePhi(std::shared_ptr<Type> ty, const std::string& name) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<PhiInst>(std::move(ty), name);
|
|
}
|
|
|
|
BranchInst* IRBuilder::CreateBr(BasicBlock* dest) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<BranchInst>(dest);
|
|
}
|
|
|
|
CondBrInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* true_dest,
|
|
BasicBlock* false_dest) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<CondBrInst>(cond, true_dest, false_dest);
|
|
}
|
|
|
|
ReturnInst* IRBuilder::CreateRet(Value* v) {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
if (!v) {
|
|
throw std::runtime_error(
|
|
FormatError("ir", "IRBuilder::CreateRet 缺少返回值"));
|
|
}
|
|
return insert_block_->Append<ReturnInst>(Type::GetVoidType(), v);
|
|
}
|
|
|
|
ReturnInst* IRBuilder::CreateRetVoid() {
|
|
if (!insert_block_) {
|
|
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
|
}
|
|
return insert_block_->Append<ReturnInst>(Type::GetVoidType());
|
|
}
|
|
|
|
} // namespace ir
|