buggy ir gen
This commit is contained in:
parent
db20cad1df
commit
53b6e3e33f
@ -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
2
.vscode/launch.json
vendored
@ -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}"
|
||||
}
|
||||
]
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,6 +38,7 @@ 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;
|
||||
@ -40,58 +46,32 @@ public:
|
||||
: 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";
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -100,6 +80,10 @@ 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 {
|
||||
@ -117,24 +101,43 @@ public:
|
||||
: 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)
|
||||
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) {
|
||||
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 {
|
||||
@ -162,6 +165,7 @@ public:
|
||||
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)
|
||||
@ -169,6 +173,13 @@ public:
|
||||
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>}*
|
||||
@ -180,10 +191,10 @@ public:
|
||||
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)) {
|
||||
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
|
||||
@ -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
|
||||
@ -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;
|
||||
@ -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 {
|
||||
@ -122,6 +150,9 @@ public:
|
||||
FunctionType(TypePtr_t return_type) : Type(TypeTag::FunctionType), return_type(return_type) {}
|
||||
FunctionType(TypePtr_t return_type, const std::vector<TypePtr_t> ¶ms_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
|
||||
@ -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,6 +109,13 @@ 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 {
|
||||
@ -97,10 +123,31 @@ 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) {
|
||||
|
||||
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;
|
||||
@ -115,6 +162,17 @@ public:
|
||||
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
|
||||
@ -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 ¤t_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;
|
||||
};
|
||||
|
||||
|
||||
@ -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,10 +65,17 @@ 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
|
||||
|
||||
@ -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
13
scripts/manual-compile.py
Normal 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}")
|
||||
33
src/main.cpp
33
src/main.cpp
@ -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
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -273,11 +272,9 @@ 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
|
||||
@ -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;
|
||||
}
|
||||
@ -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,8 +367,7 @@ 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()));
|
||||
_state.isConstInt = false;
|
||||
@ -514,7 +510,7 @@ 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 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);
|
||||
@ -531,7 +527,7 @@ std::any Visitor::visitLOrExp(SysyParser::LOrExpContext *ctx) {
|
||||
auto and_exp_list = ctx->lAndExp();
|
||||
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);
|
||||
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]);
|
||||
@ -822,8 +818,7 @@ std::any Visitor::visitLVal(SysyParser::LValContext *ctx) {
|
||||
return arr_elem_ptr;
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("Unreachable");
|
||||
default: panic("Unreachable");
|
||||
}
|
||||
}
|
||||
panic("Unreachable");
|
||||
@ -840,7 +835,7 @@ 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;
|
||||
@ -931,11 +926,11 @@ std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) {
|
||||
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);
|
||||
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()->false_block = false_block;
|
||||
@ -958,9 +953,9 @@ 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);
|
||||
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
|
||||
@ -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 {};
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 ¶m_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 ¶m_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
|
||||
Loading…
Reference in New Issue
Block a user