// IR 构建工具：
// - 管理插入点（当前基本块/位置）
// - 提供创建各类指令的便捷接口，降低 IRGen 复杂度

#include "ir/IR.h"
#include <stdexcept>

namespace ir {
IRBuilder::IRBuilder(Context& ctx, BasicBlock* bb)
    : ctx_(ctx), insertBlock_(bb) {}

void IRBuilder::SetInsertPoint(BasicBlock* bb) { insertBlock_ = bb; }

BasicBlock* IRBuilder::GetInsertBlock() const { return insertBlock_; }

ConstantInt* IRBuilder::CreateConstInt(int v) {
  // 常量不需要挂在基本块里，由 Context 负责去重与生命周期。
  return ctx_.GetConstInt(v);
}

BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
                                    const std::string& name) {
  if (!insertBlock_) {
    throw std::runtime_error("IRBuilder 未设置插入点");
  }
  if (!lhs) {
    throw std::runtime_error("IRBuilder::CreateBinary 缺少 lhs");
  }
  if (!rhs) {
    throw std::runtime_error("IRBuilder::CreateBinary 缺少 rhs");
  }
  return insertBlock_->Append<BinaryInst>(op, lhs->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 (!insertBlock_) {
    throw std::runtime_error("IRBuilder 未设置插入点");
  }
  return insertBlock_->Append<AllocaInst>(ctx_.PtrInt32(), name);
}

LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
  if (!insertBlock_) {
    throw std::runtime_error("IRBuilder 未设置插入点");
  }
  if (!ptr) {
    throw std::runtime_error("IRBuilder::CreateLoad 缺少 ptr");
  }
  return insertBlock_->Append<LoadInst>(ctx_.Int32(), ptr, name);
}

StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {
  if (!insertBlock_) {
    throw std::runtime_error("IRBuilder 未设置插入点");
  }
  if (!val) {
    throw std::runtime_error("IRBuilder::CreateStore 缺少 val");
  }
  if (!ptr) {
    throw std::runtime_error("IRBuilder::CreateStore 缺少 ptr");
  }
  return insertBlock_->Append<StoreInst>(ctx_.Void(), val, ptr);
}

ReturnInst* IRBuilder::CreateRet(Value* v) {
  if (!insertBlock_) {
    throw std::runtime_error("IRBuilder 未设置插入点");
  }
  if (!v) {
    throw std::runtime_error("IRBuilder::CreateRet 缺少返回值");
  }
  return insertBlock_->Append<ReturnInst>(ctx_.Void(), v);
}

}  // namespace ir
