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.
nudt-compiler-cpp/src/ir/IRBuilder.cpp

621 lines
21 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// IR 构建工具:
// - 管理插入点(当前基本块/位置)
// - 提供创建各类指令的便捷接口,降低 IRGen 复杂度
#include "ir/IR.h"
#include <stdexcept>
#include <cstring>
#include "utils/Log.h"
namespace ir {
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);
}
// IRBuilder 方法实现
ConstantFloat* IRBuilder::CreateConstFloat(float v) {
return ctx_.GetConstFloat(v);
}
ConstantArray* IRBuilder::CreateConstArray(std::shared_ptr<ArrayType> ty,
std::vector<ConstantValue*> elements) {
return ctx_.GetConstArray(ty, std::move(elements));
}
ConstantZero* IRBuilder::CreateZeroConstant(std::shared_ptr<Type> ty) {
return ctx_.GetZeroConstant(ty);
}
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"));
}
// 检查操作码是否为有效的二元操作符
switch (op) {
case Opcode::Add:
case Opcode::Sub:
case Opcode::Mul:
case Opcode::Div:
case Opcode::Mod:
case Opcode::And:
case Opcode::Or:
// 添加浮点操作码
case Opcode::FAdd:
case Opcode::FSub:
case Opcode::FMul:
case Opcode::FDiv:
// 有效的二元操作符
break;
case Opcode::Not:
// Not是一元操作符不应该在BinaryInst中
throw std::runtime_error(FormatError("ir", "Not是一元操作符应使用其他指令"));
default:
throw std::runtime_error(FormatError("ir", "BinaryInst 不支持的操作码"));
}
// 确定结果类型
std::shared_ptr<Type> result_type;
// 检查操作数类型是否相同
if (lhs->GetType()->GetKind() != rhs->GetType()->GetKind()) {
throw std::runtime_error(
FormatError("ir", "CreateBinary 操作数类型不匹配"));
}
// 检查是否为浮点操作
bool is_float_op = (op == Opcode::FAdd || op == Opcode::FSub ||
op == Opcode::FMul || op == Opcode::FDiv);
if (is_float_op) {
// 浮点操作要求操作数是浮点类型
if (!lhs->GetType()->IsFloat()) {
throw std::runtime_error(
FormatError("ir", "浮点运算要求操作数为浮点类型"));
}
result_type = lhs->GetType();
} else {
bool is_logical = (op == Opcode::And || op == Opcode::Or);
if (is_logical) {
// 逻辑运算的结果是 int32布尔值
result_type = Type::GetInt32Type();
} else {
// 算术运算的结果类型与操作数相同
result_type = lhs->GetType();
}
// 检查操作数类型是否支持
if (!lhs->GetType()->IsInt32() && !lhs->GetType()->IsFloat()) {
throw std::runtime_error(
FormatError("ir", "CreateBinary 只支持 int32 和 float 类型"));
}
}
return insert_block_->Append<BinaryInst>(op, result_type, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateAdd(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::Add, lhs, rhs, name);
}
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<AllocaInst>(Type::GetPtrInt32Type(), name);
}
AllocaInst* IRBuilder::CreateAllocaFloat(const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<AllocaInst>(Type::GetPtrFloatType(), 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"));
}
auto ptr_ty = ptr->GetType();
std::shared_ptr<Type> elem_ty;
if (ptr_ty->IsPtrInt32()) {
elem_ty = Type::GetInt32Type();
} else if (ptr_ty->IsPtrFloat()) {
elem_ty = Type::GetFloatType();
} else if (ptr_ty->IsPtrInt1()) {
elem_ty = Type::GetInt1Type();
} else if (ptr_ty->IsArray()) {
// 数组类型的指针,元素类型是数组元素类型
auto* array_ty = dynamic_cast<ArrayType*>(ptr_ty.get());
if (array_ty) {
elem_ty = array_ty->GetElementType();
} else {
throw std::runtime_error(FormatError("ir", "不支持的指针类型"));
}
} else {
// 尝试其他指针类型
throw std::runtime_error(FormatError("ir", "不支持的指针类型"));
}
return insert_block_->Append<LoadInst>(elem_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"));
}
// 检查类型兼容性
auto ptr_ty = ptr->GetType();
auto val_ty = val->GetType();
if (ptr_ty->IsPtrInt32()) {
if (!val_ty->IsInt32()) {
throw std::runtime_error(FormatError("ir", "存储类型不匹配:期望 int32"));
}
} else if (ptr_ty->IsPtrFloat()) {
if (!val_ty->IsFloat()) {
throw std::runtime_error(FormatError("ir", "存储类型不匹配:期望 float"));
}
} else if (ptr_ty->IsArray()) {
// 数组存储:检查元素类型
auto* array_ty = dynamic_cast<ArrayType*>(ptr_ty.get());
if (array_ty) {
auto elem_ty = array_ty->GetElementType();
if (elem_ty->IsInt32() && !val_ty->IsInt32()) {
throw std::runtime_error(FormatError("ir", "数组元素类型不匹配:期望 int32"));
} else if (elem_ty->IsFloat() && !val_ty->IsFloat()) {
throw std::runtime_error(FormatError("ir", "数组元素类型不匹配:期望 float"));
}
}
}
return insert_block_->Append<StoreInst>(Type::GetVoidType(), val, ptr);
}
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);
}
BranchInst* IRBuilder::CreateBr(BasicBlock* target) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!target) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateBr 缺少 target"));
}
return insert_block_->Append<BranchInst>(Type::GetVoidType(), target);
}
BranchInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* true_target,
BasicBlock* false_target) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!cond) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateCondBr 缺少 cond"));
}
if (!true_target) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateCondBr 缺少 true_target"));
}
if (!false_target) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateCondBr 缺少 false_target"));
}
return insert_block_->Append<BranchInst>(Type::GetVoidType(), cond, true_target, false_target);
}
// 创建整数相等比较
IcmpInst* IRBuilder::CreateICmpEQ(Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!lhs || !rhs) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateICmpEQ 缺少操作数"));
}
// 检查类型必须一致
if (lhs->GetType() != rhs->GetType()) {
throw std::runtime_error(
FormatError("ir", "比较操作数类型不匹配"));
}
return insert_block_->Append<IcmpInst>(IcmpInst::Predicate::EQ, lhs, rhs,
Type::GetInt1Type(), name);
}
// 创建整数不等比较
IcmpInst* IRBuilder::CreateICmpNE(Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!lhs || !rhs) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateICmpNE 缺少操作数"));
}
if (lhs->GetType() != rhs->GetType()) {
throw std::runtime_error(
FormatError("ir", "比较操作数类型不匹配"));
}
return insert_block_->Append<IcmpInst>(IcmpInst::Predicate::NE, lhs, rhs,
Type::GetInt1Type(), name);
}
// 创建整数小于比较
IcmpInst* IRBuilder::CreateICmpLT(Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!lhs || !rhs) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateICmpLT 缺少操作数"));
}
if (lhs->GetType() != rhs->GetType()) {
throw std::runtime_error(
FormatError("ir", "比较操作数类型不匹配"));
}
return insert_block_->Append<IcmpInst>(IcmpInst::Predicate::LT, lhs, rhs,
Type::GetInt1Type(), name);
}
// 创建整数小于等于比较
IcmpInst* IRBuilder::CreateICmpLE(Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!lhs || !rhs) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateICmpLE 缺少操作数"));
}
if (lhs->GetType() != rhs->GetType()) {
throw std::runtime_error(
FormatError("ir", "比较操作数类型不匹配"));
}
return insert_block_->Append<IcmpInst>(IcmpInst::Predicate::LE, lhs, rhs,
Type::GetInt1Type(), name);
}
// 创建整数大于比较
IcmpInst* IRBuilder::CreateICmpGT(Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!lhs || !rhs) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateICmpGT 缺少操作数"));
}
if (lhs->GetType() != rhs->GetType()) {
throw std::runtime_error(
FormatError("ir", "比较操作数类型不匹配"));
}
return insert_block_->Append<IcmpInst>(IcmpInst::Predicate::GT, lhs, rhs,
Type::GetInt1Type(), name);
}
// 创建整数大于等于比较
IcmpInst* IRBuilder::CreateICmpGE(Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!lhs || !rhs) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateICmpGE 缺少操作数"));
}
if (lhs->GetType() != rhs->GetType()) {
throw std::runtime_error(
FormatError("ir", "比较操作数类型不匹配"));
}
return insert_block_->Append<IcmpInst>(IcmpInst::Predicate::GE, lhs, rhs,
Type::GetInt1Type(), name);
}
// 创建零扩展指令
ZExtInst* IRBuilder::CreateZExt(Value* value, std::shared_ptr<Type> target_ty,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!value) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateZExt 缺少 value"));
}
if (!target_ty) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateZExt 缺少 target_ty"));
}
auto src_ty = value->GetType();
// 类型检查:源类型应该是较小的整数类型
if (!src_ty->IsInt1() && !src_ty->IsInt32()) {
throw std::runtime_error(
FormatError("ir", "ZExt 源类型必须是整数类型"));
}
// 目标类型应该是较大的整数类型
if (!target_ty->IsInt32()) {
throw std::runtime_error(
FormatError("ir", "ZExt 目标类型必须是整数类型"));
}
return insert_block_->Append<ZExtInst>(value, target_ty, name);
}
// 创建截断指令
TruncInst* IRBuilder::CreateTrunc(Value* value, std::shared_ptr<Type> target_ty,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!value) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateTrunc 缺少 value"));
}
if (!target_ty) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateTrunc 缺少 target_ty"));
}
auto src_ty = value->GetType();
// 类型检查:源类型应该是较大的整数类型
if (!src_ty->IsInt32()) {
throw std::runtime_error(
FormatError("ir", "Trunc 源类型必须是整数类型"));
}
// 目标类型应该是较小的整数类型
if (!target_ty->IsInt1() && !target_ty->IsInt32()) {
throw std::runtime_error(
FormatError("ir", "Trunc 目标类型必须是整数类型"));
}
return insert_block_->Append<TruncInst>(value, target_ty, name);
}
// 便捷方法i1 转 i32
ZExtInst* IRBuilder::CreateZExtI1ToI32(Value* value, const std::string& name) {
return CreateZExt(value, Type::GetInt32Type(), name);
}
// 便捷方法i32 转 i1
TruncInst* IRBuilder::CreateTruncI32ToI1(Value* value, const std::string& name) {
return CreateTrunc(value, Type::GetInt1Type(), name);
}
BinaryInst* IRBuilder::CreateDiv(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::CreateDiv 缺少 lhs"));
}
if (!rhs) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateDiv 缺少 rhs"));
}
return insert_block_->Append<BinaryInst>(Opcode::Div, lhs->GetType(), lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateMod(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::CreateMod 缺少 lhs"));
}
if (!rhs) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateMod 缺少 rhs"));
}
return insert_block_->Append<BinaryInst>(Opcode::Mod, lhs->GetType(), lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateAnd(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::CreateAnd 缺少 lhs"));
}
if (!rhs) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateAnd 缺少 rhs"));
}
return insert_block_->Append<BinaryInst>(Opcode::And, Type::GetInt32Type(), lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateOr(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::CreateOr 缺少 lhs"));
}
if (!rhs) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateOr 缺少 rhs"));
}
return insert_block_->Append<BinaryInst>(Opcode::Or, Type::GetInt32Type(), lhs, rhs, name);
}
IcmpInst* IRBuilder::CreateNot(Value* val, const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!val) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateNot 缺少 operand"));
}
auto zero = CreateConstInt(0);
return CreateICmpEQ(val, zero, name);
}
GEPInst* IRBuilder::CreateGEP(Value* base,
const std::vector<Value*>& indices,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!base) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateGEP 缺少 base"));
}
// 检查所有索引
for (size_t i = 0; i < indices.size(); ++i) {
if (!indices[i]) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateGEP 索引 " + std::to_string(i) + " 为空"));
}
}
// GEP返回指针类型假设与base类型相同
return insert_block_->Append<GEPInst>(base->GetType(), base, indices, name);
}
BinaryInst* IRBuilder::CreateMul(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::CreateMul 缺少 lhs"));
}
if (!rhs) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateMul 缺少 rhs"));
}
return CreateBinary(Opcode::Mul, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateSub(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::CreateSub 缺少 lhs"));
}
if (!rhs) {
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateSub 缺少 rhs"));
}
return CreateBinary(Opcode::Sub, lhs, rhs, name);
}
// 注意:当前 CreateCall 仅支持直接调用 Function且不支持变长参数列表等复杂特性。
// 创建函数调用指令的实现,被调用的函数,参数列表,返回值临时变量名
CallInst* IRBuilder::CreateCall(Function* callee,
const std::vector<Value*>& args,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!callee) { //被调用的函数不能为空
throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCall 缺少 callee"));
}
auto func_ty = std::static_pointer_cast<FunctionType>(callee->GetType());
auto ret_ty = func_ty->GetReturnType();
return insert_block_->Append<CallInst>(ret_ty, callee, args, name);
}
BinaryInst* IRBuilder::CreateFAdd(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<BinaryInst>(Opcode::FAdd, lhs->GetType(), lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateFSub(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<BinaryInst>(Opcode::FSub, lhs->GetType(), lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateFMul(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<BinaryInst>(Opcode::FMul, lhs->GetType(), lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateFDiv(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<BinaryInst>(Opcode::FDiv, lhs->GetType(), lhs, rhs, name);
}
// 浮点比较
FcmpInst* IRBuilder::CreateFCmpOEQ(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<FcmpInst>(
FcmpInst::Predicate::OEQ, lhs, rhs, Type::GetInt1Type(), name);
}
FcmpInst* IRBuilder::CreateFCmpONE(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<FcmpInst>(
FcmpInst::Predicate::ONE, lhs, rhs, Type::GetInt1Type(), name);
}
FcmpInst* IRBuilder::CreateFCmpOLT(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<FcmpInst>(
FcmpInst::Predicate::OLT, lhs, rhs, Type::GetInt1Type(), name);
}
FcmpInst* IRBuilder::CreateFCmpOLE(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<FcmpInst>(
FcmpInst::Predicate::OLE, lhs, rhs, Type::GetInt1Type(), name);
}
FcmpInst* IRBuilder::CreateFCmpOGT(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<FcmpInst>(
FcmpInst::Predicate::OGT, lhs, rhs, Type::GetInt1Type(), name);
}
FcmpInst* IRBuilder::CreateFCmpOGE(Value* lhs, Value* rhs, const std::string& name) {
return insert_block_->Append<FcmpInst>(
FcmpInst::Predicate::OGE, lhs, rhs, Type::GetInt1Type(), name);
}
// 类型转换
SIToFPInst* IRBuilder::CreateSIToFP(Value* value, std::shared_ptr<Type> target_ty,
const std::string& name) {
return insert_block_->Append<SIToFPInst>(value, target_ty, name);
}
FPToSIInst* IRBuilder::CreateFPToSI(Value* value, std::shared_ptr<Type> target_ty,
const std::string& name) {
return insert_block_->Append<FPToSIInst>(value, target_ty, name);
}
} // namespace ir