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.

264 lines
7.5 KiB

#include "ir/IR.h"
#include <stdexcept>
namespace ir {
User::User(std::shared_ptr<Type> 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<Value*>& 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<long long>(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<Type> 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<const Instruction*>(value)->GetOpcode());
}
BinaryInst::BinaryInst(Opcode opcode, std::shared_ptr<Type> 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<const Instruction*>(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<Type> 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<Type> 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<Type> 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<BasicBlock>(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<BasicBlock>(GetOperand(1));
}
BasicBlock* CondBrInst::GetElseBlock() const {
return dyncast<BasicBlock>(GetOperand(2));
}
UnreachableInst::UnreachableInst(BasicBlock* parent)
: Instruction(Opcode::Unreachable, Type::GetVoidType(), parent, "") {}
CallInst::CallInst(Function* callee, const std::vector<Value*>& args,
BasicBlock* parent, const std::string& name)
: Instruction(Opcode::Call, callee->GetReturnType(), parent, name) {
AddOperand(callee);
AddOperands(args);
}
Function* CallInst::GetCallee() const { return dyncast<Function>(GetOperand(0)); }
std::vector<Value*> CallInst::GetArguments() const {
std::vector<Value*> args;
for (size_t i = 1; i < GetNumOperands(); ++i) {
args.push_back(GetOperand(i));
}
return args;
}
GetElementPtrInst::GetElementPtrInst(std::shared_ptr<Type> source_type,
Value* ptr,
const std::vector<Value*>& 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> 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<BasicBlock>(GetOperand(static_cast<size_t>(2 * index + 1)));
}
ZextInst::ZextInst(Value* value, std::shared_ptr<Type> 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