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 Language: Cpp
BasedOnStyle: LLVM BasedOnStyle: LLVM
@ -21,8 +22,8 @@ AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true BinPackArguments: false
BinPackParameters: true BinPackParameters: false
BraceWrapping: BraceWrapping:
AfterCaseLabel: false AfterCaseLabel: false
AfterClass: false AfterClass: false
@ -87,13 +88,13 @@ MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
PackConstructorInitializers: NextLine PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2 PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakBeforeFirstCallParameter: 15
PenaltyBreakComment: 300 PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120 PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000 PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10 PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000 PenaltyExcessCharacter: 10000
PenaltyReturnTypeOnItsOwnLine: 60 PenaltyReturnTypeOnItsOwnLine: 100000
PointerAlignment: Right PointerAlignment: Right
ReflowComments: true ReflowComments: true
SortIncludes: true SortIncludes: true

2
.vscode/launch.json vendored
View File

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

View File

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

View File

@ -1,5 +1,10 @@
#pragma once #pragma once
#include "common.h"
#include "llir_type.h"
#include "llir_value.h" #include "llir_value.h"
#include <cassert>
#include <sstream>
#include <string>
namespace antlrSysY { namespace antlrSysY {
enum class InstTag { enum class InstTag {
@ -33,65 +38,40 @@ enum class InstTag {
class Instruction : public Value { class Instruction : public Value {
public: public:
int ir_seqno = -1;
InstTag tag; InstTag tag;
std::shared_ptr<BasicBlock> parent_bb; std::shared_ptr<BasicBlock> parent_bb;
std::vector<std::shared_ptr<Value>> operand_list; std::vector<std::shared_ptr<Value>> operand_list;
Instruction(InstTag inst_tag, TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb) 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 { virtual std::string to_string() override {
switch (tag) { switch (tag) {
case InstTag::Add: case InstTag::Add: return "add";
return "Add"; case InstTag::Sub: return "sub";
case InstTag::Sub: case InstTag::Mod: return "srem";
return "Sub"; case InstTag::Mul: return "mul";
case InstTag::Mod: case InstTag::Div: return "sdiv";
return "Mod"; case InstTag::Lt: return "icmp slt";
case InstTag::Mul: case InstTag::Le: return "icmp sle";
return "Mul"; case InstTag::Ge: return "icmp sge";
case InstTag::Div: case InstTag::Gt: return "icmp sgt";
return "Div"; case InstTag::Eq: return "icmp eq";
case InstTag::Lt: case InstTag::Ne: return "icmp ne";
return "Lt"; case InstTag::And: return "and";
case InstTag::Le: case InstTag::Or: return "or";
return "Le"; case InstTag::Br: return "br";
case InstTag::Ge: case InstTag::Call: return "call";
return "Ge"; case InstTag::Ret: return "ret";
case InstTag::Gt: case InstTag::Alloca: return "alloca";
return "Gt"; case InstTag::Load: return "load";
case InstTag::Eq: case InstTag::Store: return "store";
return "Eq"; case InstTag::GEP: return "GEP";
case InstTag::Ne: case InstTag::Zext: return "zext";
return "Ne"; case InstTag::Phi: return "Phi";
case InstTag::And: case InstTag::MemPhi: return "MemPhi";
return "And"; case InstTag::LoadDep: return "LoadDep";
case InstTag::Or: case InstTag::InsertEle: return "InsertEle";
return "Or"; case InstTag::ExtractEle: return "ExtractEle";
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 { class InstAlloca : public Instruction {
public: public:
InstAlloca(TypePtr_t alloc_type, std::shared_ptr<BasicBlock> parent_bb) 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 { class InstStore : public Instruction {
public: public:
InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer, std::shared_ptr<BasicBlock> parent_bb) 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(value);
operand_list.push_back(pointer); operand_list.push_back(pointer);
} }
@ -114,41 +98,60 @@ public:
class InstLoad : public Instruction { class InstLoad : public Instruction {
public: public:
InstLoad(std::shared_ptr<Value> value, TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb) 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); 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 { class InstBinary : public Instruction {
public: public:
InstBinary(InstTag inst_tag, TypePtr_t val_type, std::shared_ptr<Value> op1, std::shared_ptr<Value> op2, InstBinary(
std::shared_ptr<BasicBlock> parent_bb) InstTag inst_tag,
: Instruction(inst_tag, val_type, parent_bb) { 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(op1);
operand_list.push_back(op2); 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 { class InstZext : public Instruction {
public: public:
InstZext(std::shared_ptr<Value> op, std::shared_ptr<BasicBlock> parent_bb) 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); 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 { class InstBranch : public Instruction {
public: public:
// conditional branch // conditional branch
InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, BasicBlockPtr_t parent_bb) 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(cond);
this->operand_list.push_back(true_block); this->operand_list.push_back(true_block);
this->operand_list.push_back(false_block); this->operand_list.push_back(false_block);
} }
// unconditional branch // unconditional branch
InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb) 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); this->operand_list.push_back(target_block);
} }
}; };
@ -156,19 +159,27 @@ public:
class InstReturn : public Instruction { class InstReturn : public Instruction {
public: public:
InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb) 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); this->operand_list.push_back(ret_val);
} }
InstReturn(BasicBlockPtr_t parent_bb) : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {} 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 { class InstCall : public Instruction {
public: public:
InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args, BasicBlockPtr_t parent_bb) 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.push_back(func);
operand_list.insert(operand_list.end(), args.begin(), args.end()); 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>}* // getelementptr <ty>, ptr <ptrval>{, [inrange] <ty> <idx>}*
@ -179,11 +190,11 @@ public:
ValuePtr_t aim_to; ValuePtr_t aim_to;
TypePtr_t element_type; TypePtr_t element_type;
InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices, BasicBlockPtr_t parent_bb) 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) { : 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; 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; aim_to = pointer;
} }
else { else {
@ -195,6 +206,11 @@ public:
operand_list.insert(operand_list.end(), indices.begin(), indices.end()); 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 // get the inner
static TypePtr_t extract_type(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices) { static TypePtr_t extract_type(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices) {
auto pointer_type = std::dynamic_pointer_cast<PointerType>(pointer->type); auto pointer_type = std::dynamic_pointer_cast<PointerType>(pointer->type);
@ -215,4 +231,4 @@ public:
} }
}; };
} } // namespace antlrSysY

View File

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

View File

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

View File

@ -1,13 +1,13 @@
#pragma once #pragma once
#include <memory>
#include <shared_mutex>
#include <string>
#include <vector>
#include "3rdparty/easylogging++.h" #include "3rdparty/easylogging++.h"
#include "common.h" #include "common.h"
#include "llir_type.h" #include "llir_type.h"
#include <list>
#include <memory>
#include <shared_mutex>
#include <string>
#include <vector>
namespace antlrSysY { namespace antlrSysY {
@ -17,17 +17,31 @@ public:
TypePtr_t type; TypePtr_t type;
Value(const std::string &name, TypePtr_t type) : name(name), type(type) {} Value(const std::string &name, TypePtr_t type) : name(name), type(type) {}
virtual ~Value() = default; 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()) { if (ptr.get()) {
auto &r = *ptr.get(); // auto &r = *ptr.get();
return typeid(r) == typeid(TT); // return typeid(r) == typeid(TT);
return dynamic_cast<TT*>(ptr.get()) != nullptr;
} }
LOG(WARNING) << "Comparing with nullptr"; LOG(WARNING) << "Comparing with nullptr";
return false; 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() { virtual std::string to_string() {
return name + ": " + type->to_string(); return name + ": " + type->to_string();
} }
virtual std::string to_IR_string() {
panic("No applicable for IR gen");
}
}; };
class User : public Value { class User : public Value {
@ -39,13 +53,16 @@ class Instruction;
class FParam : public Value { class FParam : public Value {
public: public:
int ir_seqno = -1;
FParam(const std::string &name, TypePtr_t type) : Value(name, type) {} 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 { class Function : public Value {
public: public:
std::vector<std::shared_ptr<FParam>> fparam_list; 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 // 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)) {} Function(const std::string &name, TypePtr_t ret_type) : Value(name, std::make_shared<FunctionType>(ret_type)) {}
std::shared_ptr<FunctionType> get_type() { std::shared_ptr<FunctionType> get_type() {
@ -65,8 +82,10 @@ public:
class BasicBlock : public Value { class BasicBlock : public Value {
public: public:
int ir_seqno = -1;
std::vector<std::shared_ptr<Instruction>> inst_list; std::vector<std::shared_ptr<Instruction>> inst_list;
std::shared_ptr<Function> parent; std::shared_ptr<Function> parent;
BasicBlockListNode_t itr;
std::vector<std::shared_ptr<BasicBlock>> successors; std::vector<std::shared_ptr<BasicBlock>> successors;
std::vector<std::shared_ptr<BasicBlock>> predecessors; std::vector<std::shared_ptr<BasicBlock>> predecessors;
BasicBlock(const std::string &name, std::shared_ptr<Function> parent) : Value(name, TypeHelper::TYPE_LABEL) { 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) { static std::shared_ptr<ConstantInt> make_shared(int value) {
return std::make_shared<ConstantInt>("", 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 { class ConstantArr : public Constant {
public: public:
std::vector<ValuePtr_t> value_list; std::vector<ValuePtr_t> value_list;
ConstantArr(const std::string &name, const std::vector<ValuePtr_t> &value_list, std::shared_ptr<ArrayType> type) ConstantArr(const std::string &name, const std::vector<ValuePtr_t> &value_list, std::shared_ptr<ArrayType> type)
: Constant(name, type), value_list(value_list) {} : 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); 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; typedef std::shared_ptr<Constant> ConstantPtr_t;
@ -111,10 +158,21 @@ public:
ConstantPtr_t init_value; ConstantPtr_t init_value;
bool is_const; bool is_const;
GlobalVar(const std::string &name, 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) { 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); 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 } // namespace antlrSysY

View File

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

View File

@ -1,45 +1,63 @@
#pragma once #pragma once
#include "3rdparty/easylogging++.h" #include "3rdparty/easylogging++.h"
#include "antlrgen/SysyBaseVisitor.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 <any>
#include <cstddef> #include <cstddef>
#include <map> #include <map>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <ostream>
#include <string> #include <string>
#include <vector> #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 { namespace antlrSysY {
#pragma region FactoryFunctionDeclaration #pragma region FactoryFunctionDeclaration
std::shared_ptr<ConstantInt> build_ConstantInt(const std::string &name, int value); 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<InstLoad> build_InstLoad(
std::shared_ptr<BasicBlock> parent_bb); std::shared_ptr<Value> value,
std::shared_ptr<InstStore> build_InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer, TypePtr_t type,
std::shared_ptr<BasicBlock> parent_bb); 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<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<InstBinary> build_InstBinary(
std::shared_ptr<BasicBlock> parent_bb); 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<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, std::shared_ptr<InstBranch> build_InstBranch(
BasicBlockPtr_t parent_bb); 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); 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<InstReturn> build_InstReturn(BasicBlockPtr_t parent_bb);
std::shared_ptr<InstCall> build_InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args, std::shared_ptr<InstCall> build_InstCall(
BasicBlockPtr_t parent_bb); FunctionPtr_t func,
std::shared_ptr<InstGEP> build_InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices, const std::vector<ValuePtr_t> &args,
BasicBlockPtr_t parent_bb); 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 #pragma endregion
class Visitor : public antlrSysY::SysyBaseVisitor { class Visitor : public antlrSysY::SysyBaseVisitor {
private: private:
struct VisitorState { struct VisitorState {
bool isGlobalIint = false; bool isGlobalIint = false;
bool isConstInt = false; bool isConstInt = false;
bool isRealParam = false; bool isRealParam = false;
bool isCondExp = false; bool isCondExp = false;
std::shared_ptr<Function> current_func = {}; std::shared_ptr<Function> current_func = {};
std::shared_ptr<BasicBlock> current_bb = {}; std::shared_ptr<BasicBlock> current_bb = {};
std::vector<int> *arr_dim_list = nullptr; std::vector<int> *arr_dim_list = nullptr;
int arr_dim_index = 0; int arr_dim_index = 0;
struct loop_record { struct loop_record {
BasicBlockPtr_t cond, body, next; BasicBlockPtr_t cond, body, next;
int id; int id;
}; };
int loop_stmt_count = 0; int loop_stmt_count = 0;
std::vector<loop_record> loop_stack = {}; std::vector<loop_record> loop_stack = {};
}; };
ScopeTable<std::shared_ptr<Value>> _scope_tab; ScopeTable<std::shared_ptr<Value>> _scope_tab;
ScopeTable<std::shared_ptr<Function>> _func_tab; // var can have same name as func 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); inline static std::shared_ptr<ConstantInt> CONST0 = std::make_shared<ConstantInt>("CONST0", 0);
public: public:
@ -159,7 +184,7 @@ public:
std::any visitLOrExp(SysyParser::LOrExpContext *ctx) override; std::any visitLOrExp(SysyParser::LOrExpContext *ctx) override;
void llir_gen(); void llir_gen(std::ostream &);
}; };
} // namespace antlrSysY } // 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 "3rdparty/easylogging++.h"
#include "BaseErrorListener.h" #include "BaseErrorListener.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "antlr4-runtime.h" #include "antlr4-runtime.h"
#include "antlrgen/SysyLexer.h" #include "antlrgen/SysyLexer.h"
#include "antlrgen/SysyParser.h" #include "antlrgen/SysyParser.h"
#include <3rdparty/argparse.hpp>
#include "common.h" #include "common.h"
#include "visitor.h" #include "visitor.h"
#include <3rdparty/argparse.hpp>
#include <fstream>
#include <iostream>
#include <string>
INITIALIZE_EASYLOGGINGPP INITIALIZE_EASYLOGGINGPP
@ -20,10 +18,17 @@ using namespace antlr4;
class AbortErrorListener : public BaseErrorListener { class AbortErrorListener : public BaseErrorListener {
public: public:
void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line, size_t charPositionInLine, void syntaxError(
const std::string &msg, std::exception_ptr e) override { Recognizer *recognizer,
throw ParseCancellationException("line " + std::to_string(line) + ":" + std::to_string(charPositionInLine) + " " + Token *offendingSymbol,
msg); 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 source_file = arg_parser.get<std::string>("source");
auto output_file = arg_parser.get<std::string>("-o"); 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::cout << source_file << " " << output_file << " " << flg_O1 <<
// std::endl; // std::endl;
#pragma endregion #pragma endregion
@ -62,6 +67,7 @@ int main(int argc, const char **argv) {
std::ifstream ifs_source_file(source_file); std::ifstream ifs_source_file(source_file);
if (!ifs_source_file.good()) { if (!ifs_source_file.good()) {
LOG(ERROR) << "Source file " << source_file << " not found."; LOG(ERROR) << "Source file " << source_file << " not found.";
return 1;
} }
ANTLRInputStream input(ifs_source_file); ANTLRInputStream input(ifs_source_file);
SysyLexer lexer(&input); SysyLexer lexer(&input);
@ -79,6 +85,13 @@ int main(int argc, const char **argv) {
auto tree = parser.program(); auto tree = parser.program();
Visitor visitor(lexer); Visitor visitor(lexer);
visitor.visitProgram(tree); 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 #if 0
std::cout << tree->toStringTree(&parser) << std::endl << std::endl; std::cout << tree->toStringTree(&parser) << std::endl << std::endl;
#endif #endif

View File

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

View File

@ -11,34 +11,50 @@ std::shared_ptr<ConstantInt> build_ConstantInt(const std::string &name, int valu
return lala; 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); 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; return basic_block;
} }
std::shared_ptr<InstLoad> build_InstLoad(std::shared_ptr<Value> value, TypePtr_t type, std::shared_ptr<InstLoad> build_InstLoad(
std::shared_ptr<BasicBlock> parent_bb) { 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); auto inst_load = std::make_shared<InstLoad>(value, type, parent_bb);
parent_bb->inst_list.push_back(inst_load); parent_bb->inst_list.push_back(inst_load);
return inst_load; return inst_load;
} }
std::shared_ptr<InstStore> build_InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer, std::shared_ptr<InstStore> build_InstStore(
std::shared_ptr<BasicBlock> parent_bb) { 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); auto inst_store = std::make_shared<InstStore>(value, pointer, parent_bb);
parent_bb->inst_list.push_back(inst_store); parent_bb->inst_list.push_back(inst_store);
return 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) { 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); 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; 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<InstBinary> build_InstBinary(
std::shared_ptr<BasicBlock> parent_bb) { 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; std::shared_ptr<InstBinary> inst_binary;
if (InstTag::Lt <= inst_tag && inst_tag <= InstTag::Or) { if (InstTag::Lt <= inst_tag && inst_tag <= InstTag::Or) {
inst_binary = std::make_shared<InstBinary>(inst_tag, TypeHelper::TYPE_I1, op1, op2, parent_bb); 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; return inst_zext;
} }
std::shared_ptr<InstBranch> build_InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, std::shared_ptr<InstBranch> build_InstBranch(
BasicBlockPtr_t parent_bb) { 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); auto inst = std::make_shared<InstBranch>(cond, true_block, false_block, parent_bb);
parent_bb->inst_list.push_back(inst); parent_bb->inst_list.push_back(inst);
return inst; return inst;
@ -84,15 +104,21 @@ std::shared_ptr<InstReturn> build_InstReturn(BasicBlockPtr_t parent_bb) {
return inst; return inst;
} }
std::shared_ptr<InstCall> build_InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args, std::shared_ptr<InstCall> build_InstCall(
BasicBlockPtr_t parent_bb) { FunctionPtr_t func,
const std::vector<ValuePtr_t> &args,
BasicBlockPtr_t parent_bb
) {
auto inst = std::make_shared<InstCall>(func, args, parent_bb); auto inst = std::make_shared<InstCall>(func, args, parent_bb);
parent_bb->inst_list.push_back(inst); parent_bb->inst_list.push_back(inst);
return inst; return inst;
} }
std::shared_ptr<InstGEP> build_InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices, std::shared_ptr<InstGEP> build_InstGEP(
BasicBlockPtr_t parent_bb) { ValuePtr_t pointer,
const std::vector<ValuePtr_t> &indices,
BasicBlockPtr_t parent_bb
) {
auto inst = std::make_shared<InstGEP>(pointer, indices, parent_bb); auto inst = std::make_shared<InstGEP>(pointer, indices, parent_bb);
parent_bb->inst_list.push_back(inst); parent_bb->inst_list.push_back(inst);
return 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 "visitor.h"
#include <array>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
namespace antlrSysY { 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