1047 lines
40 KiB
C++
1047 lines
40 KiB
C++
#include "visitor.h"
|
|
#include "3rdparty/easylogging++.h"
|
|
#include "SysyLexer.h"
|
|
#include "common.h"
|
|
#include "llir_instruction.h"
|
|
#include "llir_type.h"
|
|
#include "llir_value.h"
|
|
#include <any>
|
|
#include <cassert>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Some virtual methods are comment out in the class definition, since they do
|
|
// nothing
|
|
// beyond base class implement
|
|
|
|
namespace antlrSysY {
|
|
|
|
#define ANY2VALUE(_my_type_) \
|
|
if (fuck_any.type() == typeid(std::shared_ptr<_my_type_>)) { \
|
|
auto value = std::any_cast<std::shared_ptr<_my_type_>>(fuck_any); \
|
|
return value; \
|
|
}
|
|
|
|
static ValuePtr_t any_to_Value(const std::any &fuck_any) {
|
|
ANY2VALUE(Value)
|
|
ANY2VALUE(User)
|
|
ANY2VALUE(FParam)
|
|
ANY2VALUE(Function)
|
|
ANY2VALUE(BasicBlock)
|
|
ANY2VALUE(ConstantInt)
|
|
ANY2VALUE(ConstantArr)
|
|
ANY2VALUE(Constant)
|
|
ANY2VALUE(GlobalVar)
|
|
ANY2VALUE(Instruction)
|
|
ANY2VALUE(InstAlloca)
|
|
ANY2VALUE(InstStore)
|
|
ANY2VALUE(InstLoad)
|
|
ANY2VALUE(InstBinary)
|
|
ANY2VALUE(InstZext)
|
|
ANY2VALUE(InstBranch)
|
|
ANY2VALUE(InstReturn)
|
|
ANY2VALUE(InstCall)
|
|
ANY2VALUE(InstGEP)
|
|
LOG(ERROR) << fuck_any.type().name();
|
|
panic("Unreachable");
|
|
}
|
|
|
|
static TypePtr_t any_to_Type(const std::any &fuck_any) {
|
|
ANY2VALUE(Type)
|
|
ANY2VALUE(ArrayType)
|
|
ANY2VALUE(FunctionType)
|
|
ANY2VALUE(IntegerType)
|
|
ANY2VALUE(PointerType)
|
|
LOG(ERROR) << fuck_any.type().name();
|
|
panic("Unreachable");
|
|
}
|
|
|
|
/*
|
|
int getint(),getch(),getarray(int a[]);
|
|
void putint(int a),putch(int a),putarray(int n,int a[]);
|
|
#define starttime() _sysy_starttime(__LINE__)
|
|
#define stoptime() _sysy_stoptime(__LINE__)
|
|
__attribute((constructor)) void before_main();
|
|
__attribute((destructor)) void after_main();
|
|
void _sysy_starttime(int lineno);
|
|
void _sysy_stoptime(int lineno);
|
|
*/
|
|
|
|
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_ptr_i32 = std::make_shared<FParam>("", pointer_type);
|
|
|
|
auto func_getint = std::make_shared<Function>("getint", TypeHelper::TYPE_I32);
|
|
// void param
|
|
_func_tab.push_name("getint", func_getint);
|
|
|
|
auto func_getch = std::make_shared<Function>("getch", TypeHelper::TYPE_I32);
|
|
// void param
|
|
_func_tab.push_name("getch", func_getch);
|
|
|
|
auto func_getarray = std::make_shared<Function>("getarray", TypeHelper::TYPE_I32);
|
|
func_getarray->fparam_list.push_back(fparam_ptr_i32);
|
|
_func_tab.push_name("getarray", func_getarray);
|
|
|
|
auto func_putint = std::make_shared<Function>("putint", TypeHelper::TYPE_VOID);
|
|
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);
|
|
func_putch->fparam_list = {fparam_i32};
|
|
_func_tab.push_name("putch", func_putch);
|
|
|
|
auto func_putarray = std::make_shared<Function>("putarray", TypeHelper::TYPE_VOID);
|
|
func_putarray->fparam_list = {fparam_i32, fparam_ptr_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);
|
|
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);
|
|
func_stoptime->fparam_list = {fparam_i32};
|
|
_func_tab.push_name("stoptime", func_stoptime);
|
|
|
|
#pragma endregion
|
|
}
|
|
|
|
std::any Visitor::visitConstDecl(SysyParser::ConstDeclContext *ctx) {
|
|
for (auto constDef : ctx->constDef()) {
|
|
visitConstDef(constDef);
|
|
}
|
|
return {};
|
|
}
|
|
|
|
// constInitVal is compulsory
|
|
// constDef : IDENT ('[' constExp ']')* '=' constInitVal ';'
|
|
std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) {
|
|
const auto const_name = ctx->IDENT()->getText();
|
|
VLOG(5) << "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()) {
|
|
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(const_name, 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] ? array_value[0] : CONST0, 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] ? array_value[i] : CONST0, 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, array_type, const_arr, true);
|
|
module.global_var_list.push_back(global_var);
|
|
_scope_tab.push_name(const_name, global_var);
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
// initVal is optional
|
|
// varDef: IDENT ('[' constExp ']')* ('=' initVal)?;
|
|
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");
|
|
// Not Array
|
|
if (ctx->constExp().empty()) {
|
|
// global variable
|
|
if (_scope_tab.get_level() == 0) {
|
|
// 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()));
|
|
_state.isGlobalIint = false;
|
|
auto global_var_int = GlobalVar::make_shared(var_name, result->type, result, false);
|
|
module.global_var_list.push_back(global_var_int);
|
|
_scope_tab.push_name(var_name, global_var_int);
|
|
}
|
|
else {
|
|
auto global_var_int = GlobalVar::make_shared(var_name, CONST0->type, CONST0, false);
|
|
module.global_var_list.push_back(global_var_int);
|
|
_scope_tab.push_name(var_name, global_var_int);
|
|
}
|
|
}
|
|
// local variable
|
|
else {
|
|
auto alloca_ = build_InstAlloca(var_name, 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);
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
// local array
|
|
if (_scope_tab.get_level()) {
|
|
auto alloca_ = build_InstAlloca(var_name, 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] ? array_value[0] : CONST0, 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] ? array_value[i] : CONST0, 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->type, const_arr, false);
|
|
module.global_var_list.push_back(global_var);
|
|
_scope_tab.push_name(var_name, global_var);
|
|
}
|
|
else {
|
|
auto global_var = GlobalVar::make_shared(var_name, array_type, nullptr, false);
|
|
module.global_var_list.push_back(global_var);
|
|
_scope_tab.push_name(var_name, global_var);
|
|
}
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) {
|
|
if (ctx->exp()) {
|
|
if (_state.isGlobalIint) _state.isConstInt = true;
|
|
auto retval = visitExp(ctx->exp());
|
|
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 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(Value::isValueType<ConstantInt>(const_value));
|
|
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(nullptr);
|
|
}
|
|
_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(nullptr);
|
|
}
|
|
return cur_arr;
|
|
}
|
|
}
|
|
|
|
// 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(nullptr);
|
|
}
|
|
_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(nullptr);
|
|
}
|
|
return cur_arr;
|
|
}
|
|
}
|
|
|
|
// @retval: int
|
|
std::any Visitor::visitConstExp(SysyParser::ConstExpContext *ctx) {
|
|
if (ctx->addExp() == nullptr) panic("Unreachable");
|
|
_state.isConstInt = true;
|
|
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitAddExp(ctx->addExp()));
|
|
_state.isConstInt = false;
|
|
VLOG(5) << "ConstExp Eval to " << result->value;
|
|
return {result};
|
|
}
|
|
|
|
// addExp: mulExp | addExp ('+' | '-') mulExp;
|
|
std::any Visitor::visitAddExp(SysyParser::AddExpContext *ctx) {
|
|
if (_state.isConstInt) {
|
|
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitMulExp(ctx->mulExp()));
|
|
if (ctx->addExp()) {
|
|
auto add_result = std::any_cast<std::shared_ptr<ConstantInt>>(visitAddExp(ctx->addExp()));
|
|
if (ctx->ADD())
|
|
result->value = add_result->value + result->value;
|
|
else if (ctx->SUB())
|
|
result->value = add_result->value - result->value;
|
|
else
|
|
panic("missing operator");
|
|
}
|
|
return {result};
|
|
}
|
|
else {
|
|
if (ctx->addExp()) {
|
|
auto add_exp = any_to_Value(visitAddExp(ctx->addExp()));
|
|
auto mul_exp = any_to_Value(visitMulExp(ctx->mulExp()));
|
|
if (std::dynamic_pointer_cast<IntegerType>(add_exp->type)->isI1()) {
|
|
add_exp = build_InstZext(add_exp, _state.current_bb);
|
|
}
|
|
if (std::dynamic_pointer_cast<IntegerType>(mul_exp->type)->isI1()) {
|
|
mul_exp = build_InstZext(mul_exp, _state.current_bb);
|
|
}
|
|
if (ctx->ADD()) {
|
|
mul_exp = build_InstBinary(InstTag::Add, add_exp, mul_exp, _state.current_bb);
|
|
}
|
|
else if (ctx->SUB()) {
|
|
mul_exp = build_InstBinary(InstTag::Sub, add_exp, mul_exp, _state.current_bb);
|
|
}
|
|
else
|
|
panic("Unreachable");
|
|
return mul_exp;
|
|
}
|
|
else {
|
|
return visitMulExp(ctx->mulExp());
|
|
}
|
|
}
|
|
}
|
|
|
|
std::any Visitor::visitMulExp(SysyParser::MulExpContext *ctx) {
|
|
if (_state.isConstInt) {
|
|
auto result = std::dynamic_pointer_cast<ConstantInt>(any_to_Value(visitUnaryExp(ctx->unaryExp())));
|
|
if (ctx->mulExp()) {
|
|
auto mul_result = std::dynamic_pointer_cast<ConstantInt>(any_to_Value(visitMulExp(ctx->mulExp())));
|
|
if (ctx->MUL()) {
|
|
result->value = mul_result->value * result->value;
|
|
}
|
|
else if (ctx->DIV()) {
|
|
result->value = mul_result->value / result->value;
|
|
}
|
|
else if (ctx->MOD()) {
|
|
result->value = mul_result->value % result->value;
|
|
}
|
|
else
|
|
panic("Unreachable");
|
|
}
|
|
return {result};
|
|
}
|
|
else {
|
|
if (ctx->mulExp()) {
|
|
auto mul_exp = any_to_Value(visitMulExp(ctx->mulExp()));
|
|
auto unary_exp = any_to_Value(visitUnaryExp(ctx->unaryExp()));
|
|
if (std::dynamic_pointer_cast<IntegerType>(unary_exp->type)->isI1()) {
|
|
unary_exp = build_InstZext(unary_exp, _state.current_bb);
|
|
}
|
|
if (std::dynamic_pointer_cast<IntegerType>(mul_exp->type)->isI1()) {
|
|
mul_exp = build_InstZext(mul_exp, _state.current_bb);
|
|
}
|
|
if (ctx->MUL()) {
|
|
unary_exp = build_InstBinary(InstTag::Mul, mul_exp, unary_exp, _state.current_bb);
|
|
}
|
|
else if (ctx->DIV()) {
|
|
unary_exp = build_InstBinary(InstTag::Div, mul_exp, unary_exp, _state.current_bb);
|
|
}
|
|
else if (ctx->MOD()) {
|
|
unary_exp = build_InstBinary(InstTag::Mod, mul_exp, unary_exp, _state.current_bb);
|
|
}
|
|
else
|
|
panic("Unreachable");
|
|
return {unary_exp};
|
|
}
|
|
else {
|
|
return visitUnaryExp(ctx->unaryExp());
|
|
}
|
|
}
|
|
}
|
|
// relExp: addExp | relExp ('<' | '>' | '<=' | '>=') addExp;
|
|
std::any Visitor::visitRelExp(SysyParser::RelExpContext *ctx) {
|
|
if (ctx->relExp()) {
|
|
auto rel_exp = any_to_Value(visitRelExp(ctx->relExp()));
|
|
auto add_exp = any_to_Value(visitAddExp(ctx->addExp()));
|
|
sysy_assert(TypeHelper::isIntegerTypeI32(rel_exp->type));
|
|
if (ctx->LE()) {
|
|
add_exp = build_InstBinary(InstTag::Le, rel_exp, add_exp, _state.current_bb);
|
|
}
|
|
else if (ctx->LT()) {
|
|
add_exp = build_InstBinary(InstTag::Lt, rel_exp, add_exp, _state.current_bb);
|
|
}
|
|
else if (ctx->GE()) {
|
|
add_exp = build_InstBinary(InstTag::Ge, rel_exp, add_exp, _state.current_bb);
|
|
}
|
|
else if (ctx->GT()) {
|
|
add_exp = build_InstBinary(InstTag::Gt, rel_exp, add_exp, _state.current_bb);
|
|
}
|
|
else {
|
|
LOG(ERROR) << ctx->relExp()->getStart()->getLine() << ":" << ctx->relExp()->getText();
|
|
panic("Unreachable");
|
|
}
|
|
return add_exp;
|
|
}
|
|
else {
|
|
return visitAddExp(ctx->addExp());
|
|
}
|
|
}
|
|
|
|
// eqExp: relExp | eqExp ('==' | '!=') relExp;
|
|
std::any Visitor::visitEqExp(SysyParser::EqExpContext *ctx) {
|
|
if (ctx->eqExp()) {
|
|
bool need_zext = false;
|
|
auto eq_exp = any_to_Value(visitEqExp(ctx->eqExp()));
|
|
auto rel_exp = any_to_Value(visitRelExp(ctx->relExp()));
|
|
if (TypeHelper::isIntegerTypeI32(eq_exp->type) || TypeHelper::isIntegerTypeI32(rel_exp->type)) {
|
|
need_zext = true;
|
|
}
|
|
if (need_zext && TypeHelper::isIntegerTypeI1(eq_exp->type)) {
|
|
eq_exp = build_InstZext(eq_exp, _state.current_bb);
|
|
}
|
|
if (need_zext && TypeHelper::isIntegerTypeI1(rel_exp->type)) {
|
|
rel_exp = build_InstZext(rel_exp, _state.current_bb);
|
|
}
|
|
if (ctx->EQ()) {
|
|
rel_exp = build_InstBinary(InstTag::Eq, eq_exp, rel_exp, _state.current_bb);
|
|
}
|
|
else if (ctx->NE()) {
|
|
rel_exp = build_InstBinary(InstTag::Ne, eq_exp, rel_exp, _state.current_bb);
|
|
}
|
|
else
|
|
panic("Unreachable");
|
|
return rel_exp;
|
|
}
|
|
else {
|
|
return visitRelExp(ctx->relExp());
|
|
}
|
|
}
|
|
|
|
// Notes about SideEffect: except for || and &&, other sub-expression evaluations are unsequenced
|
|
// as long as they are calculated before the operator
|
|
// BUT, in sysy test, it seems that, it is a must ti compute from left to right
|
|
// lAndExp: eqExp | lAndExp '&&' eqExp;
|
|
// Luckily, there is only one path to lOrExp, which is `stmt` -> `cond` -> `lOrExp`
|
|
// Thus, there is no need to care about what if it appears in a arithmetic expression
|
|
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, _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;
|
|
}
|
|
build_InstBranch(ctx->true_block, _state.current_bb);
|
|
return {};
|
|
}
|
|
|
|
// @retval: Bool
|
|
// lOrExp: lAndExp ('||' lAndExp)*;
|
|
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();
|
|
for (int i = 0; i < n_and_exp - 1; ++i) {
|
|
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)->false_block = ctx->false_block;
|
|
visitLAndExp(ctx->lAndExp(n_and_exp - 1));
|
|
return {};
|
|
}
|
|
|
|
std::any Visitor::visitCond(SysyParser::CondContext *ctx) {
|
|
_state.isCondExp = true;
|
|
visitLOrExp(ctx->lOrExp());
|
|
_state.isCondExp = false;
|
|
return {};
|
|
}
|
|
|
|
// unaryExp: primaryExp | IDENT '(' (funcRParams)? ')' | unaryOp unaryExp;
|
|
std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) {
|
|
if (_state.isConstInt) {
|
|
if (ctx->unaryExp()) {
|
|
auto result = std::any_cast<std::shared_ptr<ConstantInt>>(visitUnaryExp(ctx->unaryExp()));
|
|
if (ctx->unaryOp()->ADD())
|
|
result->value = +result->value;
|
|
else if (ctx->unaryOp()->SUB())
|
|
result->value = -result->value;
|
|
else if (ctx->unaryOp()->NOT())
|
|
result->value = !result->value;
|
|
else
|
|
panic("Unreachable");
|
|
return {result};
|
|
}
|
|
else if (ctx->primaryExp()) {
|
|
return visitPrimaryExp(ctx->primaryExp());
|
|
}
|
|
else if (ctx->IDENT()) {
|
|
panic("Unexpected func call in const expr");
|
|
}
|
|
panic("Unreachable");
|
|
}
|
|
else {
|
|
if (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()) {
|
|
unary_exp = build_InstZext(unary_exp, _state.current_bb);
|
|
}
|
|
if (ctx->unaryOp()->NOT()) {
|
|
// should eval to i1
|
|
sysy_assert(_state.isCondExp);
|
|
return build_InstBinary(InstTag::Eq, unary_exp, CONST0, _state.current_bb);
|
|
}
|
|
else if (ctx->unaryOp()->ADD()) {
|
|
return unary_exp;
|
|
}
|
|
else if (ctx->unaryOp()->SUB()) {
|
|
return build_InstBinary(InstTag::Sub, CONST0, unary_exp, _state.current_bb);
|
|
}
|
|
}
|
|
else if (ctx->IDENT()) {
|
|
// Fucntion call
|
|
// TODO: buildCall/isRealParam
|
|
// TODO: Handle string & putf()
|
|
auto func_name = ctx->IDENT()->getText();
|
|
VLOG(5) << "Calling Func: " << func_name;
|
|
auto _result = _func_tab.get_name(func_name);
|
|
sysy_assert(_result.has_value());
|
|
auto func = _result.value();
|
|
std::vector<ValuePtr_t> args;
|
|
// Directly parse RParams
|
|
if (ctx->funcRParams()) {
|
|
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];
|
|
_state.isRealParam = true;
|
|
if (Type::isType<IntegerType>(fparam->type)) _state.isRealParam = false;
|
|
auto exp = any_to_Value(visitExp(rparam->exp()));
|
|
_state.isRealParam = false;
|
|
args.push_back(exp);
|
|
}
|
|
}
|
|
return build_InstCall(func, args, _state.current_bb);
|
|
}
|
|
else if (ctx->primaryExp()) {
|
|
return visitPrimaryExp(ctx->primaryExp());
|
|
}
|
|
panic("Unreachable");
|
|
}
|
|
}
|
|
|
|
// primaryExp: ('(' exp ')') | lVal | number;
|
|
std::any Visitor::visitPrimaryExp(SysyParser::PrimaryExpContext *ctx) {
|
|
// @retval: int
|
|
if (_state.isConstInt) {
|
|
if (ctx->exp()) {
|
|
return visitExp(ctx->exp());
|
|
}
|
|
else if (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;
|
|
return value;
|
|
}
|
|
else if (ctx->number()) {
|
|
return visitNumber(ctx->number());
|
|
}
|
|
panic("Unreachable");
|
|
}
|
|
else {
|
|
if (ctx->exp()) {
|
|
return visitExp(ctx->exp());
|
|
}
|
|
else if (ctx->lVal()) {
|
|
if (_state.isRealParam) {
|
|
_state.isRealParam = false;
|
|
VLOG(5) << "isRealParam:" << ctx->getStart()->getLine();
|
|
return visitLVal(ctx->lVal());
|
|
}
|
|
else {
|
|
auto child_ret = visitLVal(ctx->lVal());
|
|
auto lval = any_to_Value(child_ret);
|
|
// @retval: ConstantInt
|
|
if (lval->type->type_tag == Type::TypeTag::IntegerType) {
|
|
return lval;
|
|
}
|
|
// @retval: InstLoad
|
|
else {
|
|
// LOG(WARNING) << "lval type is pointer: " << lval->type->type_tag;
|
|
// should be InstAlloca
|
|
auto ptr_type = std::dynamic_pointer_cast<PointerType>(lval->type);
|
|
return build_InstLoad(lval, ptr_type->pointed_type, _state.current_bb);
|
|
}
|
|
}
|
|
}
|
|
// @retval: int
|
|
else if (ctx->number()) {
|
|
return visitNumber(ctx->number());
|
|
}
|
|
panic("Unreachable");
|
|
}
|
|
}
|
|
|
|
// @retval: ConstantInt
|
|
std::any Visitor::visitNumber(SysyParser::NumberContext *ctx) {
|
|
return visitIntConst(ctx->intConst());
|
|
}
|
|
|
|
// @retval: ConstantInt
|
|
std::any Visitor::visitIntConst(SysyParser::IntConstContext *ctx) {
|
|
int const_int = 0;
|
|
if (ctx->DECIMAL_CONST()) {
|
|
const_int = std::stol(ctx->DECIMAL_CONST()->getText(), nullptr, 10);
|
|
}
|
|
else if (ctx->HEXADECIMAL_CONST()) {
|
|
const_int = std::stol(ctx->HEXADECIMAL_CONST()->getText(), nullptr, 16);
|
|
}
|
|
else if (ctx->OCTAL_CONST()) {
|
|
const_int = std::stol(ctx->OCTAL_CONST()->getText(), nullptr, 8);
|
|
}
|
|
return build_ConstantInt("", const_int);
|
|
}
|
|
|
|
// lVal: IDENT ('[' exp ']')*;
|
|
|
|
std::any Visitor::visitLVal(SysyParser::LValContext *ctx) {
|
|
auto name = ctx->IDENT()->getText();
|
|
VLOG(5) << "Eval to lVal " << name << "; lineno=" << ctx->getStart()->getLine();
|
|
auto _lval = _scope_tab.get_name(name);
|
|
sysy_assert(_lval.has_value());
|
|
auto lval = _lval.value();
|
|
VLOG(5) << "lVal found: " << lval->to_string();
|
|
// @retval: ConstantInt
|
|
if (lval->type->type_tag == Type::TypeTag::IntegerType) {
|
|
return {lval};
|
|
}
|
|
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" << lval->to_string() << " : " << ctx->getStart()->getLine();
|
|
// 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->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 = Type::asType<PointerType>(lval->type)->pointed_type;
|
|
auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb);
|
|
auto exp_list = ctx->exp();
|
|
if (exp_list.size() == 1) {
|
|
auto exp_val = any_to_Value(visitExp(exp_list[0]));
|
|
auto ptr = build_InstGEP(inst_load, {exp_val}, _state.current_bb);
|
|
pointed_type = Type::asType<PointerType>(ptr->type)->pointed_type;
|
|
assert(Type::isType<IntegerType>(pointed_type));
|
|
return ptr;
|
|
}
|
|
// LOG(INFO) << lval->to_string() << " " << lval->type->to_string();
|
|
auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb);
|
|
pointed_type = Type::asType<PointerType>(ptr->type)->pointed_type;
|
|
ValuePtr_t offset = ConstantInt::make_shared(0);
|
|
// LOG(INFO) << pointed_type->to_string();
|
|
assert(Type::isType<ArrayType>(pointed_type));
|
|
|
|
// calculate offset by hand: offset = (offset + exp[i]) * dim_size[i]
|
|
for (int i = 0; i < exp_list.size() - 1; ++i) {
|
|
sysy_assert(Type::isType<ArrayType>(pointed_type));
|
|
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 {
|
|
LOG(WARNING) << "Should be int";
|
|
auto arr_ptr = build_InstGEP(ptr, {CONST0, offset}, _state.current_bb);
|
|
return arr_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);
|
|
offset = build_InstBinary(InstTag::Mul, offset, dim_size, _state.current_bb);
|
|
auto arr_elem_ptr = build_InstGEP(ptr, {CONST0, offset}, _state.current_bb);
|
|
return arr_elem_ptr;
|
|
}
|
|
}
|
|
default: panic("Unreachable");
|
|
}
|
|
}
|
|
panic("Unreachable");
|
|
}
|
|
|
|
std::any Visitor::visitFuncDef(SysyParser::FuncDefContext *ctx) {
|
|
auto func_name = ctx->IDENT()->getText();
|
|
VLOG(5) << "Visit FuncDef " << func_name;
|
|
auto func_ret_type = TypeHelper::TYPE_VOID;
|
|
if (ctx->funcType()->INT()) {
|
|
func_ret_type = TypeHelper::TYPE_I32;
|
|
}
|
|
// param list will get collected as well as locally allocated in FuncFParam
|
|
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, func_obj->bb_list.begin());
|
|
_scope_tab.enter_scope(true);
|
|
_state.current_func = func_obj;
|
|
_state.current_bb = basic_block;
|
|
if (ctx->funcFParams()) {
|
|
visitFuncFParams(ctx->funcFParams());
|
|
}
|
|
VLOG(5) << func_obj->to_string();
|
|
visitBlock(ctx->block());
|
|
// add return
|
|
// _scope_tab.leave_scope();
|
|
// there may be an empty bb in the end
|
|
|
|
// avoid duplicate ret
|
|
if (func_obj->bb_list.back()->inst_list.size() == 0 && func_obj->bb_list.back()->name == "after_ret") {
|
|
func_obj->bb_list.pop_back();
|
|
}
|
|
if (func_obj->bb_list.back()->inst_list.size()==0
|
|
|| !Value::isValueType<InstReturn>(func_obj->bb_list.back()->inst_list.back())){
|
|
if (func_ret_type->type_tag == Type::TypeTag::VoidType) {
|
|
build_InstReturn(_state.current_bb);
|
|
}
|
|
else {
|
|
build_InstReturn(CONST0, _state.current_bb);
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
// @retval: any
|
|
// Directly add to function, rather than return something...
|
|
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_name, 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};
|
|
}
|
|
else {
|
|
// array type
|
|
std::vector<int> dim_list = {0}; // the first dim must be empty, though
|
|
TypePtr_t array_type = TypeHelper::TYPE_I32;
|
|
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);
|
|
array_type = std::make_shared<ArrayType>(array_type, 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};
|
|
// return {array_type};
|
|
}
|
|
}
|
|
|
|
std::any Visitor::visitBlock(SysyParser::BlockContext *ctx) {
|
|
_scope_tab.enter_scope();
|
|
for (auto block_item : ctx->blockItem()) {
|
|
visitBlockItem(block_item);
|
|
}
|
|
_scope_tab.leave_scope();
|
|
return {};
|
|
}
|
|
|
|
/*
|
|
* nobody needs the value of stmt, so return nothing
|
|
|
|
stmt: lVal '=' exp ';' # assignStmt
|
|
| (exp)? ';' # expStmt // do nothing
|
|
| block # blockStmt // do nothing
|
|
| 'if' '(' cond ')' stmt ('else' stmt)? # ifStmt
|
|
| 'while' '(' cond ')' stmt # whileStmt
|
|
| 'break' ';' # breakStmt
|
|
| 'continue' ';' # continueStmt
|
|
| 'return' (exp)? ';' # returnStmt;
|
|
*/
|
|
|
|
std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) {
|
|
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 {};
|
|
}
|
|
|
|
// 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, _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, true_block->itr);
|
|
}
|
|
ctx->cond()->lOrExp()->true_block = true_block;
|
|
ctx->cond()->lOrExp()->false_block = false_block;
|
|
visitCond(ctx->cond());
|
|
|
|
_state.current_bb = true_block;
|
|
visit(ctx->stmt(0));
|
|
build_InstBranch(next_block, _state.current_bb); // use current_bb, god knows what happened
|
|
if (ctx->ELSE()) {
|
|
_state.current_bb = false_block;
|
|
visit(ctx->stmt(1));
|
|
build_InstBranch(next_block, _state.current_bb);
|
|
}
|
|
_state.current_bb = next_block;
|
|
return {};
|
|
}
|
|
|
|
// 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, _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()->false_block = next_block;
|
|
_state.current_bb = cond_block;
|
|
visitCond(ctx->cond());
|
|
// body
|
|
_state.current_bb = body_block;
|
|
visit(ctx->stmt());
|
|
build_InstBranch(cond_block, _state.current_bb);
|
|
// exit
|
|
_state.loop_stack.pop_back();
|
|
_state.current_bb = next_block;
|
|
return {};
|
|
}
|
|
|
|
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->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->itr);
|
|
return {};
|
|
}
|
|
|
|
std::any Visitor::visitReturnStmt(SysyParser::ReturnStmtContext *ctx) {
|
|
if (ctx->exp()) {
|
|
auto exp = any_to_Value(visitExp(ctx->exp()));
|
|
build_InstReturn(exp, _state.current_bb);
|
|
}
|
|
else {
|
|
build_InstReturn(_state.current_bb);
|
|
}
|
|
auto new_bb = build_BasicBlock("after_ret", _state.current_func, _state.current_bb->itr);
|
|
_state.current_bb = new_bb;
|
|
return {};
|
|
}
|
|
|
|
} // namespace antlrSysY
|