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
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 ¶ : 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 ¶m : 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 ;
|
|
}
|
|
}
|
|
} |