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
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
|