238 lines
6.8 KiB
C++
238 lines
6.8 KiB
C++
#pragma once
|
|
#include "common.h"
|
|
#include "llir_type.h"
|
|
#include "llir_value.h"
|
|
#include <cassert>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace antlrSysY {
|
|
enum class InstTag {
|
|
Add,
|
|
Sub,
|
|
Mod,
|
|
Mul,
|
|
Div,
|
|
Lt,
|
|
Le,
|
|
Ge,
|
|
Gt,
|
|
Eq,
|
|
Ne,
|
|
And,
|
|
Or,
|
|
Br,
|
|
Call,
|
|
Ret,
|
|
Alloca,
|
|
Load,
|
|
Store,
|
|
GEP,
|
|
Zext,
|
|
Phi,
|
|
MemPhi,
|
|
LoadDep,
|
|
InsertEle,
|
|
ExtractEle
|
|
};
|
|
|
|
class Instruction : public User {
|
|
public:
|
|
int ir_seqno = -1;
|
|
InstTag tag;
|
|
BasicBlockPtr_t parent_bb;
|
|
Instruction(InstTag inst_tag, TypePtr_t type, BasicBlockPtr_t parent_bb)
|
|
: User("", type), tag(inst_tag), parent_bb(parent_bb) {}
|
|
virtual std::string to_string() override {
|
|
switch (tag) {
|
|
case InstTag::Add: return "add";
|
|
case InstTag::Sub: return "sub";
|
|
case InstTag::Mod: return "srem";
|
|
case InstTag::Mul: return "mul";
|
|
case InstTag::Div: return "sdiv";
|
|
case InstTag::Lt: return "icmp slt";
|
|
case InstTag::Le: return "icmp sle";
|
|
case InstTag::Ge: return "icmp sge";
|
|
case InstTag::Gt: return "icmp sgt";
|
|
case InstTag::Eq: return "icmp eq";
|
|
case InstTag::Ne: return "icmp ne";
|
|
case InstTag::And: return "and";
|
|
case InstTag::Or: return "or";
|
|
case InstTag::Br: return "br";
|
|
case InstTag::Call: return "call";
|
|
case InstTag::Ret: return "ret";
|
|
case InstTag::Alloca: return "alloca";
|
|
case InstTag::Load: return "load";
|
|
case InstTag::Store: return "store";
|
|
case InstTag::GEP: return "GEP";
|
|
case InstTag::Zext: return "zext";
|
|
case InstTag::Phi: return "Phi";
|
|
case InstTag::MemPhi: return "MemPhi";
|
|
case InstTag::LoadDep: return "LoadDep";
|
|
case InstTag::InsertEle: return "InsertEle";
|
|
case InstTag::ExtractEle: return "ExtractEle";
|
|
}
|
|
}
|
|
};
|
|
|
|
class InstAlloca : public Instruction {
|
|
public:
|
|
InstAlloca(TypePtr_t alloc_type, std::shared_ptr<BasicBlock> parent_bb)
|
|
: Instruction(InstTag::Alloca, std::make_shared<PointerType>(alloc_type), parent_bb) {}
|
|
virtual std::string to_IR_string() override {
|
|
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
|
return str;
|
|
}
|
|
};
|
|
|
|
class InstStore : public Instruction {
|
|
public:
|
|
InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer, std::shared_ptr<BasicBlock> parent_bb)
|
|
: Instruction(InstTag::Store, TypeHelper::TYPE_VOID, parent_bb) {
|
|
assert(value);
|
|
Add_Operand(value);
|
|
Add_Operand(pointer);
|
|
}
|
|
};
|
|
|
|
class InstLoad : public Instruction {
|
|
public:
|
|
InstLoad(std::shared_ptr<Value> value, TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb)
|
|
: Instruction(InstTag::Load, type, parent_bb) {
|
|
Add_Operand(value);
|
|
}
|
|
virtual std::string to_IR_string() override {
|
|
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
|
return str;
|
|
}
|
|
};
|
|
|
|
class InstBinary : public Instruction {
|
|
public:
|
|
InstBinary(
|
|
InstTag inst_tag,
|
|
TypePtr_t val_type,
|
|
std::shared_ptr<Value> op1,
|
|
std::shared_ptr<Value> op2,
|
|
std::shared_ptr<BasicBlock> parent_bb
|
|
)
|
|
: Instruction(inst_tag, val_type, parent_bb) {
|
|
Add_Operand(op1);
|
|
Add_Operand(op2);
|
|
}
|
|
virtual std::string to_IR_string() override {
|
|
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
|
return str;
|
|
}
|
|
};
|
|
|
|
//<result> = zext <ty> <value> to <ty2>
|
|
// zext is integer type, i32
|
|
class InstZext : public Instruction {
|
|
public:
|
|
InstZext(std::shared_ptr<Value> op, std::shared_ptr<BasicBlock> parent_bb)
|
|
: Instruction(InstTag::Zext, TypeHelper::TYPE_I32, parent_bb) {
|
|
Add_Operand(op);
|
|
}
|
|
virtual std::string to_IR_string() override {
|
|
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
|
return str;
|
|
}
|
|
};
|
|
|
|
class InstBranch : public Instruction {
|
|
public:
|
|
// conditional branch
|
|
InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, BasicBlockPtr_t parent_bb)
|
|
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
|
|
this->Add_Operand(cond);
|
|
this->Add_Operand(true_block);
|
|
this->Add_Operand(false_block);
|
|
}
|
|
// unconditional branch
|
|
InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb)
|
|
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
|
|
this->Add_Operand(target_block);
|
|
}
|
|
};
|
|
|
|
class InstReturn : public Instruction {
|
|
public:
|
|
InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb)
|
|
: Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {
|
|
this->Add_Operand(ret_val);
|
|
}
|
|
InstReturn(BasicBlockPtr_t parent_bb) : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {}
|
|
};
|
|
|
|
// call's type is the function's return type
|
|
class InstCall : public Instruction {
|
|
public:
|
|
InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args, BasicBlockPtr_t parent_bb)
|
|
: Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) {
|
|
Add_Operand(func);
|
|
for (auto arg : args) {
|
|
Add_Operand(arg);
|
|
}
|
|
}
|
|
virtual std::string to_IR_string() override {
|
|
if (Type::isType<VoidType>(type)) {
|
|
panic("No ret val");
|
|
}
|
|
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
|
return str;
|
|
}
|
|
};
|
|
|
|
// getelementptr <ty>, ptr <ptrval>{, [inrange] <ty> <idx>}*
|
|
// Example: lea arr[2][3] from arr[5][4]:
|
|
// &arr[2][3] = GEP [5x[4xi32]], [5x[4xi32]]* arr, i32 0, i32 2, i32 3
|
|
class InstGEP : public Instruction {
|
|
public:
|
|
ValuePtr_t aim_to;
|
|
TypePtr_t element_type;
|
|
InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices, BasicBlockPtr_t parent_bb)
|
|
: Instruction(InstTag::GEP, std::make_shared<PointerType>(extract_type(pointer, indices)), parent_bb) {
|
|
if (Value::is<InstGEP>(pointer)) {
|
|
aim_to = std::dynamic_pointer_cast<InstGEP>(pointer)->aim_to;
|
|
}
|
|
else if (Value::is<InstAlloca>(pointer) || Value::is<GlobalVar>(pointer)) {
|
|
aim_to = pointer;
|
|
}
|
|
else {
|
|
// LOG(WARNING) << "Unexpected pointer type " << pointer->to_string();
|
|
aim_to = nullptr;
|
|
}
|
|
element_type = extract_type(pointer, indices);
|
|
Add_Operand(pointer);
|
|
for (auto index : indices) {
|
|
Add_Operand(index);
|
|
}
|
|
}
|
|
|
|
virtual std::string to_IR_string() override {
|
|
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
|
return str;
|
|
}
|
|
|
|
// get the inner
|
|
static TypePtr_t extract_type(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices) {
|
|
auto pointer_type = std::dynamic_pointer_cast<PointerType>(pointer->type);
|
|
auto pointed_type = pointer_type->pointed_type;
|
|
if (pointed_type->type_tag == Type::TypeTag::IntegerType) {
|
|
return pointed_type;
|
|
}
|
|
else if (Type::isType<ArrayType>(pointed_type)) {
|
|
for (int i = 1; i < indices.size(); ++i) {
|
|
pointed_type = std::dynamic_pointer_cast<ArrayType>(pointed_type)->element_type;
|
|
}
|
|
return pointed_type;
|
|
}
|
|
else {
|
|
LOG(ERROR) << "unexpected type: " << pointer->to_string();
|
|
assert(0);
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace antlrSysY
|