|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
#include "IRBuilder.h"
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
namespace SysYF
|
|
|
|
|
{
|
|
|
|
|
namespace IR
|
|
|
|
@ -9,10 +9,23 @@ namespace IR
|
|
|
|
|
|
|
|
|
|
// You can define global variables here
|
|
|
|
|
// to store state
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
INT = 0,
|
|
|
|
|
VOID,
|
|
|
|
|
STRING,
|
|
|
|
|
BOOL,
|
|
|
|
|
FLOAT
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::vector<BasicBlock *> tmp_condbb_while;
|
|
|
|
|
std::vector<BasicBlock *> tmp_falsebb_while;
|
|
|
|
|
std::vector<BasicBlock *> tmp_truebb;
|
|
|
|
|
std::vector<BasicBlock *> tmp_falsebb;
|
|
|
|
|
std::map<SyntaxTree::Type, Ptr<Type>> type_map; // 把类型转换成类型指针
|
|
|
|
|
// store temporary value
|
|
|
|
|
Ptr<Value> tmp_val = nullptr;
|
|
|
|
|
|
|
|
|
|
vector<Ptr<Value>> init_list;
|
|
|
|
|
// types
|
|
|
|
|
Ptr<Type> VOID_T;
|
|
|
|
|
Ptr<Type> INT1_T;
|
|
|
|
@ -21,61 +34,871 @@ Ptr<Type> FLOAT_T;
|
|
|
|
|
Ptr<Type> INT32PTR_T;
|
|
|
|
|
Ptr<Type> FLOATPTR_T;
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::Assembly &node) {
|
|
|
|
|
#define LVal_to_RVal(lval) \
|
|
|
|
|
if(lval->get_type()==INT32PTR_T || lval->get_type()==FLOATPTR_T){\
|
|
|
|
|
lval=builder->create_load(lval);\
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::Assembly &node)
|
|
|
|
|
{
|
|
|
|
|
VOID_T = Type::get_void_type(module);
|
|
|
|
|
INT1_T = Type::get_int1_type(module);
|
|
|
|
|
INT32_T = Type::get_int32_type(module);
|
|
|
|
|
FLOAT_T = Type::get_float_type(module);
|
|
|
|
|
INT32PTR_T = Type::get_int32_ptr_type(module);
|
|
|
|
|
FLOATPTR_T = Type::get_float_ptr_type(module);
|
|
|
|
|
for (const auto &def : node.global_defs) {
|
|
|
|
|
// type mapping
|
|
|
|
|
type_map[SyntaxTree::Type::VOID] = VOID_T;
|
|
|
|
|
type_map[SyntaxTree::Type::BOOL] = INT1_T;
|
|
|
|
|
type_map[SyntaxTree::Type::INT] = INT32_T;
|
|
|
|
|
type_map[SyntaxTree::Type::FLOAT] = FLOAT_T;
|
|
|
|
|
|
|
|
|
|
for (const auto &def : node.global_defs)
|
|
|
|
|
{
|
|
|
|
|
def->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// You need to fill them
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::InitVal &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::InitVal &node)
|
|
|
|
|
{
|
|
|
|
|
if (!node.isExp) // is not exp, values are in node.elementList
|
|
|
|
|
{
|
|
|
|
|
for (const auto &element : node.elementList)
|
|
|
|
|
{
|
|
|
|
|
element->accept(*this); // 这里是嵌套定义,读取的是elementList里面的element,肯能会在下一次进入的时候赋值给元素
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // is exp, values are in node.expr
|
|
|
|
|
{
|
|
|
|
|
node.expr->accept(*this); // 有可能是计算表达式,也有可能是赋值语句
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
init_list.push_back(tmp_val); // 把tmp_val放到init_list里面
|
|
|
|
|
}
|
|
|
|
|
} // init values
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncDef &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncDef &node) // 考虑一下什么时候要用scope.enter()和scope.exit()
|
|
|
|
|
{
|
|
|
|
|
auto return_type = type_map[node.ret_type];
|
|
|
|
|
auto func_name = node.name;
|
|
|
|
|
// deal with param_list
|
|
|
|
|
PtrVec<Type> params;
|
|
|
|
|
for (const auto ¶m : node.param_list->params)
|
|
|
|
|
{
|
|
|
|
|
if (param->array_index.empty()) // not array
|
|
|
|
|
{
|
|
|
|
|
params.push_back(type_map[param->param_type]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
params.push_back(type_map[param->param_type]->get_pointer_element_type()); // 这里是指针
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// build function
|
|
|
|
|
auto Func_Type = FunctionType::create(return_type, params);
|
|
|
|
|
auto func = Function::create(Func_Type, func_name, module);
|
|
|
|
|
scope.push(func_name, func);
|
|
|
|
|
// deal with block
|
|
|
|
|
auto block = BasicBlock::create(module, "entry", func);
|
|
|
|
|
builder->set_insert_point(block);
|
|
|
|
|
scope.enter();
|
|
|
|
|
// read param_list
|
|
|
|
|
node.param_list->accept(*this);
|
|
|
|
|
// read body
|
|
|
|
|
bool is_return = false;
|
|
|
|
|
for (const auto &stmt : node.body->body)
|
|
|
|
|
{
|
|
|
|
|
stmt->accept(*this);
|
|
|
|
|
if (dynamic_cast<SyntaxTree::ReturnStmt *>(stmt.get()))
|
|
|
|
|
{
|
|
|
|
|
is_return = true;
|
|
|
|
|
break; // 如果有return语句,就不用再往下读了
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
scope.exit();
|
|
|
|
|
// 处理一些不写返回值的情况(不会有代码不写返回值吧,不会吧不会吧)
|
|
|
|
|
if (!is_return)
|
|
|
|
|
{
|
|
|
|
|
switch (node.ret_type)
|
|
|
|
|
{
|
|
|
|
|
case SyntaxTree::Type::VOID:
|
|
|
|
|
builder->create_void_ret();
|
|
|
|
|
case SyntaxTree::Type::INT:
|
|
|
|
|
builder->create_ret(CONST_INT(0));
|
|
|
|
|
case SyntaxTree::Type::FLOAT:
|
|
|
|
|
builder->create_ret(CONST_FLOAT(0));
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncFParamList &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncFParamList &node)
|
|
|
|
|
{
|
|
|
|
|
auto func_arg_list = module->get_functions().back()->arg_begin(); // 取出堆栈中最后一个函数的参数列表,并且指向第一个参数
|
|
|
|
|
for (const auto ¶m : node.params)
|
|
|
|
|
{
|
|
|
|
|
param->accept(*this); // 获取数据
|
|
|
|
|
// 处理获取的数据
|
|
|
|
|
if ((*func_arg_list)->get_type()->is_pointer_type()) // 如果是指针类型,传址调用
|
|
|
|
|
{
|
|
|
|
|
scope.push(param->name, *func_arg_list); // 这里是指针
|
|
|
|
|
}
|
|
|
|
|
else // 传值调用,要分配空间
|
|
|
|
|
{
|
|
|
|
|
auto alloca = builder->create_alloca((*func_arg_list)->get_type());
|
|
|
|
|
builder->create_store(*func_arg_list, alloca);
|
|
|
|
|
scope.push(param->name, alloca);
|
|
|
|
|
}
|
|
|
|
|
func_arg_list++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncParam &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncParam &node)
|
|
|
|
|
{
|
|
|
|
|
auto param_name = node.name;
|
|
|
|
|
auto param_type = node.param_type;
|
|
|
|
|
auto param_value = node.array_index;
|
|
|
|
|
// deal with array_index
|
|
|
|
|
if (!node.array_index.empty()) // array
|
|
|
|
|
{
|
|
|
|
|
for (const auto &exp : param_value)
|
|
|
|
|
{
|
|
|
|
|
exp->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::VarDef &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::VarDef &node)
|
|
|
|
|
{
|
|
|
|
|
bool is_const = node.is_constant;
|
|
|
|
|
auto var_name = node.name;
|
|
|
|
|
auto var_type = type_map[node.btype];
|
|
|
|
|
auto is_initialized = node.is_inited;
|
|
|
|
|
auto length = node.array_length;
|
|
|
|
|
auto init_val = node.initializers;
|
|
|
|
|
// deal with array_length
|
|
|
|
|
if (length.empty()) // 说明不是数组
|
|
|
|
|
{
|
|
|
|
|
if (scope.in_global()) // 如果是全局变量
|
|
|
|
|
{
|
|
|
|
|
auto global_var = GlobalVariable::create(var_name, module, var_type, is_const, ConstantZero::create(var_type, module));
|
|
|
|
|
if (is_initialized)
|
|
|
|
|
{
|
|
|
|
|
init_val->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
builder->create_store(tmp_val, global_var);
|
|
|
|
|
}
|
|
|
|
|
else if (is_const) // 说明是const,但是没有初始化
|
|
|
|
|
cout << "const variable must be initialized" << endl;
|
|
|
|
|
scope.push(var_name, global_var);
|
|
|
|
|
}
|
|
|
|
|
else // 如果是局部变量
|
|
|
|
|
{
|
|
|
|
|
auto var = builder->create_alloca(var_type);
|
|
|
|
|
if (is_initialized)
|
|
|
|
|
{
|
|
|
|
|
init_val->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
builder->create_store(tmp_val , var);
|
|
|
|
|
}
|
|
|
|
|
else if (is_const) // 说明是const,但是没有初始化
|
|
|
|
|
cout << "const variable must be initialized" << endl;
|
|
|
|
|
scope.push(var_name, var);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // 数组
|
|
|
|
|
{
|
|
|
|
|
auto arrayType = ArrayType::get(var_type, length.size());
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::LVal &node) {}
|
|
|
|
|
if (scope.in_global()) // 如果是全局变量
|
|
|
|
|
{
|
|
|
|
|
auto global_array = GlobalVariable::create(var_name, module, arrayType, is_const, ConstantZero::create(var_type, module));
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::AssignStmt &node) {}
|
|
|
|
|
if (is_initialized)
|
|
|
|
|
{
|
|
|
|
|
init_list.clear(); // 清空init_list
|
|
|
|
|
init_val->accept(*this); // 把init_val里面的值放到init_list里面
|
|
|
|
|
while (init_list.size() < length.size()) // 如果init_list的长度小于length的长度,就把init_list其他的值补上0
|
|
|
|
|
{
|
|
|
|
|
init_list.push_back(ConstantZero::create(type_map[node.btype], module));
|
|
|
|
|
}
|
|
|
|
|
// initilize
|
|
|
|
|
for (auto i = 0; i < static_cast<int>(init_list.size()); i++)
|
|
|
|
|
{
|
|
|
|
|
auto GEP = builder->create_gep(global_array, {CONST_INT(0), CONST_INT(i)});
|
|
|
|
|
builder->create_store(init_list[i], GEP);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (is_const) // 说明是const,但是没有初始化
|
|
|
|
|
cout << "const variable must be initialized" << endl;
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::Literal &node) {}
|
|
|
|
|
scope.push(var_name, global_array);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto array = builder->create_alloca(arrayType);
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::ReturnStmt &node) {}
|
|
|
|
|
if (is_initialized)
|
|
|
|
|
{
|
|
|
|
|
init_list.clear(); // 清空init_list
|
|
|
|
|
init_val->accept(*this); // 把init_val里面的值放到init_list里面
|
|
|
|
|
while (init_list.size() < length.size()) // 如果init_list的长度小于length的长度,就把init_list其他的值补上0
|
|
|
|
|
{
|
|
|
|
|
init_list.push_back(ConstantZero::create(type_map[node.btype], module));
|
|
|
|
|
}
|
|
|
|
|
// initilize
|
|
|
|
|
for (int i = 0; i < static_cast<int>(init_list.size()); i++)
|
|
|
|
|
{
|
|
|
|
|
auto GEP = builder->create_gep(array, {CONST_INT(0), CONST_INT(i)});
|
|
|
|
|
builder->create_store(init_list[i], GEP);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (is_const) // 说明是const,但是没有初始化
|
|
|
|
|
cout << "const variable must be initialized" << endl;
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BlockStmt &node) {}
|
|
|
|
|
scope.push(var_name, array);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::EmptyStmt &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::LVal &node)
|
|
|
|
|
{
|
|
|
|
|
auto name = node.name;
|
|
|
|
|
auto index = node.array_index;
|
|
|
|
|
auto lval = scope.find(name, false);
|
|
|
|
|
if (lval)
|
|
|
|
|
{
|
|
|
|
|
if (!index.empty())
|
|
|
|
|
{
|
|
|
|
|
for (const auto &exp : index)
|
|
|
|
|
{
|
|
|
|
|
exp->accept(*this);
|
|
|
|
|
auto tmp = tmp_val;
|
|
|
|
|
auto GEP = builder->create_gep(lval, {tmp});
|
|
|
|
|
lval = GEP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ // 从符号表中取出的是字面值
|
|
|
|
|
tmp_val = lval;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::cout << "LVal pointer or literal not found" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
} // lval: Identifier|Identifier LeftBracket exp RightBracket
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::ExprStmt &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::AssignStmt &node)
|
|
|
|
|
{
|
|
|
|
|
node.target->accept(*this);
|
|
|
|
|
auto target = builder->create_load(tmp_val);//?
|
|
|
|
|
auto name = target->get_name();
|
|
|
|
|
node.value->accept(*this);//?
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto value = tmp_val;
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::UnaryCondExpr &node) {}
|
|
|
|
|
builder->create_store(value, target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BinaryCondExpr &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::Literal &node)
|
|
|
|
|
{
|
|
|
|
|
auto type = node.literal_type;
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case SyntaxTree::Type::INT:
|
|
|
|
|
tmp_val = CONST_INT(node.int_const);
|
|
|
|
|
case SyntaxTree::Type::FLOAT:
|
|
|
|
|
tmp_val = CONST_FLOAT(node.float_const);
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} // literal: IntegerLiteral|FloatLiteral
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BinaryExpr &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::ReturnStmt &node)
|
|
|
|
|
{
|
|
|
|
|
auto return_value = node.ret;
|
|
|
|
|
if (return_value != nullptr)
|
|
|
|
|
{
|
|
|
|
|
return_value->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto value_type = tmp_val->get_type();
|
|
|
|
|
auto ret_type = module->get_functions().back()->get_return_type();
|
|
|
|
|
// 类型检查
|
|
|
|
|
if(ret_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
if(value_type == FLOAT_T)
|
|
|
|
|
tmp_val = builder->create_fptosi(tmp_val, INT32_T);
|
|
|
|
|
else if(value_type == INT1_T)
|
|
|
|
|
tmp_val = builder->create_zext(tmp_val, INT32_T);
|
|
|
|
|
}
|
|
|
|
|
auto value = tmp_val;
|
|
|
|
|
builder->create_ret(value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
builder->create_void_ret();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::UnaryExpr &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BlockStmt &node)
|
|
|
|
|
{
|
|
|
|
|
scope.enter();
|
|
|
|
|
for (const auto &stmt : node.body)
|
|
|
|
|
{
|
|
|
|
|
stmt->accept(*this);
|
|
|
|
|
if (dynamic_cast<SyntaxTree::BreakStmt *>(stmt.get()) != nullptr || dynamic_cast<SyntaxTree::ContinueStmt *>(stmt.get()) != nullptr || dynamic_cast<SyntaxTree::ReturnStmt *>(stmt.get()) != nullptr)
|
|
|
|
|
{ // break,continue,return后面的语句不再编译
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
scope.exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncCallStmt &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::EmptyStmt &node)
|
|
|
|
|
{
|
|
|
|
|
node.accept(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::IfStmt &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::ExprStmt &node)
|
|
|
|
|
{
|
|
|
|
|
node.exp->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::WhileStmt &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::UnaryCondExpr &node)
|
|
|
|
|
{
|
|
|
|
|
node.rhs->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto rhs = tmp_val;
|
|
|
|
|
// 整数
|
|
|
|
|
if (rhs->get_type() == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
auto UnaryCondExpr = builder->create_icmp_eq(rhs, CONST_INT(0));
|
|
|
|
|
scope.push("CondExpr", UnaryCondExpr);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto UnaryCondExpr = builder->create_fcmp_eq(rhs, CONST_FLOAT(0));
|
|
|
|
|
scope.push("CondExpr", UnaryCondExpr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BreakStmt &node) {}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BinaryCondExpr &node)
|
|
|
|
|
{
|
|
|
|
|
node.rhs->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto rhs = tmp_val;
|
|
|
|
|
auto rhs_type = rhs->get_type();
|
|
|
|
|
node.lhs->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto lhs = tmp_val;
|
|
|
|
|
auto lhs_type = lhs->get_type();
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::ContinueStmt &node) {}
|
|
|
|
|
if (node.op == SyntaxTree::BinaryCondOp::LAND)
|
|
|
|
|
{
|
|
|
|
|
auto falseBB = scope.find("falseBB", 0);
|
|
|
|
|
auto trueBB = BasicBlock::create(module,
|
|
|
|
|
"trueBB_lhs", module->get_functions().back());
|
|
|
|
|
|
|
|
|
|
if (lhs_type == INT1_T)
|
|
|
|
|
{
|
|
|
|
|
builder->create_cond_br(lhs, trueBB, dynamic_pointer_cast<SysYF::IR::BasicBlock>(falseBB));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
auto lhs_cond = builder->create_icmp_eq(lhs, CONST_INT(0));
|
|
|
|
|
builder->create_cond_br(lhs_cond, trueBB, dynamic_pointer_cast<SysYF::IR::BasicBlock>(falseBB));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == FLOAT_T)
|
|
|
|
|
{
|
|
|
|
|
auto lhs_cond = builder->create_fcmp_eq(lhs, CONST_FLOAT(0));
|
|
|
|
|
builder->create_cond_br(lhs_cond, trueBB, dynamic_pointer_cast<SysYF::IR::BasicBlock>(falseBB));
|
|
|
|
|
}
|
|
|
|
|
builder->set_insert_point(trueBB);
|
|
|
|
|
node.rhs->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
else if (node.op == SyntaxTree::BinaryCondOp::LOR)
|
|
|
|
|
{
|
|
|
|
|
auto trueBB = scope.find("trueBB", 0);
|
|
|
|
|
auto falseBB = BasicBlock::create(module,
|
|
|
|
|
"falseBB_lhs", module->get_functions().back());
|
|
|
|
|
|
|
|
|
|
if (lhs_type == INT1_T)
|
|
|
|
|
{
|
|
|
|
|
builder->create_cond_br(lhs, dynamic_pointer_cast<SysYF::IR::BasicBlock>(trueBB), falseBB);
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
auto lhs_cond = builder->create_icmp_eq(lhs, CONST_INT(0));
|
|
|
|
|
builder->create_cond_br(lhs_cond, dynamic_pointer_cast<SysYF::IR::BasicBlock>(trueBB), falseBB);
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == FLOAT_T)
|
|
|
|
|
{
|
|
|
|
|
auto lhs_cond = builder->create_fcmp_eq(lhs, CONST_FLOAT(0));
|
|
|
|
|
builder->create_cond_br(lhs_cond, dynamic_pointer_cast<SysYF::IR::BasicBlock>(trueBB), falseBB);
|
|
|
|
|
}
|
|
|
|
|
builder->set_insert_point(falseBB);
|
|
|
|
|
node.rhs->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto expr_type = FLOAT_T;
|
|
|
|
|
|
|
|
|
|
if (lhs_type == INT1_T && rhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(lhs, INT32_T));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == INT1_T && rhs_type == FLOAT_T)
|
|
|
|
|
{
|
|
|
|
|
lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(lhs, FLOAT_T));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == INT32_T && rhs_type == INT1_T)
|
|
|
|
|
{
|
|
|
|
|
rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(rhs, INT32_T));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == FLOAT_T && rhs_type == INT1_T)
|
|
|
|
|
{
|
|
|
|
|
rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(rhs, FLOAT_T));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == FLOAT_T && rhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_sitofp(rhs, FLOAT_T));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == INT32_T && rhs_type == FLOAT_T)
|
|
|
|
|
{
|
|
|
|
|
lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_sitofp(lhs, FLOAT_T));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == INT1_T && rhs_type == INT1_T)
|
|
|
|
|
{
|
|
|
|
|
lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(lhs, INT32_T));
|
|
|
|
|
rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(rhs, INT32_T));
|
|
|
|
|
}
|
|
|
|
|
// 整数
|
|
|
|
|
if (rhs->get_type() == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
switch (node.op)
|
|
|
|
|
{
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::LT:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_icmp_lt(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::LTE:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_icmp_le(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::GT:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_icmp_gt(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::GTE:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_icmp_ge(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::EQ:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_icmp_eq(lhs, rhs);
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (node.op)
|
|
|
|
|
{
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::LT:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_fcmp_lt(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::LTE:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_fcmp_le(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::GT:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_fcmp_gt(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::GTE:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_fcmp_ge(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SysYF::SyntaxTree::BinaryCondOp::EQ:
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_fcmp_eq(lhs, rhs);
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
scope.push("CondExpr", tmp_val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BinaryExpr &node)
|
|
|
|
|
{
|
|
|
|
|
// 整数
|
|
|
|
|
node.rhs->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto rhs = tmp_val;
|
|
|
|
|
auto rhs_type = rhs->get_type();
|
|
|
|
|
node.lhs->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto lhs = tmp_val;
|
|
|
|
|
auto lhs_type = lhs->get_type();
|
|
|
|
|
if (lhs_type == FLOAT_T && rhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_sitofp(rhs, FLOAT_T));
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == INT32_T && rhs_type == FLOAT_T)
|
|
|
|
|
{
|
|
|
|
|
lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_sitofp(lhs, FLOAT_T));
|
|
|
|
|
}
|
|
|
|
|
auto expr_type = lhs->get_type();
|
|
|
|
|
|
|
|
|
|
// 计算出可以直接计算的值
|
|
|
|
|
if ((dynamic_pointer_cast<ConstantFloat>(lhs) || dynamic_pointer_cast<ConstantFloat>(lhs)) && (dynamic_pointer_cast<ConstantFloat>(rhs) || dynamic_pointer_cast<ConstantFloat>(rhs)))
|
|
|
|
|
{ // 简单字面量计算
|
|
|
|
|
int lhs_int;
|
|
|
|
|
int rhs_int;
|
|
|
|
|
float lhs_float;
|
|
|
|
|
float rhs_float;
|
|
|
|
|
if (expr_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
lhs_int = dynamic_pointer_cast<ConstantInt>(lhs)->get_value();
|
|
|
|
|
rhs_int = dynamic_pointer_cast<ConstantInt>(rhs)->get_value();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lhs_float = dynamic_pointer_cast<ConstantFloat>(lhs)->get_value();
|
|
|
|
|
rhs_float = dynamic_pointer_cast<ConstantFloat>(rhs)->get_value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (node.op)
|
|
|
|
|
{
|
|
|
|
|
case SyntaxTree::BinOp::PLUS:
|
|
|
|
|
if (expr_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_INT(lhs_int + rhs_int);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_FLOAT(lhs_float + rhs_float);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SyntaxTree::BinOp::MINUS:
|
|
|
|
|
if (expr_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_INT(lhs_int - rhs_int);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_FLOAT(lhs_float - rhs_float);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SyntaxTree::BinOp::MULTIPLY:
|
|
|
|
|
if (expr_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_INT(lhs_int * rhs_int);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_FLOAT(lhs_float * rhs_float);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SyntaxTree::BinOp::DIVIDE:
|
|
|
|
|
if (expr_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_INT(lhs_int / rhs_int);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_FLOAT(lhs_float / rhs_float);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SyntaxTree::BinOp::MODULO:
|
|
|
|
|
if (expr_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_INT(lhs_int % rhs_int);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_INT(static_cast<int>(lhs_float) % static_cast<int>(rhs_float));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (lhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
switch (node.op)
|
|
|
|
|
{
|
|
|
|
|
case SyntaxTree::BinOp::PLUS:
|
|
|
|
|
{
|
|
|
|
|
builder->create_iadd(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::BinOp::MINUS:
|
|
|
|
|
{
|
|
|
|
|
builder->create_isub(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::BinOp::MULTIPLY:
|
|
|
|
|
{
|
|
|
|
|
builder->create_imul(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::BinOp::DIVIDE:
|
|
|
|
|
{
|
|
|
|
|
builder->create_isdiv(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::BinOp::MODULO:
|
|
|
|
|
{
|
|
|
|
|
builder->create_isrem(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (lhs_type == FLOAT_T)
|
|
|
|
|
{
|
|
|
|
|
switch (node.op)
|
|
|
|
|
{
|
|
|
|
|
case SyntaxTree::BinOp::PLUS:
|
|
|
|
|
{
|
|
|
|
|
builder->create_fadd(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::BinOp::MINUS:
|
|
|
|
|
{
|
|
|
|
|
builder->create_fsub(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::BinOp::MULTIPLY:
|
|
|
|
|
{
|
|
|
|
|
builder->create_fmul(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::BinOp::DIVIDE:
|
|
|
|
|
{
|
|
|
|
|
builder->create_fdiv(lhs, rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::BinOp::MODULO:
|
|
|
|
|
{
|
|
|
|
|
// builder->create_isrem(static_pointer_cast<ConstantInt>(lhs), static_pointer_cast<ConstantInt>(rhs));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::UnaryExpr &node)
|
|
|
|
|
{
|
|
|
|
|
// 整数
|
|
|
|
|
node.rhs->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto rhs = tmp_val;
|
|
|
|
|
auto rhs_type = rhs->get_type();
|
|
|
|
|
|
|
|
|
|
// 直接计算的
|
|
|
|
|
if (dynamic_pointer_cast<ConstantInt>(rhs) || dynamic_pointer_cast<ConstantFloat>(rhs))
|
|
|
|
|
{
|
|
|
|
|
int rhs_int;
|
|
|
|
|
float rhs_float;
|
|
|
|
|
if (rhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
rhs_int = dynamic_pointer_cast<ConstantInt>(rhs)->get_value();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rhs_float = dynamic_pointer_cast<ConstantFloat>(rhs)->get_value();
|
|
|
|
|
}
|
|
|
|
|
switch (node.op)
|
|
|
|
|
{
|
|
|
|
|
case SyntaxTree::UnaryOp::PLUS:
|
|
|
|
|
if (rhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_INT(rhs_int);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_FLOAT(rhs_float);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SyntaxTree::UnaryOp::MINUS:
|
|
|
|
|
if (rhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_INT(-rhs_int);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp_val = CONST_FLOAT(-rhs_float);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (rhs_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
switch (node.op)
|
|
|
|
|
{
|
|
|
|
|
case SyntaxTree::UnaryOp::PLUS:
|
|
|
|
|
{
|
|
|
|
|
builder->create_iadd(rhs, CONST_INT(0));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::UnaryOp::MINUS:
|
|
|
|
|
{
|
|
|
|
|
builder->create_isub(CONST_INT(0), rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (rhs_type == FLOAT_T)
|
|
|
|
|
{
|
|
|
|
|
switch (node.op)
|
|
|
|
|
{
|
|
|
|
|
case SyntaxTree::UnaryOp::PLUS:
|
|
|
|
|
{
|
|
|
|
|
builder->create_fadd(rhs, CONST_FLOAT(0));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SyntaxTree::UnaryOp::MINUS:
|
|
|
|
|
{
|
|
|
|
|
builder->create_fsub(CONST_FLOAT(0), rhs);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncCallStmt &node)
|
|
|
|
|
{
|
|
|
|
|
auto func = scope.find(node.name, true);
|
|
|
|
|
if (func)
|
|
|
|
|
{
|
|
|
|
|
PtrVec<Value> args{};
|
|
|
|
|
|
|
|
|
|
auto arg_func = dynamic_pointer_cast<SysYF::IR::Function>(func)->arg_begin();
|
|
|
|
|
|
|
|
|
|
for (auto &arg : node.params)
|
|
|
|
|
{
|
|
|
|
|
auto arg_func_type = (*arg_func)->get_type();
|
|
|
|
|
|
|
|
|
|
arg->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto value = tmp_val;
|
|
|
|
|
|
|
|
|
|
// 数组
|
|
|
|
|
if (arg_func_type == INT32PTR_T || arg_func_type == FLOATPTR_T)
|
|
|
|
|
{
|
|
|
|
|
// if(value->get_type() == INT32PTR_T || value->get_type() == FLOATPTR_T){
|
|
|
|
|
// tmp_val = value;
|
|
|
|
|
// }
|
|
|
|
|
// else{
|
|
|
|
|
// tmp_val = builder->create_alloca(arg_func_type);
|
|
|
|
|
// builder->create_store(value, tmp_val);
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (value->get_type() == INT32_T && arg_func_type == FLOAT_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_sitofp(value, FLOAT_T);
|
|
|
|
|
}
|
|
|
|
|
else if (value->get_type() == FLOAT_T && arg_func_type == INT32_T)
|
|
|
|
|
{
|
|
|
|
|
tmp_val = builder->create_fptosi(value, INT32_T);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
args.push_back(tmp_val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
builder->create_call(func, args);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::IfStmt &node)
|
|
|
|
|
{
|
|
|
|
|
scope.enter();
|
|
|
|
|
auto trueBB = BasicBlock::create(module, "trueBB_if",
|
|
|
|
|
module->get_functions().back());
|
|
|
|
|
auto nextBB = BasicBlock::create(module, "nextBB_if",
|
|
|
|
|
module->get_functions().back());
|
|
|
|
|
|
|
|
|
|
scope.push("trueBB", trueBB);
|
|
|
|
|
scope.push("falseBB", nextBB);
|
|
|
|
|
|
|
|
|
|
node.cond_exp->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto cond = tmp_val;
|
|
|
|
|
|
|
|
|
|
builder->create_cond_br(cond, trueBB, nextBB);
|
|
|
|
|
builder->set_insert_point(trueBB);
|
|
|
|
|
node.if_statement->accept(*this);
|
|
|
|
|
|
|
|
|
|
builder->set_insert_point(nextBB);
|
|
|
|
|
if (node.else_statement)
|
|
|
|
|
{
|
|
|
|
|
node.else_statement->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
scope.exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::WhileStmt &node)
|
|
|
|
|
{
|
|
|
|
|
// auto func_name = scope.find("func", 0);
|
|
|
|
|
scope.enter();
|
|
|
|
|
auto condBB = BasicBlock::create(module, "condBB_while",
|
|
|
|
|
module->get_functions().back());
|
|
|
|
|
auto trueBB = BasicBlock::create(module, "trueBB_while",
|
|
|
|
|
module->get_functions().back());
|
|
|
|
|
auto falseBB = BasicBlock::create(module, "falseBB_while",
|
|
|
|
|
module->get_functions().back());
|
|
|
|
|
|
|
|
|
|
scope.push("condBB", condBB);
|
|
|
|
|
scope.push("trueBB", trueBB);
|
|
|
|
|
scope.push("falseBB", falseBB);
|
|
|
|
|
|
|
|
|
|
builder->create_br(condBB);
|
|
|
|
|
node.cond_exp->accept(*this);
|
|
|
|
|
LVal_to_RVal(tmp_val);
|
|
|
|
|
auto cond = tmp_val;
|
|
|
|
|
builder->create_cond_br(cond, trueBB, falseBB);
|
|
|
|
|
|
|
|
|
|
auto cond_val = tmp_val;
|
|
|
|
|
scope.exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BreakStmt &node)
|
|
|
|
|
{
|
|
|
|
|
node.accept(*this);
|
|
|
|
|
auto falseBB = scope.find("falseBB", 0);
|
|
|
|
|
builder->create_br(dynamic_pointer_cast<SysYF::IR::BasicBlock>(falseBB));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::ContinueStmt &node)
|
|
|
|
|
{
|
|
|
|
|
node.accept(*this);
|
|
|
|
|
auto condBB = scope.find("condBB", 0);
|
|
|
|
|
builder->create_br(dynamic_pointer_cast<SysYF::IR::BasicBlock>(condBB));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|