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,65 +38,40 @@ enum class InstTag {
|
||||
|
||||
class Instruction : public Value {
|
||||
public:
|
||||
int ir_seqno = -1;
|
||||
InstTag tag;
|
||||
std::shared_ptr<BasicBlock> parent_bb;
|
||||
std::vector<std::shared_ptr<Value>> operand_list;
|
||||
Instruction(InstTag inst_tag, TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb)
|
||||
: Value("", type), tag(inst_tag), parent_bb(parent_bb) {}
|
||||
: Value("", type), tag(inst_tag), parent_bb(parent_bb) {}
|
||||
virtual std::string to_string() override {
|
||||
switch (tag) {
|
||||
case InstTag::Add:
|
||||
return "Add";
|
||||
case InstTag::Sub:
|
||||
return "Sub";
|
||||
case InstTag::Mod:
|
||||
return "Mod";
|
||||
case InstTag::Mul:
|
||||
return "Mul";
|
||||
case InstTag::Div:
|
||||
return "Div";
|
||||
case InstTag::Lt:
|
||||
return "Lt";
|
||||
case InstTag::Le:
|
||||
return "Le";
|
||||
case InstTag::Ge:
|
||||
return "Ge";
|
||||
case InstTag::Gt:
|
||||
return "Gt";
|
||||
case InstTag::Eq:
|
||||
return "Eq";
|
||||
case InstTag::Ne:
|
||||
return "Ne";
|
||||
case InstTag::And:
|
||||
return "And";
|
||||
case InstTag::Or:
|
||||
return "Or";
|
||||
case InstTag::Br:
|
||||
return "Br";
|
||||
case InstTag::Call:
|
||||
return "Call";
|
||||
case InstTag::Ret:
|
||||
return "Ret";
|
||||
case InstTag::Alloca:
|
||||
return "Alloca";
|
||||
case InstTag::Load:
|
||||
return "Load";
|
||||
case InstTag::Store:
|
||||
return "Store";
|
||||
case InstTag::GEP:
|
||||
return "GEP";
|
||||
case InstTag::Zext:
|
||||
return "Zext";
|
||||
case InstTag::Phi:
|
||||
return "Phi";
|
||||
case InstTag::MemPhi:
|
||||
return "MemPhi";
|
||||
case InstTag::LoadDep:
|
||||
return "LoadDep";
|
||||
case InstTag::InsertEle:
|
||||
return "InsertEle";
|
||||
case InstTag::ExtractEle:
|
||||
return "ExtractEle";
|
||||
case InstTag::Add: return "add";
|
||||
case InstTag::Sub: return "sub";
|
||||
case InstTag::Mod: return "srem";
|
||||
case InstTag::Mul: return "mul";
|
||||
case InstTag::Div: return "sdiv";
|
||||
case InstTag::Lt: return "icmp slt";
|
||||
case InstTag::Le: return "icmp sle";
|
||||
case InstTag::Ge: return "icmp sge";
|
||||
case InstTag::Gt: return "icmp sgt";
|
||||
case InstTag::Eq: return "icmp eq";
|
||||
case InstTag::Ne: return "icmp ne";
|
||||
case InstTag::And: return "and";
|
||||
case InstTag::Or: return "or";
|
||||
case InstTag::Br: return "br";
|
||||
case InstTag::Call: return "call";
|
||||
case InstTag::Ret: return "ret";
|
||||
case InstTag::Alloca: return "alloca";
|
||||
case InstTag::Load: return "load";
|
||||
case InstTag::Store: return "store";
|
||||
case InstTag::GEP: return "GEP";
|
||||
case InstTag::Zext: return "zext";
|
||||
case InstTag::Phi: return "Phi";
|
||||
case InstTag::MemPhi: return "MemPhi";
|
||||
case InstTag::LoadDep: return "LoadDep";
|
||||
case InstTag::InsertEle: return "InsertEle";
|
||||
case InstTag::ExtractEle: return "ExtractEle";
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -99,13 +79,17 @@ public:
|
||||
class InstAlloca : public Instruction {
|
||||
public:
|
||||
InstAlloca(TypePtr_t alloc_type, std::shared_ptr<BasicBlock> parent_bb)
|
||||
: Instruction(InstTag::Alloca, std::make_shared<PointerType>(alloc_type), parent_bb) {}
|
||||
: Instruction(InstTag::Alloca, std::make_shared<PointerType>(alloc_type), parent_bb) {}
|
||||
virtual std::string to_IR_string() override {
|
||||
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
class InstStore : public Instruction {
|
||||
public:
|
||||
InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer, std::shared_ptr<BasicBlock> parent_bb)
|
||||
: Instruction(InstTag::Store, TypeHelper::TYPE_VOID, parent_bb) {
|
||||
: Instruction(InstTag::Store, TypeHelper::TYPE_VOID, parent_bb) {
|
||||
operand_list.push_back(value);
|
||||
operand_list.push_back(pointer);
|
||||
}
|
||||
@ -114,41 +98,60 @@ public:
|
||||
class InstLoad : public Instruction {
|
||||
public:
|
||||
InstLoad(std::shared_ptr<Value> value, TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb)
|
||||
: Instruction(InstTag::Load, type, parent_bb) {
|
||||
: Instruction(InstTag::Load, type, parent_bb) {
|
||||
operand_list.push_back(value);
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
class InstBinary : public Instruction {
|
||||
public:
|
||||
InstBinary(InstTag inst_tag, TypePtr_t val_type, std::shared_ptr<Value> op1, std::shared_ptr<Value> op2,
|
||||
std::shared_ptr<BasicBlock> parent_bb)
|
||||
: Instruction(inst_tag, val_type, parent_bb) {
|
||||
InstBinary(
|
||||
InstTag inst_tag,
|
||||
TypePtr_t val_type,
|
||||
std::shared_ptr<Value> op1,
|
||||
std::shared_ptr<Value> op2,
|
||||
std::shared_ptr<BasicBlock> parent_bb
|
||||
)
|
||||
: Instruction(inst_tag, val_type, parent_bb) {
|
||||
operand_list.push_back(op1);
|
||||
operand_list.push_back(op2);
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
//<result> = zext <ty> <value> to <ty2>
|
||||
// zext is integer type, i32
|
||||
class InstZext : public Instruction {
|
||||
public:
|
||||
InstZext(std::shared_ptr<Value> op, std::shared_ptr<BasicBlock> parent_bb)
|
||||
: Instruction(InstTag::Zext, TypeHelper::TYPE_I32, parent_bb) {
|
||||
: Instruction(InstTag::Zext, TypeHelper::TYPE_I32, parent_bb) {
|
||||
operand_list.push_back(op);
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
class InstBranch : public Instruction {
|
||||
public:
|
||||
// conditional branch
|
||||
InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, BasicBlockPtr_t parent_bb)
|
||||
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
|
||||
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
|
||||
this->operand_list.push_back(cond);
|
||||
this->operand_list.push_back(true_block);
|
||||
this->operand_list.push_back(false_block);
|
||||
}
|
||||
// unconditional branch
|
||||
InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb)
|
||||
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
|
||||
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
|
||||
this->operand_list.push_back(target_block);
|
||||
}
|
||||
};
|
||||
@ -156,19 +159,27 @@ public:
|
||||
class InstReturn : public Instruction {
|
||||
public:
|
||||
InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb)
|
||||
: Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {
|
||||
: Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {
|
||||
this->operand_list.push_back(ret_val);
|
||||
}
|
||||
InstReturn(BasicBlockPtr_t parent_bb) : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {}
|
||||
};
|
||||
|
||||
// call's type is the function's return type
|
||||
class InstCall : public Instruction {
|
||||
public:
|
||||
InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args, BasicBlockPtr_t parent_bb)
|
||||
: Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) {
|
||||
: Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) {
|
||||
operand_list.push_back(func);
|
||||
operand_list.insert(operand_list.end(), args.begin(), args.end());
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
if (Type::isType<VoidType>(type)) {
|
||||
panic("No ret val");
|
||||
}
|
||||
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
// getelementptr <ty>, ptr <ptrval>{, [inrange] <ty> <idx>}*
|
||||
@ -179,11 +190,11 @@ public:
|
||||
ValuePtr_t aim_to;
|
||||
TypePtr_t element_type;
|
||||
InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices, BasicBlockPtr_t parent_bb)
|
||||
: Instruction(InstTag::GEP, std::make_shared<PointerType>(extract_type(pointer, indices)), parent_bb) {
|
||||
if (Value::isType<InstGEP>(pointer)) {
|
||||
: Instruction(InstTag::GEP, std::make_shared<PointerType>(extract_type(pointer, indices)), parent_bb) {
|
||||
if (Value::isValueType<InstGEP>(pointer)) {
|
||||
aim_to = std::dynamic_pointer_cast<InstGEP>(pointer)->aim_to;
|
||||
}
|
||||
else if (Value::isType<InstAlloca>(pointer) || Value::isType<GlobalVar>(pointer)){
|
||||
else if (Value::isValueType<InstAlloca>(pointer) || Value::isValueType<GlobalVar>(pointer)) {
|
||||
aim_to = pointer;
|
||||
}
|
||||
else {
|
||||
@ -195,6 +206,11 @@ public:
|
||||
operand_list.insert(operand_list.end(), indices.begin(), indices.end());
|
||||
}
|
||||
|
||||
virtual std::string to_IR_string() override {
|
||||
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
|
||||
return str;
|
||||
}
|
||||
|
||||
// get the inner
|
||||
static TypePtr_t extract_type(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices) {
|
||||
auto pointer_type = std::dynamic_pointer_cast<PointerType>(pointer->type);
|
||||
@ -215,4 +231,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace antlrSysY
|
||||
@ -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;
|
||||
@ -76,19 +95,19 @@ public:
|
||||
static bool isIntegerTypeI1(TypePtr_t &type) {
|
||||
return isIntegerType(type) && std::dynamic_pointer_cast<IntegerType>(type)->isI1();
|
||||
}
|
||||
inline static TypePtr_t TYPE_I32 = std::make_shared<IntegerType>();
|
||||
inline static TypePtr_t TYPE_I1 = std::make_shared<IntegerType>(IntegerType::IntTypes::I1);
|
||||
inline static TypePtr_t TYPE_I32 = std::make_shared<IntegerType>();
|
||||
inline static TypePtr_t TYPE_I1 = std::make_shared<IntegerType>(IntegerType::IntTypes::I1);
|
||||
inline static TypePtr_t TYPE_LABEL = std::make_shared<LabelType>();
|
||||
inline static TypePtr_t TYPE_VOID = std::make_shared<VoidType>();
|
||||
inline static TypePtr_t TYPE_VOID = std::make_shared<VoidType>();
|
||||
};
|
||||
|
||||
class ArrayType : public Type {
|
||||
public:
|
||||
TypePtr_t element_type = TypeHelper::TYPE_I32;
|
||||
int element_count = 0;
|
||||
int element_count = 0;
|
||||
ArrayType() : Type(TypeTag::ArrayType) {}
|
||||
ArrayType(TypePtr_t element_type, int element_count)
|
||||
: Type(TypeTag::ArrayType), element_count(element_count), element_type(element_type) {}
|
||||
: Type(TypeTag::ArrayType), element_count(element_count), element_type(element_type) {}
|
||||
static std::shared_ptr<ArrayType> build_from_list(const std::vector<int> &dim_list) {
|
||||
TypePtr_t array_type = TypeHelper::TYPE_I32;
|
||||
sysy_assert(dim_list.size() != 0);
|
||||
@ -100,6 +119,9 @@ public:
|
||||
virtual std::string to_string() override {
|
||||
return "Array[" + std::to_string(element_count) + " x " + element_type->to_string() + "]";
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
return "[" + std::to_string(element_count) + " x " + element_type->to_IR_string() + "]";
|
||||
}
|
||||
};
|
||||
|
||||
class PointerType : public Type {
|
||||
@ -113,6 +135,12 @@ public:
|
||||
virtual std::string to_string() override {
|
||||
return "Pointer->" + pointed_type->to_string();
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
if (pointed_type->type_tag == TypeTag::IntegerType) {
|
||||
return "i32*";
|
||||
}
|
||||
panic("Unknown");
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionType : public Type {
|
||||
@ -121,7 +149,10 @@ public:
|
||||
std::vector<TypePtr_t> params_type;
|
||||
FunctionType(TypePtr_t return_type) : Type(TypeTag::FunctionType), return_type(return_type) {}
|
||||
FunctionType(TypePtr_t return_type, const std::vector<TypePtr_t> ¶ms_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
|
||||
@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "3rdparty/easylogging++.h"
|
||||
#include "common.h"
|
||||
#include "llir_type.h"
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace antlrSysY {
|
||||
|
||||
@ -17,17 +17,31 @@ public:
|
||||
TypePtr_t type;
|
||||
Value(const std::string &name, TypePtr_t type) : name(name), type(type) {}
|
||||
virtual ~Value() = default;
|
||||
template <typename TT> static bool isType(std::shared_ptr<Value> ptr) {
|
||||
|
||||
template <typename TT>
|
||||
static bool isValueType(std::shared_ptr<Value> ptr) {
|
||||
if (ptr.get()) {
|
||||
auto &r = *ptr.get();
|
||||
return typeid(r) == typeid(TT);
|
||||
// auto &r = *ptr.get();
|
||||
// return typeid(r) == typeid(TT);
|
||||
return dynamic_cast<TT*>(ptr.get()) != nullptr;
|
||||
}
|
||||
LOG(WARNING) << "Comparing with nullptr";
|
||||
return false;
|
||||
}
|
||||
|
||||
// it is caller's duty to check before use `asType`
|
||||
template <typename TT>
|
||||
static std::shared_ptr<TT> asValueType(std::shared_ptr<Value> ptr) {
|
||||
return std::dynamic_pointer_cast<TT>(ptr);
|
||||
}
|
||||
|
||||
virtual std::string to_string() {
|
||||
return name + ": " + type->to_string();
|
||||
}
|
||||
|
||||
virtual std::string to_IR_string() {
|
||||
panic("No applicable for IR gen");
|
||||
}
|
||||
};
|
||||
|
||||
class User : public Value {
|
||||
@ -39,13 +53,16 @@ class Instruction;
|
||||
|
||||
class FParam : public Value {
|
||||
public:
|
||||
int ir_seqno = -1;
|
||||
FParam(const std::string &name, TypePtr_t type) : Value(name, type) {}
|
||||
};
|
||||
|
||||
typedef std::list<std::shared_ptr<antlrSysY::BasicBlock>>::iterator BasicBlockListNode_t;
|
||||
|
||||
class Function : public Value {
|
||||
public:
|
||||
std::vector<std::shared_ptr<FParam>> fparam_list;
|
||||
std::vector<std::shared_ptr<BasicBlock>> bb_list;
|
||||
std::list<std::shared_ptr<BasicBlock>> bb_list;
|
||||
// we use empty basic_block to represent lib function
|
||||
Function(const std::string &name, TypePtr_t ret_type) : Value(name, std::make_shared<FunctionType>(ret_type)) {}
|
||||
std::shared_ptr<FunctionType> get_type() {
|
||||
@ -65,8 +82,10 @@ public:
|
||||
|
||||
class BasicBlock : public Value {
|
||||
public:
|
||||
int ir_seqno = -1;
|
||||
std::vector<std::shared_ptr<Instruction>> inst_list;
|
||||
std::shared_ptr<Function> parent;
|
||||
BasicBlockListNode_t itr;
|
||||
std::vector<std::shared_ptr<BasicBlock>> successors;
|
||||
std::vector<std::shared_ptr<BasicBlock>> predecessors;
|
||||
BasicBlock(const std::string &name, std::shared_ptr<Function> parent) : Value(name, TypeHelper::TYPE_LABEL) {
|
||||
@ -90,17 +109,45 @@ public:
|
||||
static std::shared_ptr<ConstantInt> make_shared(int value) {
|
||||
return std::make_shared<ConstantInt>("", value);
|
||||
}
|
||||
virtual std::string to_string() override {
|
||||
std::string str = type->to_string() + " " + std::to_string(value);
|
||||
return str;
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
return to_string();
|
||||
}
|
||||
};
|
||||
|
||||
class ConstantArr : public Constant {
|
||||
public:
|
||||
std::vector<ValuePtr_t> value_list;
|
||||
ConstantArr(const std::string &name, const std::vector<ValuePtr_t> &value_list, std::shared_ptr<ArrayType> type)
|
||||
: Constant(name, type), value_list(value_list) {}
|
||||
static std::shared_ptr<ConstantArr> make_shared(const std::string &name, const std::vector<ValuePtr_t> &value_list,
|
||||
std::shared_ptr<ArrayType> type) {
|
||||
: Constant(name, type), value_list(value_list) {}
|
||||
|
||||
int real_size() const {
|
||||
return std::dynamic_pointer_cast<ArrayType>(type)->element_count;
|
||||
}
|
||||
static std::shared_ptr<ConstantArr> make_shared(
|
||||
const std::string &name,
|
||||
const std::vector<ValuePtr_t> &value_list,
|
||||
std::shared_ptr<ArrayType> type
|
||||
) {
|
||||
return std::make_shared<ConstantArr>(name, value_list, type);
|
||||
}
|
||||
virtual std::string to_string() override {
|
||||
std::string str = "{";
|
||||
for (auto elem : value_list) {
|
||||
if (elem)
|
||||
str += elem->to_string() + ", ";
|
||||
else
|
||||
str += "{...}, ";
|
||||
}
|
||||
if (real_size() > value_list.size()) {
|
||||
str += std::to_string(real_size() - value_list.size()) + " zeros";
|
||||
}
|
||||
str += "}";
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Constant> ConstantPtr_t;
|
||||
@ -111,10 +158,21 @@ public:
|
||||
ConstantPtr_t init_value;
|
||||
bool is_const;
|
||||
GlobalVar(const std::string &name, ConstantPtr_t init_value, bool is_const)
|
||||
: Value(name, PointerType::make_shared(init_value->type)), init_value(init_value), is_const(is_const) {}
|
||||
: Value(name, PointerType::make_shared(init_value->type)), init_value(init_value), is_const(is_const) {}
|
||||
static std::shared_ptr<GlobalVar> make_shared(const std::string &name, ConstantPtr_t init_value, bool is_const) {
|
||||
return std::make_shared<GlobalVar>(name, init_value, is_const);
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
std::string str = type->to_IR_string() + " @" + name;
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<ConstantArr> gen_arr_hierarchy(
|
||||
const std::shared_ptr<ArrayType> array_type,
|
||||
const std::vector<ValuePtr_t> &const_array,
|
||||
int base,
|
||||
int length
|
||||
);
|
||||
|
||||
} // namespace antlrSysY
|
||||
@ -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,35 +65,42 @@ std::shared_ptr<InstReturn> build_InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t
|
||||
|
||||
std::shared_ptr<InstReturn> build_InstReturn(BasicBlockPtr_t parent_bb);
|
||||
|
||||
std::shared_ptr<InstCall> build_InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args,
|
||||
BasicBlockPtr_t parent_bb);
|
||||
std::shared_ptr<InstGEP> build_InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices,
|
||||
BasicBlockPtr_t parent_bb);
|
||||
std::shared_ptr<InstCall> build_InstCall(
|
||||
FunctionPtr_t func,
|
||||
const std::vector<ValuePtr_t> &args,
|
||||
BasicBlockPtr_t parent_bb
|
||||
);
|
||||
|
||||
std::shared_ptr<InstGEP> build_InstGEP(
|
||||
ValuePtr_t pointer,
|
||||
const std::vector<ValuePtr_t> &indices,
|
||||
BasicBlockPtr_t parent_bb
|
||||
);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
class Visitor : public antlrSysY::SysyBaseVisitor {
|
||||
private:
|
||||
struct VisitorState {
|
||||
bool isGlobalIint = false;
|
||||
bool isConstInt = false;
|
||||
bool isRealParam = false;
|
||||
bool isCondExp = false;
|
||||
bool isGlobalIint = false;
|
||||
bool isConstInt = false;
|
||||
bool isRealParam = false;
|
||||
bool isCondExp = false;
|
||||
std::shared_ptr<Function> current_func = {};
|
||||
std::shared_ptr<BasicBlock> current_bb = {};
|
||||
std::vector<int> *arr_dim_list = nullptr;
|
||||
int arr_dim_index = 0;
|
||||
std::vector<int> *arr_dim_list = nullptr;
|
||||
int arr_dim_index = 0;
|
||||
struct loop_record {
|
||||
BasicBlockPtr_t cond, body, next;
|
||||
int id;
|
||||
};
|
||||
int loop_stmt_count = 0;
|
||||
int loop_stmt_count = 0;
|
||||
std::vector<loop_record> loop_stack = {};
|
||||
};
|
||||
|
||||
|
||||
ScopeTable<std::shared_ptr<Value>> _scope_tab;
|
||||
ScopeTable<std::shared_ptr<Function>> _func_tab; // var can have same name as func
|
||||
VisitorState _state = {};
|
||||
VisitorState _state = {};
|
||||
inline static std::shared_ptr<ConstantInt> CONST0 = std::make_shared<ConstantInt>("CONST0", 0);
|
||||
|
||||
public:
|
||||
@ -159,7 +184,7 @@ public:
|
||||
|
||||
std::any visitLOrExp(SysyParser::LOrExpContext *ctx) override;
|
||||
|
||||
void llir_gen();
|
||||
void llir_gen(std::ostream &);
|
||||
};
|
||||
|
||||
} // namespace antlrSysY
|
||||
13
scripts/manual-compile.py
Normal file
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}")
|
||||
35
src/main.cpp
35
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
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -44,7 +49,7 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
auto source_file = arg_parser.get<std::string>("source");
|
||||
auto output_file = arg_parser.get<std::string>("-o");
|
||||
auto flg_O1 = arg_parser["-O1"] == true;
|
||||
auto flg_O1 = arg_parser["-O1"] == true;
|
||||
// std::cout << source_file << " " << output_file << " " << flg_O1 <<
|
||||
// std::endl;
|
||||
#pragma endregion
|
||||
@ -62,6 +67,7 @@ int main(int argc, const char **argv) {
|
||||
std::ifstream ifs_source_file(source_file);
|
||||
if (!ifs_source_file.good()) {
|
||||
LOG(ERROR) << "Source file " << source_file << " not found.";
|
||||
return 1;
|
||||
}
|
||||
ANTLRInputStream input(ifs_source_file);
|
||||
SysyLexer lexer(&input);
|
||||
@ -79,6 +85,13 @@ int main(int argc, const char **argv) {
|
||||
auto tree = parser.program();
|
||||
Visitor visitor(lexer);
|
||||
visitor.visitProgram(tree);
|
||||
auto llir_file = source_file + ".ll";
|
||||
std::ofstream ofs_llir_file(llir_file);
|
||||
if (!ofs_llir_file.good()) {
|
||||
LOG(ERROR) << "Failed to create/overwrite LLIR output file " << llir_file;
|
||||
return 1;
|
||||
}
|
||||
visitor.llir_gen(ofs_llir_file);
|
||||
#if 0
|
||||
std::cout << tree->toStringTree(&parser) << std::endl << std::endl;
|
||||
#endif
|
||||
|
||||
327
src/visitor.cpp
327
src/visitor.cpp
@ -66,10 +66,10 @@ void _sysy_starttime(int lineno);
|
||||
void _sysy_stoptime(int lineno);
|
||||
*/
|
||||
|
||||
Visitor::Visitor(SysyLexer&) {
|
||||
Visitor::Visitor(SysyLexer &) {
|
||||
#pragma region RegisterLibFunc
|
||||
auto fparam_i32 = std::make_shared<FParam>("", TypeHelper::TYPE_I32);
|
||||
auto pointer_type = std::make_shared<PointerType>(TypeHelper::TYPE_I32);
|
||||
auto fparam_i32 = std::make_shared<FParam>("", TypeHelper::TYPE_I32);
|
||||
auto pointer_type = std::make_shared<PointerType>(TypeHelper::TYPE_I32);
|
||||
auto fparam_ptr_i32 = std::make_shared<FParam>("", pointer_type);
|
||||
|
||||
auto func_getint = std::make_shared<Function>("getint", TypeHelper::TYPE_I32);
|
||||
@ -88,22 +88,22 @@ Visitor::Visitor(SysyLexer&) {
|
||||
func_putint->fparam_list.push_back(fparam_i32);
|
||||
_func_tab.push_name("putint", func_putint);
|
||||
|
||||
auto func_putch = std::make_shared<Function>("putch", TypeHelper::TYPE_VOID);
|
||||
auto func_putch = std::make_shared<Function>("putch", TypeHelper::TYPE_VOID);
|
||||
func_putch->fparam_list = {fparam_i32};
|
||||
_func_tab.push_name("putch", func_putch);
|
||||
|
||||
auto func_putarray = std::make_shared<Function>("putarray", TypeHelper::TYPE_VOID);
|
||||
auto func_putarray = std::make_shared<Function>("putarray", TypeHelper::TYPE_VOID);
|
||||
func_putarray->fparam_list = {fparam_ptr_i32, fparam_i32};
|
||||
_func_tab.push_name("putarray", func_putarray);
|
||||
|
||||
// auto func_putf = std::make_shared<Function>("putf", TypeHelper::TYPE_VOID);
|
||||
// should not be used
|
||||
|
||||
auto func_starttime = std::make_shared<Function>("_sysy_starttime", TypeHelper::TYPE_VOID);
|
||||
auto func_starttime = std::make_shared<Function>("_sysy_starttime", TypeHelper::TYPE_VOID);
|
||||
func_starttime->fparam_list = {fparam_i32};
|
||||
_func_tab.push_name("starttime", func_starttime);
|
||||
|
||||
auto func_stoptime = std::make_shared<Function>("_sysy_stoptime", TypeHelper::TYPE_VOID);
|
||||
auto func_stoptime = std::make_shared<Function>("_sysy_stoptime", TypeHelper::TYPE_VOID);
|
||||
func_stoptime->fparam_list = {fparam_i32};
|
||||
_func_tab.push_name("stoptime", func_stoptime);
|
||||
|
||||
@ -142,9 +142,9 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) {
|
||||
auto array_type = ArrayType::build_from_list(dim_list);
|
||||
// anyways, first collect init value
|
||||
_state.arr_dim_index = 0;
|
||||
_state.arr_dim_list = &dim_list;
|
||||
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitConstInitVal(ctx->constInitVal()));
|
||||
_state.arr_dim_list = nullptr;
|
||||
_state.arr_dim_list = &dim_list;
|
||||
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitConstInitVal(ctx->constInitVal()));
|
||||
_state.arr_dim_list = nullptr;
|
||||
sysy_assert(_state.arr_dim_index == 0);
|
||||
|
||||
if (_scope_tab.get_level()) {
|
||||
@ -167,7 +167,7 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) {
|
||||
}
|
||||
else {
|
||||
// global const array
|
||||
auto const_arr = ConstantArr::make_shared("const_arr", array_value, array_type);
|
||||
auto const_arr = ConstantArr::make_shared("const_arr", array_value, array_type);
|
||||
auto global_var = GlobalVar::make_shared(const_name, const_arr, true);
|
||||
module.global_var_list.push_back(global_var);
|
||||
_scope_tab.push_name(const_name, global_var);
|
||||
@ -181,8 +181,7 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) {
|
||||
std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
|
||||
auto var_name = ctx->IDENT()->getText();
|
||||
VLOG(5) << "Visiting VarDef " << var_name;
|
||||
if (_scope_tab.get_name(var_name, _scope_tab.get_level()).has_value())
|
||||
panic("Duplicate const def");
|
||||
if (_scope_tab.get_name(var_name, _scope_tab.get_level()).has_value()) panic("Duplicate const def");
|
||||
// Not Array
|
||||
if (ctx->constExp().empty()) {
|
||||
// global variable
|
||||
@ -190,7 +189,7 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
|
||||
// global variable must be initialized, either specified or zeroed
|
||||
if (ctx->initVal()) {
|
||||
_state.isGlobalIint = true;
|
||||
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitInitVal(ctx->initVal()));
|
||||
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitInitVal(ctx->initVal()));
|
||||
_state.isGlobalIint = false;
|
||||
auto global_var_int = std::make_shared<GlobalVar>(var_name, result, false);
|
||||
module.global_var_list.push_back(global_var_int);
|
||||
@ -227,9 +226,9 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
|
||||
_scope_tab.push_name(var_name, alloca_);
|
||||
if (ctx->initVal()) {
|
||||
_state.arr_dim_index = 0;
|
||||
_state.arr_dim_list = &dim_list;
|
||||
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(ctx->initVal()));
|
||||
_state.arr_dim_list = nullptr;
|
||||
_state.arr_dim_list = &dim_list;
|
||||
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(ctx->initVal()));
|
||||
_state.arr_dim_list = nullptr;
|
||||
sysy_assert(_state.arr_dim_index == 0);
|
||||
// Build GEP
|
||||
auto base_ptr = build_InstGEP(alloca_, {CONST0, CONST0}, _state.current_bb);
|
||||
@ -249,15 +248,15 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
|
||||
else {
|
||||
if (ctx->initVal()) {
|
||||
// first collect init value
|
||||
_state.isGlobalIint = true;
|
||||
_state.isGlobalIint = true;
|
||||
_state.arr_dim_index = 0;
|
||||
_state.arr_dim_list = &dim_list;
|
||||
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(ctx->initVal()));
|
||||
_state.arr_dim_list = nullptr;
|
||||
_state.arr_dim_list = &dim_list;
|
||||
auto array_value = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(ctx->initVal()));
|
||||
_state.arr_dim_list = nullptr;
|
||||
sysy_assert(_state.arr_dim_index == 0);
|
||||
_state.isGlobalIint = false;
|
||||
auto const_arr = ConstantArr::make_shared("var_arr", array_value, array_type);
|
||||
auto global_var = GlobalVar::make_shared(var_name, const_arr, false);
|
||||
auto const_arr = ConstantArr::make_shared("var_arr", array_value, array_type);
|
||||
auto global_var = GlobalVar::make_shared(var_name, const_arr, false);
|
||||
module.global_var_list.push_back(global_var);
|
||||
_scope_tab.push_name(var_name, global_var);
|
||||
}
|
||||
@ -273,17 +272,15 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
|
||||
|
||||
std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
|
||||
if (ctx->exp()) {
|
||||
if (_state.isGlobalIint)
|
||||
_state.isConstInt = true;
|
||||
if (_state.isGlobalIint) _state.isConstInt = true;
|
||||
auto retval = visitExp(ctx->exp());
|
||||
if (_state.isGlobalIint)
|
||||
_state.isConstInt = false;
|
||||
if (_state.isGlobalIint) _state.isConstInt = false;
|
||||
return retval;
|
||||
}
|
||||
// Array
|
||||
else {
|
||||
sysy_assert(_state.arr_dim_list);
|
||||
int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index);
|
||||
int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index);
|
||||
int elem_size = 1;
|
||||
std::vector<ValuePtr_t> cur_arr;
|
||||
for (int i = _state.arr_dim_index + 1; i < _state.arr_dim_list->size(); ++i) {
|
||||
@ -294,7 +291,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
|
||||
if (_state.isGlobalIint) {
|
||||
auto const_value = any_to_Value(visitInitVal(init_val));
|
||||
// should evaluate to const int
|
||||
sysy_assert(Value::isType<ConstantInt>(const_value));
|
||||
sysy_assert(Value::isValueType<ConstantInt>(const_value));
|
||||
cur_arr.push_back(const_value);
|
||||
}
|
||||
else {
|
||||
@ -309,7 +306,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
|
||||
const int pos = cur_arr.size();
|
||||
// the additional `%elem_size`: what if the last dim is {}?
|
||||
for (int i = 0; i < (elem_size - (pos % elem_size)) % elem_size; ++i) {
|
||||
cur_arr.push_back(CONST0);
|
||||
cur_arr.push_back(nullptr);
|
||||
}
|
||||
_state.arr_dim_index++;
|
||||
auto sub_array = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(init_val));
|
||||
@ -319,7 +316,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
|
||||
}
|
||||
// fill up the rest
|
||||
for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) {
|
||||
cur_arr.push_back(CONST0);
|
||||
cur_arr.push_back(nullptr);
|
||||
}
|
||||
return cur_arr;
|
||||
}
|
||||
@ -333,7 +330,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
|
||||
}
|
||||
else {
|
||||
sysy_assert(_state.arr_dim_list);
|
||||
int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index);
|
||||
int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index);
|
||||
int elem_size = 1;
|
||||
std::vector<ValuePtr_t> cur_arr;
|
||||
for (int i = _state.arr_dim_index + 1; i < _state.arr_dim_list->size(); ++i) {
|
||||
@ -352,7 +349,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
|
||||
int pos = cur_arr.size();
|
||||
// the additional `%elem_size`: what if the last dim is {}?
|
||||
for (int i = 0; i < (elem_size - (pos % elem_size)) % elem_size; ++i) {
|
||||
cur_arr.push_back(CONST0);
|
||||
cur_arr.push_back(nullptr);
|
||||
}
|
||||
_state.arr_dim_index++;
|
||||
auto sub_array = std::any_cast<std::vector<ValuePtr_t>>(visitConstInitVal(init_val));
|
||||
@ -362,7 +359,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
|
||||
}
|
||||
// fill up the rest
|
||||
for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) {
|
||||
cur_arr.push_back(CONST0);
|
||||
cur_arr.push_back(nullptr);
|
||||
}
|
||||
return cur_arr;
|
||||
}
|
||||
@ -370,10 +367,9 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
|
||||
|
||||
// @retval: int
|
||||
std::any Visitor::visitConstExp(SysyParser::ConstExpContext *ctx) {
|
||||
if (ctx->addExp() == nullptr)
|
||||
panic("Unreachable");
|
||||
if (ctx->addExp() == nullptr) panic("Unreachable");
|
||||
_state.isConstInt = true;
|
||||
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitAddExp(ctx->addExp()));
|
||||
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitAddExp(ctx->addExp()));
|
||||
_state.isConstInt = false;
|
||||
VLOG(5) << "ConstExp Eval to " << result->value;
|
||||
return {result};
|
||||
@ -514,9 +510,9 @@ std::any Visitor::visitEqExp(SysyParser::EqExpContext *ctx) {
|
||||
std::any Visitor::visitLAndExp(SysyParser::LAndExpContext *ctx) {
|
||||
auto eq_exp_list = ctx->eqExp();
|
||||
for (int i = 0; i < eq_exp_list.size(); ++i) {
|
||||
auto next_block = build_BasicBlock("", _state.current_func);
|
||||
auto eq_exp = any_to_Value(visitEqExp(eq_exp_list[i]));
|
||||
auto condition = build_InstBinary(InstTag::Ne, eq_exp, CONST0, _state.current_bb);
|
||||
auto next_block = build_BasicBlock("", _state.current_func, _state.current_bb->itr);
|
||||
auto eq_exp = any_to_Value(visitEqExp(eq_exp_list[i]));
|
||||
auto condition = build_InstBinary(InstTag::Ne, eq_exp, CONST0, _state.current_bb);
|
||||
build_InstBranch(condition, next_block, ctx->false_block, _state.current_bb);
|
||||
_state.current_bb = next_block;
|
||||
}
|
||||
@ -529,17 +525,17 @@ std::any Visitor::visitLAndExp(SysyParser::LAndExpContext *ctx) {
|
||||
std::any Visitor::visitLOrExp(SysyParser::LOrExpContext *ctx) {
|
||||
VLOG(5) << "Eval to Cond(lOrExp); lineno=" << ctx->getStart()->getLine();
|
||||
auto and_exp_list = ctx->lAndExp();
|
||||
auto n_and_exp = and_exp_list.size();
|
||||
auto n_and_exp = and_exp_list.size();
|
||||
for (int i = 0; i < n_and_exp - 1; ++i) {
|
||||
auto next_block = build_BasicBlock("", _state.current_func);
|
||||
ctx->lAndExp(i)->true_block = ctx->true_block;
|
||||
auto next_block = build_BasicBlock("", _state.current_func, _state.current_bb->itr);
|
||||
ctx->lAndExp(i)->true_block = ctx->true_block;
|
||||
ctx->lAndExp(i)->false_block = next_block;
|
||||
visitLAndExp(and_exp_list[i]);
|
||||
_state.current_bb = next_block;
|
||||
}
|
||||
ctx->lAndExp(n_and_exp - 1)->true_block = ctx->true_block;
|
||||
ctx->lAndExp(n_and_exp - 1)->true_block = ctx->true_block;
|
||||
ctx->lAndExp(n_and_exp - 1)->false_block = ctx->false_block;
|
||||
visitLAndExp(ctx->lAndExp(n_and_exp-1));
|
||||
visitLAndExp(ctx->lAndExp(n_and_exp - 1));
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -575,7 +571,7 @@ std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) {
|
||||
}
|
||||
else {
|
||||
if (ctx->unaryExp()) {
|
||||
auto _result = visitUnaryExp(ctx->unaryExp());
|
||||
auto _result = visitUnaryExp(ctx->unaryExp());
|
||||
auto unary_exp = any_to_Value(_result);
|
||||
sysy_assert(unary_exp->type->type_tag == Type::TypeTag::IntegerType);
|
||||
if (std::dynamic_pointer_cast<IntegerType>(unary_exp->type)->isI1()) {
|
||||
@ -605,12 +601,12 @@ std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) {
|
||||
std::vector<ValuePtr_t> args;
|
||||
// Directly parse RParams
|
||||
if (ctx->funcRParams()) {
|
||||
auto rparams = ctx->funcRParams()->funcRParam();
|
||||
auto rparams = ctx->funcRParams()->funcRParam();
|
||||
const auto &fparams = func->fparam_list;
|
||||
for (int i = 0; i < rparams.size(); ++i) {
|
||||
auto rparam = rparams[i];
|
||||
auto fparam = fparams[i];
|
||||
auto exp = any_to_Value(visitExp(rparam->exp()));
|
||||
auto exp = any_to_Value(visitExp(rparam->exp()));
|
||||
args.push_back(exp);
|
||||
}
|
||||
}
|
||||
@ -654,7 +650,7 @@ std::any Visitor::visitPrimaryExp(SysyParser::PrimaryExpContext *ctx) {
|
||||
}
|
||||
else {
|
||||
auto child_ret = visitLVal(ctx->lVal());
|
||||
auto lval = any_to_Value(child_ret);
|
||||
auto lval = any_to_Value(child_ret);
|
||||
// @retval: ConstantInt
|
||||
if (lval->type->type_tag == Type::TypeTag::IntegerType) {
|
||||
return lval;
|
||||
@ -712,118 +708,117 @@ std::any Visitor::visitLVal(SysyParser::LValContext *ctx) {
|
||||
if (lval->type->type_tag == Type::TypeTag::PointerType) {
|
||||
auto ptr_type = std::dynamic_pointer_cast<PointerType>(lval->type);
|
||||
switch (ptr_type->pointed_type->type_tag) {
|
||||
case Type::TypeTag::IntegerType: {
|
||||
// Int
|
||||
if (ctx->exp().empty()) {
|
||||
// int ref
|
||||
// @retval: InstAlloca
|
||||
return lval;
|
||||
}
|
||||
else {
|
||||
LOG(WARNING) << "Unexpected array referece";
|
||||
// array index, perhaps
|
||||
// @retval: InstGEP
|
||||
auto gep = lval;
|
||||
for (auto exp_ctx : ctx->exp()) {
|
||||
auto exp = any_to_Value(visitExp(exp_ctx));
|
||||
gep = build_InstGEP(gep, {exp}, _state.current_bb);
|
||||
case Type::TypeTag::IntegerType: {
|
||||
// Int
|
||||
if (ctx->exp().empty()) {
|
||||
// int ref
|
||||
// @retval: InstAlloca
|
||||
return lval;
|
||||
}
|
||||
return gep;
|
||||
}
|
||||
};
|
||||
case Type::TypeTag::PointerType: {
|
||||
sysy_assert(0);
|
||||
if (ctx->exp().empty()) {
|
||||
// ??? Pointer
|
||||
// @retval: InstLoad
|
||||
LOG(WARNING) << "Unexpected pointer";
|
||||
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval->type)->pointed_type;
|
||||
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
|
||||
return inst_load;
|
||||
}
|
||||
else {
|
||||
// fparam array, whose first dim is represented by a pointer
|
||||
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval->type)->pointed_type;
|
||||
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
|
||||
else {
|
||||
LOG(WARNING) << "Unexpected array referece";
|
||||
// array index, perhaps
|
||||
// @retval: InstGEP
|
||||
auto gep = lval;
|
||||
for (auto exp_ctx : ctx->exp()) {
|
||||
auto exp = any_to_Value(visitExp(exp_ctx));
|
||||
gep = build_InstGEP(gep, {exp}, _state.current_bb);
|
||||
}
|
||||
return gep;
|
||||
}
|
||||
};
|
||||
case Type::TypeTag::PointerType: {
|
||||
sysy_assert(0);
|
||||
if (ctx->exp().empty()) {
|
||||
// ??? Pointer
|
||||
// @retval: InstLoad
|
||||
LOG(WARNING) << "Unexpected pointer";
|
||||
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval->type)->pointed_type;
|
||||
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
|
||||
return inst_load;
|
||||
}
|
||||
else {
|
||||
// fparam array, whose first dim is represented by a pointer
|
||||
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval->type)->pointed_type;
|
||||
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
|
||||
|
||||
LOG(INFO) << lval->to_string() << " " << lval->type->to_string();
|
||||
auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb);
|
||||
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
|
||||
LOG(INFO) << pointed_type->to_string();
|
||||
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
|
||||
LOG(INFO) << lval->to_string() << " " << lval->type->to_string();
|
||||
auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb);
|
||||
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
|
||||
LOG(INFO) << pointed_type->to_string();
|
||||
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
|
||||
ValuePtr_t offset = ConstantInt::make_shared(0);
|
||||
auto exp_list = ctx->exp();
|
||||
// calculate offset by hand: offset = (offset + exp[i]) * dim_size[i]
|
||||
for (int i = 0; i < exp_list.size() - 1; ++i) {
|
||||
sysy_assert(typeid(pointed_type) == typeid(std::shared_ptr<ArrayType>));
|
||||
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
|
||||
auto exp_val = any_to_Value(visitExp(exp_list[i]));
|
||||
auto dim_size = ConstantInt::make_shared(array_type->element_count);
|
||||
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
|
||||
auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb);
|
||||
offset = inst_mul;
|
||||
pointed_type = array_type->element_type;
|
||||
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
|
||||
}
|
||||
|
||||
// visit the last dimension, mul is not needed
|
||||
auto exp_val = any_to_Value(visitExp(exp_list.back()));
|
||||
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
|
||||
offset = inst_add; // finally, we get the offset
|
||||
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
|
||||
if (TypeHelper::isIntegerType(pointed_type)) {
|
||||
// return the address of the array element
|
||||
auto arr_elem_ptr = build_InstGEP(ptr, {offset}, _state.current_bb);
|
||||
return arr_elem_ptr;
|
||||
}
|
||||
else {
|
||||
panic("Should be int");
|
||||
}
|
||||
}
|
||||
}
|
||||
case Type::TypeTag::ArrayType: {
|
||||
if (ctx->exp().empty()) {
|
||||
// passing an array to function
|
||||
auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb);
|
||||
return ptr;
|
||||
}
|
||||
// get &array[0]
|
||||
auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb);
|
||||
auto pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
|
||||
ValuePtr_t offset = ConstantInt::make_shared(0);
|
||||
auto exp_list = ctx->exp();
|
||||
auto exp_list = ctx->exp();
|
||||
// calculate offset by hand: offset = (offset + exp[i]) * dim_size[i]
|
||||
for (int i = 0; i < exp_list.size() - 1; ++i) {
|
||||
sysy_assert(typeid(pointed_type) == typeid(std::shared_ptr<ArrayType>));
|
||||
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
|
||||
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
|
||||
auto exp_val = any_to_Value(visitExp(exp_list[i]));
|
||||
auto dim_size = ConstantInt::make_shared(array_type->element_count);
|
||||
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
|
||||
auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb);
|
||||
offset = inst_mul;
|
||||
pointed_type = array_type->element_type;
|
||||
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
|
||||
auto exp_val = any_to_Value(visitExp(exp_list[i]));
|
||||
auto dim_size = ConstantInt::make_shared(array_type->element_count);
|
||||
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
|
||||
auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb);
|
||||
offset = inst_mul;
|
||||
pointed_type = array_type->element_type;
|
||||
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
|
||||
}
|
||||
|
||||
// visit the last dimension, mul is not needed
|
||||
auto exp_val = any_to_Value(visitExp(exp_list.back()));
|
||||
auto exp_val = any_to_Value(visitExp(exp_list.back()));
|
||||
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
|
||||
offset = inst_add; // finally, we get the offset
|
||||
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
|
||||
offset = inst_add; // finally, we get the offset
|
||||
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
|
||||
if (TypeHelper::isIntegerType(pointed_type)) {
|
||||
// return the address of the array element
|
||||
auto arr_elem_ptr = build_InstGEP(ptr, {offset}, _state.current_bb);
|
||||
return arr_elem_ptr;
|
||||
}
|
||||
else {
|
||||
panic("Should be int");
|
||||
// return the address of an sub array
|
||||
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
|
||||
auto dim_size = ConstantInt::make_shared(array_type->element_count);
|
||||
auto inst_mul = build_InstBinary(InstTag::Mul, offset, dim_size, _state.current_bb);
|
||||
auto arr_elem_ptr = build_InstGEP(ptr, {CONST0, offset}, _state.current_bb);
|
||||
return arr_elem_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
case Type::TypeTag::ArrayType: {
|
||||
if (ctx->exp().empty()) {
|
||||
// passing an array to function
|
||||
auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb);
|
||||
return ptr;
|
||||
}
|
||||
// get &array[0]
|
||||
auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb);
|
||||
auto pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
|
||||
ValuePtr_t offset = ConstantInt::make_shared(0);
|
||||
auto exp_list = ctx->exp();
|
||||
// calculate offset by hand: offset = (offset + exp[i]) * dim_size[i]
|
||||
for (int i = 0; i < exp_list.size() - 1; ++i) {
|
||||
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
|
||||
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
|
||||
auto exp_val = any_to_Value(visitExp(exp_list[i]));
|
||||
auto dim_size = ConstantInt::make_shared(array_type->element_count);
|
||||
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
|
||||
auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb);
|
||||
offset = inst_mul;
|
||||
pointed_type = array_type->element_type;
|
||||
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
|
||||
}
|
||||
auto exp_val = any_to_Value(visitExp(exp_list.back()));
|
||||
auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb);
|
||||
offset = inst_add; // finally, we get the offset
|
||||
pointed_type = std::dynamic_pointer_cast<PointerType>(ptr->type)->pointed_type;
|
||||
if (TypeHelper::isIntegerType(pointed_type)) {
|
||||
// return the address of the array element
|
||||
auto arr_elem_ptr = build_InstGEP(ptr, {offset}, _state.current_bb);
|
||||
return arr_elem_ptr;
|
||||
}
|
||||
else {
|
||||
// return the address of an sub array
|
||||
auto array_type = std::dynamic_pointer_cast<ArrayType>(pointed_type);
|
||||
auto dim_size = ConstantInt::make_shared(array_type->element_count);
|
||||
auto inst_mul = build_InstBinary(InstTag::Mul, offset, dim_size, _state.current_bb);
|
||||
auto arr_elem_ptr = build_InstGEP(ptr, {CONST0, offset}, _state.current_bb);
|
||||
return arr_elem_ptr;
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("Unreachable");
|
||||
default: panic("Unreachable");
|
||||
}
|
||||
}
|
||||
panic("Unreachable");
|
||||
@ -840,10 +835,10 @@ std::any Visitor::visitFuncDef(SysyParser::FuncDefContext *ctx) {
|
||||
auto func_obj = std::make_shared<Function>(func_name, func_ret_type);
|
||||
module.function_list.push_back(func_obj);
|
||||
_func_tab.push_name(func_name, func_obj);
|
||||
auto basic_block = build_BasicBlock(func_name + "_ENTRY", func_obj);
|
||||
auto basic_block = build_BasicBlock(func_name + "_ENTRY", func_obj, func_obj->bb_list.begin());
|
||||
_scope_tab.enter_scope(true);
|
||||
_state.current_func = func_obj;
|
||||
_state.current_bb = basic_block;
|
||||
_state.current_bb = basic_block;
|
||||
if (ctx->funcFParams()) {
|
||||
visitFuncFParams(ctx->funcFParams());
|
||||
}
|
||||
@ -867,8 +862,8 @@ std::any Visitor::visitFuncFParams(SysyParser::FuncFParamsContext *ctx) {
|
||||
for (auto fparam_ctx : ctx->funcFParam()) {
|
||||
auto fparam_type = any_to_Type(visitFuncFParam(fparam_ctx));
|
||||
auto fparam_name = fparam_ctx->IDENT()->getText();
|
||||
auto fparam = std::make_shared<FParam>(fparam_name, fparam_type);
|
||||
auto alloca_ = build_InstAlloca(fparam_type, _state.current_bb);
|
||||
auto fparam = std::make_shared<FParam>(fparam_name, fparam_type);
|
||||
auto alloca_ = build_InstAlloca(fparam_type, _state.current_bb);
|
||||
build_InstStore(fparam, alloca_, _state.current_bb);
|
||||
_scope_tab.push_name(fparam_name, alloca_);
|
||||
_state.current_func->fparam_list.push_back(fparam);
|
||||
@ -887,7 +882,7 @@ std::any Visitor::visitFuncFParam(SysyParser::FuncFParamContext *ctx) {
|
||||
std::vector<int> dim_list = {0}; // the first dim must be empty, though
|
||||
for (auto exp_ctx : ctx->exp()) {
|
||||
_state.isConstInt = true;
|
||||
auto exp_val = std::dynamic_pointer_cast<ConstantInt>(any_to_Value(visitExp(exp_ctx)));
|
||||
auto exp_val = std::dynamic_pointer_cast<ConstantInt>(any_to_Value(visitExp(exp_ctx)));
|
||||
_state.isConstInt = false;
|
||||
dim_list.push_back(exp_val->value);
|
||||
}
|
||||
@ -921,8 +916,8 @@ stmt: lVal '=' exp ';' # assignStmt
|
||||
*/
|
||||
|
||||
std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) {
|
||||
auto lval = any_to_Value(visitLVal(ctx->lVal()));
|
||||
auto rhs = any_to_Value(visitExp(ctx->exp()));
|
||||
auto lval = any_to_Value(visitLVal(ctx->lVal()));
|
||||
auto rhs = any_to_Value(visitExp(ctx->exp()));
|
||||
auto store = build_InstStore(rhs, lval, _state.current_bb);
|
||||
return {};
|
||||
}
|
||||
@ -930,14 +925,14 @@ std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) {
|
||||
// TODO: Remove RETURN in else stmt
|
||||
std::any Visitor::visitIfStmt(SysyParser::IfStmtContext *ctx) {
|
||||
VLOG(5) << "Visiting IfStmt "
|
||||
<< "; lineno=" << ctx->getStart()->getLine();
|
||||
auto true_block = build_BasicBlock("_then", _state.current_func);
|
||||
auto next_block = build_BasicBlock("_next", _state.current_func);
|
||||
<< "; lineno=" << ctx->getStart()->getLine();
|
||||
auto true_block = build_BasicBlock("_then", _state.current_func, _state.current_bb->itr);
|
||||
auto next_block = build_BasicBlock("_next", _state.current_func, true_block->itr);
|
||||
auto false_block = next_block;
|
||||
if (ctx->ELSE()) {
|
||||
false_block = build_BasicBlock("_else", _state.current_func);
|
||||
false_block = build_BasicBlock("_else", _state.current_func, true_block->itr);
|
||||
}
|
||||
ctx->cond()->lOrExp()->true_block = true_block;
|
||||
ctx->cond()->lOrExp()->true_block = true_block;
|
||||
ctx->cond()->lOrExp()->false_block = false_block;
|
||||
visitCond(ctx->cond());
|
||||
|
||||
@ -956,17 +951,17 @@ std::any Visitor::visitIfStmt(SysyParser::IfStmtContext *ctx) {
|
||||
// TODO: backpatching? I am not sure whether it is necessary
|
||||
std::any Visitor::visitWhileStmt(SysyParser::WhileStmtContext *ctx) {
|
||||
VLOG(5) << "Visiting WhileStmt "
|
||||
<< "; lineno=" << ctx->getStart()->getLine();
|
||||
auto while_id = std::to_string(_state.loop_stmt_count);
|
||||
auto cond_block = build_BasicBlock("_loop_cond_" + while_id, _state.current_func);
|
||||
auto body_block = build_BasicBlock("_loop_body_" + while_id, _state.current_func);
|
||||
auto next_block = build_BasicBlock("_loop_exit_" + while_id, _state.current_func);
|
||||
<< "; lineno=" << ctx->getStart()->getLine();
|
||||
auto while_id = std::to_string(_state.loop_stmt_count);
|
||||
auto cond_block = build_BasicBlock("_loop_cond_" + while_id, _state.current_func, _state.current_bb->itr);
|
||||
auto body_block = build_BasicBlock("_loop_body_" + while_id, _state.current_func, cond_block->itr);
|
||||
auto next_block = build_BasicBlock("_loop_exit_" + while_id, _state.current_func, body_block->itr);
|
||||
build_InstBranch(cond_block, _state.current_bb);
|
||||
_state.loop_stack.push_back({cond_block, body_block, next_block, _state.loop_stmt_count++});
|
||||
// condition
|
||||
ctx->cond()->lOrExp()->true_block = body_block;
|
||||
ctx->cond()->lOrExp()->true_block = body_block;
|
||||
ctx->cond()->lOrExp()->false_block = next_block;
|
||||
_state.current_bb = cond_block;
|
||||
_state.current_bb = cond_block;
|
||||
visitCond(ctx->cond());
|
||||
// body
|
||||
_state.current_bb = body_block;
|
||||
@ -981,14 +976,14 @@ std::any Visitor::visitWhileStmt(SysyParser::WhileStmtContext *ctx) {
|
||||
std::any Visitor::visitBreakStmt(SysyParser::BreakStmtContext *ctx) {
|
||||
sysy_assert(!_state.loop_stack.empty());
|
||||
build_InstBranch(_state.loop_stack.back().next, _state.current_bb);
|
||||
_state.current_bb = build_BasicBlock("_after_break", _state.current_func);
|
||||
_state.current_bb = build_BasicBlock("_after_break", _state.current_func, _state.current_bb->itr);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::any Visitor::visitContinueStmt(SysyParser::ContinueStmtContext *ctx) {
|
||||
sysy_assert(!_state.loop_stack.empty());
|
||||
build_InstBranch(_state.loop_stack.back().cond, _state.current_bb);
|
||||
_state.current_bb = build_BasicBlock("_after_continue", _state.current_func);
|
||||
_state.current_bb = build_BasicBlock("_after_continue", _state.current_func, _state.current_bb->itr);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@ -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