|
|
|
@ -13,12 +13,32 @@ namespace IR
|
|
|
|
|
// to store state
|
|
|
|
|
|
|
|
|
|
// store temporary value
|
|
|
|
|
|
|
|
|
|
std::vector<Ptr<Type>> funcFParam;
|
|
|
|
|
|
|
|
|
|
struct WhileBlock {
|
|
|
|
|
BasicBlock *condBB;
|
|
|
|
|
BasicBlock *innerBB;
|
|
|
|
|
BasicBlock *exitBB;
|
|
|
|
|
};
|
|
|
|
|
auto curWhileBlock = WhileBlock{nullptr, nullptr, nullptr};
|
|
|
|
|
|
|
|
|
|
struct CondBlock {
|
|
|
|
|
BasicBlock *trueBB;
|
|
|
|
|
BasicBlock *falseBB;
|
|
|
|
|
};
|
|
|
|
|
auto curCondStruct = CondBlock{nullptr, nullptr};
|
|
|
|
|
|
|
|
|
|
Ptr<BasicBlock> retBB;
|
|
|
|
|
Ptr<Value> retAlloca;
|
|
|
|
|
|
|
|
|
|
Ptr<Value> tmpInst;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int tmpConstVal = 0;
|
|
|
|
|
Ptr<Value> tmpVal = nullptr;
|
|
|
|
|
std::vector<Ptr<Type>> funcFParam;
|
|
|
|
|
std::vector<Ptr<Value>> arrayInitializer;
|
|
|
|
|
std::string curFuncName = "";
|
|
|
|
|
Ptr<SysYF::IR::Instruction> tmpInst;
|
|
|
|
|
bool isFloat = false;
|
|
|
|
|
bool isAddr = false;
|
|
|
|
|
Ptr<BasicBlock> curCondBB;
|
|
|
|
@ -32,12 +52,12 @@ Ptr<Type> FLOAT_T;
|
|
|
|
|
Ptr<Type> INT32PTR_T;
|
|
|
|
|
Ptr<Type> FLOATPTR_T;
|
|
|
|
|
|
|
|
|
|
Ptr<Type> GetType(SyntaxTree::Type type){
|
|
|
|
|
Ptr<Type> GetBaseType(SyntaxTree::Type type){
|
|
|
|
|
switch(type){
|
|
|
|
|
case SyntaxTree::Type::INT:
|
|
|
|
|
return INT32_T;
|
|
|
|
|
case SyntaxTree::Type::FLOAT:
|
|
|
|
|
return INT1_T;
|
|
|
|
|
return FLOAT_T;
|
|
|
|
|
case SyntaxTree::Type::VOID:
|
|
|
|
|
return VOID_T;
|
|
|
|
|
default:
|
|
|
|
@ -45,6 +65,62 @@ Ptr<Type> GetType(SyntaxTree::Type type){
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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::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 == FLOAT_T) {
|
|
|
|
|
origin = builder->create_sitofp(origin, expected);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (type == FLOAT_T && expected == INT32_T) {
|
|
|
|
|
origin = 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);
|
|
|
|
@ -54,53 +130,86 @@ void IRBuilder::visit(SyntaxTree::Assembly &node) {
|
|
|
|
|
INT32PTR_T = Type::get_int32_ptr_type(module);
|
|
|
|
|
FLOATPTR_T = Type::get_float_ptr_type(module);
|
|
|
|
|
for (const auto &def : node.global_defs) {
|
|
|
|
|
//std::cout << "4" << std::endl;
|
|
|
|
|
def->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// You need to fill them
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
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(GetType(node.ret_type), funcFParam);
|
|
|
|
|
auto createFunc = Function::create(funcType, node.name, module);
|
|
|
|
|
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();
|
|
|
|
|
for (auto arg = func->arg_begin(); arg != func->arg_end() ; arg++) {
|
|
|
|
|
auto name = (*para)->name;
|
|
|
|
|
auto val = (*arg);
|
|
|
|
|
auto argAlloca = builder->create_alloca(val->get_type());
|
|
|
|
|
builder->create_store(val, 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) {
|
|
|
|
|
switch(node.param_type) {
|
|
|
|
|
case SyntaxTree::Type::INT:
|
|
|
|
|
if (!node.array_index.empty()) {
|
|
|
|
|
// TODO: high dim array
|
|
|
|
|
funcFParam.push_back(INT32PTR_T);
|
|
|
|
|
} else {
|
|
|
|
|
funcFParam.push_back(INT32_T);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SyntaxTree::Type::FLOAT:
|
|
|
|
|
if (!node.array_index.empty()) {
|
|
|
|
|
// TODO: high dim array (not now)
|
|
|
|
|
funcFParam.push_back(FLOATPTR_T);
|
|
|
|
|
} else {
|
|
|
|
|
funcFParam.push_back(FLOAT_T);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
funcFParam.push_back(INT32_T);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
auto tmpType = GetParamType(node.param_type, node.array_index[0] != nullptr);
|
|
|
|
|
funcFParam.push_back(tmpType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::VarDef &node) {
|
|
|
|
|
// TODO: high dim array (not now)
|
|
|
|
|
int arrayLength;
|
|
|
|
@ -233,43 +342,42 @@ void IRBuilder::visit(SyntaxTree::VarDef &node) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::LVal &node) {
|
|
|
|
|
auto ident = scope.find(node.name, false);
|
|
|
|
|
|
|
|
|
|
if (!node.array_index.empty()) {
|
|
|
|
|
//TODO: high dim array (not now)
|
|
|
|
|
node.array_index[0]->accept(*this);
|
|
|
|
|
auto index = tmpInst;
|
|
|
|
|
tmpInst = builder->create_gep(ident, {CONST_INT(0), index});
|
|
|
|
|
//TODO
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
tmpInst = dynamic_pointer_cast<Instruction>(ident);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
isAddr = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FINISH
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::AssignStmt &node) {
|
|
|
|
|
node.target->accept(*this);
|
|
|
|
|
auto target = tmpInst;
|
|
|
|
|
node.value->accept(*this);
|
|
|
|
|
Ptr<Value> value;
|
|
|
|
|
if (isAddr) {
|
|
|
|
|
value = builder->create_load(tmpInst);
|
|
|
|
|
isAddr = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
value = dynamic_pointer_cast<Value>(tmpInst);
|
|
|
|
|
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:
|
|
|
|
|
tmpVal = CONST_INT(node.int_const);
|
|
|
|
|
isFloat = false;
|
|
|
|
|
break;
|
|
|
|
|
case SyntaxTree::Type::FLOAT:
|
|
|
|
|
tmpVal = CONST_FLOAT(node.float_const);
|
|
|
|
|
isFloat = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
tmpVal = CONST_INT(0);
|
|
|
|
@ -277,44 +385,60 @@ void IRBuilder::visit(SyntaxTree::Literal &node) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Finish
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::ReturnStmt &node) {
|
|
|
|
|
node.ret->accept(*this);
|
|
|
|
|
builder->create_ret(tmpVal);
|
|
|
|
|
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);
|
|
|
|
|
if (builder->get_insert_block()->get_terminator() != nullptr)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
switch (node.op) {
|
|
|
|
|
case SyntaxTree::UnaryCondOp::NOT:
|
|
|
|
|
if (isFloat) {
|
|
|
|
|
tmpInst = builder->create_fcmp_eq(tmpInst, CONST_FLOAT(0.0));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
tmpInst = builder->create_icmp_eq(tmpInst, CONST_INT(0));
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
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 ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BinaryCondExpr &node) {
|
|
|
|
|
auto curFunc = builder->get_insert_block()->get_parent();
|
|
|
|
|
auto trueBB = BasicBlock::create(module, "trueBB_and", curFunc);
|
|
|
|
@ -412,6 +536,7 @@ void IRBuilder::visit(SyntaxTree::BinaryCondExpr &node) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BinaryExpr &node) {
|
|
|
|
|
node.lhs->accept(*this);
|
|
|
|
|
auto lhs = tmpInst;
|
|
|
|
@ -465,6 +590,7 @@ void IRBuilder::visit(SyntaxTree::BinaryExpr &node) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::UnaryExpr &node) {
|
|
|
|
|
node.rhs->accept(*this);
|
|
|
|
|
switch (node.op) {
|
|
|
|
@ -482,6 +608,7 @@ void IRBuilder::visit(SyntaxTree::UnaryExpr &node) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::FuncCallStmt &node) {
|
|
|
|
|
auto curFunc = builder->get_insert_block()->get_parent();
|
|
|
|
|
std::vector<Ptr<Value>> funcRParam;
|
|
|
|
@ -492,6 +619,7 @@ void IRBuilder::visit(SyntaxTree::FuncCallStmt &node) {
|
|
|
|
|
builder->create_call(curFunc, funcRParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::IfStmt &node) {
|
|
|
|
|
auto curFunc = builder->get_insert_block()->get_parent();
|
|
|
|
|
node.cond_exp->accept(*this);
|
|
|
|
@ -505,6 +633,7 @@ void IRBuilder::visit(SyntaxTree::IfStmt &node) {
|
|
|
|
|
node.else_statement->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::WhileStmt &node) {
|
|
|
|
|
auto curFunc = builder->get_insert_block()->get_parent();
|
|
|
|
|
auto condBB = BasicBlock::create(module, "condBB_while", curFunc);
|
|
|
|
@ -530,11 +659,13 @@ void IRBuilder::visit(SyntaxTree::WhileStmt &node) {
|
|
|
|
|
return ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::BreakStmt &node) {
|
|
|
|
|
builder->create_br(curAfterBB);
|
|
|
|
|
return ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
void IRBuilder::visit(SyntaxTree::ContinueStmt &node) {
|
|
|
|
|
builder->create_br(curCondBB);
|
|
|
|
|
return ;
|
|
|
|
|