#include "ir/IR.h" #include namespace ir { User::User(std::shared_ptr ty, std::string name) : Value(std::move(ty), std::move(name)) {} Value* User::GetOperand(size_t index) const { if (index >= operands_.size()) { throw std::out_of_range("operand index out of range"); } return operands_[index].GetValue(); } void User::SetOperand(size_t index, Value* value) { if (index >= operands_.size()) { throw std::out_of_range("operand index out of range"); } auto* old_value = operands_[index].GetValue(); if (old_value == value) { return; } if (old_value) { old_value->RemoveUse(this, index); } operands_[index].SetValue(value); if (value) { value->AddUse(this, index); } } void User::AddOperand(Value* value) { if (!value) { throw std::runtime_error("operand cannot be null"); } operands_.emplace_back(value, this, operands_.size()); value->AddUse(this, operands_.size() - 1); } void User::AddOperands(const std::vector& values) { for (auto* value : values) { AddOperand(value); } } void User::RemoveOperand(size_t index) { if (index >= operands_.size()) { throw std::out_of_range("operand index out of range"); } if (auto* value = operands_[index].GetValue()) { value->RemoveUse(this, index); } operands_.erase(operands_.begin() + static_cast(index)); for (size_t i = index; i < operands_.size(); ++i) { if (auto* value = operands_[i].GetValue()) { value->RemoveUse(this, i + 1); value->AddUse(this, i); } operands_[i].SetOperandIndex(i); } } void User::ClearAllOperands() { for (size_t i = 0; i < operands_.size(); ++i) { if (auto* value = operands_[i].GetValue()) { value->RemoveUse(this, i); } } operands_.clear(); } Instruction::Instruction(Opcode opcode, std::shared_ptr ty, BasicBlock* parent, const std::string& name) : User(std::move(ty), name), opcode_(opcode), parent_(parent) {} bool Instruction::IsTerminator() const { return opcode_ == Opcode::Br || opcode_ == Opcode::CondBr || opcode_ == Opcode::Return || opcode_ == Opcode::Unreachable; } static bool IsBinaryOpcode(Opcode opcode) { switch (opcode) { case Opcode::Add: case Opcode::Sub: case Opcode::Mul: case Opcode::Div: case Opcode::Rem: case Opcode::FAdd: case Opcode::FSub: case Opcode::FMul: case Opcode::FDiv: case Opcode::FRem: case Opcode::And: case Opcode::Or: case Opcode::Xor: case Opcode::Shl: case Opcode::AShr: case Opcode::LShr: case Opcode::ICmpEQ: case Opcode::ICmpNE: case Opcode::ICmpLT: case Opcode::ICmpGT: case Opcode::ICmpLE: case Opcode::ICmpGE: case Opcode::FCmpEQ: case Opcode::FCmpNE: case Opcode::FCmpLT: case Opcode::FCmpGT: case Opcode::FCmpLE: case Opcode::FCmpGE: return true; default: return false; } } bool BinaryInst::classof(const Value* value) { return value && Instruction::classof(value) && IsBinaryOpcode(static_cast(value)->GetOpcode()); } BinaryInst::BinaryInst(Opcode opcode, std::shared_ptr ty, Value* lhs, Value* rhs, BasicBlock* parent, const std::string& name) : Instruction(opcode, std::move(ty), parent, name) { AddOperand(lhs); AddOperand(rhs); } bool UnaryInst::classof(const Value* value) { if (!value || !Instruction::classof(value)) { return false; } switch (static_cast(value)->GetOpcode()) { case Opcode::Neg: case Opcode::Not: case Opcode::FNeg: case Opcode::FtoI: case Opcode::IToF: return true; default: return false; } } UnaryInst::UnaryInst(Opcode opcode, std::shared_ptr ty, Value* operand, BasicBlock* parent, const std::string& name) : Instruction(opcode, std::move(ty), parent, name) { AddOperand(operand); } ReturnInst::ReturnInst(Value* value, BasicBlock* parent) : Instruction(Opcode::Return, Type::GetVoidType(), parent, "") { if (value) { AddOperand(value); } } AllocaInst::AllocaInst(std::shared_ptr allocated_type, BasicBlock* parent, const std::string& name) : Instruction(Opcode::Alloca, Type::GetPointerType(allocated_type), parent, name), allocated_type_(std::move(allocated_type)) {} LoadInst::LoadInst(std::shared_ptr value_type, Value* ptr, BasicBlock* parent, const std::string& name) : Instruction(Opcode::Load, std::move(value_type), parent, name) { AddOperand(ptr); } StoreInst::StoreInst(Value* value, Value* ptr, BasicBlock* parent) : Instruction(Opcode::Store, Type::GetVoidType(), parent, "") { AddOperand(value); AddOperand(ptr); } UncondBrInst::UncondBrInst(BasicBlock* dest, BasicBlock* parent) : Instruction(Opcode::Br, Type::GetVoidType(), parent, "") { AddOperand(dest); } BasicBlock* UncondBrInst::GetDest() const { return dyncast(GetOperand(0)); } CondBrInst::CondBrInst(Value* cond, BasicBlock* then_block, BasicBlock* else_block, BasicBlock* parent) : Instruction(Opcode::CondBr, Type::GetVoidType(), parent, "") { AddOperand(cond); AddOperand(then_block); AddOperand(else_block); } BasicBlock* CondBrInst::GetThenBlock() const { return dyncast(GetOperand(1)); } BasicBlock* CondBrInst::GetElseBlock() const { return dyncast(GetOperand(2)); } UnreachableInst::UnreachableInst(BasicBlock* parent) : Instruction(Opcode::Unreachable, Type::GetVoidType(), parent, "") {} CallInst::CallInst(Function* callee, const std::vector& args, BasicBlock* parent, const std::string& name) : Instruction(Opcode::Call, callee->GetReturnType(), parent, name) { AddOperand(callee); AddOperands(args); } Function* CallInst::GetCallee() const { return dyncast(GetOperand(0)); } std::vector CallInst::GetArguments() const { std::vector args; for (size_t i = 1; i < GetNumOperands(); ++i) { args.push_back(GetOperand(i)); } return args; } GetElementPtrInst::GetElementPtrInst(std::shared_ptr source_type, Value* ptr, const std::vector& indices, BasicBlock* parent, const std::string& name) : Instruction(Opcode::GetElementPtr, Type::GetPointerType(), parent, name), source_type_(std::move(source_type)) { AddOperand(ptr); AddOperands(indices); } PhiInst::PhiInst(std::shared_ptr type, BasicBlock* parent, const std::string& name) : Instruction(Opcode::Phi, std::move(type), parent, name) {} void PhiInst::AddIncoming(Value* value, BasicBlock* block) { AddOperand(value); AddOperand(block); } BasicBlock* PhiInst::GetIncomingBlock(int index) const { return dyncast(GetOperand(static_cast(2 * index + 1))); } ZextInst::ZextInst(Value* value, std::shared_ptr target_type, BasicBlock* parent, const std::string& name) : Instruction(Opcode::Zext, std::move(target_type), parent, name) { AddOperand(value); } MemsetInst::MemsetInst(Value* dst, Value* value, Value* len, Value* is_volatile, BasicBlock* parent) : Instruction(Opcode::Memset, Type::GetVoidType(), parent, "") { AddOperand(dst); AddOperand(value); AddOperand(len); AddOperand(is_volatile); } } // namespace ir