You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

802 lines
26 KiB

#include <cassert>
#include "IRBuilder.h"
namespace SysYF
{
namespace IR
{
#define CONST_INT(num) ConstantInt::create(num, module)
#define CONST_FLOAT(num) ConstantFloat::create(num, module)
// You can define global variables here
// to store state
// store temporary value
std::vector<Ptr<Type>> funcFParam;
struct WhileBlock {
Ptr<BasicBlock> condBB;
Ptr<BasicBlock> bodyBB;
Ptr<BasicBlock> afterBB;
};
auto curWhileBlock = WhileBlock{nullptr, nullptr, nullptr};
Ptr<BasicBlock> retBB;
Ptr<Value> retAlloca;
Ptr<Value> tmpInst;
// types
Ptr<Type> VOID_T;
Ptr<Type> INT1_T;
Ptr<Type> INT32_T;
Ptr<Type> FLOAT_T;
Ptr<Type> INT32PTR_T;
Ptr<Type> FLOATPTR_T;
Ptr<Type> GetBaseType(SyntaxTree::Type type){
switch(type){
case SyntaxTree::Type::INT:
return INT32_T;
case SyntaxTree::Type::FLOAT:
return FLOAT_T;
case SyntaxTree::Type::VOID:
return VOID_T;
default:
return nullptr;
}
}
Ptr<Type> GetParamType(SyntaxTree::Type type, bool isPtr = false){
auto tmpType = GetBaseType(type);
if(!isPtr || tmpType == nullptr || tmpType == VOID_T){
return tmpType;
}
else {
if(tmpType == INT32_T){
return INT32PTR_T;
}
else if(tmpType == FLOAT_T){
return FLOATPTR_T;
}
}
}
void IRBuilder::BinaryExprGen(Ptr<Value> lhs, Ptr<Value> rhs, SyntaxTree::BinOp op){
bool isFloat = false;
int lInt, rInt;
float lFloat, rFloat;
if (dynamic_pointer_cast<Constant>(lhs) && dynamic_pointer_cast<Constant>(rhs)) {
if (dynamic_pointer_cast<ConstantFloat>(lhs) || dynamic_pointer_cast<ConstantFloat>(rhs)) {
isFloat = true;
lFloat = dynamic_pointer_cast<ConstantFloat>(lhs)->get_value();
rFloat = dynamic_pointer_cast<ConstantFloat>(rhs)->get_value();
}
else {
isFloat = false;
lInt = dynamic_pointer_cast<ConstantInt>(lhs)->get_value();
rInt = dynamic_pointer_cast<ConstantInt>(rhs)->get_value();
}
switch (op) {
case SyntaxTree::BinOp::PLUS:
if (isFloat) {
tmpInst = CONST_FLOAT(lFloat + rFloat);
} else
tmpInst = CONST_INT(lInt + rInt);
break;
case SyntaxTree::BinOp::MINUS:
if (isFloat) {
tmpInst = CONST_FLOAT(lFloat - rFloat);
} else
tmpInst = CONST_INT(lInt - rInt);
break;
case SyntaxTree::BinOp::MULTIPLY:
if (isFloat) {
tmpInst = CONST_FLOAT(lFloat * rFloat);
} else
tmpInst = CONST_INT(lInt * rInt);
break;
case SyntaxTree::BinOp::DIVIDE:
if (isFloat) {
tmpInst = CONST_FLOAT(lFloat / rFloat);
} else {
tmpInst = CONST_INT(lInt / rInt);
}
break;
case SyntaxTree::BinOp::MODULO:
if (isFloat) { ;// not support
} else {
tmpInst = CONST_INT(lInt % rInt);
}
break;
}
} else {
if (lhs->get_type()->is_pointer_type()) {
lhs = builder->create_load(lhs);
}
if (rhs->get_type()->is_pointer_type()) {
rhs = builder->create_load(rhs);
}
if (lhs->get_type()->is_float_type() &&
rhs->get_type()->is_integer_type()) {
rhs = builder->create_sitofp(rhs, FLOAT_T);
}
if (lhs->get_type()->is_integer_type() &&
rhs->get_type()->is_float_type()) {
lhs = builder->create_sitofp(lhs, FLOAT_T);
}
isFloat = lhs->get_type()->is_float_type();
switch (op) {
case SyntaxTree::BinOp::PLUS:
if (isFloat) {
tmpInst = builder->create_fadd(lhs, rhs);
} else
tmpInst = builder->create_iadd(lhs, rhs);
break;
case SyntaxTree::BinOp::MINUS:
if (isFloat) {
tmpInst = builder->create_fsub(lhs, rhs);
} else
tmpInst = builder->create_isub(lhs, rhs);
break;
case SyntaxTree::BinOp::MULTIPLY:
if (isFloat) {
tmpInst = builder->create_fmul(lhs, rhs);
} else
tmpInst = builder->create_imul(lhs, rhs);
break;
case SyntaxTree::BinOp::DIVIDE:
if (isFloat) {
tmpInst = builder->create_fdiv(lhs, rhs);
} else {
tmpInst = builder->create_isdiv(lhs, rhs);
}
break;
case SyntaxTree::BinOp::MODULO:
if (isFloat) { ;// not support
} else {
tmpInst = builder->create_isrem(lhs, rhs);
}
break;
}
}
}
void IRBuilder::BinaryCondExprGen(Ptr<Value> lhs, Ptr<Value> rhs, SyntaxTree::BinaryCondOp op) {
bool isFloat = false;
int lInt, rInt;
float lFloat, rFloat;
if (dynamic_pointer_cast<Constant>(lhs) && dynamic_pointer_cast<Constant>(rhs)) {
if (dynamic_pointer_cast<ConstantFloat>(lhs) || dynamic_pointer_cast<ConstantFloat>(rhs)) {
isFloat = true;
lFloat = dynamic_pointer_cast<ConstantFloat>(lhs)->get_value();
rFloat = dynamic_pointer_cast<ConstantFloat>(rhs)->get_value();
}
else {
isFloat = false;
lInt = dynamic_pointer_cast<ConstantInt>(lhs)->get_value();
rInt = dynamic_pointer_cast<ConstantInt>(rhs)->get_value();
}
switch (op) {
case SyntaxTree::BinaryCondOp::LT:
if (isFloat) {
tmpInst = CONST_INT(lFloat < rFloat);
}
else {
tmpInst = CONST_INT(lInt < rInt);
}
break;
case SyntaxTree::BinaryCondOp::LTE:
if (isFloat) {
tmpInst = CONST_INT(lFloat <= rFloat);
}
else {
tmpInst = CONST_INT(lInt <= rInt);
}
break;
case SyntaxTree::BinaryCondOp::GT:
if (isFloat) {
tmpInst = CONST_INT(lFloat > rFloat);
}
else {
tmpInst = CONST_INT(lInt > rInt);
}
break;
case SyntaxTree::BinaryCondOp::GTE:
if (isFloat) {
tmpInst = CONST_INT(lFloat >= rFloat);
}
else {
tmpInst = CONST_INT(lInt >= rInt);
}
break;
case SyntaxTree::BinaryCondOp::EQ:
if (isFloat) {
tmpInst = CONST_INT(lFloat == rFloat);
}
else {
tmpInst = CONST_INT(lInt == rInt);
}
break;
case SyntaxTree::BinaryCondOp::NEQ:
if (isFloat) {
tmpInst = CONST_INT(lFloat != rFloat);
}
else {
tmpInst = CONST_INT(lInt != rInt);
}
break;
default:
break;
}
} else {
if (lhs->get_type()->is_pointer_type()) {
lhs = builder->create_load(lhs);
}
if (rhs->get_type()->is_pointer_type()) {
rhs = builder->create_load(rhs);
}
if (lhs->get_type()->is_float_type() &&
rhs->get_type()->is_integer_type()) {
rhs = builder->create_sitofp(rhs, FLOAT_T);
}
if (lhs->get_type()->is_integer_type() &&
rhs->get_type()->is_float_type()) {
lhs = builder->create_sitofp(lhs, FLOAT_T);
}
isFloat = lhs->get_type()->is_float_type();
switch (op) {
case SyntaxTree::BinaryCondOp::LT:
if (isFloat) {
tmpInst = builder->create_fcmp_lt(lhs, rhs);
}
else {
tmpInst = builder->create_icmp_gt(lhs, rhs);
}
break;
case SyntaxTree::BinaryCondOp::LTE:
if (isFloat) {
tmpInst = builder->create_fcmp_le(lhs, rhs);
}
else {
tmpInst = builder->create_icmp_le(lhs, rhs);
}
break;
case SyntaxTree::BinaryCondOp::GT:
if (isFloat) {
tmpInst = builder->create_fcmp_gt(lhs, rhs);
}
else {
tmpInst = builder->create_icmp_gt(lhs, rhs);
}
break;
case SyntaxTree::BinaryCondOp::GTE:
if (isFloat) {
tmpInst = builder->create_fcmp_ge(lhs, rhs);
}
else {
tmpInst = builder->create_icmp_ge(lhs, rhs);
}
break;
case SyntaxTree::BinaryCondOp::EQ:
if (isFloat) {
tmpInst = builder->create_fcmp_eq(lhs, rhs);
}
else {
tmpInst = builder->create_icmp_eq(lhs, rhs);
}
break;
case SyntaxTree::BinaryCondOp::NEQ:
if (isFloat) {
tmpInst = builder->create_fcmp_ne(lhs, rhs);
}
else {
tmpInst = builder->create_icmp_ne(lhs, rhs);
}
break;
default:
break;
}
}
}
void IRBuilder::TypeConvert(Ptr<Value> origin, Ptr<Type> expected) {
if (dynamic_pointer_cast<Constant>(origin) == nullptr) {
auto type = origin->get_type();
if (type == expected) {
return;
}
if (type->is_pointer_type()) {
type = type->get_pointer_element_type();
origin = builder->create_load(origin);
}
if (type == INT32_T && expected == INT1_T) {
tmpInst = builder->create_icmp_ne(origin, CONST_INT(0));
return;
}
if (type == FLOAT_T && expected == INT1_T) {
tmpInst = builder->create_fcmp_ne(origin, CONST_FLOAT(0));
return;
}
if (type == INT32_T && expected == FLOAT_T) {
tmpInst = builder->create_sitofp(origin, expected);
return;
}
if (type == FLOAT_T && expected == INT32_T) {
tmpInst = builder->create_fptosi(origin, expected);
return;
}
} else {
auto tmpInt = dynamic_pointer_cast<ConstantInt>(origin);
auto tmpFloat = dynamic_pointer_cast<ConstantFloat>(origin);
if (tmpInt != nullptr) {
if (expected == FLOAT_T)
tmpInst = CONST_FLOAT(tmpInt->get_value());
else if (expected == INT1_T)
tmpInst = CONST_INT(tmpInt->get_value() != 0);
}
if (tmpFloat != nullptr) {
if (expected == INT32_T)
tmpInst =
CONST_INT(static_cast<int>(tmpInt->get_value()));
else if (expected == INT1_T)
tmpInst = CONST_INT(tmpFloat->get_value() != 0);
}
return;
}
}
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) {
def->accept(*this);
}
}
// You need to fill them
// FINISH
void IRBuilder::visit(SyntaxTree::InitVal &node) {
node.expr->accept(*this);
}
// FINISH
void IRBuilder::visit(SyntaxTree::FuncDef &node) {
auto funcRetType = GetParamType(node.ret_type);
node.param_list->accept(*this);
auto funcType = FunctionType::create(funcRetType, funcFParam);
auto func = Function::create(funcType, node.name, module);
scope.push(node.name, func);
scope.enter();
auto entryBlock = BasicBlock::create(module, "funcEntry", func);
retBB = BasicBlock::create(module, "ret", func);
builder->set_insert_point(entryBlock);
auto para = node.param_list->params.begin();
auto para_end = node.param_list->params.end();
auto funcArgs = func->get_args();
for (const auto &arg : funcArgs) {
if(para == para_end)
break;
auto name = (*para)->name;
auto argAlloca = builder->create_alloca(arg->get_type());
builder->create_store(arg, argAlloca);
scope.push(name, argAlloca);
para++;
}
if (funcRetType == VOID_T) {
;
} else {
retAlloca = builder->create_alloca(funcRetType);
}
node.body->accept(*this);
if (builder->get_insert_block()->get_terminator() == nullptr) {
if (funcRetType == INT32_T) {
builder->create_store(CONST_INT(0), retAlloca);
} else if (funcRetType == FLOAT_T) {
builder->create_store(CONST_FLOAT(0), retAlloca);
}
builder->create_br(retBB);
}
builder->set_insert_point(retBB);
if (funcRetType == VOID_T) {
builder->create_void_ret();
} else {
auto ret_val = builder->create_load(retAlloca);
builder->create_ret(ret_val);
}
scope.exit();
}
// FINISH
void IRBuilder::visit(SyntaxTree::FuncFParamList &node) {
funcFParam.clear();
for (const auto &para : node.params) {
para->accept(*this);
}
}
// FINISH
void IRBuilder::visit(SyntaxTree::FuncParam &node) {
auto tmpType = GetParamType(node.param_type, node.array_index.empty());
funcFParam.push_back(tmpType);
}
// FINISH
void IRBuilder::visit(SyntaxTree::VarDef &node) {
// type
auto varType = GetBaseType(node.btype);
Ptr<ArrayType> arrayType;
if (!node.array_length.empty()) {
node.array_length[0]->accept(*this);
auto constInt = dynamic_pointer_cast<ConstantInt>(tmpInst);
arrayType = ArrayType::create(varType, constInt->get_value());
}
Ptr<Value> identAlloca;
if (scope.in_global()) {
if (!node.is_inited || (!node.array_length.empty() && node.initializers->elementList.empty())) {
auto zeroInit = ConstantZero::create(varType, module);
identAlloca = GlobalVariable::create(node.name, module, varType, false, zeroInit);
} else {
if (!node.array_length.empty()) {
std::vector<Ptr<Constant>> varInit;
for (const auto &init : node.initializers->elementList) {
init->accept(*this);
TypeConvert(tmpInst, varType);
varInit.push_back(dynamic_pointer_cast<Constant>(tmpInst));
}
auto otherLen = arrayType->get_num_of_elements() - node.initializers->elementList.size();
auto tmpZero = CONST_INT(0);
TypeConvert(tmpZero, varType);
for (int i = 0; i < otherLen; i++) {
varInit.push_back(dynamic_pointer_cast<Constant>(tmpInst));
}
auto zeroInit = ConstantZero::create(varType, module);
identAlloca = GlobalVariable::create(node.name, module, arrayType, false, zeroInit);
for (int i = 0; i < varInit.size(); i++) {
auto index = CONST_INT(i);
auto ptr = builder->create_gep(identAlloca, {CONST_INT(0), index});
builder->create_store(varInit[i], ptr);
}
//alter
//auto tmpInit = ConstantArray::create(static_pointer_cast<ArrayType>(varType), varInit);
//identAlloca = GlobalVariable::create(node.name, module, varType, false, tmpInit);
} else {
if (node.is_constant) {
node.initializers->expr->accept(*this);
TypeConvert(tmpInst, varType);
identAlloca = tmpInst;
} else {
node.initializers->expr->accept(*this);
TypeConvert(tmpInst, varType);
auto constInit = dynamic_pointer_cast<Constant>(tmpInst);
identAlloca = GlobalVariable::create(node.name, module, varType,
false, constInit);
}
}
}
scope.push(node.name, identAlloca);
} else {
if (node.is_constant && node.array_length.empty()) {
node.initializers->expr->accept(*this);
TypeConvert(tmpInst, varType);
identAlloca = tmpInst;
scope.push(node.name, identAlloca);
return ;
} else {
identAlloca = builder->create_alloca(varType);
scope.push(node.name, identAlloca);
if (node.array_length.empty()) {
node.initializers->expr->accept(*this);
TypeConvert(tmpInst, varType);
builder->create_store(tmpInst, identAlloca);
return ;
} else {
std::vector<Ptr<Constant>> varInit;
for (const auto &init : node.initializers->elementList) {
init->accept(*this);
TypeConvert(tmpInst, varType);
varInit.push_back(dynamic_pointer_cast<Constant>(tmpInst));
}
auto otherLen = arrayType->get_num_of_elements() - node.initializers->elementList.size();
auto tmpZero = CONST_INT(0);
TypeConvert(tmpZero, varType);
for (int i = 0; i < otherLen; i++) {
varInit.push_back(dynamic_pointer_cast<Constant>(tmpInst));
}
auto zeroInit = ConstantZero::create(varType, module);
identAlloca = GlobalVariable::create(node.name, module, arrayType, false, zeroInit);
for (int i = 0; i < varInit.size(); i++) {
auto index = CONST_INT(i);
auto ptr = builder->create_gep(identAlloca, {CONST_INT(0), index});
builder->create_store(varInit[i], ptr);
}
}
}
}
}
// FINISH
void IRBuilder::visit(SyntaxTree::LVal &node) {
auto ident = scope.find(node.name, false);
if (!node.array_index.empty()) {
node.array_index[0]->accept(*this);
auto constIndex = dynamic_pointer_cast<ConstantInt>(tmpInst);
auto globalIdent = dynamic_pointer_cast<GlobalVariable>(ident);
if(globalIdent != nullptr && globalIdent->is_const() && constIndex == nullptr) {
auto arrayInit = dynamic_pointer_cast<ConstantArray>(globalIdent->get_init());
tmpInst = arrayInit->get_element_value(constIndex->get_value());
} else {
tmpInst = builder->create_gep(ident, {CONST_INT(0), tmpInst});
}
}
else {
if (ident->get_type()->is_pointer_type() && ident->get_type()->get_pointer_element_type()->is_array_type()) {
tmpInst = builder->create_gep(ident, {CONST_INT(0), CONST_INT(0)});
} else {
tmpInst = ident;
}
}
return ;
}
// FINISH
void IRBuilder::visit(SyntaxTree::AssignStmt &node) {
node.target->accept(*this);
auto target = tmpInst;
node.value->accept(*this);
auto value = tmpInst;
TypeConvert(value, target->get_type());
value = tmpInst;
builder->create_store(value, target);
}
//FINISH
void IRBuilder::visit(SyntaxTree::Literal &node) {
switch(node.literal_type) {
case SyntaxTree::Type::INT:
tmpInst = CONST_INT(node.int_const);
break;
case SyntaxTree::Type::FLOAT:
tmpInst = CONST_FLOAT(node.float_const);
break;
default:
tmpInst = CONST_INT(0);
break;
}
}
// Finish
void IRBuilder::visit(SyntaxTree::ReturnStmt &node) {
if (node.ret) {
node.ret->accept(*this);
auto expectRetType =
builder->get_insert_block()->get_parent()->get_return_type();
TypeConvert(tmpInst, expectRetType);
auto retValue = tmpInst;
builder->create_store(retValue, retAlloca);
}
// every ret stmt only store the value and jump to the retBB
builder->create_br(retBB);
return ;
}
// Finish
void IRBuilder::visit(SyntaxTree::BlockStmt &node) {
scope.enter();
for (const auto &stmt : node.body) {
stmt->accept(*this);
}
scope.exit();
return ;
}
// FINISH
void IRBuilder::visit(SyntaxTree::EmptyStmt &node) {
return ;
}
// FINISH
void IRBuilder::visit(SyntaxTree::ExprStmt &node) {
node.exp->accept(*this);
return ;
}
// FINISH
void IRBuilder::visit(SyntaxTree::UnaryCondExpr &node) {
node.rhs->accept(*this);
TypeConvert(tmpInst, INT32_T);
auto constInt = dynamic_pointer_cast<ConstantInt>(tmpInst);
auto constFloat = dynamic_pointer_cast<ConstantInt>(tmpInst);
if (constInt == nullptr && constFloat == nullptr) {
tmpInst = builder->create_icmp_eq(tmpInst, CONST_INT(0));
} else {
tmpInst = CONST_INT((constInt->get_value() == 0 || constFloat->get_value() == 0 ) ? 1 : 0);
}
return ;
}
// FINISH
void IRBuilder::visit(SyntaxTree::BinaryCondExpr &node) {
auto curFunc = builder->get_insert_block()->get_parent();
auto trueBB = BasicBlock::create(module, "trueBB_and", curFunc);
auto falseBB = BasicBlock::create(module, "falseBB_and", curFunc);
Ptr<Instruction> cond;
switch (node.op) {
case SyntaxTree::BinaryCondOp::LAND:
node.lhs->accept(*this);
TypeConvert(tmpInst, INT1_T);
builder->create_cond_br(tmpInst, trueBB, falseBB);
// True - continue
builder->set_insert_point(trueBB);
node.rhs->accept(*this);
TypeConvert(tmpInst, INT1_T);
// False
builder->set_insert_point(falseBB);
TypeConvert(tmpInst, INT1_T);
break;
case SyntaxTree::BinaryCondOp::LOR:
node.lhs->accept(*this);
TypeConvert(tmpInst, INT1_T);
builder->create_cond_br(tmpInst, trueBB, falseBB);
// False - continue
builder->set_insert_point(falseBB);
node.rhs->accept(*this);
TypeConvert(tmpInst, INT1_T);
// True
builder->set_insert_point(trueBB);
TypeConvert(tmpInst, INT1_T);
break;
default:
node.lhs->accept(*this);
auto lhs = tmpInst;
node.rhs->accept(*this);
auto rhs = tmpInst;
BinaryCondExprGen(lhs, rhs, node.op);
}
}
// FINISH
void IRBuilder::visit(SyntaxTree::BinaryExpr &node) {
node.lhs->accept(*this);
auto lhs = tmpInst;
node.rhs->accept(*this);
auto rhs = tmpInst;
BinaryExprGen(lhs, rhs, node.op);
}
// FINISH
void IRBuilder::visit(SyntaxTree::UnaryExpr &node) {
node.rhs->accept(*this);
Ptr<ConstantInt> constInt;
Ptr<ConstantFloat> constFloat;
switch (node.op) {
case SyntaxTree::UnaryOp::PLUS:
break;
case SyntaxTree::UnaryOp::MINUS:
constInt = dynamic_pointer_cast<ConstantInt>(tmpInst);
constFloat = dynamic_pointer_cast<ConstantFloat>(tmpInst);
if (constInt != nullptr) {
tmpInst = CONST_INT(-constInt->get_value());
} else if (constFloat != nullptr) {
tmpInst = CONST_FLOAT(-constFloat->get_value());
} else {
BinaryExprGen(CONST_INT(0), tmpInst, SyntaxTree::BinOp::MINUS);
}
break;
default:
break;
}
}
// Finish
void IRBuilder::visit(SyntaxTree::FuncCallStmt &node) {
auto name = node.name;
auto funcIdent = dynamic_pointer_cast<Function>(scope.find(name, true));
std::vector<Ptr<Value>> funcRParam;
auto arg = funcIdent->arg_begin();
auto arg_end = funcIdent->arg_end();
for (const auto &param : node.params) {
if(arg == arg_end) {
break;
}
param->accept(*this);
TypeConvert(tmpInst, (*arg)->get_type());
funcRParam.push_back(tmpInst);
arg++;
}
tmpInst = builder->create_call(funcIdent, funcRParam);
}
// FINISH
void IRBuilder::visit(SyntaxTree::IfStmt &node) {
auto curFunc = builder->get_insert_block()->get_parent();
auto trueBB = BasicBlock::create(module, "trueBB_if", curFunc);
auto falseBB = BasicBlock::create(module, "falseBB_if", curFunc);
auto exitBB = node.else_statement == nullptr ? falseBB : BasicBlock::create(module, "exitBB_if", curFunc);
node.cond_exp->accept(*this);
TypeConvert(tmpInst, INT1_T);
builder->create_cond_br(tmpInst, trueBB, falseBB);
builder->set_insert_point(trueBB);
node.if_statement->accept(*this);
builder->create_br(exitBB);
if (node.else_statement) {
builder->set_insert_point(falseBB);
node.else_statement->accept(*this);
builder->create_br(exitBB);
}
if (!exitBB->get_pre_basic_blocks().empty()) {
builder->set_insert_point(exitBB);
}
}
//FINISH
void IRBuilder::visit(SyntaxTree::WhileStmt &node) {
auto curFunc = builder->get_insert_block()->get_parent();
auto condBB = BasicBlock::create(module, "condBB_while", curFunc);
auto bodyBB = BasicBlock::create(module, "bodyBB_while", curFunc);
auto afterBB = BasicBlock::create(module, "afterBB_while", curFunc);
auto tmpWhileBlock = curWhileBlock;
curWhileBlock = WhileBlock{condBB, bodyBB, afterBB};
builder->create_br(condBB);
builder->set_insert_point(condBB);
node.cond_exp->accept(*this);
TypeConvert(tmpInst, INT1_T);
builder->create_cond_br(tmpInst, bodyBB, afterBB);
builder->set_insert_point(bodyBB);
node.statement->accept(*this);
builder->create_br(condBB);
builder->set_insert_point(afterBB);
curWhileBlock = tmpWhileBlock;
return ;
}
//FINISH
void IRBuilder::visit(SyntaxTree::BreakStmt &node) {
builder->create_br(curWhileBlock.afterBB);
return ;
}
//FINISH
void IRBuilder::visit(SyntaxTree::ContinueStmt &node) {
builder->create_br(curWhileBlock.condBB);
return ;
}
}
}