#include #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> funcFParam; struct WhileBlock { Ptr condBB; Ptr bodyBB; Ptr afterBB; }; auto curWhileBlock = WhileBlock{nullptr, nullptr, nullptr}; Ptr retBB; Ptr retAlloca; Ptr tmpInst; // types Ptr VOID_T; Ptr INT1_T; Ptr INT32_T; Ptr FLOAT_T; Ptr INT32PTR_T; Ptr FLOATPTR_T; Ptr 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 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 lhs, Ptr rhs, SyntaxTree::BinOp op){ bool isFloat = false; int lInt, rInt; float lFloat, rFloat; if (dynamic_pointer_cast(lhs) && dynamic_pointer_cast(rhs)) { if (dynamic_pointer_cast(lhs) || dynamic_pointer_cast(rhs)) { isFloat = true; lFloat = dynamic_pointer_cast(lhs)->get_value(); rFloat = dynamic_pointer_cast(rhs)->get_value(); } else { isFloat = false; lInt = dynamic_pointer_cast(lhs)->get_value(); rInt = dynamic_pointer_cast(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 lhs, Ptr rhs, SyntaxTree::BinaryCondOp op) { bool isFloat = false; int lInt, rInt; float lFloat, rFloat; if (dynamic_pointer_cast(lhs) && dynamic_pointer_cast(rhs)) { if (dynamic_pointer_cast(lhs) || dynamic_pointer_cast(rhs)) { isFloat = true; lFloat = dynamic_pointer_cast(lhs)->get_value(); rFloat = dynamic_pointer_cast(rhs)->get_value(); } else { isFloat = false; lInt = dynamic_pointer_cast(lhs)->get_value(); rInt = dynamic_pointer_cast(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 origin, Ptr expected) { if (dynamic_pointer_cast(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(origin); auto tmpFloat = dynamic_pointer_cast(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(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; if (!node.array_length.empty()) { node.array_length[0]->accept(*this); auto constInt = dynamic_pointer_cast(tmpInst); arrayType = ArrayType::create(varType, constInt->get_value()); } Ptr 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> varInit; for (const auto &init : node.initializers->elementList) { init->accept(*this); TypeConvert(tmpInst, varType); varInit.push_back(dynamic_pointer_cast(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(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(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(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> varInit; for (const auto &init : node.initializers->elementList) { init->accept(*this); TypeConvert(tmpInst, varType); varInit.push_back(dynamic_pointer_cast(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(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(tmpInst); auto globalIdent = dynamic_pointer_cast(ident); if(globalIdent != nullptr && globalIdent->is_const() && constIndex == nullptr) { auto arrayInit = dynamic_pointer_cast(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(tmpInst); auto constFloat = dynamic_pointer_cast(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 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 constInt; Ptr constFloat; switch (node.op) { case SyntaxTree::UnaryOp::PLUS: break; case SyntaxTree::UnaryOp::MINUS: constInt = dynamic_pointer_cast(tmpInst); constFloat = dynamic_pointer_cast(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(scope.find(name, true)); std::vector> 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 ; } } }