buggy ir gen

This commit is contained in:
ridethepig 2023-05-13 10:37:31 +08:00
parent db20cad1df
commit 53b6e3e33f
14 changed files with 993 additions and 348 deletions

View File

@ -1,3 +1,4 @@
# https://releases.llvm.org/15.0.0/tools/clang/docs/ClangFormatStyleOptions.html
---
Language: Cpp
BasedOnStyle: LLVM
@ -21,8 +22,8 @@ AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
@ -87,13 +88,13 @@ MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakBeforeFirstCallParameter: 15
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyExcessCharacter: 10000
PenaltyReturnTypeOnItsOwnLine: 100000
PointerAlignment: Right
ReflowComments: true
SortIncludes: true

2
.vscode/launch.json vendored
View File

@ -9,7 +9,7 @@
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/build/sysy",
"args": ["testcases/functional/55_sort_test1.sy", "-S", "-o", "sss"],
"args": ["build/ManualTest/a.c", "-S", "-o", "sss"],
"cwd": "${workspaceFolder}"
}
]

View File

@ -1,6 +1,5 @@
#pragma once
#include "3rdparty/easylogging++.h"
#include <any>
#include <exception>
#include <optional>
@ -14,8 +13,7 @@
#define sysy_assert(cond) \
do { \
if (!(cond)) \
throw GrammarException(__FILE__, __LINE__, #cond); \
if (!(cond)) throw GrammarException(__FILE__, __LINE__, #cond); \
} while (0)
namespace antlrSysY {

View File

@ -1,5 +1,10 @@
#pragma once
#include "common.h"
#include "llir_type.h"
#include "llir_value.h"
#include <cassert>
#include <sstream>
#include <string>
namespace antlrSysY {
enum class InstTag {
@ -33,65 +38,40 @@ enum class InstTag {
class Instruction : public Value {
public:
int ir_seqno = -1;
InstTag tag;
std::shared_ptr<BasicBlock> parent_bb;
std::vector<std::shared_ptr<Value>> operand_list;
Instruction(InstTag inst_tag, TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb)
: Value("", type), tag(inst_tag), parent_bb(parent_bb) {}
: Value("", 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 "Mod";
case InstTag::Mul:
return "Mul";
case InstTag::Div:
return "Div";
case InstTag::Lt:
return "Lt";
case InstTag::Le:
return "Le";
case InstTag::Ge:
return "Ge";
case InstTag::Gt:
return "Gt";
case InstTag::Eq:
return "Eq";
case InstTag::Ne:
return "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";
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";
}
}
};
@ -99,13 +79,17 @@ public:
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) {}
: 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) {
: Instruction(InstTag::Store, TypeHelper::TYPE_VOID, parent_bb) {
operand_list.push_back(value);
operand_list.push_back(pointer);
}
@ -114,41 +98,60 @@ public:
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) {
: Instruction(InstTag::Load, type, parent_bb) {
operand_list.push_back(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) {
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) {
operand_list.push_back(op1);
operand_list.push_back(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) {
: Instruction(InstTag::Zext, TypeHelper::TYPE_I32, parent_bb) {
operand_list.push_back(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) {
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
this->operand_list.push_back(cond);
this->operand_list.push_back(true_block);
this->operand_list.push_back(false_block);
}
// unconditional branch
InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb)
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
this->operand_list.push_back(target_block);
}
};
@ -156,19 +159,27 @@ public:
class InstReturn : public Instruction {
public:
InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb)
: Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {
: Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {
this->operand_list.push_back(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) {
: Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) {
operand_list.push_back(func);
operand_list.insert(operand_list.end(), args.begin(), args.end());
}
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>}*
@ -179,11 +190,11 @@ 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::isType<InstGEP>(pointer)) {
: Instruction(InstTag::GEP, std::make_shared<PointerType>(extract_type(pointer, indices)), parent_bb) {
if (Value::isValueType<InstGEP>(pointer)) {
aim_to = std::dynamic_pointer_cast<InstGEP>(pointer)->aim_to;
}
else if (Value::isType<InstAlloca>(pointer) || Value::isType<GlobalVar>(pointer)){
else if (Value::isValueType<InstAlloca>(pointer) || Value::isValueType<GlobalVar>(pointer)) {
aim_to = pointer;
}
else {
@ -195,6 +206,11 @@ public:
operand_list.insert(operand_list.end(), indices.begin(), indices.end());
}
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);
@ -215,4 +231,4 @@ public:
}
};
}
} // namespace antlrSysY

View File

@ -1,7 +1,7 @@
#pragma once
#include "llir_instruction.h"
#include "llir_type.h"
#include "llir_value.h"
#include "llir_instruction.h"
#include <memory>
#include <vector>
@ -11,4 +11,4 @@ struct Module {
std::vector<std::shared_ptr<GlobalVar>> global_var_list;
std::vector<std::shared_ptr<Instruction>> instruction_list;
};
}
} // namespace antlrSysY

View File

@ -22,22 +22,29 @@ public:
virtual ~Type() = default;
virtual std::string to_string() {
switch (type_tag) {
case TypeTag::IntegerType:
return "IntegerType";
case TypeTag::FunctionType:
return "FunctionType";
case TypeTag::ArrayType:
return "ArrayType";
case TypeTag::PointerType:
return "PointerType";
case TypeTag::VectorType:
return "VectorType";
case TypeTag::VoidType:
return "VoidType";
case TypeTag::LabelType:
return "LabelType";
case TypeTag::IntegerType: return "IntegerType";
case TypeTag::FunctionType: return "FunctionType";
case TypeTag::ArrayType: return "ArrayType";
case TypeTag::PointerType: return "PointerType";
case TypeTag::VectorType: return "VectorType";
case TypeTag::VoidType: return "VoidType";
case TypeTag::LabelType: return "LabelType";
}
}
template <typename TT>
static bool isType(std::shared_ptr<Type> ptr) {
if (ptr) {
return dynamic_cast<TT*>(ptr.get()) != nullptr;
}
else {
return false;
}
}
template <typename TT>
static std::shared_ptr<TT> asType(std::shared_ptr<Type> ptr) {
return std::dynamic_pointer_cast<TT>(ptr);
}
virtual std::string to_IR_string() = 0;
};
class IntegerType : public Type {
@ -51,16 +58,28 @@ public:
bool isI1() {
return int_type == IntTypes::I1;
}
virtual std::string to_IR_string() override {
if (isI1())
return "i1";
else
return "i32";
}
};
class VoidType : public Type {
public:
VoidType() : Type(TypeTag::VoidType) {}
virtual std::string to_IR_string() override {
return "void";
}
};
class LabelType : public Type {
public:
LabelType() : Type(TypeTag::LabelType) {}
virtual std::string to_IR_string() override {
panic("Cannot generate LabelType");
}
};
typedef std::shared_ptr<Type> TypePtr_t;
@ -76,19 +95,19 @@ public:
static bool isIntegerTypeI1(TypePtr_t &type) {
return isIntegerType(type) && std::dynamic_pointer_cast<IntegerType>(type)->isI1();
}
inline static TypePtr_t TYPE_I32 = std::make_shared<IntegerType>();
inline static TypePtr_t TYPE_I1 = std::make_shared<IntegerType>(IntegerType::IntTypes::I1);
inline static TypePtr_t TYPE_I32 = std::make_shared<IntegerType>();
inline static TypePtr_t TYPE_I1 = std::make_shared<IntegerType>(IntegerType::IntTypes::I1);
inline static TypePtr_t TYPE_LABEL = std::make_shared<LabelType>();
inline static TypePtr_t TYPE_VOID = std::make_shared<VoidType>();
inline static TypePtr_t TYPE_VOID = std::make_shared<VoidType>();
};
class ArrayType : public Type {
public:
TypePtr_t element_type = TypeHelper::TYPE_I32;
int element_count = 0;
int element_count = 0;
ArrayType() : Type(TypeTag::ArrayType) {}
ArrayType(TypePtr_t element_type, int element_count)
: Type(TypeTag::ArrayType), element_count(element_count), element_type(element_type) {}
: Type(TypeTag::ArrayType), element_count(element_count), element_type(element_type) {}
static std::shared_ptr<ArrayType> build_from_list(const std::vector<int> &dim_list) {
TypePtr_t array_type = TypeHelper::TYPE_I32;
sysy_assert(dim_list.size() != 0);
@ -100,6 +119,9 @@ public:
virtual std::string to_string() override {
return "Array[" + std::to_string(element_count) + " x " + element_type->to_string() + "]";
}
virtual std::string to_IR_string() override {
return "[" + std::to_string(element_count) + " x " + element_type->to_IR_string() + "]";
}
};
class PointerType : public Type {
@ -113,6 +135,12 @@ public:
virtual std::string to_string() override {
return "Pointer->" + pointed_type->to_string();
}
virtual std::string to_IR_string() override {
if (pointed_type->type_tag == TypeTag::IntegerType) {
return "i32*";
}
panic("Unknown");
}
};
class FunctionType : public Type {
@ -121,7 +149,10 @@ public:
std::vector<TypePtr_t> params_type;
FunctionType(TypePtr_t return_type) : Type(TypeTag::FunctionType), return_type(return_type) {}
FunctionType(TypePtr_t return_type, const std::vector<TypePtr_t> &params_type)
: Type(TypeTag::FunctionType), return_type(return_type), params_type(params_type) {}
: Type(TypeTag::FunctionType), return_type(return_type), params_type(params_type) {}
virtual std::string to_IR_string() override {
panic("Cannot generate FunctionType");
}
};
} // namespace antlrSysY

View File

@ -1,13 +1,13 @@
#pragma once
#include <memory>
#include <shared_mutex>
#include <string>
#include <vector>
#include "3rdparty/easylogging++.h"
#include "common.h"
#include "llir_type.h"
#include <list>
#include <memory>
#include <shared_mutex>
#include <string>
#include <vector>
namespace antlrSysY {
@ -17,17 +17,31 @@ public:
TypePtr_t type;
Value(const std::string &name, TypePtr_t type) : name(name), type(type) {}
virtual ~Value() = default;
template <typename TT> static bool isType(std::shared_ptr<Value> ptr) {
template <typename TT>
static bool isValueType(std::shared_ptr<Value> ptr) {
if (ptr.get()) {
auto &r = *ptr.get();
return typeid(r) == typeid(TT);
// auto &r = *ptr.get();
// return typeid(r) == typeid(TT);
return dynamic_cast<TT*>(ptr.get()) != nullptr;
}
LOG(WARNING) << "Comparing with nullptr";
return false;
}
// it is caller's duty to check before use `asType`
template <typename TT>
static std::shared_ptr<TT> asValueType(std::shared_ptr<Value> ptr) {
return std::dynamic_pointer_cast<TT>(ptr);
}
virtual std::string to_string() {
return name + ": " + type->to_string();
}
virtual std::string to_IR_string() {
panic("No applicable for IR gen");
}
};
class User : public Value {
@ -39,13 +53,16 @@ class Instruction;
class FParam : public Value {
public:
int ir_seqno = -1;
FParam(const std::string &name, TypePtr_t type) : Value(name, type) {}
};
typedef std::list<std::shared_ptr<antlrSysY::BasicBlock>>::iterator BasicBlockListNode_t;
class Function : public Value {
public:
std::vector<std::shared_ptr<FParam>> fparam_list;
std::vector<std::shared_ptr<BasicBlock>> bb_list;
std::list<std::shared_ptr<BasicBlock>> bb_list;
// we use empty basic_block to represent lib function
Function(const std::string &name, TypePtr_t ret_type) : Value(name, std::make_shared<FunctionType>(ret_type)) {}
std::shared_ptr<FunctionType> get_type() {
@ -65,8 +82,10 @@ public:
class BasicBlock : public Value {
public:
int ir_seqno = -1;
std::vector<std::shared_ptr<Instruction>> inst_list;
std::shared_ptr<Function> parent;
BasicBlockListNode_t itr;
std::vector<std::shared_ptr<BasicBlock>> successors;
std::vector<std::shared_ptr<BasicBlock>> predecessors;
BasicBlock(const std::string &name, std::shared_ptr<Function> parent) : Value(name, TypeHelper::TYPE_LABEL) {
@ -90,17 +109,45 @@ public:
static std::shared_ptr<ConstantInt> make_shared(int value) {
return std::make_shared<ConstantInt>("", value);
}
virtual std::string to_string() override {
std::string str = type->to_string() + " " + std::to_string(value);
return str;
}
virtual std::string to_IR_string() override {
return to_string();
}
};
class ConstantArr : public Constant {
public:
std::vector<ValuePtr_t> value_list;
ConstantArr(const std::string &name, const std::vector<ValuePtr_t> &value_list, std::shared_ptr<ArrayType> type)
: Constant(name, type), value_list(value_list) {}
static std::shared_ptr<ConstantArr> make_shared(const std::string &name, const std::vector<ValuePtr_t> &value_list,
std::shared_ptr<ArrayType> type) {
: Constant(name, type), value_list(value_list) {}
int real_size() const {
return std::dynamic_pointer_cast<ArrayType>(type)->element_count;
}
static std::shared_ptr<ConstantArr> make_shared(
const std::string &name,
const std::vector<ValuePtr_t> &value_list,
std::shared_ptr<ArrayType> type
) {
return std::make_shared<ConstantArr>(name, value_list, type);
}
virtual std::string to_string() override {
std::string str = "{";
for (auto elem : value_list) {
if (elem)
str += elem->to_string() + ", ";
else
str += "{...}, ";
}
if (real_size() > value_list.size()) {
str += std::to_string(real_size() - value_list.size()) + " zeros";
}
str += "}";
return str;
}
};
typedef std::shared_ptr<Constant> ConstantPtr_t;
@ -111,10 +158,21 @@ public:
ConstantPtr_t init_value;
bool is_const;
GlobalVar(const std::string &name, ConstantPtr_t init_value, bool is_const)
: Value(name, PointerType::make_shared(init_value->type)), init_value(init_value), is_const(is_const) {}
: Value(name, PointerType::make_shared(init_value->type)), init_value(init_value), is_const(is_const) {}
static std::shared_ptr<GlobalVar> make_shared(const std::string &name, ConstantPtr_t init_value, bool is_const) {
return std::make_shared<GlobalVar>(name, init_value, is_const);
}
virtual std::string to_IR_string() override {
std::string str = type->to_IR_string() + " @" + name;
return str;
}
};
std::shared_ptr<ConstantArr> gen_arr_hierarchy(
const std::shared_ptr<ArrayType> array_type,
const std::vector<ValuePtr_t> &const_array,
int base,
int length
);
} // namespace antlrSysY

View File

@ -2,8 +2,8 @@
#include "common.h"
namespace antlrSysY {
template <typename T_V> class ScopeTable {
template <typename T_V>
class ScopeTable {
typedef std::map<std::string, T_V> ScopeTableEntry_t;
private:
@ -23,22 +23,19 @@ public:
sysy_assert(!pre_enter);
return;
}
if (pre_enter)
_pre_enter = true;
if (pre_enter) _pre_enter = true;
_scope_list.push_back(ScopeTableEntry_t());
};
void leave_scope() {
if (_scope_list.size() <= 1)
throw GrammarException("Unable to leave global scope");
if (_scope_list.size() <= 1) throw GrammarException("Unable to leave global scope");
_scope_list.pop_back();
};
void push_name(const std::string &name, const T_V &value) {
auto &current_scope = _scope_list.back();
if (current_scope.count(name))
throw GrammarException("Duplicate name in current scope");
if (current_scope.count(name)) throw GrammarException("Duplicate name in current scope");
current_scope[name] = value;
};

View File

@ -1,45 +1,63 @@
#pragma once
#include "3rdparty/easylogging++.h"
#include "antlrgen/SysyBaseVisitor.h"
#include "antlrgen/SysyLexer.h"
#include "antlrgen/SysyParser.h"
#include "common.h"
#include "llir_instruction.h"
#include "llir_module.h"
#include "llir_type.h"
#include "llir_value.h"
#include "scopetable.h"
#include <any>
#include <cstddef>
#include <map>
#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <vector>
#include "antlrgen/SysyLexer.h"
#include "antlrgen/SysyParser.h"
#include "common.h"
#include "llir_module.h"
#include "llir_type.h"
#include "llir_value.h"
#include "llir_instruction.h"
#include "scopetable.h"
namespace antlrSysY {
#pragma region FactoryFunctionDeclaration
std::shared_ptr<ConstantInt> build_ConstantInt(const std::string &name, int value);
std::shared_ptr<BasicBlock> build_BasicBlock(const std::string &name, std::shared_ptr<Function> parent);
std::shared_ptr<BasicBlock> build_BasicBlock(
const std::string &name,
std::shared_ptr<Function> parent,
const BasicBlockListNode_t &cur_bb_itr
);
std::shared_ptr<InstLoad> build_InstLoad(std::shared_ptr<Value> value, TypePtr_t type,
std::shared_ptr<BasicBlock> parent_bb);
std::shared_ptr<InstStore> build_InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer,
std::shared_ptr<BasicBlock> parent_bb);
std::shared_ptr<InstLoad> build_InstLoad(
std::shared_ptr<Value> value,
TypePtr_t type,
std::shared_ptr<BasicBlock> parent_bb
);
std::shared_ptr<InstStore> build_InstStore(
std::shared_ptr<Value> value,
std::shared_ptr<Value> pointer,
std::shared_ptr<BasicBlock> parent_bb
);
std::shared_ptr<InstAlloca> build_InstAlloca(TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb);
std::shared_ptr<InstBinary> build_InstBinary(InstTag inst_tag, std::shared_ptr<Value> op1, std::shared_ptr<Value> op2,
std::shared_ptr<BasicBlock> parent_bb);
std::shared_ptr<InstBinary> build_InstBinary(
InstTag inst_tag,
std::shared_ptr<Value> op1,
std::shared_ptr<Value> op2,
std::shared_ptr<BasicBlock> parent_bb
);
std::shared_ptr<InstZext> build_InstZext(std::shared_ptr<Value> op, std::shared_ptr<BasicBlock> parent_bb);
std::shared_ptr<InstBranch> build_InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block,
BasicBlockPtr_t parent_bb);
std::shared_ptr<InstBranch> build_InstBranch(
ValuePtr_t cond,
BasicBlockPtr_t true_block,
BasicBlockPtr_t false_block,
BasicBlockPtr_t parent_bb
);
std::shared_ptr<InstBranch> build_InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb);
@ -47,35 +65,42 @@ std::shared_ptr<InstReturn> build_InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t
std::shared_ptr<InstReturn> build_InstReturn(BasicBlockPtr_t parent_bb);
std::shared_ptr<InstCall> build_InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args,
BasicBlockPtr_t parent_bb);
std::shared_ptr<InstGEP> build_InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices,
BasicBlockPtr_t parent_bb);
std::shared_ptr<InstCall> build_InstCall(
FunctionPtr_t func,
const std::vector<ValuePtr_t> &args,
BasicBlockPtr_t parent_bb
);
std::shared_ptr<InstGEP> build_InstGEP(
ValuePtr_t pointer,
const std::vector<ValuePtr_t> &indices,
BasicBlockPtr_t parent_bb
);
#pragma endregion
class Visitor : public antlrSysY::SysyBaseVisitor {
private:
struct VisitorState {
bool isGlobalIint = false;
bool isConstInt = false;
bool isRealParam = false;
bool isCondExp = false;
bool isGlobalIint = false;
bool isConstInt = false;
bool isRealParam = false;
bool isCondExp = false;
std::shared_ptr<Function> current_func = {};
std::shared_ptr<BasicBlock> current_bb = {};
std::vector<int> *arr_dim_list = nullptr;
int arr_dim_index = 0;
std::vector<int> *arr_dim_list = nullptr;
int arr_dim_index = 0;
struct loop_record {
BasicBlockPtr_t cond, body, next;
int id;
};
int loop_stmt_count = 0;
int loop_stmt_count = 0;
std::vector<loop_record> loop_stack = {};
};
ScopeTable<std::shared_ptr<Value>> _scope_tab;
ScopeTable<std::shared_ptr<Function>> _func_tab; // var can have same name as func
VisitorState _state = {};
VisitorState _state = {};
inline static std::shared_ptr<ConstantInt> CONST0 = std::make_shared<ConstantInt>("CONST0", 0);
public:
@ -159,7 +184,7 @@ public:
std::any visitLOrExp(SysyParser::LOrExpContext *ctx) override;
void llir_gen();
void llir_gen(std::ostream &);
};
} // namespace antlrSysY

13
scripts/manual-compile.py Normal file
View File

@ -0,0 +1,13 @@
import sys
import os
assert len(sys.argv) > 2
print("compile {}".format(sys.argv[1]))
fullpath = sys.argv[1]
libpath = sys.argv[2]
(filename, extname) = os.path.splitext(sys.argv[1])
os.system(f"clang -emit-llvm -S {fullpath} -o {filename}.ll -O0 -fno-builtin")
os.system(f"llc{filename}.ll -o {filename}.s")
os.system(f"as {filename}.s -o {filename}.o")
os.system(f"clang {filename}.o {libpath} -o {filename}")

View File

@ -1,17 +1,15 @@
#include <fstream>
#include <iostream>
#include <string>
#include "3rdparty/easylogging++.h"
#include "BaseErrorListener.h"
#include "Exceptions.h"
#include "antlr4-runtime.h"
#include "antlrgen/SysyLexer.h"
#include "antlrgen/SysyParser.h"
#include <3rdparty/argparse.hpp>
#include "common.h"
#include "visitor.h"
#include <3rdparty/argparse.hpp>
#include <fstream>
#include <iostream>
#include <string>
INITIALIZE_EASYLOGGINGPP
@ -20,10 +18,17 @@ using namespace antlr4;
class AbortErrorListener : public BaseErrorListener {
public:
void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line, size_t charPositionInLine,
const std::string &msg, std::exception_ptr e) override {
throw ParseCancellationException("line " + std::to_string(line) + ":" + std::to_string(charPositionInLine) + " " +
msg);
void syntaxError(
Recognizer *recognizer,
Token *offendingSymbol,
size_t line,
size_t charPositionInLine,
const std::string &msg,
std::exception_ptr e
) override {
throw ParseCancellationException(
"line " + std::to_string(line) + ":" + std::to_string(charPositionInLine) + " " + msg
);
}
};
@ -44,7 +49,7 @@ int main(int argc, const char **argv) {
}
auto source_file = arg_parser.get<std::string>("source");
auto output_file = arg_parser.get<std::string>("-o");
auto flg_O1 = arg_parser["-O1"] == true;
auto flg_O1 = arg_parser["-O1"] == true;
// std::cout << source_file << " " << output_file << " " << flg_O1 <<
// std::endl;
#pragma endregion
@ -62,6 +67,7 @@ int main(int argc, const char **argv) {
std::ifstream ifs_source_file(source_file);
if (!ifs_source_file.good()) {
LOG(ERROR) << "Source file " << source_file << " not found.";
return 1;
}
ANTLRInputStream input(ifs_source_file);
SysyLexer lexer(&input);
@ -79,6 +85,13 @@ int main(int argc, const char **argv) {
auto tree = parser.program();
Visitor visitor(lexer);
visitor.visitProgram(tree);
auto llir_file = source_file + ".ll";
std::ofstream ofs_llir_file(llir_file);
if (!ofs_llir_file.good()) {
LOG(ERROR) << "Failed to create/overwrite LLIR output file " << llir_file;
return 1;
}
visitor.llir_gen(ofs_llir_file);
#if 0
std::cout << tree->toStringTree(&parser) << std::endl << std::endl;
#endif

View File

@ -66,10 +66,10 @@ void _sysy_starttime(int lineno);
void _sysy_stoptime(int lineno);
*/
Visitor::Visitor(SysyLexer&) {
Visitor::Visitor(SysyLexer &) {
#pragma region RegisterLibFunc
auto fparam_i32 = std::make_shared<FParam>("", TypeHelper::TYPE_I32);
auto pointer_type = std::make_shared<PointerType>(TypeHelper::TYPE_I32);
auto fparam_i32 = std::make_shared<FParam>("", TypeHelper::TYPE_I32);
auto pointer_type = std::make_shared<PointerType>(TypeHelper::TYPE_I32);
auto fparam_ptr_i32 = std::make_shared<FParam>("", pointer_type);
auto func_getint = std::make_shared<Function>("getint", TypeHelper::TYPE_I32);
@ -88,22 +88,22 @@ Visitor::Visitor(SysyLexer&) {
func_putint->fparam_list.push_back(fparam_i32);
_func_tab.push_name("putint", func_putint);
auto func_putch = std::make_shared<Function>("putch", TypeHelper::TYPE_VOID);
auto func_putch = std::make_shared<Function>("putch", TypeHelper::TYPE_VOID);
func_putch->fparam_list = {fparam_i32};
_func_tab.push_name("putch", func_putch);
auto func_putarray = std::make_shared<Function>("putarray", TypeHelper::TYPE_VOID);
auto func_putarray = std::make_shared<Function>("putarray", TypeHelper::TYPE_VOID);
func_putarray->fparam_list = {fparam_ptr_i32, fparam_i32};
_func_tab.push_name("putarray", func_putarray);
// auto func_putf = std::make_shared<Function>("putf", TypeHelper::TYPE_VOID);
// should not be used
auto func_starttime = std::make_shared<Function>("_sysy_starttime", TypeHelper::TYPE_VOID);
auto func_starttime = std::make_shared<Function>("_sysy_starttime", TypeHelper::TYPE_VOID);
func_starttime->fparam_list = {fparam_i32};
_func_tab.push_name("starttime", func_starttime);
auto func_stoptime = std::make_shared<Function>("_sysy_stoptime", TypeHelper::TYPE_VOID);
auto func_stoptime = std::make_shared<Function>("_sysy_stoptime", TypeHelper::TYPE_VOID);
func_stoptime->fparam_list = {fparam_i32};
_func_tab.push_name("stoptime", func_stoptime);
@ -142,9 +142,9 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) {
auto array_type = ArrayType::build_from_list(dim_list);
// anyways, first collect init value
_state.arr_dim_index = 0;
_state.arr_dim_list = &dim_list;
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitConstInitVal(ctx->constInitVal()));
_state.arr_dim_list = nullptr;
_state.arr_dim_list = &dim_list;
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitConstInitVal(ctx->constInitVal()));
_state.arr_dim_list = nullptr;
sysy_assert(_state.arr_dim_index == 0);
if (_scope_tab.get_level()) {
@ -167,7 +167,7 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) {
}
else {
// global const array
auto const_arr = ConstantArr::make_shared("const_arr", array_value, array_type);
auto const_arr = ConstantArr::make_shared("const_arr", array_value, array_type);
auto global_var = GlobalVar::make_shared(const_name, const_arr, true);
module.global_var_list.push_back(global_var);
_scope_tab.push_name(const_name, global_var);
@ -181,8 +181,7 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) {
std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
auto var_name = ctx->IDENT()->getText();
VLOG(5) << "Visiting VarDef " << var_name;
if (_scope_tab.get_name(var_name, _scope_tab.get_level()).has_value())
panic("Duplicate const def");
if (_scope_tab.get_name(var_name, _scope_tab.get_level()).has_value()) panic("Duplicate const def");
// Not Array
if (ctx->constExp().empty()) {
// global variable
@ -190,7 +189,7 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
// global variable must be initialized, either specified or zeroed
if (ctx->initVal()) {
_state.isGlobalIint = true;
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitInitVal(ctx->initVal()));
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitInitVal(ctx->initVal()));
_state.isGlobalIint = false;
auto global_var_int = std::make_shared<GlobalVar>(var_name, result, false);
module.global_var_list.push_back(global_var_int);
@ -227,9 +226,9 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
_scope_tab.push_name(var_name, alloca_);
if (ctx->initVal()) {
_state.arr_dim_index = 0;
_state.arr_dim_list = &dim_list;
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(ctx->initVal()));
_state.arr_dim_list = nullptr;
_state.arr_dim_list = &dim_list;
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(ctx->initVal()));
_state.arr_dim_list = nullptr;
sysy_assert(_state.arr_dim_index == 0);
// Build GEP
auto base_ptr = build_InstGEP(alloca_, {CONST0, CONST0}, _state.current_bb);
@ -249,15 +248,15 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
else {
if (ctx->initVal()) {
// first collect init value
_state.isGlobalIint = true;
_state.isGlobalIint = true;
_state.arr_dim_index = 0;
_state.arr_dim_list = &dim_list;
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(ctx->initVal()));
_state.arr_dim_list = nullptr;
_state.arr_dim_list = &dim_list;
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(ctx->initVal()));
_state.arr_dim_list = nullptr;
sysy_assert(_state.arr_dim_index == 0);
_state.isGlobalIint = false;
auto const_arr = ConstantArr::make_shared("var_arr", array_value, array_type);
auto global_var = GlobalVar::make_shared(var_name, const_arr, false);
auto const_arr = ConstantArr::make_shared("var_arr", array_value, array_type);
auto global_var = GlobalVar::make_shared(var_name, const_arr, false);
module.global_var_list.push_back(global_var);
_scope_tab.push_name(var_name, global_var);
}
@ -273,17 +272,15 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
if (ctx->exp()) {
if (_state.isGlobalIint)
_state.isConstInt = true;
if (_state.isGlobalIint) _state.isConstInt = true;
auto retval = visitExp(ctx->exp());
if (_state.isGlobalIint)
_state.isConstInt = false;
if (_state.isGlobalIint) _state.isConstInt = false;
return retval;
}
// Array
else {
sysy_assert(_state.arr_dim_list);
int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index);
int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index);
int elem_size = 1;
std::vector<ValuePtr_t> cur_arr;
for (int i = _state.arr_dim_index + 1; i < _state.arr_dim_list->size(); ++i) {
@ -294,7 +291,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
if (_state.isGlobalIint) {
auto const_value = any_to_Value(visitInitVal(init_val));
// should evaluate to const int
sysy_assert(Value::isType<ConstantInt>(const_value));
sysy_assert(Value::isValueType<ConstantInt>(const_value));
cur_arr.push_back(const_value);
}
else {
@ -309,7 +306,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
const int pos = cur_arr.size();
// the additional `%elem_size`: what if the last dim is {}?
for (int i = 0; i < (elem_size - (pos % elem_size)) % elem_size; ++i) {
cur_arr.push_back(CONST0);
cur_arr.push_back(nullptr);
}
_state.arr_dim_index++;
auto sub_array = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(init_val));
@ -319,7 +316,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
}
// fill up the rest
for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) {
cur_arr.push_back(CONST0);
cur_arr.push_back(nullptr);
}
return cur_arr;
}
@ -333,7 +330,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
}
else {
sysy_assert(_state.arr_dim_list);
int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index);
int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index);
int elem_size = 1;
std::vector<ValuePtr_t> cur_arr;
for (int i = _state.arr_dim_index + 1; i < _state.arr_dim_list->size(); ++i) {
@ -352,7 +349,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
int pos = cur_arr.size();
// the additional `%elem_size`: what if the last dim is {}?
for (int i = 0; i < (elem_size - (pos % elem_size)) % elem_size; ++i) {
cur_arr.push_back(CONST0);
cur_arr.push_back(nullptr);
}
_state.arr_dim_index++;
auto sub_array = std::any_cast<std::vector<ValuePtr_t>>(visitConstInitVal(init_val));
@ -362,7 +359,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
}
// fill up the rest
for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) {
cur_arr.push_back(CONST0);
cur_arr.push_back(nullptr);
}
return cur_arr;
}
@ -370,10 +367,9 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
// @retval: int
std::any Visitor::visitConstExp(SysyParser::ConstExpContext *ctx) {
if (ctx->addExp() == nullptr)
panic("Unreachable");
if (ctx->addExp() == nullptr) panic("Unreachable");
_state.isConstInt = true;
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitAddExp(ctx->addExp()));
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitAddExp(ctx->addExp()));
_state.isConstInt = false;
VLOG(5) << "ConstExp Eval to " << result->value;
return {result};
@ -514,9 +510,9 @@ std::any Visitor::visitEqExp(SysyParser::EqExpContext *ctx) {
std::any Visitor::visitLAndExp(SysyParser::LAndExpContext *ctx) {
auto eq_exp_list = ctx->eqExp();
for (int i = 0; i < eq_exp_list.size(); ++i) {
auto next_block = build_BasicBlock("", _state.current_func);
auto eq_exp = any_to_Value(visitEqExp(eq_exp_list[i]));
auto condition = build_InstBinary(InstTag::Ne, eq_exp, CONST0, _state.current_bb);
auto next_block = build_BasicBlock("", _state.current_func, _state.current_bb->itr);
auto eq_exp = any_to_Value(visitEqExp(eq_exp_list[i]));
auto condition = build_InstBinary(InstTag::Ne, eq_exp, CONST0, _state.current_bb);
build_InstBranch(condition, next_block, ctx->false_block, _state.current_bb);
_state.current_bb = next_block;
}
@ -529,17 +525,17 @@ std::any Visitor::visitLAndExp(SysyParser::LAndExpContext *ctx) {
std::any Visitor::visitLOrExp(SysyParser::LOrExpContext *ctx) {
VLOG(5) << "Eval to Cond(lOrExp); lineno=" << ctx->getStart()->getLine();
auto and_exp_list = ctx->lAndExp();
auto n_and_exp = and_exp_list.size();
auto n_and_exp = and_exp_list.size();
for (int i = 0; i < n_and_exp - 1; ++i) {
auto next_block = build_BasicBlock("", _state.current_func);
ctx->lAndExp(i)->true_block = ctx->true_block;
auto next_block = build_BasicBlock("", _state.current_func, _state.current_bb->itr);
ctx->lAndExp(i)->true_block = ctx->true_block;
ctx->lAndExp(i)->false_block = next_block;
visitLAndExp(and_exp_list[i]);
_state.current_bb = next_block;
}
ctx->lAndExp(n_and_exp - 1)->true_block = ctx->true_block;
ctx->lAndExp(n_and_exp - 1)->true_block = ctx->true_block;
ctx->lAndExp(n_and_exp - 1)->false_block = ctx->false_block;
visitLAndExp(ctx->lAndExp(n_and_exp-1));
visitLAndExp(ctx->lAndExp(n_and_exp - 1));
return {};
}
@ -575,7 +571,7 @@ std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) {
}
else {
if (ctx->unaryExp()) {
auto _result = visitUnaryExp(ctx->unaryExp());
auto _result = visitUnaryExp(ctx->unaryExp());
auto unary_exp = any_to_Value(_result);
sysy_assert(unary_exp->type->type_tag == Type::TypeTag::IntegerType);
if (std::dynamic_pointer_cast<IntegerType>(unary_exp->type)->isI1()) {
@ -605,12 +601,12 @@ std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) {
std::vector<ValuePtr_t> args;
// Directly parse RParams
if (ctx->funcRParams()) {
auto rparams = ctx->funcRParams()->funcRParam();
auto rparams = ctx->funcRParams()->funcRParam();
const auto &fparams = func->fparam_list;
for (int i = 0; i < rparams.size(); ++i) {
auto rparam = rparams[i];
auto fparam = fparams[i];
auto exp = any_to_Value(visitExp(rparam->exp()));
auto exp = any_to_Value(visitExp(rparam->exp()));
args.push_back(exp);
}
}
@ -654,7 +650,7 @@ std::any Visitor::visitPrimaryExp(SysyParser::PrimaryExpContext *ctx) {
}
else {
auto child_ret = visitLVal(ctx->lVal());
auto lval = any_to_Value(child_ret);
auto lval = any_to_Value(child_ret);
// @retval: ConstantInt
if (lval->type->type_tag == Type::TypeTag::IntegerType) {
return lval;
@ -712,118 +708,117 @@ std::any Visitor::visitLVal(SysyParser::LValContext *ctx) {
if (lval->type->type_tag == Type::TypeTag::PointerType) {
auto ptr_type = std::dynamic_pointer_cast<PointerType>(lval->type);
switch (ptr_type->pointed_type->type_tag) {
case Type::TypeTag::IntegerType: {
// Int
if (ctx->exp().empty()) {
// int ref
// @retval: InstAlloca
return lval;
}
else {
LOG(WARNING) << "Unexpected array referece";
// array index, perhaps
// @retval: InstGEP
auto gep = lval;
for (auto exp_ctx : ctx->exp()) {
auto exp = any_to_Value(visitExp(exp_ctx));
gep = build_InstGEP(gep, {exp}, _state.current_bb);
case Type::TypeTag::IntegerType: {
// Int
if (ctx->exp().empty()) {
// int ref
// @retval: InstAlloca
return lval;
}
return gep;
}
};
case Type::TypeTag::PointerType: {
sysy_assert(0);
if (ctx->exp().empty()) {
// ??? Pointer
// @retval: InstLoad
LOG(WARNING) << "Unexpected pointer";
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval->type)->pointed_type;
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
return inst_load;
}
else {
// fparam array, whose first dim is represented by a pointer
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval->type)->pointed_type;
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
else {
LOG(WARNING) << "Unexpected array referece";
// array index, perhaps
// @retval: InstGEP
auto gep = lval;
for (auto exp_ctx : ctx->exp()) {
auto exp = any_to_Value(visitExp(exp_ctx));
gep = build_InstGEP(gep, {exp}, _state.current_bb);
}
return gep;
}
};
case Type::TypeTag::PointerType: {
sysy_assert(0);
if (ctx->exp().empty()) {
// ??? Pointer
// @retval: InstLoad
LOG(WARNING) << "Unexpected pointer";
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval->type)->pointed_type;
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
return inst_load;
}
else {
// fparam array, whose first dim is represented by a pointer
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval->type)->pointed_type;
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
LOG(INFO) << lval->to_string() << " " << lval->type->to_string();
auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb);
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
LOG(INFO) << pointed_type->to_string();
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
LOG(INFO) << lval->to_string() << " " << lval->type->to_string();
auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb);
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
LOG(INFO) << pointed_type->to_string();
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
ValuePtr_t offset = ConstantInt::make_shared(0);
auto exp_list = ctx->exp();
// calculate offset by hand: offset = (offset + exp[i]) * dim_size[i]
for (int i = 0; i < exp_list.size() - 1; ++i) {
sysy_assert(typeid(pointed_type) == typeid(std::shared_ptr<ArrayType>));
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
auto exp_val = any_to_Value(visitExp(exp_list[i]));
auto dim_size = ConstantInt::make_shared(array_type->element_count);
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb);
offset = inst_mul;
pointed_type = array_type->element_type;
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
}
// visit the last dimension, mul is not needed
auto exp_val = any_to_Value(visitExp(exp_list.back()));
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
offset = inst_add; // finally, we get the offset
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
if (TypeHelper::isIntegerType(pointed_type)) {
// return the address of the array element
auto arr_elem_ptr = build_InstGEP(ptr, {offset}, _state.current_bb);
return arr_elem_ptr;
}
else {
panic("Should be int");
}
}
}
case Type::TypeTag::ArrayType: {
if (ctx->exp().empty()) {
// passing an array to function
auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb);
return ptr;
}
// get &array[0]
auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb);
auto pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
ValuePtr_t offset = ConstantInt::make_shared(0);
auto exp_list = ctx->exp();
auto exp_list = ctx->exp();
// calculate offset by hand: offset = (offset + exp[i]) * dim_size[i]
for (int i = 0; i < exp_list.size() - 1; ++i) {
sysy_assert(typeid(pointed_type) == typeid(std::shared_ptr<ArrayType>));
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
auto exp_val = any_to_Value(visitExp(exp_list[i]));
auto dim_size = ConstantInt::make_shared(array_type->element_count);
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb);
offset = inst_mul;
pointed_type = array_type->element_type;
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
auto exp_val = any_to_Value(visitExp(exp_list[i]));
auto dim_size = ConstantInt::make_shared(array_type->element_count);
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb);
offset = inst_mul;
pointed_type = array_type->element_type;
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
}
// visit the last dimension, mul is not needed
auto exp_val = any_to_Value(visitExp(exp_list.back()));
auto exp_val = any_to_Value(visitExp(exp_list.back()));
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
offset = inst_add; // finally, we get the offset
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
offset = inst_add; // finally, we get the offset
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
if (TypeHelper::isIntegerType(pointed_type)) {
// return the address of the array element
auto arr_elem_ptr = build_InstGEP(ptr, {offset}, _state.current_bb);
return arr_elem_ptr;
}
else {
panic("Should be int");
// return the address of an sub array
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
auto dim_size = ConstantInt::make_shared(array_type->element_count);
auto inst_mul = build_InstBinary(InstTag::Mul, offset, dim_size, _state.current_bb);
auto arr_elem_ptr = build_InstGEP(ptr, {CONST0, offset}, _state.current_bb);
return arr_elem_ptr;
}
}
}
case Type::TypeTag::ArrayType: {
if (ctx->exp().empty()) {
// passing an array to function
auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb);
return ptr;
}
// get &array[0]
auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb);
auto pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
ValuePtr_t offset = ConstantInt::make_shared(0);
auto exp_list = ctx->exp();
// calculate offset by hand: offset = (offset + exp[i]) * dim_size[i]
for (int i = 0; i < exp_list.size() - 1; ++i) {
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
auto exp_val = any_to_Value(visitExp(exp_list[i]));
auto dim_size = ConstantInt::make_shared(array_type->element_count);
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb);
offset = inst_mul;
pointed_type = array_type->element_type;
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
}
auto exp_val = any_to_Value(visitExp(exp_list.back()));
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
offset = inst_add; // finally, we get the offset
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
if (TypeHelper::isIntegerType(pointed_type)) {
// return the address of the array element
auto arr_elem_ptr = build_InstGEP(ptr, {offset}, _state.current_bb);
return arr_elem_ptr;
}
else {
// return the address of an sub array
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
auto dim_size = ConstantInt::make_shared(array_type->element_count);
auto inst_mul = build_InstBinary(InstTag::Mul, offset, dim_size, _state.current_bb);
auto arr_elem_ptr = build_InstGEP(ptr, {CONST0, offset}, _state.current_bb);
return arr_elem_ptr;
}
}
default:
panic("Unreachable");
default: panic("Unreachable");
}
}
panic("Unreachable");
@ -840,10 +835,10 @@ std::any Visitor::visitFuncDef(SysyParser::FuncDefContext *ctx) {
auto func_obj = std::make_shared<Function>(func_name, func_ret_type);
module.function_list.push_back(func_obj);
_func_tab.push_name(func_name, func_obj);
auto basic_block = build_BasicBlock(func_name + "_ENTRY", func_obj);
auto basic_block = build_BasicBlock(func_name + "_ENTRY", func_obj, func_obj->bb_list.begin());
_scope_tab.enter_scope(true);
_state.current_func = func_obj;
_state.current_bb = basic_block;
_state.current_bb = basic_block;
if (ctx->funcFParams()) {
visitFuncFParams(ctx->funcFParams());
}
@ -867,8 +862,8 @@ std::any Visitor::visitFuncFParams(SysyParser::FuncFParamsContext *ctx) {
for (auto fparam_ctx : ctx->funcFParam()) {
auto fparam_type = any_to_Type(visitFuncFParam(fparam_ctx));
auto fparam_name = fparam_ctx->IDENT()->getText();
auto fparam = std::make_shared<FParam>(fparam_name, fparam_type);
auto alloca_ = build_InstAlloca(fparam_type, _state.current_bb);
auto fparam = std::make_shared<FParam>(fparam_name, fparam_type);
auto alloca_ = build_InstAlloca(fparam_type, _state.current_bb);
build_InstStore(fparam, alloca_, _state.current_bb);
_scope_tab.push_name(fparam_name, alloca_);
_state.current_func->fparam_list.push_back(fparam);
@ -887,7 +882,7 @@ std::any Visitor::visitFuncFParam(SysyParser::FuncFParamContext *ctx) {
std::vector<int> dim_list = {0}; // the first dim must be empty, though
for (auto exp_ctx : ctx->exp()) {
_state.isConstInt = true;
auto exp_val = std::dynamic_pointer_cast<ConstantInt>(any_to_Value(visitExp(exp_ctx)));
auto exp_val = std::dynamic_pointer_cast<ConstantInt>(any_to_Value(visitExp(exp_ctx)));
_state.isConstInt = false;
dim_list.push_back(exp_val->value);
}
@ -921,8 +916,8 @@ stmt: lVal '=' exp ';' # assignStmt
*/
std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) {
auto lval = any_to_Value(visitLVal(ctx->lVal()));
auto rhs = any_to_Value(visitExp(ctx->exp()));
auto lval = any_to_Value(visitLVal(ctx->lVal()));
auto rhs = any_to_Value(visitExp(ctx->exp()));
auto store = build_InstStore(rhs, lval, _state.current_bb);
return {};
}
@ -930,14 +925,14 @@ std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) {
// TODO: Remove RETURN in else stmt
std::any Visitor::visitIfStmt(SysyParser::IfStmtContext *ctx) {
VLOG(5) << "Visiting IfStmt "
<< "; lineno=" << ctx->getStart()->getLine();
auto true_block = build_BasicBlock("_then", _state.current_func);
auto next_block = build_BasicBlock("_next", _state.current_func);
<< "; lineno=" << ctx->getStart()->getLine();
auto true_block = build_BasicBlock("_then", _state.current_func, _state.current_bb->itr);
auto next_block = build_BasicBlock("_next", _state.current_func, true_block->itr);
auto false_block = next_block;
if (ctx->ELSE()) {
false_block = build_BasicBlock("_else", _state.current_func);
false_block = build_BasicBlock("_else", _state.current_func, true_block->itr);
}
ctx->cond()->lOrExp()->true_block = true_block;
ctx->cond()->lOrExp()->true_block = true_block;
ctx->cond()->lOrExp()->false_block = false_block;
visitCond(ctx->cond());
@ -956,17 +951,17 @@ std::any Visitor::visitIfStmt(SysyParser::IfStmtContext *ctx) {
// TODO: backpatching? I am not sure whether it is necessary
std::any Visitor::visitWhileStmt(SysyParser::WhileStmtContext *ctx) {
VLOG(5) << "Visiting WhileStmt "
<< "; lineno=" << ctx->getStart()->getLine();
auto while_id = std::to_string(_state.loop_stmt_count);
auto cond_block = build_BasicBlock("_loop_cond_" + while_id, _state.current_func);
auto body_block = build_BasicBlock("_loop_body_" + while_id, _state.current_func);
auto next_block = build_BasicBlock("_loop_exit_" + while_id, _state.current_func);
<< "; lineno=" << ctx->getStart()->getLine();
auto while_id = std::to_string(_state.loop_stmt_count);
auto cond_block = build_BasicBlock("_loop_cond_" + while_id, _state.current_func, _state.current_bb->itr);
auto body_block = build_BasicBlock("_loop_body_" + while_id, _state.current_func, cond_block->itr);
auto next_block = build_BasicBlock("_loop_exit_" + while_id, _state.current_func, body_block->itr);
build_InstBranch(cond_block, _state.current_bb);
_state.loop_stack.push_back({cond_block, body_block, next_block, _state.loop_stmt_count++});
// condition
ctx->cond()->lOrExp()->true_block = body_block;
ctx->cond()->lOrExp()->true_block = body_block;
ctx->cond()->lOrExp()->false_block = next_block;
_state.current_bb = cond_block;
_state.current_bb = cond_block;
visitCond(ctx->cond());
// body
_state.current_bb = body_block;
@ -981,14 +976,14 @@ std::any Visitor::visitWhileStmt(SysyParser::WhileStmtContext *ctx) {
std::any Visitor::visitBreakStmt(SysyParser::BreakStmtContext *ctx) {
sysy_assert(!_state.loop_stack.empty());
build_InstBranch(_state.loop_stack.back().next, _state.current_bb);
_state.current_bb = build_BasicBlock("_after_break", _state.current_func);
_state.current_bb = build_BasicBlock("_after_break", _state.current_func, _state.current_bb->itr);
return {};
}
std::any Visitor::visitContinueStmt(SysyParser::ContinueStmtContext *ctx) {
sysy_assert(!_state.loop_stack.empty());
build_InstBranch(_state.loop_stack.back().cond, _state.current_bb);
_state.current_bb = build_BasicBlock("_after_continue", _state.current_func);
_state.current_bb = build_BasicBlock("_after_continue", _state.current_func, _state.current_bb->itr);
return {};
}

View File

@ -11,34 +11,50 @@ std::shared_ptr<ConstantInt> build_ConstantInt(const std::string &name, int valu
return lala;
}
std::shared_ptr<BasicBlock> build_BasicBlock(const std::string &name, std::shared_ptr<Function> parent) {
std::shared_ptr<BasicBlock> build_BasicBlock(
const std::string &name,
std::shared_ptr<Function> parent,
const BasicBlockListNode_t &cur_bb_itr
) {
auto basic_block = std::make_shared<BasicBlock>(name, parent);
parent->bb_list.push_back(basic_block);
basic_block->itr = parent->bb_list.insert(std::next(cur_bb_itr), basic_block);
return basic_block;
}
std::shared_ptr<InstLoad> build_InstLoad(std::shared_ptr<Value> value, TypePtr_t type,
std::shared_ptr<BasicBlock> parent_bb) {
std::shared_ptr<InstLoad> build_InstLoad(
std::shared_ptr<Value> value,
TypePtr_t type,
std::shared_ptr<BasicBlock> parent_bb
) {
auto inst_load = std::make_shared<InstLoad>(value, type, parent_bb);
parent_bb->inst_list.push_back(inst_load);
return inst_load;
}
std::shared_ptr<InstStore> build_InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer,
std::shared_ptr<BasicBlock> parent_bb) {
std::shared_ptr<InstStore> build_InstStore(
std::shared_ptr<Value> value,
std::shared_ptr<Value> pointer,
std::shared_ptr<BasicBlock> parent_bb
) {
auto inst_store = std::make_shared<InstStore>(value, pointer, parent_bb);
parent_bb->inst_list.push_back(inst_store);
return inst_store;
}
// a little bit different, we put all alloca in the head of each basic block
std::shared_ptr<InstAlloca> build_InstAlloca(TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb) {
auto inst_alloca = std::make_shared<InstAlloca>(type, parent_bb);
parent_bb->inst_list.push_back(inst_alloca);
parent_bb->inst_list.insert(parent_bb->inst_list.begin(), inst_alloca);
// parent_bb->inst_list.push_back(inst_alloca);
return inst_alloca;
}
std::shared_ptr<InstBinary> build_InstBinary(InstTag inst_tag, std::shared_ptr<Value> op1, std::shared_ptr<Value> op2,
std::shared_ptr<BasicBlock> parent_bb) {
std::shared_ptr<InstBinary> build_InstBinary(
InstTag inst_tag,
std::shared_ptr<Value> op1,
std::shared_ptr<Value> op2,
std::shared_ptr<BasicBlock> parent_bb
) {
std::shared_ptr<InstBinary> inst_binary;
if (InstTag::Lt <= inst_tag && inst_tag <= InstTag::Or) {
inst_binary = std::make_shared<InstBinary>(inst_tag, TypeHelper::TYPE_I1, op1, op2, parent_bb);
@ -59,8 +75,12 @@ std::shared_ptr<InstZext> build_InstZext(std::shared_ptr<Value> op, std::shared_
return inst_zext;
}
std::shared_ptr<InstBranch> build_InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block,
BasicBlockPtr_t parent_bb) {
std::shared_ptr<InstBranch> build_InstBranch(
ValuePtr_t cond,
BasicBlockPtr_t true_block,
BasicBlockPtr_t false_block,
BasicBlockPtr_t parent_bb
) {
auto inst = std::make_shared<InstBranch>(cond, true_block, false_block, parent_bb);
parent_bb->inst_list.push_back(inst);
return inst;
@ -84,15 +104,21 @@ std::shared_ptr<InstReturn> build_InstReturn(BasicBlockPtr_t parent_bb) {
return inst;
}
std::shared_ptr<InstCall> build_InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args,
BasicBlockPtr_t parent_bb) {
std::shared_ptr<InstCall> build_InstCall(
FunctionPtr_t func,
const std::vector<ValuePtr_t> &args,
BasicBlockPtr_t parent_bb
) {
auto inst = std::make_shared<InstCall>(func, args, parent_bb);
parent_bb->inst_list.push_back(inst);
return inst;
}
std::shared_ptr<InstGEP> build_InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices,
BasicBlockPtr_t parent_bb) {
std::shared_ptr<InstGEP> build_InstGEP(
ValuePtr_t pointer,
const std::vector<ValuePtr_t> &indices,
BasicBlockPtr_t parent_bb
) {
auto inst = std::make_shared<InstGEP>(pointer, indices, parent_bb);
parent_bb->inst_list.push_back(inst);
return inst;

View File

@ -1,9 +1,481 @@
#include "3rdparty/easylogging++.h"
#include "common.h"
#include "llir_instruction.h"
#include "llir_type.h"
#include "llir_value.h"
#include "visitor.h"
#include <array>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
namespace antlrSysY {
void Visitor::llir_gen() {
const std::array<std::string, 8> libfunc_list =
{"getint", "getch", "getarray", "putint", "putch", "putarray", "starttime", "stoptime"};
// On generation, the array is flattened, thus we have to calculate them
std::shared_ptr<ConstantArr> gen_arr_hierarchy(
const std::shared_ptr<ArrayType> array_type,
const std::vector<ValuePtr_t> &const_array,
int base,
int length
) {
int dim_n = array_type->element_count;
int dim_size = length / dim_n;
std::vector<ValuePtr_t> value_list;
if (array_type->element_type->type_tag == Type::TypeTag::IntegerType) {
sysy_assert(dim_size == 1);
for (int i = 0; i < dim_n; ++i) {
if (const_array[base + i]) {
value_list.push_back(const_array[base + i]);
}
else {
break;
}
}
if (!value_list.empty())
return ConstantArr::make_shared("", value_list, array_type);
else
return nullptr;
}
else {
int last_non_null = -1;
for (int i = 0; i < dim_n; ++i) {
auto sub_arr = gen_arr_hierarchy(
std::dynamic_pointer_cast<ArrayType>(array_type->element_type), const_array, dim_size * i, dim_size
);
value_list.push_back(sub_arr);
if (sub_arr) last_non_null = i;
}
if (last_non_null == -1) {
return nullptr;
}
else {
// if (last_non_null + 1 < value_list.size())
value_list.erase(value_list.begin() + last_non_null + 1, value_list.end());
return ConstantArr::make_shared("", value_list, array_type);
}
}
}
}
static void _build_arr_init_list(
std::ostream &ostr,
std::shared_ptr<ConstantArr> arr,
std::shared_ptr<ArrayType> arr_type
) {
if (arr_type->element_type->type_tag == Type::TypeTag::IntegerType) {
ostr << arr_type->to_IR_string();
ostr << " [";
for (int i = 0; i < arr->value_list.size(); ++i) {
ostr << "i32 " << std::dynamic_pointer_cast<ConstantInt>(arr->value_list[i])->value;
if (i < arr->value_list.size() - 1) {
ostr << ", ";
}
}
for (int i = 0; i < arr_type->element_count - arr->value_list.size(); ++i) {
ostr << ", i32 0";
}
ostr << "]";
}
else {
ostr << "[";
for (int i = 0; i < arr->value_list.size(); ++i) {
if (arr->value_list[i])
_build_arr_init_list(
ostr,
std::dynamic_pointer_cast<ConstantArr>(arr->value_list[i]),
std::dynamic_pointer_cast<ArrayType>(arr_type->element_type)
);
else
ostr << arr_type->element_type->to_IR_string() << " zeroinitializer";
if (i < arr->value_list.size() - 1) {
ostr << ", ";
}
}
for (int i = 0; i < arr_type->element_count - arr->value_list.size(); ++i) {
ostr << ", " << arr_type->element_type->to_IR_string() << " zeroinitializer";
}
ostr << "]";
}
}
static void _gen_blocks(const std::list<BasicBlockPtr_t> &block_list, int reg_count) {
std::stringstream ostr;
// first pass, allocate sequence number
for (auto block_itr = block_list.begin(); block_itr != block_list.end(); ++block_itr) {
auto block = *block_itr;
for (int j = 0; j < block->inst_list.size(); ++j) {
auto inst = block->inst_list[j];
sysy_assert(inst->ir_seqno == -1); // multi-alloc is error
switch (inst->tag) {
// These are not to get a seqno
case InstTag::Br:
case InstTag::Ret:
case InstTag::Store: break;
// Call's seqno is dependent on its return type
case InstTag::Call:
if (inst->type->type_tag == Type::TypeTag::IntegerType) {
inst->ir_seqno = reg_count++;
}
break;
// These should have a seqno
case InstTag::Add:
case InstTag::Sub:
case InstTag::Mod:
case InstTag::Mul:
case InstTag::Div:
case InstTag::Lt:
case InstTag::Le:
case InstTag::Ge:
case InstTag::Gt:
case InstTag::Eq:
case InstTag::Ne:
case InstTag::And:
case InstTag::Or:
case InstTag::Load:
case InstTag::GEP:
case InstTag::Alloca:
case InstTag::Zext: inst->ir_seqno = reg_count++; break;
// These should not be generated in frontend stage
default: panic("Unexpected instruction");
}
}
sysy_assert(block->ir_seqno == -1); // multi-alloc is error
if (block_itr != block_list.begin()) {
block->ir_seqno = reg_count++;
}
}
// second pass, generate IR
for (auto block_itr = block_list.begin(); block_itr != block_list.end(); ++block_itr) {
auto block = *block_itr;
if (block_itr != block_list.begin()) {
ostr << block->ir_seqno << ":" << std::endl;
}
for (int j = 0; j < block->inst_list.size(); ++j) {
auto _inst = block->inst_list[j];
switch (_inst->tag) {
case InstTag::Br: {
auto inst = Value::asValueType<InstBranch>(_inst);
assert(inst->ir_seqno == -1);
std::stringstream ostr;
ostr << "br ";
if (inst->operand_list.size() == 1) {
assert(Value::isValueType<BasicBlock>(inst->operand_list[0]));
auto bb_dest = Value::asValueType<BasicBlock>(inst->operand_list[0]);
assert(bb_dest->ir_seqno >= 0);
ostr << "label %" << bb_dest->ir_seqno;
}
else {
assert(Value::isValueType<Instruction>(inst->operand_list[0]));
assert(Type::isType<IntegerType>(inst->operand_list[0]->type));
auto cond = Value::asValueType<Instruction>(inst->operand_list[0]);
auto bb_true = Value::asValueType<BasicBlock>(inst->operand_list[1]);
auto bb_false = Value::asValueType<BasicBlock>(inst->operand_list[2]);
if (!Type::asType<IntegerType>(cond->type)->isI1()) {
LOG(ERROR) << "Expect cond evals to i1: " << cond->to_string();
panic("Grammar check");
}
assert(cond->ir_seqno >= 0);
assert(bb_true->ir_seqno >= 0);
assert(bb_false->ir_seqno >= 0);
ostr << "i1 " << cond->ir_seqno << ", label %" << bb_true->ir_seqno << ", label %" << bb_false->ir_seqno;
}
break;
}
case InstTag::Ret: {
auto inst = Value::asValueType<InstReturn>(_inst);
assert(inst->ir_seqno == -1);
ostr << "ret ";
if (inst->operand_list.size() == 0) {
assert(Type::isType<VoidType>(inst->type));
ostr << "void";
}
else {
if (Value::isValueType<Instruction>(inst->operand_list[0])) {
auto op0 = Value::asValueType<Instruction>(inst->operand_list[0]);
assert(op0->ir_seqno >= 0);
ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno;
}
else if (Value::isValueType<ConstantInt>(inst->operand_list[0])) {
auto op0 = Value::asValueType<ConstantInt>(inst->operand_list[0]);
ostr << op0->to_string();
}
else {
LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string();
assert(0);
}
}
break;
}
case InstTag::Store: {
auto inst = Value::asValueType<InstStore>(_inst);
assert(inst->ir_seqno == -1);
ostr << "store ";
assert(Type::isType<IntegerType>(inst->operand_list[0]->type));
assert(Type::isType<PointerType>(inst->operand_list[1]->type));
if (Value::isValueType<Instruction>(inst->operand_list[0])) {
auto op0 = Value::asValueType<Instruction>(inst->operand_list[0]);
assert(op0->ir_seqno >= 0);
ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno << ", ";
}
else if (Value::isValueType<ConstantInt>(inst->operand_list[0])) {
auto op0 = Value::asValueType<ConstantInt>(inst->operand_list[0]);
ostr << "i32 " << op0->value << ", ";
}
else {
LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string();
assert(0);
}
if (Value::isValueType<GlobalVar>(inst->operand_list[1])) {
auto op1 = Value::asValueType<GlobalVar>(inst->operand_list[1]);
ostr << op1->type->to_IR_string() << " @" << op1->name;
}
else if (Value::isValueType<Instruction>(inst->operand_list[1])) {
auto op1 = Value::asValueType<Instruction>(inst->operand_list[1]);
assert(op1->ir_seqno >= 0);
ostr << op1->type->to_IR_string() << " %" << op1->ir_seqno;
}
else {
LOG(ERROR) << "Unexpected type of op1: " << inst->operand_list[1]->to_string();
assert(0);
}
break;
}
// Call's seqno is dependent on its return type
case InstTag::Call: {
auto inst = Value::asValueType<InstReturn>(_inst);
auto func = Value::asValueType<Function>(inst->operand_list[0]);
auto func_type = Type::asType<FunctionType>(func->type);
if (Type::isType<VoidType>(func_type->return_type)) {
assert(inst->ir_seqno == -1);
ostr << "call void @";
}
else {
assert(inst->ir_seqno >= 0);
ostr << "%" << inst->ir_seqno << " = call i32 @";
}
ostr << func->name << "(";
if (inst->operand_list.size() > 1) {
for (int i = 1; i < inst->operand_list.size(); ++i) {
if (Value::isValueType<Instruction>(inst->operand_list[i])) {
auto op0 = Value::asValueType<Instruction>(inst->operand_list[i]);
assert(op0->ir_seqno >= 0);
ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno;
}
else if (Value::isValueType<ConstantInt>(inst->operand_list[i])) {
auto op0 = Value::asValueType<ConstantInt>(inst->operand_list[i]);
ostr << op0->to_string();
}
else {
LOG(ERROR) << "Unexpected type of op_i: " << inst->operand_list[i]->to_string();
assert(0);
}
if (i < inst->operand_list.size() - 1) ostr << ", ";
}
}
ostr << ")";
break;
}
// These should have a seqno
case InstTag::Add:
case InstTag::Sub:
case InstTag::Mod:
case InstTag::Mul:
case InstTag::Div:
case InstTag::Lt:
case InstTag::Le:
case InstTag::Ge:
case InstTag::Gt:
case InstTag::Eq:
case InstTag::Ne:
case InstTag::And:
case InstTag::Or: {
auto inst = Value::asValueType<InstBinary>(_inst);
ostr << "%" << inst->ir_seqno << " = " << inst->to_string();
if (Value::isValueType<Instruction>(inst->operand_list[0])) {
auto op0 = Value::asValueType<Instruction>(inst->operand_list[0]);
assert(op0->ir_seqno >= 0);
ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno << ", ";
}
else if (Value::isValueType<ConstantInt>(inst->operand_list[0])) {
auto op0 = Value::asValueType<ConstantInt>(inst->operand_list[0]);
ostr << op0->to_string() << ", ";
}
else {
LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string();
assert(0);
}
if (Value::isValueType<Instruction>(inst->operand_list[1])) {
auto op1 = Value::asValueType<Instruction>(inst->operand_list[1]);
assert(op1->ir_seqno >= 0);
ostr << "%" << op1->ir_seqno;
}
else if (Value::isValueType<ConstantInt>(inst->operand_list[1])) {
auto op1 = Value::asValueType<ConstantInt>(inst->operand_list[1]);
ostr << op1->value;
}
else {
LOG(ERROR) << "Unexpected type of op1: " << inst->operand_list[1]->to_string();
assert(0);
}
break;
}
case InstTag::Load: {
auto inst = Value::asValueType<InstLoad>(_inst);
assert(inst->ir_seqno != -1);
assert(Type::isType<PointerType>(inst->operand_list[0]->type));
ostr << "%" << inst->ir_seqno << " = load " << inst->type->to_IR_string() << ", ";
if (Value::isValueType<GlobalVar>(inst->operand_list[0])) {
auto op1 = Value::asValueType<GlobalVar>(inst->operand_list[0]);
ostr << op1->type->to_IR_string() << " @" << op1->name;
}
else if (Value::isValueType<Instruction>(inst->operand_list[0])) {
auto op1 = Value::asValueType<Instruction>(inst->operand_list[0]);
assert(op1->ir_seqno >= 0);
ostr << op1->type->to_IR_string() << " %" << op1->ir_seqno;
}
else {
LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[1]->to_string();
assert(0);
}
break;
}
case InstTag::GEP: {
auto inst = Value::asValueType<InstGEP>(_inst);
assert(inst->ir_seqno >= 0);
std::stringstream ostr;
auto pointer_type = Type::asType<PointerType>(inst->operand_list[0]->type);
ostr << "%" << inst->ir_seqno << " = getelementptr " << pointer_type->pointed_type->to_IR_string() << ", ";
if (Value::isValueType<GlobalVar>(inst->operand_list[0])) {
auto op0 = Value::asValueType<GlobalVar>(inst->operand_list[0]);
ostr << op0->to_IR_string();
}
else if (Value::isValueType<Instruction>(inst->operand_list[0])) {
auto op0 = Value::asValueType<Instruction>(inst->operand_list[0]);
ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno;
}
else {
LOG(WARNING) << "Unexpected type of op0: " << inst->operand_list[0]->to_string();
assert(0);
}
for (int i = 1; i < inst->operand_list.size(); ++i) {
ostr << ", " << inst->operand_list[i]->to_IR_string();
}
break;
}
case InstTag::Alloca: {
auto inst = Value::asValueType<InstAlloca>(_inst);
assert(inst->ir_seqno != -1);
ostr << "%" << inst->ir_seqno << " = alloca i32, align 4";
break;
}
case InstTag::Zext: {
auto inst = Value::asValueType<InstZext>(_inst);
assert(inst->ir_seqno >= 0);
std::stringstream ostr;
ostr << "%" << inst->ir_seqno << " = zext ";
if (Value::isValueType<Instruction>(inst->operand_list[0])) {
auto op0 = Value::asValueType<Instruction>(inst->operand_list[0]);
assert(op0->ir_seqno >= 0);
ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno << ", ";
}
else if (Value::isValueType<ConstantInt>(inst->operand_list[0])) {
auto op0 = Value::asValueType<ConstantInt>(inst->operand_list[0]);
ostr << op0->to_string() << ", ";
}
else {
LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string();
assert(0);
}
ostr << "i32";
break;
}
// These should not be generated in frontend stage
default: panic("Unexpected instruction");
}
}
}
}
void Visitor::llir_gen(std::ostream &ostr) {
#pragma region GenLibFuncDecl
for (auto &lib_func_name : libfunc_list) {
LOG(DEBUG) << "Gen LibFunc " << lib_func_name;
auto lib_func = _func_tab.get_name(lib_func_name).value();
auto lib_func_type = std::dynamic_pointer_cast<FunctionType>(lib_func->type);
ostr << "declare"
<< " " << lib_func_type->return_type->to_IR_string() << " "
<< "@" << lib_func_name << "(";
auto &param_list = lib_func->fparam_list;
for (int i = 0; i < (int)param_list.size() - 1; ++i) {
ostr << param_list[i]->type->to_IR_string() << ", ";
}
if (param_list.size()) ostr << param_list.back()->type->to_IR_string();
ostr << ")" << std::endl;
}
// ostr.flush();
#pragma endregion
#pragma region GenGlobDecl
for (auto &global_var : module.global_var_list) {
// both int and arr have the same leading part
LOG(DEBUG) << "Gen Global " << global_var->name;
ostr << "@" << global_var->name << " = "
<< "dso_local"
<< " " << (global_var->is_const ? "const" : "global") << " ";
auto global_var_type = std::dynamic_pointer_cast<PointerType>(global_var->type);
if (global_var_type->pointed_type->type_tag == Type::TypeTag::IntegerType) {
auto init_value = std::dynamic_pointer_cast<ConstantInt>(global_var->init_value);
ostr << "i32"
<< " " << init_value->value << std::endl;
}
else if (global_var_type->pointed_type->type_tag == Type::TypeTag::ArrayType) {
// sysy_assert(global_var->)
auto array_type = std::dynamic_pointer_cast<ArrayType>(global_var_type->pointed_type);
auto init_value = std::dynamic_pointer_cast<ConstantArr>(global_var->init_value);
auto hierarchy_array = gen_arr_hierarchy(array_type, init_value->value_list, 0, init_value->value_list.size());
if (hierarchy_array) {
// LOG(DEBUG) << hierarchy_array->to_string();
ostr << array_type->to_IR_string() << " ";
_build_arr_init_list(ostr, hierarchy_array, array_type);
}
else {
ostr << array_type->to_IR_string() << " zeroinitializer";
}
ostr << ", align 4" << std::endl;
}
else {
LOG(ERROR) << global_var->to_string();
panic("Invalid Global Declaration");
}
}
#pragma endregion
#pragma region GenFunction
for (auto &func : module.function_list) {
if (func->is_libfunc()) {
LOG(WARNING) << "Lib func";
continue;
}
int reg_count = 0; // allocate unique register name from %0
auto func_type = std::dynamic_pointer_cast<FunctionType>(func->type);
ostr << "define dso_local " << func_type->return_type->to_IR_string() << " @" << func->name;
ostr << "(";
auto &param_list = func->fparam_list;
for (int i = 0; i < (int)param_list.size() - 1; ++i) {
ostr << param_list[i]->type->to_IR_string() << " %" << reg_count++ << ", ";
}
if (param_list.size()) ostr << param_list.back()->type->to_IR_string();
ostr << ") {" << std::endl;
_gen_blocks(func->bb_list, reg_count);
ostr << "}" << std::endl;
}
#pragma endregion
}
} // namespace antlrSysY