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.
179 lines
5.8 KiB
179 lines
5.8 KiB
#include "ir/IR.h"
|
|
|
|
#include <stdexcept>
|
|
|
|
namespace ir {
|
|
namespace {
|
|
|
|
void RequireInsertBlock(BasicBlock* bb) {
|
|
if (!bb) {
|
|
throw std::runtime_error("IRBuilder 未设置插入点");
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<Type> InferLoadType(Value* ptr) {
|
|
if (!ptr || !ptr->GetType() || !ptr->GetType()->IsPointer()) {
|
|
throw std::runtime_error("CreateLoad 需要指针");
|
|
}
|
|
return ptr->GetType()->GetElementType();
|
|
}
|
|
|
|
std::shared_ptr<Type> InferGEPResultType(Value* base_ptr,
|
|
const std::vector<Value*>& indices) {
|
|
if (!base_ptr || !base_ptr->GetType() || !base_ptr->GetType()->IsPointer()) {
|
|
throw std::runtime_error("CreateGEP 需要指针基址");
|
|
}
|
|
auto current = base_ptr->GetType()->GetElementType();
|
|
for (size_t i = 0; i < indices.size(); ++i) {
|
|
auto* index = indices[i];
|
|
(void)index;
|
|
if (!current) {
|
|
throw std::runtime_error("CreateGEP 遇到空类型");
|
|
}
|
|
if (i == 0) {
|
|
continue;
|
|
}
|
|
if (current->IsArray()) {
|
|
current = current->GetElementType();
|
|
continue;
|
|
}
|
|
if (current->IsPointer()) {
|
|
current = current->GetElementType();
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return Type::GetPointerType(current);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
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) { return ctx_.GetConstInt(v); }
|
|
|
|
ConstantFloat* IRBuilder::CreateConstFloat(float v) { return ctx_.GetConstFloat(v); }
|
|
|
|
ConstantValue* IRBuilder::CreateZero(std::shared_ptr<Type> type) {
|
|
if (!type) {
|
|
throw std::runtime_error("CreateZero 缺少类型");
|
|
}
|
|
if (type->IsInt1() || type->IsInt32()) {
|
|
return CreateConstInt(0);
|
|
}
|
|
if (type->IsFloat32()) {
|
|
return CreateConstFloat(0.0f);
|
|
}
|
|
return ctx_.CreateOwnedConstant<ConstantZero>(type);
|
|
}
|
|
|
|
BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
if (!lhs || !rhs) {
|
|
throw std::runtime_error("CreateBinary 缺少操作数");
|
|
}
|
|
return insert_block_->Append<BinaryInst>(op, lhs->GetType(), lhs, rhs, name);
|
|
}
|
|
|
|
AllocaInst* IRBuilder::CreateAlloca(std::shared_ptr<Type> allocated_type,
|
|
const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
auto* parent = insert_block_->GetParent();
|
|
if (!parent || !parent->GetEntry()) {
|
|
throw std::runtime_error("CreateAlloca 需要所在函数入口块");
|
|
}
|
|
return parent->GetEntry()->Append<AllocaInst>(std::move(allocated_type), name);
|
|
}
|
|
|
|
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
|
|
return CreateAlloca(Type::GetInt32Type(), name);
|
|
}
|
|
|
|
LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<LoadInst>(ptr, InferLoadType(ptr), name);
|
|
}
|
|
|
|
StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<StoreInst>(val, ptr);
|
|
}
|
|
|
|
CompareInst* IRBuilder::CreateICmp(ICmpPred pred, Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<CompareInst>(pred, lhs, rhs, name);
|
|
}
|
|
|
|
CompareInst* IRBuilder::CreateFCmp(FCmpPred pred, Value* lhs, Value* rhs,
|
|
const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<CompareInst>(pred, lhs, rhs, name);
|
|
}
|
|
|
|
BranchInst* IRBuilder::CreateBr(BasicBlock* target) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<BranchInst>(target);
|
|
}
|
|
|
|
CondBranchInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* true_block,
|
|
BasicBlock* false_block) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<CondBranchInst>(cond, true_block, false_block);
|
|
}
|
|
|
|
CallInst* IRBuilder::CreateCall(Function* callee, const std::vector<Value*>& args,
|
|
const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
std::string actual_name = name;
|
|
if (callee && callee->GetReturnType()->IsVoid()) {
|
|
actual_name.clear();
|
|
}
|
|
return insert_block_->Append<CallInst>(callee, args, actual_name);
|
|
}
|
|
|
|
GetElementPtrInst* IRBuilder::CreateGEP(Value* base_ptr,
|
|
const std::vector<Value*>& indices,
|
|
const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<GetElementPtrInst>(
|
|
base_ptr, indices, InferGEPResultType(base_ptr, indices), name);
|
|
}
|
|
|
|
CastInst* IRBuilder::CreateSIToFP(Value* value, const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<CastInst>(Opcode::SIToFP, value,
|
|
Type::GetFloatType(), name);
|
|
}
|
|
|
|
CastInst* IRBuilder::CreateFPToSI(Value* value, const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<CastInst>(Opcode::FPToSI, value,
|
|
Type::GetInt32Type(), name);
|
|
}
|
|
|
|
CastInst* IRBuilder::CreateZExt(Value* value, std::shared_ptr<Type> dst_type,
|
|
const std::string& name) {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<CastInst>(Opcode::ZExt, value, std::move(dst_type),
|
|
name);
|
|
}
|
|
|
|
ReturnInst* IRBuilder::CreateRet(Value* value) {
|
|
RequireInsertBlock(insert_block_);
|
|
return value ? insert_block_->Append<ReturnInst>(value)
|
|
: insert_block_->Append<ReturnInst>();
|
|
}
|
|
|
|
ReturnInst* IRBuilder::CreateRetVoid() {
|
|
RequireInsertBlock(insert_block_);
|
|
return insert_block_->Append<ReturnInst>();
|
|
}
|
|
|
|
} // namespace ir
|