buggy buggy frontend

This commit is contained in:
ridethepig 2023-05-07 21:59:04 +08:00
parent 619145bf22
commit dd48562daa
7 changed files with 470 additions and 109 deletions

View File

@ -1,5 +1,6 @@
#pragma once
#include "common.h"
#include <memory>
#include <vector>
namespace antlrSysY {
@ -69,6 +70,14 @@ public:
ArrayType() : Type(TypeTag::ArrayType) {}
ArrayType(TypePtr_t element_type, int element_count)
: 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);
for (auto itr = dim_list.rbegin(); itr != dim_list.rend(); ++itr) {
array_type = std::make_shared<ArrayType>(array_type, *itr);
}
return std::dynamic_pointer_cast<ArrayType>(array_type);
}
};
class PointerType : public Type {

View File

@ -5,6 +5,7 @@
#include <string>
#include <vector>
#include "common.h"
#include "llir_type.h"
namespace antlrSysY {
@ -50,18 +51,46 @@ public:
}
};
class ConstantInt : public Value {
typedef std::shared_ptr<Value> ValuePtr_t;
typedef std::shared_ptr<BasicBlock> BasicBlockPtr_t;
typedef std::shared_ptr<Function> FunctionPtr_t;
class Constant : public Value {
public:
int value;
ConstantInt(const std::string &name, int value) : Value(name, TypeHelper::TYPE_I32), value(value) {}
Constant(const std::string &name, TypePtr_t type) : Value(name, type) {}
};
class ConstantArr : public Value {};
class GlobalVarInt : public Value {
class ConstantInt : public Constant {
public:
int init_value;
GlobalVarInt(const std::string &name, int init_value) : Value(name, TypeHelper::TYPE_I32), init_value(init_value) {}
int value;
ConstantInt(const std::string &name, int value) : Constant(name, TypeHelper::TYPE_I32), value(value) {}
static std::shared_ptr<ConstantInt> make_shared(int value) {
return std::make_shared<ConstantInt>("", value);
}
};
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) {
return std::make_shared<ConstantArr>(name, value_list, type);
}
};
typedef std::shared_ptr<Constant> ConstantPtr_t;
class GlobalVar : public Value {
public:
ConstantPtr_t init_value;
bool is_const;
GlobalVar(const std::string &name, ConstantPtr_t init_value, bool is_const)
: Value(name, 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);
}
};
enum class InstTag {
@ -93,9 +122,6 @@ enum class InstTag {
ExtractEle
};
typedef std::shared_ptr<Value> ValuePtr_t;
typedef std::shared_ptr<BasicBlock> BasicBlockPtr_t;
typedef std::shared_ptr<Function> FunctionPtr_t;
class Instruction : public Value {
public:
InstTag tag;
@ -107,9 +133,8 @@ public:
class InstAlloca : public Instruction {
public:
bool isInit = false;
InstAlloca(TypePtr_t alloc_type, bool isInit, std::shared_ptr<BasicBlock> parent_bb)
: Instruction(InstTag::Alloca, std::make_shared<PointerType>(alloc_type), parent_bb), isInit(isInit) {}
InstAlloca(TypePtr_t alloc_type, std::shared_ptr<BasicBlock> parent_bb)
: Instruction(InstTag::Alloca, std::make_shared<PointerType>(alloc_type), parent_bb) {}
};
class InstStore : public Instruction {
@ -177,8 +202,46 @@ 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) {
operand_list.push_back(func);
for (auto arg : args) {
operand_list.push_back(arg);
operand_list.insert(operand_list.end(), args.begin(), args.end());
}
};
// getelementptr <ty>, ptr <ptrval>{, [inrange] <ty> <idx>}*
// Example: lea arr[2][3] from arr[5][4]:
// &arr[2][3] = GEP [5x[4xi32]], [5x[4xi32]]* arr, i32 0, i32 2, i32 3
class InstGEP : public Instruction {
public:
ValuePtr_t aim_to;
TypePtr_t element_type;
InstGEP(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices, BasicBlockPtr_t parent_bb)
: Instruction(InstTag::GEP, std::make_shared<PointerType>(extract_type(pointer, indices)), parent_bb) {
if (typeid(pointer) == typeid(std::shared_ptr<InstGEP>)) {
aim_to = std::dynamic_pointer_cast<InstGEP>(pointer)->aim_to;
}
else {
sysy_assert(typeid(pointer) == typeid(std::shared_ptr<InstAlloca>) ||
typeid(pointer) == typeid(std::shared_ptr<GlobalVar>));
aim_to = pointer;
}
element_type = extract_type(pointer, indices);
operand_list.push_back(pointer);
operand_list.insert(operand_list.end(), indices.begin(), indices.end());
}
// get the inner
static TypePtr_t extract_type(ValuePtr_t pointer, const std::vector<ValuePtr_t> &indices) {
auto pointer_type = std::dynamic_pointer_cast<PointerType>(pointer->type);
auto pointed_type = pointer_type->pointed_type;
if (pointed_type->type_tag == Type::TypeTag::ArrayType) {
for (int i = 1; i < indices.size() - 1; ++i) {
pointed_type = std::dynamic_pointer_cast<ArrayType>(pointed_type)->element_type;
}
}
if (pointed_type->type_tag == Type::TypeTag::IntegerType) {
return pointed_type;
}
else {
panic("Unmatch indices and array pointer");
}
}
};

View File

@ -29,7 +29,7 @@ std::shared_ptr<InstLoad> build_InstLoad(std::shared_ptr<Value> value, TypePtr_t
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, bool isInit, 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);
@ -47,18 +47,22 @@ 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);
#pragma endregion
class Visitor : public antlrSysY::SysyBaseVisitor {
private:
struct VisitorState {
bool isGlobalInt = 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;
struct loop_record {
BasicBlockPtr_t cond, body, next;
int id;

View File

@ -19,6 +19,8 @@ class Compiler:
self.bin_template = f"build/test_results/{{testcase}}/bin/{scheme}"
self.compile_log = f"build/log/compile_log/{{testcase}}/{scheme}.log"
self.count_error = 0
for testcase in testcases:
self.__generate_path(testcase)
@ -64,6 +66,7 @@ class Compiler:
completed = subprocess.run(frontend_instr.format(header=header, sy=sy, ir=ir).split(), stdout=log_file, stderr=log_file, bufsize=1)
if completed.returncode != 0:
Print_C.print_error(f"Generating {self.scheme}.ll failed! See {log}")
self.count_error += 1
log_file.close()
@ -142,5 +145,8 @@ class Compiler:
for testcase in self.testcases:
Print_C.print_subheader(f"[Compiling {self.scheme} | {testcase}]")
self.sy_to_ir(frontend_instr=frontend_instr, testcase=testcase, category=category)
if self.count_error >= 10:
Print_C.print_error(f"Test script stopped due to too many errors")
return

View File

@ -59,6 +59,9 @@ int main(int argc, const char **argv) {
#pragma endregion
std::ifstream ifs_source_file(source_file);
if (!ifs_source_file.good()) {
LOG(ERROR) << "Source file " << source_file << " not found.";
}
ANTLRInputStream input(ifs_source_file);
SysyLexer lexer(&input);
CommonTokenStream tokens(&lexer);

View File

@ -31,8 +31,8 @@ std::shared_ptr<InstStore> build_InstStore(std::shared_ptr<Value> value, std::sh
return inst_store;
}
std::shared_ptr<InstAlloca> build_InstAlloca(TypePtr_t type, bool isInit, std::shared_ptr<BasicBlock> parent_bb) {
auto inst_alloca = std::make_shared<InstAlloca>(type, isInit, 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);
parent_bb->inst_list.push_back(inst_alloca);
return inst_alloca;
}
@ -91,4 +91,11 @@ std::shared_ptr<InstCall> build_InstCall(FunctionPtr_t func, const std::vector<V
return inst;
}
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;
}
} // namespace antlrSysY

View File

@ -1,4 +1,5 @@
#include "visitor.h"
#include "3rdparty/easylogging++.h"
#include "common.h"
#include "llir_type.h"
#include "llir_value.h"
@ -19,7 +20,7 @@ namespace antlrSysY {
return value; \
}
ValuePtr_t any_to_Value(const std::any &fuck_any) {
static ValuePtr_t any_to_Value(const std::any &fuck_any) {
ANY2VALUE(Value)
ANY2VALUE(User)
ANY2VALUE(FParam)
@ -27,7 +28,8 @@ ValuePtr_t any_to_Value(const std::any &fuck_any) {
ANY2VALUE(BasicBlock)
ANY2VALUE(ConstantInt)
ANY2VALUE(ConstantArr)
ANY2VALUE(GlobalVarInt)
ANY2VALUE(Constant)
ANY2VALUE(GlobalVar)
ANY2VALUE(Instruction)
ANY2VALUE(InstAlloca)
ANY2VALUE(InstStore)
@ -48,101 +50,273 @@ std::any Visitor::visitConstDecl(SysyParser::ConstDeclContext *ctx) {
return {};
}
// constInitVal is compulsory
// constDef : IDENT ('[' constExp ']')* '=' constInitVal ';'
std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) {
auto name = ctx->IDENT()->getText();
LOG(DEBUG) << "Visiting ConstDef " << name;
if (_scope_tab.get_name(name, _scope_tab.get_level()).has_value())
const auto const_name = ctx->IDENT()->getText();
LOG(DEBUG) << "Visiting ConstDef " << const_name;
if (_scope_tab.get_name(const_name, _scope_tab.get_level()).has_value())
throw GrammarException("Duplicate const def");
// not array
if (ctx->constExp().empty()) {
if (ctx->constInitVal() != nullptr) {
auto result = std::any_cast<int>(visit(ctx->constInitVal()));
auto constint = build_ConstantInt(name, result);
_scope_tab.push_name(name, constint);
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitConstInitVal(ctx->constInitVal()));
_scope_tab.push_name(const_name, result);
}
// const array
else {
std::vector<int> dim_list;
auto const_exp_list = ctx->constExp();
// collect size of each dimension
for (auto const_exp : const_exp_list) {
auto n_elem = std::any_cast<std::shared_ptr<ConstantInt>>(visitConstExp(const_exp));
dim_list.push_back(n_elem->value);
}
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;
sysy_assert(_state.arr_dim_index == 0);
if (_scope_tab.get_level()) {
// local const array
// Keep a pointer to the base address, alloca_ = &array, *alloca_ = &array[0]
auto alloca_ = build_InstAlloca(array_type, _state.current_bb);
_scope_tab.push_name(const_name, alloca_);
// first dim base, ptr = *alloca_ = &array[0]
auto base_ptr = build_InstGEP(alloca_, {CONST0, CONST0}, _state.current_bb);
// get the first element's base, final ptr = &a[0][0]...[0]
for (int i = 1; i < dim_list.size(); ++i) {
base_ptr = build_InstGEP(base_ptr, {CONST0, CONST0}, _state.current_bb);
}
// we store the elements in 1-dim shape
build_InstStore(array_value[0], base_ptr, _state.current_bb);
for (int i = 1; i < array_value.size(); ++i) {
auto ptr = build_InstGEP(base_ptr, {ConstantInt::make_shared(i)}, _state.current_bb);
build_InstStore(array_value[i], ptr, _state.current_bb);
}
}
else {
// global const array
auto const_arr = ConstantArr::make_shared("const_arr", array_value, array_type);
auto global_var = GlobalVar::make_shared(const_name, const_arr, true);
_scope_tab.push_name(const_name, global_var);
}
}
return {};
}
// initVal is optional
// varDef: IDENT ('[' constExp ']')* ('=' initVal)?;
std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) {
auto name = ctx->IDENT()->getText();
LOG(DEBUG) << "Visiting VarDef " << name;
if (_scope_tab.get_name(name, _scope_tab.get_level()).has_value())
auto var_name = ctx->IDENT()->getText();
LOG(DEBUG) << "Visiting VarDef " << var_name;
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
if (_scope_tab.get_level() == 0) {
// global variable must be initialized, either specified or zeroed
int result = 0;
if (ctx->initVal()) {
_state.isGlobalInt = true;
result = std::any_cast<int>(visit(ctx->initVal()));
_state.isGlobalInt = false;
_state.isGlobalIint = true;
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);
_scope_tab.push_name(var_name, global_var_int);
}
else {
auto global_var_int = std::make_shared<GlobalVar>(var_name, CONST0, false);
_scope_tab.push_name(var_name, global_var_int);
}
auto global_var_int = std::make_shared<GlobalVarInt>(name, result);
_scope_tab.push_name(name, global_var_int);
}
// local variable
else {
auto alloca = build_InstAlloca(TypeHelper::TYPE_I32, false, _state.current_bb);
_scope_tab.push_name(name, alloca);
auto alloca_ = build_InstAlloca(TypeHelper::TYPE_I32, _state.current_bb);
_scope_tab.push_name(var_name, alloca_);
if (ctx->initVal()) {
auto init_val = any_to_Value(visitInitVal(ctx->initVal()));
build_InstStore(init_val, alloca, _state.current_bb);
build_InstStore(init_val, alloca_, _state.current_bb);
}
}
}
else {
// Array
panic("To be implemented");
std::vector<int> dim_list;
auto const_exp_list = ctx->constExp();
// collect size of each dimension
for (auto const_exp : const_exp_list) {
auto n_elem = std::any_cast<std::shared_ptr<ConstantInt>>(visitConstExp(const_exp));
dim_list.push_back(n_elem->value);
}
auto array_type = ArrayType::build_from_list(dim_list);
// local array
if (_scope_tab.get_level()) {
auto alloca_ = build_InstAlloca(array_type, _state.current_bb);
_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;
sysy_assert(_state.arr_dim_index == 0);
// Build GEP
auto base_ptr = build_InstGEP(alloca_, {CONST0, CONST0}, _state.current_bb);
for (int i = 1; i < dim_list.size(); ++i) {
base_ptr = build_InstGEP(base_ptr, {CONST0, CONST0}, _state.current_bb);
}
// TODO: BAAU-2021 calls memset in `libc` (not sysylib) to optimize this process
build_InstStore(array_value[0], base_ptr, _state.current_bb);
for (int i = 1; i < array_value.size(); ++i) {
auto ptr = build_InstGEP(base_ptr, {ConstantInt::make_shared(i)}, _state.current_bb);
build_InstStore(array_value[i], ptr, _state.current_bb);
}
}
// If there is no init expr, let it be
}
// global array, generally the same as constant global array
else {
if (ctx->initVal()) {
// first collect init value
_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;
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);
_scope_tab.push_name(var_name, global_var);
}
else {
auto global_var = GlobalVar::make_shared(var_name, CONST0, false);
_scope_tab.push_name(var_name, global_var);
}
}
}
return {};
}
std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
if (ctx->exp()) {
if (_state.isGlobalInt)
if (_state.isGlobalIint)
_state.isConstInt = true;
auto retval = visit(ctx->exp());
if (_state.isGlobalInt)
auto retval = visitExp(ctx->exp());
if (_state.isGlobalIint)
_state.isConstInt = false;
return retval;
}
// Array
panic("To be implemented");
}
std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
if (ctx->constExp() != nullptr /*&& ctx->arrDim.size() == 0*/) {
return visit(ctx->constExp());
else {
sysy_assert(_state.arr_dim_list);
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) {
elem_size *= _state.arr_dim_list->at(i);
}
for (auto init_val : ctx->initVal()) {
if (init_val->exp()) {
if (_state.isGlobalIint) {
auto const_value = any_to_Value(visitInitVal(init_val));
// should evaluate to const int
sysy_assert(typeid(const_value) == typeid(std::shared_ptr<ConstantInt>));
cur_arr.push_back(const_value);
}
else {
// God knows what it evaluates to
auto exp_value = any_to_Value(visitInitVal(init_val));
cur_arr.push_back(exp_value);
}
}
else {
// evaluate sub-array
// before evaluate the new sub-array, first fill up the last one
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);
}
_state.arr_dim_index++;
auto sub_array = std::any_cast<std::vector<ValuePtr_t>>(visitInitVal(init_val));
_state.arr_dim_index--;
cur_arr.insert(cur_arr.end(), sub_array.begin(), sub_array.end());
}
}
// fill up the rest
for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) {
cur_arr.push_back(CONST0);
}
return cur_arr;
}
panic("To be implemented");
}
// TODO: Replace all any<int> to ConstantInt
// constInitVal: constExp | ('{' (constInitVal (',' constInitVal)*)? '}');
std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) {
if (ctx->constExp() != nullptr) {
return visitConstExp(ctx->constExp());
}
else {
sysy_assert(_state.arr_dim_list);
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) {
elem_size *= _state.arr_dim_list->at(i);
}
for (auto init_val : ctx->constInitVal()) {
if (init_val->constExp()) {
// evaluate to const int
auto const_value = any_to_Value(visitConstInitVal(init_val));
sysy_assert(TypeHelper::isIntegerType(const_value->type));
cur_arr.push_back(const_value);
}
else {
// evaluate to sub-array
// before evaluate the new sub-array, first fill up the last one
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);
}
_state.arr_dim_index++;
auto sub_array = std::any_cast<std::vector<ValuePtr_t>>(visitConstInitVal(init_val));
_state.arr_dim_index--;
cur_arr.insert(cur_arr.end(), sub_array.begin(), sub_array.end());
}
}
// fill up the rest
for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) {
cur_arr.push_back(CONST0);
}
return cur_arr;
}
}
// @retval: int
std::any Visitor::visitConstExp(SysyParser::ConstExpContext *ctx) {
if (ctx->addExp() == nullptr)
panic("Unreachable");
_state.isConstInt = true;
int result = std::any_cast<int>(visit(ctx->addExp()));
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitAddExp(ctx->addExp()));
_state.isConstInt = false;
LOG(DEBUG) << "ConstExp Eval to " << result;
LOG(DEBUG) << "ConstExp Eval to " << result->value;
return {result};
}
// addExp: mulExp | addExp ('+' | '-') mulExp;
std::any Visitor::visitAddExp(SysyParser::AddExpContext *ctx) {
if (_state.isConstInt) {
int result = std::any_cast<int>(visit(ctx->mulExp()));
int add_result = 0;
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitMulExp(ctx->mulExp()));
if (ctx->addExp()) {
add_result = std::any_cast<int>(visit(ctx->addExp()));
auto add_result = std::any_cast<std::shared_ptr<ConstantInt>>(visitAddExp(ctx->addExp()));
if (ctx->ADD())
result = add_result + result;
result->value = add_result->value + result->value;
else if (ctx->SUB())
result = add_result - result;
result->value = add_result->value - result->value;
else
panic("missing operator");
}
@ -173,17 +347,17 @@ std::any Visitor::visitAddExp(SysyParser::AddExpContext *ctx) {
std::any Visitor::visitMulExp(SysyParser::MulExpContext *ctx) {
if (_state.isConstInt) {
int result = std::any_cast<int>(visitUnaryExp(ctx->unaryExp()));
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitUnaryExp(ctx->unaryExp()));
if (ctx->mulExp()) {
int mul_result = std::any_cast<int>(visit(ctx->mulExp()));
auto mul_result = std::any_cast<std::shared_ptr<ConstantInt>>(visitMulExp(ctx->mulExp()));
if (ctx->MUL()) {
result = mul_result * result;
result->value = mul_result->value * result->value;
}
else if (ctx->DIV()) {
result = mul_result / result;
result->value = mul_result->value / result->value;
}
else if (ctx->MOD()) {
result = mul_result % result;
result->value = mul_result->value % result->value;
}
else
panic("Unreachable");
@ -299,13 +473,13 @@ std::any Visitor::visitLOrExp(SysyParser::LOrExpContext *ctx) {
std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) {
if (_state.isConstInt) {
if (ctx->unaryExp()) {
int result = std::any_cast<int>(visit(ctx->unaryExp()));
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitUnaryExp(ctx->unaryExp()));
if (ctx->unaryOp()->ADD())
result = +result;
result->value = +result->value;
else if (ctx->unaryOp()->SUB())
result = -result;
result->value = -result->value;
else if (ctx->unaryOp()->NOT())
result = !result;
result->value = !result->value;
else
panic("Unreachable");
return {result};
@ -376,7 +550,7 @@ std::any Visitor::visitPrimaryExp(SysyParser::PrimaryExpContext *ctx) {
return visitExp(ctx->exp());
}
else if (ctx->lVal()) {
auto value = any_to_Value(visit(ctx->lVal()));
auto value = any_to_Value(visitLVal(ctx->lVal()));
auto constint = std::dynamic_pointer_cast<ConstantInt>(value);
// actually, it is only a type assertion
return constint->value;
@ -418,32 +592,26 @@ std::any Visitor::visitPrimaryExp(SysyParser::PrimaryExpContext *ctx) {
}
panic("Unreachable");
}
return {};
}
// @retval: int
// @retval: ConstantInt
std::any Visitor::visitNumber(SysyParser::NumberContext *ctx) {
auto int_const = std::any_cast<int>(visit(ctx->intConst()));
if (_state.isConstInt) {
return int_const;
}
else {
return std::dynamic_pointer_cast<Value>(build_ConstantInt("", int_const));
}
return visitIntConst(ctx->intConst());
}
// @retval: int
// @retval: ConstantInt
std::any Visitor::visitIntConst(SysyParser::IntConstContext *ctx) {
int const_int = 0;
if (ctx->DECIMAL_CONST()) {
return std::stoi(ctx->DECIMAL_CONST()->getText(), nullptr, 10);
const_int = std::stoi(ctx->DECIMAL_CONST()->getText(), nullptr, 10);
}
else if (ctx->HEXADECIMAL_CONST()) {
return std::stoi(ctx->HEXADECIMAL_CONST()->getText(), nullptr, 16);
const_int = std::stoi(ctx->HEXADECIMAL_CONST()->getText(), nullptr, 16);
}
else if (ctx->OCTAL_CONST()) {
return std::stoi(ctx->OCTAL_CONST()->getText(), nullptr, 8);
const_int = std::stoi(ctx->OCTAL_CONST()->getText(), nullptr, 8);
}
return {};
return build_ConstantInt("", const_int);
}
// lVal: IDENT ('[' exp ']')*;
@ -460,17 +628,107 @@ 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);
if (ptr_type->pointed_type->type_tag == Type::TypeTag::IntegerType) {
// @retval: InstAlloca
switch (ptr_type->pointed_type->type_tag) {
case Type::TypeTag::IntegerType: {
// Int
if (ctx->exp().empty()) {
// int ref
// @retval: InstAlloca
return lval;
}
else {
panic("To be implemented");
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: {
if (ctx->exp().empty()) {
// ??? Pointer
// @retval: InstLoad
LOG(WARNING) << "Unexpected pointer";
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval)->pointed_type;
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
return inst_load;
}
else {
panic("To be implemented");
// fparam array, whose first dim is represented by a pointer
auto pointed_type = std::dynamic_pointer_cast<PointerType>(lval)->pointed_type;
sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType);
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb);
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(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: {
sysy_assert(!ctx->exp().empty());
// 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(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);
}
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");
}
}
default:
panic("Unreachable");
}
}
panic("Unreachable");
@ -494,7 +752,7 @@ std::any Visitor::visitFuncDef(SysyParser::FuncDefContext *ctx) {
if (ctx->funcFParams()) {
visitFuncFParams(ctx->funcFParams());
}
visit(ctx->block());
visitBlock(ctx->block());
// add return
// _scope_tab.leave_scope();
// TODO: avoid duplicate ret
@ -507,36 +765,47 @@ std::any Visitor::visitFuncDef(SysyParser::FuncDefContext *ctx) {
return {};
}
// @retval: any
// Directly add to function, rather than return something...
std::any Visitor::visitFuncFParams(SysyParser::FuncFParamsContext *ctx) {
for (auto fparam : ctx->funcFParam()) {
auto fparam_type = std::any_cast<TypePtr_t>(visit(fparam));
auto fparam_name = fparam->getText();
auto fparam_ptr = std::make_shared<FParam>(fparam_name, fparam_type);
_state.current_func->fparam_list.push_back(fparam_ptr);
if (fparam->LBRACKET().empty()) {
auto alloca = build_InstAlloca(TypeHelper::TYPE_I32, false, _state.current_bb);
auto store = build_InstStore(fparam_ptr, alloca, _state.current_bb);
_scope_tab.push_name(fparam_name, alloca);
_state.current_func->fparam_list.push_back(fparam_ptr);
}
else {
panic("To be implemented");
}
for (auto fparam_ctx : ctx->funcFParam()) {
auto fparam_type = std::any_cast<TypePtr_t>(visitFuncFParam(fparam_ctx));
auto fparam_name = fparam_ctx->getText();
auto fparam = std::make_shared<FParam>(fparam_name, fparam_type);
_state.current_func->fparam_list.push_back(fparam);
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);
}
return {};
}
// funcFParam: bType IDENT ('[' ']' ('[' exp ']')*)?;
std::any Visitor::visitFuncFParam(SysyParser::FuncFParamContext *ctx) {
if (ctx->LBRACKET().empty()) {
// int type
return {TypeHelper::TYPE_I32};
}
panic("To be implemented");
else {
// array type
std::vector<int> dim_list; // 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)));
_state.isConstInt = false;
dim_list.push_back(exp_val->value);
}
auto array_type = ArrayType::build_from_list(dim_list);
auto true_array_type = std::make_shared<PointerType>(array_type);
return {true_array_type};
}
}
std::any Visitor::visitBlock(SysyParser::BlockContext *ctx) {
_scope_tab.enter_scope();
for (auto block_item : ctx->blockItem()) {
visit(block_item);
visitBlockItem(block_item);
}
_scope_tab.leave_scope();
return {};
@ -556,8 +825,8 @@ stmt: lVal '=' exp ';' # assignStmt
*/
std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) {
auto lval = any_to_Value(visit(ctx->lVal()));
auto rhs = any_to_Value(visit(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 {};
}