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

// 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