diff --git a/codegen/CMakeLists.txt b/codegen/CMakeLists.txt index 255b69c..6bbf80b 100644 --- a/codegen/CMakeLists.txt +++ b/codegen/CMakeLists.txt @@ -1,6 +1,19 @@ add_library(scarCodegen STATIC codegen.cc codegen.hh + common.hh + + scargen/scar.cc + scargen/scar_statement.cc + scargen/scar_factor.cc + scargen/scar_expression.cc + scargen/scar_declaration.cc + scargen/scar_block.cc + scargen/pretty_print.cc + + scasmgen/scasm_generation.cc + scasmgen/fix_pseudo_registers.cc + scasmgen/fix_instructions.cc ) set_basic_compile_options(scarCodegen) diff --git a/codegen/codegen.cc b/codegen/codegen.cc index 6fbe234..ade9ca3 100644 --- a/codegen/codegen.cc +++ b/codegen/codegen.cc @@ -1,1504 +1,8 @@ #include "codegen.hh" -#define MAKE_SHARED(a, b) std::shared_ptr b = std::make_shared() namespace scarlet { namespace codegen { -#define UNREACHABLE() \ - std::cout << "Unreachable code reached in " << __FILE__ << " at line " \ - << __LINE__ << std::endl; \ - __builtin_unreachable(); - -void Codegen::gen_scar_factor( - std::shared_ptr factor, - std::shared_ptr scar_function) { - // firstly put all the unops (if they exist) in the unop buffer - for (auto it : factor->get_unop_nodes()) { - unop_buffer[curr_buff].emplace_back(it->get_op()); - } - // if exp exists, parse that. If exp is null, it will simply return - if (factor->get_exp_node() != nullptr) { - curr_buff++; - if (curr_buff >= (int)unop_buffer.size()) - unop_buffer.resize(curr_buff + 1); - gen_scar_exp(factor->get_exp_node(), scar_function); - curr_buff--; - } - // If we have an integer node and unops to operate on, proceed... - if (!unop_buffer[curr_buff].empty()) { - int num_unpos = unop_buffer[curr_buff].size(); - for (int i = num_unpos - 1; i >= 0; i--) { - // SPECIAL CASE WHEN WE HAVE INCREMENT OR DECREMENT OPERATOR - unop::UNOP op = unop_buffer[curr_buff][i]; - if (op == unop::UNOP::PREINCREMENT or op == unop::UNOP::PREDECREMENT) { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::BINARY); - if (op == unop::UNOP::PREINCREMENT) { - scar_instruction->set_binop(binop::BINOP::ADD); - } else { - scar_instruction->set_binop(binop::BINOP::SUB); - } - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - - scar_val_dst->set_type(scar::val_type::VAR); - // The destination will always be a variable - if (!variable_buffer.empty()) { - scar_val_dst->set_reg_name(variable_buffer); - variable_buffer.clear(); - } else { - scar_val_dst->set_reg_name( - factor->get_identifier_node()->get_value()); - } - - reg_name = scar_val_dst->get_reg(); - scar_instruction->set_dst(std::move(scar_val_dst)); - - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name(reg_name); - scar_instruction->set_src1(std::move(scar_val_src)); - - scar_val_src2->set_type(scar::val_type::CONSTANT); - scar_val_src2->set_value("1"); - scar_instruction->set_src2(std::move(scar_val_src2)); - - scar_function->add_instruction(std::move(scar_instruction)); - continue; - } else if (op == unop::UNOP::POSTINCREMENT or - op == unop::UNOP::POSTDECREMENT) { - // SPECIAL CASE WHEN WE HAVE POST INCREMENT OR DECREMENT - // Since these return the original value and then increment or decrement - // We first make a copy of the original value and then increment or - // decrement - - // COPY THE ORIGINAL VALUE INTO A NEW SCAR REGISTER - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::COPY); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_src->set_type(scar::val_type::VAR); - if (!variable_buffer.empty()) { - scar_val_src->set_reg_name(variable_buffer); - variable_buffer.clear(); - } else { - scar_val_src->set_reg_name( - factor->get_identifier_node()->get_value()); - } - std::string _variable = scar_val_src->get_reg(); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_val_dst->set_type(scar::val_type::VAR); - scar_val_dst->set_reg_name(get_reg_name()); - scar_instruction->set_dst(std::move(scar_val_dst)); - scar_function->add_instruction(std::move(scar_instruction)); - - // NOW DO THE BINARY OPERATION - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::BINARY); - if (op == unop::UNOP::POSTINCREMENT) { - scar_instruction2->set_binop(binop::BINOP::ADD); - } else { - scar_instruction2->set_binop(binop::BINOP::SUB); - } - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - - scar_val_src2->set_type(scar::val_type::VAR); - scar_val_src2->set_reg_name(_variable); - scar_instruction2->set_src1(std::move(scar_val_src2)); - - scar_val_src3->set_type(scar::val_type::CONSTANT); - scar_val_src3->set_value("1"); - scar_instruction2->set_src2(std::move(scar_val_src3)); - - scar_val_dst2->set_type(scar::val_type::VAR); - scar_val_dst2->set_reg_name(_variable); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - - scar_function->add_instruction(std::move(scar_instruction2)); - continue; - } - // scar::scar_Instruction_Node scar_instruction; - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::UNARY); - scar_instruction->set_unop(op); - - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - - // deal with the source - if (i == num_unpos - 1) { - if (factor->get_int_node() != nullptr and - !factor->get_int_node()->get_value().empty()) { - scar_val_src->set_type(scar::val_type::CONSTANT); - scar_val_src->set_value(factor->get_int_node()->get_value()); - } else if (factor->get_identifier_node() != nullptr and - !factor->get_identifier_node()->get_value().empty()) { - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name( - factor->get_identifier_node()->get_value()); - } else if (!constant_buffer.empty()) { - scar_val_src->set_type(scar::val_type::CONSTANT); - scar_val_src->set_value(constant_buffer); - constant_buffer.clear(); - } else if (!variable_buffer.empty()) { - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name(variable_buffer); - variable_buffer.clear(); - } else { - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name(get_prev_reg_name()); - } - } else { - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name(get_prev_reg_name()); - } - scar_instruction->set_src1(std::move(scar_val_src)); - - // deal with the destination - scar_val_dst->set_type(scar::val_type::VAR); - scar_val_dst->set_reg_name(get_reg_name()); - scar_instruction->set_dst(std::move(scar_val_dst)); - - scar_function->add_instruction(std::move(scar_instruction)); - } - // empty the unop buffer - unop_buffer[curr_buff].clear(); - } else { - // NOTE: It is guaranteed that the factor node will have either an int node - // or an identifier node - - // save constant for later use - if (factor->get_int_node() != nullptr and - !factor->get_int_node()->get_value().empty()) { - constant_buffer = factor->get_int_node()->get_value(); - } - - // save variable for later use - if (factor->get_identifier_node() != nullptr and - !factor->get_identifier_node()->get_value().empty()) { - variable_buffer = factor->get_identifier_node()->get_value(); - } - } -} - -#define SETVARCONSTANTREG(src) \ - if (!variable_buffer.empty()) { \ - src->set_type(scar::val_type::VAR); \ - src->set_reg_name(variable_buffer); \ - variable_buffer.clear(); \ - } else if (!constant_buffer.empty()) { \ - src->set_type(scar::val_type::CONSTANT); \ - src->set_value(constant_buffer); \ - constant_buffer.clear(); \ - } else { \ - src->set_type(scar::val_type::VAR); \ - src->set_reg_name(get_prev_reg_name()); \ - } - -#define SETUPLANDLOR(num) \ - if (exp->get_binop_node()->get_op() == binop::BINOP::LAND) { \ - /* Logical and */ \ - scar_instruction##num->set_type(scar::instruction_type::JUMP_IF_ZERO); \ - } else { \ - /* Logical or */ \ - scar_instruction##num->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); \ - } \ - \ - if (exp->get_left() == nullptr) { \ - if (num == 1) \ - gen_scar_factor(exp->get_factor_node(), scar_function); \ - SETVARCONSTANTREG(scar_val_src##num); \ - } else { \ - scar_val_src##num->set_type(scar::val_type::VAR); \ - scar_val_src##num->set_reg_name(get_prev_reg_name()); \ - } \ - \ - scar_instruction##num->set_src1(std::move(scar_val_src##num)); \ - scar_val_dst##num->set_type(scar::val_type::UNKNOWN); - -void Codegen::gen_scar_exp( - std::shared_ptr exp, - std::shared_ptr scar_function) { - if (exp == nullptr) - return; - gen_scar_exp(exp->get_left(), scar_function); - if (exp->get_binop_node() != nullptr and - exp->get_binop_node()->get_op() != binop::BINOP::UNKNOWN) { - // when we have a binary operator - // deal with && and || separately using jmpif(not)zero, labels and copy - // operations since we need to apply short circuit for them - // - // There will be a separate case for the assignment operator as that - // will be represented by a simple copy operation - // - // There will be a separate case for the ternary operator as well - // So first we need to check whether it is the first expression - // or the second expression that will be returned using jmpifzero - // and copy the result to a new register. Ternary is actually a special - // case of short circuiting - if (exp->get_binop_node()->get_op() == binop::BINOP::ASSIGN) { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::COPY); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - // the semantic analyis phase should have ensured that the left child - // is null, factor is an identifier with no unops and the right child - // is an expression - gen_scar_exp(exp->get_right(), scar_function); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(std::move(scar_val_src)); - - scar_val_dst->set_type(scar::val_type::VAR); - scar_val_dst->set_reg_name( - exp->get_factor_node()->get_identifier_node()->get_value()); - // NOTE: we update the current scar register name to use the variable - // since we can have expressions like: - // int b = a = 5; - reg_name = scar_val_dst->get_reg(); - scar_instruction->set_dst(std::move(scar_val_dst)); - - scar_function->add_instruction(std::move(scar_instruction)); - return; - } - bool short_circuit = binop::short_circuit(exp->get_binop_node()->get_op()); - binop::BINOP sc_binop = exp->get_binop_node()->get_op(); - const binop::BINOP compound_binop = sc_binop; - if (binop::is_compound(compound_binop)) { - sc_binop = compound_to_base[compound_binop]; - } - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - if (short_circuit) { - if (sc_binop == binop::BINOP::LAND) { - scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); - } else if (sc_binop == binop::BINOP::LOR) { - scar_instruction->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); - } else if (sc_binop == binop::BINOP::TERNARY) { - scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); - } - } else { - scar_instruction->set_type(scar::instruction_type::BINARY); - scar_instruction->set_binop(sc_binop); - } - MAKE_SHARED(scar::scar_Val_Node, scar_val_src1); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - - if (exp->get_left() == nullptr) { - gen_scar_factor(exp->get_factor_node(), scar_function); - SETVARCONSTANTREG(scar_val_src1); - } else { - scar_val_src1->set_type(scar::val_type::VAR); - scar_val_src1->set_reg_name(get_prev_reg_name()); - } - - scar_instruction->set_src1(std::move(scar_val_src1)); - - if (short_circuit) { - // create a label to jump to - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst1); - scar_val_dst1->set_type(scar::val_type::UNKNOWN); - scar_val_dst1->set_value(get_fr_label_name()); - scar_instruction->set_dst(std::move(scar_val_dst1)); - scar_function->add_instruction(std::move(scar_instruction)); - } - - // TERNARY SPECIAL CASE - if (sc_binop == binop::BINOP::TERNARY) { - // generate the first expression - gen_scar_exp(exp->get_middle(), scar_function); - - // copy this result in a new register - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_instruction2->set_type(scar::instruction_type::COPY); - SETVARCONSTANTREG(scar_val_src2); - scar_instruction2->set_src1(std::move(scar_val_src2)); - scar_val_dst2->set_type(scar::val_type::VAR); - // Doing this so that we can use the same scar register to - // store the result of the second expression as well. - // We cannot simply use get_prev_reg_name() since we need to - // parse the second expression first and that will change the - // register counter - std::string result = get_reg_name(); - scar_val_dst2->set_reg_name(result); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(std::move(scar_instruction2)); - - // jump to the end - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_instruction3->set_type(scar::instruction_type::JUMP); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value(get_res_label_name()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(std::move(scar_instruction3)); - - // generate the intermediate label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_instruction4->set_type(scar::instruction_type::LABEL); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value(get_last_fr_label_name(true)); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(std::move(scar_instruction4)); - - // generate the second expression - gen_scar_exp(exp->get_right(), scar_function); - - // copy this result in a new register - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst5); - scar_instruction5->set_type(scar::instruction_type::COPY); - SETVARCONSTANTREG(scar_val_src5); - scar_instruction5->set_src1(std::move(scar_val_src5)); - scar_val_dst5->set_type(scar::val_type::VAR); - scar_val_dst5->set_reg_name(result); - scar_instruction5->set_dst(std::move(scar_val_dst5)); - scar_function->add_instruction(std::move(scar_instruction5)); - - // generate the final label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction6); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src6); - scar_instruction6->set_type(scar::instruction_type::LABEL); - scar_val_src6->set_type(scar::val_type::UNKNOWN); - scar_val_src6->set_value(get_last_res_label_name()); - scar_instruction6->set_src1(std::move(scar_val_src6)); - scar_function->add_instruction(std::move(scar_instruction6)); - - // early return - return; - } - gen_scar_exp(exp->get_right(), scar_function); - SETVARCONSTANTREG(scar_val_src2); - - if (short_circuit) { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - if (sc_binop == binop::BINOP::LAND) { - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); - } else { - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); - } - scar_instruction2->set_src1(std::move(scar_val_src2)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_val_dst2->set_type(scar::val_type::UNKNOWN); - scar_val_dst2->set_value(get_last_fr_label_name()); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(std::move(scar_instruction2)); - - // now copy 1(LAND) / 0(LOR) into a scar register - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst3); - scar_instruction3->set_type(scar::instruction_type::COPY); - scar_val_src3->set_type(scar::val_type::CONSTANT); - if (sc_binop == binop::BINOP::LAND) { - scar_val_src3->set_value(std::to_string(1)); - } else { - scar_val_src3->set_value(std::to_string(0)); - } - scar_val_dst3->set_type(scar::val_type::VAR); - scar_val_dst3->set_reg_name(get_reg_name()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_instruction3->set_dst(std::move(scar_val_dst3)); - scar_function->add_instruction(std::move(scar_instruction3)); - - // now jump to the end - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_instruction4->set_type(scar::instruction_type::JUMP); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value(get_res_label_name()); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(std::move(scar_instruction4)); - - // Now generate the intermediate label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); - scar_instruction5->set_type(scar::instruction_type::LABEL); - scar_val_src5->set_type(scar::val_type::UNKNOWN); - scar_val_src5->set_value(get_last_fr_label_name(true)); - scar_instruction5->set_src1(std::move(scar_val_src5)); - scar_function->add_instruction(std::move(scar_instruction5)); - - // now copy 0(LAND) / 1(LOR) into a scar register - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction6); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src6); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst6); - scar_instruction6->set_type(scar::instruction_type::COPY); - scar_val_src6->set_type(scar::val_type::CONSTANT); - if (sc_binop == binop::BINOP::LAND) { - scar_val_src6->set_value(std::to_string(0)); - } else { - scar_val_src6->set_value(std::to_string(1)); - } - scar_val_dst6->set_type(scar::val_type::VAR); - scar_val_dst6->set_reg_name(get_prev_reg_name()); - scar_instruction6->set_src1(std::move(scar_val_src6)); - scar_instruction6->set_dst(std::move(scar_val_dst6)); - scar_function->add_instruction(std::move(scar_instruction6)); - - // now generate the final label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction7); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src7); - scar_instruction7->set_type(scar::instruction_type::LABEL); - scar_val_src7->set_type(scar::val_type::UNKNOWN); - scar_val_src7->set_value(get_last_res_label_name()); - scar_instruction7->set_src1(std::move(scar_val_src7)); - scar_function->add_instruction(std::move(scar_instruction7)); - } else { - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_dst->set_type(scar::val_type::VAR); - if (binop::is_compound(compound_binop)) { - scar_val_dst->set_reg_name( - exp->get_factor_node()->get_identifier_node()->get_value()); - reg_name = scar_val_dst->get_reg(); - } else { - scar_val_dst->set_reg_name(get_reg_name()); - } - scar_instruction->set_src2(std::move(scar_val_src2)); - scar_instruction->set_dst(std::move(scar_val_dst)); - - scar_function->add_instruction(std::move(scar_instruction)); - } - } else { - // When we do not have a binary operator, so only parse the factor node - gen_scar_factor(exp->get_factor_node(), scar_function); - } -} - -void Codegen::gen_scar_statement( - std::shared_ptr statement, - std::shared_ptr scar_function) { - switch (statement->get_type()) { - case ast::statementType::NULLSTMT: - break; - case ast::statementType::RETURN: { - gen_scar_exp(statement->get_exps(), scar_function); - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::RETURN); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(scar_val_src); - scar_function->add_instruction(scar_instruction); - } break; - case ast::statementType::EXP: { - gen_scar_exp(statement->get_exps(), scar_function); - } break; - case ast::statementType::IF: { - // (stored in exps) - // c = - // JumpIfZero(c, end) - // (handled in the next iteration) - // Label(end) (Added during the end of if statement) - auto if_statement = - std::static_pointer_cast(statement); - gen_scar_exp(if_statement->get_exps(), scar_function); - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(std::move(scar_val_src)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_dst->set_type(scar::val_type::UNKNOWN); - scar_val_dst->set_value(if_statement->get_labels().first->get_value()); - scar_instruction->set_dst(std::move(scar_val_dst)); - scar_function->add_instruction(std::move(scar_instruction)); - - // generate scar for the statement - gen_scar_statement(if_statement->get_stmt1(), scar_function); - - // generate the end label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - scar_val_src2->set_type(scar::val_type::UNKNOWN); - scar_val_src2->set_value(if_statement->get_labels().first->get_value()); - scar_instruction2->set_src1(std::move(scar_val_src2)); - scar_function->add_instruction(std::move(scar_instruction2)); - } break; - case ast::statementType::IFELSE: { - // - // c = - // JumpIfZero(c, else_label) - // - // Jump(end) - // Label(else_label) - // - // Label(end) - - auto if_else_statement = - std::static_pointer_cast(statement); - gen_scar_exp(if_else_statement->get_exps(), scar_function); - - // Jump if zero to else statement - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(std::move(scar_val_src)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_dst->set_type(scar::val_type::UNKNOWN); - scar_val_dst->set_value(if_else_statement->get_labels().first->get_value()); - scar_instruction->set_dst(std::move(scar_val_dst)); - scar_function->add_instruction(std::move(scar_instruction)); - - // generate scar for the if statement - gen_scar_statement(if_else_statement->get_stmt1(), scar_function); - - // jump to the end - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::JUMP); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - scar_val_src2->set_type(scar::val_type::UNKNOWN); - scar_val_src2->set_value( - if_else_statement->get_labels().second->get_value()); - scar_instruction2->set_src1(std::move(scar_val_src2)); - scar_function->add_instruction(std::move(scar_instruction2)); - - // generate the else label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - scar_instruction3->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value( - if_else_statement->get_labels().first->get_value()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(std::move(scar_instruction3)); - - // generate scar for the else statement - gen_scar_statement(if_else_statement->get_stmt2(), scar_function); - - // generate the end label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - scar_instruction4->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value( - if_else_statement->get_labels().second->get_value()); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(std::move(scar_instruction4)); - } break; - - case ast::statementType::GOTO: - case ast::statementType::BREAK: - case ast::statementType::CONTINUE: { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::JUMP); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(statement->get_labels().first->get_value()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - } break; - - case ast::statementType::LABEL: { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(statement->get_labels().first->get_value()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - } break; - - case ast::statementType::BLOCK: { - auto block_statement = - std::static_pointer_cast(statement); - gen_scar_block(block_statement->get_block(), scar_function); - } break; - - case ast::statementType::WHILE: { - auto while_statement = - std::static_pointer_cast(statement); - - // Label(start) - // - // c = - // JumpIfZero(c, end) - // - // Jump(start) - // Label(end) - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(while_statement->get_labels().first->get_value()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - - gen_scar_exp(while_statement->get_exps(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - SETVARCONSTANTREG(scar_val_src2); - scar_instruction2->set_src1(std::move(scar_val_src2)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_val_dst2->set_type(scar::val_type::UNKNOWN); - scar_val_dst2->set_value(while_statement->get_labels().second->get_value()); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(scar_instruction2); - - gen_scar_statement(while_statement->get_stmt(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - scar_instruction3->set_type(scar::instruction_type::JUMP); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value(while_statement->get_labels().first->get_value()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(scar_instruction3); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - scar_instruction4->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value(while_statement->get_labels().second->get_value()); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(scar_instruction4); - } break; - - case ast::statementType::DO_WHILE: { - auto do_while_statement = - std::static_pointer_cast(statement); - - // Label(start) - // - // Label(continue) - // - // c = - // JumpIfNotZero(c, start) - // Label(end) - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(do_while_statement->get_start_label()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - - gen_scar_statement(do_while_statement->get_stmt(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction1); - scar_instruction1->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src1); - scar_val_src1->set_type(scar::val_type::UNKNOWN); - scar_val_src1->set_value( - do_while_statement->get_labels().first->get_value()); - scar_instruction1->set_src1(std::move(scar_val_src1)); - scar_function->add_instruction(scar_instruction1); - - gen_scar_exp(do_while_statement->get_exps(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - SETVARCONSTANTREG(scar_val_src2); - scar_instruction2->set_src1(std::move(scar_val_src2)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_val_dst2->set_type(scar::val_type::UNKNOWN); - scar_val_dst2->set_value(do_while_statement->get_start_label()); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(scar_instruction2); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - scar_instruction3->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value( - do_while_statement->get_labels().second->get_value()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(scar_instruction3); - } break; - - case ast::statementType::FOR: { - auto for_statement = - std::static_pointer_cast(statement); - - // - // Label(Forstart) - // - // c = - // JumpIfZero(c, end) - // - // Label(continue) - // - // Jump(Forstart) - // Label(end) - - if (for_statement->get_for_init() != nullptr) { - if (for_statement->get_for_init()->get_declaration() != nullptr) { - gen_scar_declaration(for_statement->get_for_init()->get_declaration(), - scar_function); - } else { - gen_scar_exp(for_statement->get_for_init()->get_exp(), scar_function); - } - } - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(for_statement->get_start_label()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - - gen_scar_exp(for_statement->get_exps(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - SETVARCONSTANTREG(scar_val_src2); - scar_instruction2->set_src1(std::move(scar_val_src2)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_val_dst2->set_type(scar::val_type::UNKNOWN); - scar_val_dst2->set_value(for_statement->get_labels().second->get_value()); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(scar_instruction2); - - gen_scar_statement(for_statement->get_stmt(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - scar_instruction3->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value(for_statement->get_labels().first->get_value()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(scar_instruction3); - - gen_scar_exp(for_statement->get_exp2(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - scar_instruction4->set_type(scar::instruction_type::JUMP); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value(for_statement->get_start_label()); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(scar_instruction4); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); - scar_instruction5->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); - scar_val_src5->set_type(scar::val_type::UNKNOWN); - scar_val_src5->set_value(for_statement->get_labels().second->get_value()); - scar_instruction5->set_src1(std::move(scar_val_src5)); - scar_function->add_instruction(scar_instruction5); - } break; - case ast::statementType::UNKNOWN: - UNREACHABLE() - } -} -void Codegen::gen_scar_declaration( - std::shared_ptr declaration, - std::shared_ptr scar_function) { - // if there is no definition, we ignore it - if (declaration->get_exp() != nullptr) { - gen_scar_exp(declaration->get_exp(), scar_function); - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::COPY); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_dst->set_type(scar::val_type::VAR); - scar_val_dst->set_reg_name(declaration->get_identifier()->get_value()); - scar_instruction->set_dst(scar_val_dst); - scar_function->add_instruction(scar_instruction); - } -} - -void Codegen::gen_scar_block( - std::shared_ptr block, - std::shared_ptr scar_function) { - for (auto inst : block->get_blockItems()) { - switch (inst->get_type()) { - case ast::BlockItemType::STATEMENT: - gen_scar_statement(inst->get_statement(), scar_function); - break; - case ast::BlockItemType::DECLARATION: - gen_scar_declaration(inst->get_declaration(), scar_function); - break; - case ast::BlockItemType::UNKNOWN: - UNREACHABLE() - } - } -} - -void Codegen::gen_scar() { - scar::scar_Program_Node scar_program; - for (auto it : program.get_functions()) { - MAKE_SHARED(scar::scar_Function_Node, scar_function); - MAKE_SHARED(scar::scar_Identifier_Node, identifier); - identifier->set_value(it->get_identifier()->get_value()); - scar_function->set_identifier(identifier); - - gen_scar_block(it->get_block(), scar_function); - - // Add a complementary return 0 at the end of the function - // in case there is no return statement - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::RETURN); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::CONSTANT); - scar_val_src->set_value("0"); - scar_instruction->set_src1(scar_val_src); - scar_function->add_instruction(scar_instruction); - - scar_program.add_function(scar_function); - } - - this->scar = scar_program; -} - -void Codegen::pretty_print() { - std::cout << "Program(" << std::endl; - for (auto function : scar.get_functions()) { - std::cout << "\tFunction(" << std::endl; - std::cout << "\t\tname=\"" << function->get_identifier()->get_value() - << "\"," << std::endl; - std::cout << "\t\tbody=[" << std::endl; - for (auto statement : function->get_instructions()) { - std::cout << "\t\t\t" << to_string(statement->get_type()) << "("; - if (statement->get_type() == scar::instruction_type::RETURN) { - if (statement->get_src1()->get_type() == scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } else if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } - std::cout << ")" << std::endl; - } else if (statement->get_type() == scar::instruction_type::UNARY) { - std::cout << unop::to_string(statement->get_unop()) << ", "; - if (statement->get_src1()->get_type() == scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } else if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } - std::cout << ", "; - if (statement->get_dst()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; - } else if (statement->get_dst()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_dst()->get_value() << ")"; - } - std::cout << ")" << std::endl; - } else if (statement->get_type() == scar::instruction_type::BINARY) { - std::cout << binop::to_string(statement->get_binop()) << ", "; - if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } else if (statement->get_src1()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } - std::cout << ", "; - if (statement->get_src2()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src2()->get_reg() << ")"; - } else if (statement->get_src2()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src2()->get_value() << ")"; - } - std::cout << ", "; - if (statement->get_dst()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; - } else if (statement->get_dst()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_dst()->get_value() << ")"; - } - std::cout << ")" << std::endl; - } else if (statement->get_type() == scar::instruction_type::COPY) { - if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } else if (statement->get_src1()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } - std::cout << " ,"; - if (statement->get_dst()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; - } - std::cout << ")" << std::endl; - } else if (statement->get_type() == scar::instruction_type::JUMP or - statement->get_type() == scar::instruction_type::LABEL) { - std::cout << statement->get_src1()->get_value() << ")" << std::endl; - } else if (statement->get_type() == - scar::instruction_type::JUMP_IF_ZERO or - statement->get_type() == - scar::instruction_type::JUMP_IF_NOT_ZERO) { - if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } else if (statement->get_src1()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } - std::cout << ", "; - std::cout << statement->get_dst()->get_value() << ")" << std::endl; - } - } - std::cout << "\t\t]" << std::endl; - std::cout << "\t)," << std::endl; - } - std::cout << ")" << std::endl; -} - -#define SET_MOV_SOURCE() \ - switch (inst->get_src1()->get_type()) { \ - case scar::val_type::VAR: \ - scasm_src->set_type(scasm::operand_type::PSEUDO); \ - scasm_src->set_identifier_stack(inst->get_src1()->get_reg()); \ - break; \ - case scar::val_type::CONSTANT: \ - scasm_src->set_type(scasm::operand_type::IMM); \ - scasm_src->set_imm(stoi(inst->get_src1()->get_value())); \ - break; \ - default: \ - break; \ - } \ - scasm_inst->set_src(std::move(scasm_src)) - -#define SET_DST(dst) \ - switch (inst->get_dst()->get_type()) { \ - case scar::val_type::VAR: \ - dst->set_type(scasm::operand_type::PSEUDO); \ - dst->set_identifier_stack(inst->get_dst()->get_reg()); \ - break; \ - default: \ - break; \ - } - -void Codegen::gen_scasm() { - scasm::scasm_program scasm_program{}; - for (auto func : scar.get_functions()) { - MAKE_SHARED(scasm::scasm_function, scasm_func); - scasm_func->set_name(func->get_identifier()->get_value()); - for (auto inst : func->get_instructions()) { - if (inst->get_type() == scar::instruction_type::RETURN) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - scasm_dst->set_type(scasm::operand_type::REG); - scasm_dst->set_reg(scasm::register_type::AX); - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::RET); - scasm_func->add_instruction(std::move(scasm_inst2)); - - } else if (inst->get_type() == scar::instruction_type::UNARY) { - if (inst->get_unop() == unop::UNOP::NOT) { - // Cmp(Imm(0), src) - // Mov(Imm(0), dst) - // SetCC(E, dst) - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::CMP); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - scasm_src->set_type(scasm::operand_type::IMM); - scasm_src->set_imm(0); - scasm_inst->set_src(std::move(scasm_src)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - switch (inst->get_src1()->get_type()) { - case scar::val_type::VAR: - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); - break; - case scar::val_type::CONSTANT: - scasm_dst->set_type(scasm::operand_type::IMM); - scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); - break; - default: - break; - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(0); - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - SET_DST(scasm_dst2); - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); - scasm_inst3->set_type(scasm::instruction_type::SETCC); - MAKE_SHARED(scasm::scasm_operand, scasm_src3); - scasm_src3->set_type(scasm::operand_type::COND); - scasm_src3->set_cond(scasm::cond_code::E); - scasm_inst3->set_src(std::move(scasm_src3)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst3); - switch (inst->get_dst()->get_type()) { - case scar::val_type::VAR: - scasm_dst3->set_type(scasm::operand_type::PSEUDO); - scasm_dst3->set_identifier_stack(inst->get_dst()->get_reg()); - break; - default: - break; - } - scasm_inst3->set_dst(std::move(scasm_dst3)); - scasm_func->add_instruction(std::move(scasm_inst3)); - } else { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst->set_dst(std::move(scasm_dst)); - - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::UNARY); - scasm_inst2->set_unop(inst->get_unop()); - - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst2->set_type(scasm::operand_type::PSEUDO); - scasm_dst2->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst2->set_dst(std::move(scasm_dst2)); - - scasm_func->add_instruction(std::move(scasm_inst2)); - } - } else if (inst->get_type() == scar::instruction_type::BINARY) { - if (binop::is_relational(inst->get_binop())) { - // Cmp(src2, src1) - // Mov(Imm(0), dst) - // SetCC(conditional, dst) - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::CMP); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - switch (inst->get_src2()->get_type()) { - case scar::val_type::VAR: - scasm_src->set_type(scasm::operand_type::PSEUDO); - scasm_src->set_identifier_stack(inst->get_src2()->get_reg()); - break; - case scar::val_type::CONSTANT: - scasm_src->set_type(scasm::operand_type::IMM); - scasm_src->set_imm(stoi(inst->get_src2()->get_value())); - break; - default: - break; - } - scasm_inst->set_src(std::move(scasm_src)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - switch (inst->get_src1()->get_type()) { - case scar::val_type::VAR: - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); - break; - case scar::val_type::CONSTANT: - scasm_dst->set_type(scasm::operand_type::IMM); - scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); - break; - default: - break; - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(0); - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - SET_DST(scasm_dst2); - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); - scasm_inst3->set_type(scasm::instruction_type::SETCC); - MAKE_SHARED(scasm::scasm_operand, scasm_src3); - scasm_src3->set_type(scasm::operand_type::COND); - switch (inst->get_binop()) { - case binop::BINOP::EQUAL: - scasm_src3->set_cond(scasm::cond_code::E); - break; - case binop::BINOP::NOTEQUAL: - scasm_src3->set_cond(scasm::cond_code::NE); - break; - case binop::BINOP::LESSTHAN: - scasm_src3->set_cond(scasm::cond_code::L); - break; - case binop::BINOP::LESSTHANEQUAL: - scasm_src3->set_cond(scasm::cond_code::LE); - break; - case binop::BINOP::GREATERTHAN: - scasm_src3->set_cond(scasm::cond_code::G); - break; - case binop::BINOP::GREATERTHANEQUAL: - scasm_src3->set_cond(scasm::cond_code::GE); - break; - default: - break; - } - scasm_inst3->set_src(std::move(scasm_src3)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst3); - SET_DST(scasm_dst3); - scasm_inst3->set_dst(std::move(scasm_dst3)); - scasm_func->add_instruction(std::move(scasm_inst3)); - } else if (inst->get_binop() == binop::BINOP::DIV or - inst->get_binop() == binop::BINOP::MOD) { - // Mov(src1, Reg(AX)) - // Cdq - // Idiv(src2) - // Mov(Reg(AX), dst) | Mov(Reg(DX), dst) - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - scasm_dst->set_type(scasm::operand_type::REG); - scasm_dst->set_reg(scasm::register_type::AX); - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::CDQ); - scasm_func->add_instruction(std::move(scasm_inst2)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); - scasm_inst3->set_type(scasm::instruction_type::IDIV); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - if (inst->get_src2()->get_type() == scar::val_type::VAR) { - scasm_src2->set_type(scasm::operand_type::PSEUDO); - scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); - } else if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); - } - scasm_inst3->set_src(std::move(scasm_src2)); - scasm_func->add_instruction(std::move(scasm_inst3)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst4); - scasm_inst4->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - SET_DST(scasm_dst2); - scasm_inst4->set_dst(std::move(scasm_dst2)); - MAKE_SHARED(scasm::scasm_operand, scasm_src3); - scasm_src3->set_type(scasm::operand_type::REG); - if (inst->get_binop() == binop::BINOP::DIV) { - scasm_src3->set_reg(scasm::register_type::AX); - } else { - scasm_src3->set_reg(scasm::register_type::DX); - } - scasm_inst4->set_src(std::move(scasm_src3)); - scasm_func->add_instruction(std::move(scasm_inst4)); - } else if (inst->get_binop() == binop::BINOP::LEFT_SHIFT or - inst->get_binop() == binop::BINOP::RIGHT_SHIFT) { - // Mov(src1,dst) - // Mov(src2, Reg(CX)) - // Binary(binary operand, CL, dst) - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); - } else if (inst->get_src2()->get_type() == scar::val_type::VAR) { - scasm_src2->set_type(scasm::operand_type::PSEUDO); - scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); - } - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - scasm_dst2->set_type(scasm::operand_type::REG); - scasm_dst2->set_reg(scasm::register_type::CX); - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); - scasm_inst3->set_type(scasm::instruction_type::BINARY); - scasm_inst3->set_binop( - scasm::scar_binop_to_scasm_binop(inst->get_binop())); - MAKE_SHARED(scasm::scasm_operand, scasm_src3); - scasm_src3->set_type(scasm::operand_type::REG); - scasm_src3->set_reg(scasm::register_type::CL); - scasm_inst3->set_src(std::move(scasm_src3)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst3); - scasm_dst3->set_type(scasm::operand_type::PSEUDO); - scasm_dst3->set_identifier_stack(inst->get_dst()->get_reg()); - scasm_inst3->set_dst(std::move(scasm_dst3)); - scasm_func->add_instruction(std::move(scasm_inst3)); - - } else { - // Mov(src1, dst) - // Binary(binary_operator, src2, dst) - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::BINARY); - scasm_inst2->set_binop( - scasm::scar_binop_to_scasm_binop(inst->get_binop())); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - if (inst->get_src2()->get_type() == scar::val_type::VAR) { - scasm_src2->set_type(scasm::operand_type::PSEUDO); - scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); - } else if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); - } - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst2->set_type(scasm::operand_type::PSEUDO); - scasm_dst2->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - } - } else if (inst->get_type() == scar::instruction_type::COPY) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - SET_DST(scasm_dst); - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - } else if (inst->get_type() == scar::instruction_type::LABEL) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::LABEL); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - scasm_src->set_type(scasm::operand_type::LABEL); - scasm_src->set_identifier_stack(inst->get_src1()->get_value()); - scasm_inst->set_src(std::move(scasm_src)); - scasm_func->add_instruction(std::move(scasm_inst)); - } else if (inst->get_type() == scar::instruction_type::JUMP) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::JMP); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - scasm_src->set_type(scasm::operand_type::LABEL); - scasm_src->set_identifier_stack(inst->get_src1()->get_value()); - scasm_inst->set_src(std::move(scasm_src)); - scasm_func->add_instruction(std::move(scasm_inst)); - } else if (inst->get_type() == scar::instruction_type::JUMP_IF_ZERO or - inst->get_type() == scar::instruction_type::JUMP_IF_NOT_ZERO) { - // Cmp(Imm(0), condition) - // JmpCC(E, label) | JmpCC(NE, label) - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::CMP); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - scasm_src->set_type(scasm::operand_type::IMM); - scasm_src->set_imm(0); - scasm_inst->set_src(std::move(scasm_src)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - switch (inst->get_src1()->get_type()) { - case scar::val_type::VAR: - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); - break; - case scar::val_type::CONSTANT: - scasm_dst->set_type(scasm::operand_type::IMM); - scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); - break; - default: - break; - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::JMPCC); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - scasm_src2->set_type(scasm::operand_type::COND); - if (inst->get_type() == scar::instruction_type::JUMP_IF_ZERO) { - scasm_src2->set_cond(scasm::cond_code::E); - } else { - scasm_src2->set_cond(scasm::cond_code::NE); - } - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - scasm_dst2->set_type(scasm::operand_type::LABEL); - scasm_dst2->set_identifier_stack(inst->get_dst()->get_value()); - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - } - } - scasm_program.add_function(std::move(scasm_func)); - } - - this->scasm = scasm_program; -} - -#define FIX_PSEUDO(target) \ - if (NOTNULL(inst->get_##target()) && \ - inst->get_##target()->get_type() == scasm::operand_type::PSEUDO) { \ - if (pseduo_registers.find(inst->get_##target()->get_identifier_stack()) != \ - pseduo_registers.end()) { \ - inst->get_##target()->set_identifier_stack( \ - pseduo_registers[inst->get_##target()->get_identifier_stack()]); \ - } else { \ - std::string temp = inst->get_##target()->get_identifier_stack(); \ - inst->get_##target()->set_identifier_stack( \ - "-" + std::to_string(offset * 4) + "(%rbp)"); \ - pseduo_registers[temp] = inst->get_##target()->get_identifier_stack(); \ - offset++; \ - } \ - inst->get_##target()->set_type(scasm::operand_type::STACK); \ - } - -void Codegen::fix_pseudo_registers() { - int offset = 1; - for (auto &funcs : scasm.get_functions()) { - for (auto &inst : funcs->get_instructions()) { - FIX_PSEUDO(src); - FIX_PSEUDO(dst); - } - } - stack_offset = 4 * (offset - 1); -} - -void Codegen::fix_instructions() { - MAKE_SHARED(scasm::scasm_instruction, scasm_stack_instr); - scasm_stack_instr->set_type(scasm::instruction_type::ALLOCATE_STACK); - MAKE_SHARED(scasm::scasm_operand, val); - val->set_type(scasm::operand_type::IMM); - val->set_imm(stack_offset); - scasm_stack_instr->set_src(std::move(val)); - - scasm.get_functions()[0]->get_instructions().insert( - scasm.get_functions()[0]->get_instructions().begin(), - std::move(scasm_stack_instr)); - - for (auto &funcs : scasm.get_functions()) { - for (auto it = funcs->get_instructions().begin(); - it != funcs->get_instructions().end(); it++) { - if (NOTNULL((*it)->get_src()) && NOTNULL((*it)->get_dst()) && - (*it)->get_src()->get_type() == scasm::operand_type::STACK && - (*it)->get_dst()->get_type() == scasm::operand_type::STACK) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - scasm_inst->set_src((*it)->get_src()); - - // fixing up stack to stack move - MAKE_SHARED(scasm::scasm_operand, dst); - dst->set_type(scasm::operand_type::REG); - dst->set_reg(scasm::register_type::R10); - scasm_inst->set_dst(dst); - - (*it)->set_src(std::move(dst)); - it = funcs->get_instructions().insert(it, std::move(scasm_inst)); - it++; - } - } - } - - // case when DIV uses a constant as an operand - // case when MUL have dst as a stack value - for (auto &funcs : scasm.get_functions()) { - for (auto it = funcs->get_instructions().begin(); - it != funcs->get_instructions().end(); it++) { - - if ((*it)->get_type() == scasm::instruction_type::CMP and - (*it)->get_dst()->get_type() == scasm::operand_type::IMM) { - // cmpl stack/reg, $5 - // | - // v - // movl $5, %r11d - // cmpl stack/reg, %r11d - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - scasm_inst->set_src((*it)->get_dst()); - MAKE_SHARED(scasm::scasm_operand, dst); - dst->set_type(scasm::operand_type::REG); - dst->set_reg(scasm::register_type::R11); - scasm_inst->set_dst(dst); - (*it)->set_dst(std::move(dst)); - it = funcs->get_instructions().insert(it, std::move(scasm_inst)); - it++; - } - if ((*it)->get_type() == scasm::instruction_type::IDIV and - (*it)->get_src()->get_type() == scasm::operand_type::IMM) { - // idivl $3 - // | - // v - // movl $3, %r10d - // idivl %r10d - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - scasm_inst->set_src((*it)->get_src()); - MAKE_SHARED(scasm::scasm_operand, dst); - dst->set_type(scasm::operand_type::REG); - dst->set_reg(scasm::register_type::R10); - scasm_inst->set_dst(dst); - (*it)->set_src(std::move(dst)); - it = funcs->get_instructions().insert(it, std::move(scasm_inst)); - it++; - } else if ((*it)->get_type() == scasm::instruction_type::BINARY and - (*it)->get_binop() == scasm::Binop::MUL and - (*it)->get_dst()->get_type() == scasm::operand_type::STACK) { - // imull $3, STACK - // | - // v - // movl STACK, %r11d - // imull $3, %r11d - // movl %r11d, STACK - - MAKE_SHARED(scasm::scasm_operand, dst); - dst->set_type(scasm::operand_type::REG); - dst->set_reg(scasm::register_type::R11); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - scasm_inst->set_src((*it)->get_dst()); - scasm_inst->set_dst(dst); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::MOV); - scasm_inst2->set_src(dst); - scasm_inst2->set_dst((*it)->get_dst()); - - (*it)->set_dst(std::move(dst)); - - it = funcs->get_instructions().insert(it, std::move(scasm_inst)); - it++; - it = funcs->get_instructions().insert(it + 1, std::move(scasm_inst2)); - } - } - } -} - #define CODEGEN_SRC_DST() \ if (instr->get_src()->get_type() == scasm::operand_type::IMM) { \ assembly << "$" << instr->get_src()->get_imm(); \ diff --git a/codegen/codegen.hh b/codegen/codegen.hh index 9444c4a..f74c97d 100644 --- a/codegen/codegen.hh +++ b/codegen/codegen.hh @@ -36,6 +36,11 @@ namespace scarlet { namespace codegen { #define NOTNULL(x) x != nullptr +#define UNREACHABLE() \ + std::cout << "Unreachable code reached in " << __FILE__ << " at line " \ + << __LINE__ << std::endl; \ + __builtin_unreachable(); +#define MAKE_SHARED(a, b) std::shared_ptr b = std::make_shared() class Codegen { private: diff --git a/codegen/common.hh b/codegen/common.hh new file mode 100644 index 0000000..3e35f9a --- /dev/null +++ b/codegen/common.hh @@ -0,0 +1,23 @@ +#pragma once + +#include "codegen.hh" + +namespace scarlet { +namespace codegen { + +#define SETVARCONSTANTREG(src) \ + if (!variable_buffer.empty()) { \ + src->set_type(scar::val_type::VAR); \ + src->set_reg_name(variable_buffer); \ + variable_buffer.clear(); \ + } else if (!constant_buffer.empty()) { \ + src->set_type(scar::val_type::CONSTANT); \ + src->set_value(constant_buffer); \ + constant_buffer.clear(); \ + } else { \ + src->set_type(scar::val_type::VAR); \ + src->set_reg_name(get_prev_reg_name()); \ + } + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/pretty_print.cc b/codegen/scargen/pretty_print.cc new file mode 100644 index 0000000..6e66b0c --- /dev/null +++ b/codegen/scargen/pretty_print.cc @@ -0,0 +1,96 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::pretty_print() { + std::cout << "Program(" << std::endl; + for (auto function : scar.get_functions()) { + std::cout << "\tFunction(" << std::endl; + std::cout << "\t\tname=\"" << function->get_identifier()->get_value() + << "\"," << std::endl; + std::cout << "\t\tbody=[" << std::endl; + for (auto statement : function->get_instructions()) { + std::cout << "\t\t\t" << to_string(statement->get_type()) << "("; + if (statement->get_type() == scar::instruction_type::RETURN) { + if (statement->get_src1()->get_type() == scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } else if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } + std::cout << ")" << std::endl; + } else if (statement->get_type() == scar::instruction_type::UNARY) { + std::cout << unop::to_string(statement->get_unop()) << ", "; + if (statement->get_src1()->get_type() == scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } else if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } + std::cout << ", "; + if (statement->get_dst()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; + } else if (statement->get_dst()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_dst()->get_value() << ")"; + } + std::cout << ")" << std::endl; + } else if (statement->get_type() == scar::instruction_type::BINARY) { + std::cout << binop::to_string(statement->get_binop()) << ", "; + if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } else if (statement->get_src1()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } + std::cout << ", "; + if (statement->get_src2()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src2()->get_reg() << ")"; + } else if (statement->get_src2()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src2()->get_value() << ")"; + } + std::cout << ", "; + if (statement->get_dst()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; + } else if (statement->get_dst()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_dst()->get_value() << ")"; + } + std::cout << ")" << std::endl; + } else if (statement->get_type() == scar::instruction_type::COPY) { + if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } else if (statement->get_src1()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } + std::cout << " ,"; + if (statement->get_dst()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; + } + std::cout << ")" << std::endl; + } else if (statement->get_type() == scar::instruction_type::JUMP or + statement->get_type() == scar::instruction_type::LABEL) { + std::cout << statement->get_src1()->get_value() << ")" << std::endl; + } else if (statement->get_type() == + scar::instruction_type::JUMP_IF_ZERO or + statement->get_type() == + scar::instruction_type::JUMP_IF_NOT_ZERO) { + if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } else if (statement->get_src1()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } + std::cout << ", "; + std::cout << statement->get_dst()->get_value() << ")" << std::endl; + } + } + std::cout << "\t\t]" << std::endl; + std::cout << "\t)," << std::endl; + } + std::cout << ")" << std::endl; +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar.cc b/codegen/scargen/scar.cc new file mode 100644 index 0000000..8d785b2 --- /dev/null +++ b/codegen/scargen/scar.cc @@ -0,0 +1,33 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar() { + scar::scar_Program_Node scar_program; + for (auto it : program.get_functions()) { + MAKE_SHARED(scar::scar_Function_Node, scar_function); + MAKE_SHARED(scar::scar_Identifier_Node, identifier); + identifier->set_value(it->get_identifier()->get_value()); + scar_function->set_identifier(identifier); + + gen_scar_block(it->get_block(), scar_function); + + // Add a complementary return 0 at the end of the function + // in case there is no return statement + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::RETURN); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::CONSTANT); + scar_val_src->set_value("0"); + scar_instruction->set_src1(scar_val_src); + scar_function->add_instruction(scar_instruction); + + scar_program.add_function(scar_function); + } + + this->scar = scar_program; +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_block.cc b/codegen/scargen/scar_block.cc new file mode 100644 index 0000000..2576be5 --- /dev/null +++ b/codegen/scargen/scar_block.cc @@ -0,0 +1,24 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar_block( + std::shared_ptr block, + std::shared_ptr scar_function) { + for (auto inst : block->get_blockItems()) { + switch (inst->get_type()) { + case ast::BlockItemType::STATEMENT: + gen_scar_statement(inst->get_statement(), scar_function); + break; + case ast::BlockItemType::DECLARATION: + gen_scar_declaration(inst->get_declaration(), scar_function); + break; + case ast::BlockItemType::UNKNOWN: + UNREACHABLE() + } + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_declaration.cc b/codegen/scargen/scar_declaration.cc new file mode 100644 index 0000000..7ed5d50 --- /dev/null +++ b/codegen/scargen/scar_declaration.cc @@ -0,0 +1,26 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar_declaration( + std::shared_ptr declaration, + std::shared_ptr scar_function) { + // if there is no definition, we ignore it + if (declaration->get_exp() != nullptr) { + gen_scar_exp(declaration->get_exp(), scar_function); + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::COPY); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_dst->set_type(scar::val_type::VAR); + scar_val_dst->set_reg_name(declaration->get_identifier()->get_value()); + scar_instruction->set_dst(scar_val_dst); + scar_function->add_instruction(scar_instruction); + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_expression.cc b/codegen/scargen/scar_expression.cc new file mode 100644 index 0000000..c1a8b88 --- /dev/null +++ b/codegen/scargen/scar_expression.cc @@ -0,0 +1,279 @@ +#include + +namespace scarlet { +namespace codegen { + +#define SETUPLANDLOR(num) \ + if (exp->get_binop_node()->get_op() == binop::BINOP::LAND) { \ + /* Logical and */ \ + scar_instruction##num->set_type(scar::instruction_type::JUMP_IF_ZERO); \ + } else { \ + /* Logical or */ \ + scar_instruction##num->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); \ + } \ + \ + if (exp->get_left() == nullptr) { \ + if (num == 1) \ + gen_scar_factor(exp->get_factor_node(), scar_function); \ + SETVARCONSTANTREG(scar_val_src##num); \ + } else { \ + scar_val_src##num->set_type(scar::val_type::VAR); \ + scar_val_src##num->set_reg_name(get_prev_reg_name()); \ + } \ + \ + scar_instruction##num->set_src1(std::move(scar_val_src##num)); \ + scar_val_dst##num->set_type(scar::val_type::UNKNOWN); + +void Codegen::gen_scar_exp( + std::shared_ptr exp, + std::shared_ptr scar_function) { + if (exp == nullptr) + return; + gen_scar_exp(exp->get_left(), scar_function); + if (exp->get_binop_node() != nullptr and + exp->get_binop_node()->get_op() != binop::BINOP::UNKNOWN) { + // when we have a binary operator + // deal with && and || separately using jmpif(not)zero, labels and copy + // operations since we need to apply short circuit for them + // + // There will be a separate case for the assignment operator as that + // will be represented by a simple copy operation + // + // There will be a separate case for the ternary operator as well + // So first we need to check whether it is the first expression + // or the second expression that will be returned using jmpifzero + // and copy the result to a new register. Ternary is actually a special + // case of short circuiting + if (exp->get_binop_node()->get_op() == binop::BINOP::ASSIGN) { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::COPY); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + // the semantic analyis phase should have ensured that the left child + // is null, factor is an identifier with no unops and the right child + // is an expression + gen_scar_exp(exp->get_right(), scar_function); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(std::move(scar_val_src)); + + scar_val_dst->set_type(scar::val_type::VAR); + scar_val_dst->set_reg_name( + exp->get_factor_node()->get_identifier_node()->get_value()); + // NOTE: we update the current scar register name to use the variable + // since we can have expressions like: + // int b = a = 5; + reg_name = scar_val_dst->get_reg(); + scar_instruction->set_dst(std::move(scar_val_dst)); + + scar_function->add_instruction(std::move(scar_instruction)); + return; + } + bool short_circuit = binop::short_circuit(exp->get_binop_node()->get_op()); + binop::BINOP sc_binop = exp->get_binop_node()->get_op(); + const binop::BINOP compound_binop = sc_binop; + if (binop::is_compound(compound_binop)) { + sc_binop = compound_to_base[compound_binop]; + } + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + if (short_circuit) { + if (sc_binop == binop::BINOP::LAND) { + scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); + } else if (sc_binop == binop::BINOP::LOR) { + scar_instruction->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); + } else if (sc_binop == binop::BINOP::TERNARY) { + scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); + } + } else { + scar_instruction->set_type(scar::instruction_type::BINARY); + scar_instruction->set_binop(sc_binop); + } + MAKE_SHARED(scar::scar_Val_Node, scar_val_src1); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + + if (exp->get_left() == nullptr) { + gen_scar_factor(exp->get_factor_node(), scar_function); + SETVARCONSTANTREG(scar_val_src1); + } else { + scar_val_src1->set_type(scar::val_type::VAR); + scar_val_src1->set_reg_name(get_prev_reg_name()); + } + + scar_instruction->set_src1(std::move(scar_val_src1)); + + if (short_circuit) { + // create a label to jump to + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst1); + scar_val_dst1->set_type(scar::val_type::UNKNOWN); + scar_val_dst1->set_value(get_fr_label_name()); + scar_instruction->set_dst(std::move(scar_val_dst1)); + scar_function->add_instruction(std::move(scar_instruction)); + } + + // TERNARY SPECIAL CASE + if (sc_binop == binop::BINOP::TERNARY) { + // generate the first expression + gen_scar_exp(exp->get_middle(), scar_function); + + // copy this result in a new register + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_instruction2->set_type(scar::instruction_type::COPY); + SETVARCONSTANTREG(scar_val_src2); + scar_instruction2->set_src1(std::move(scar_val_src2)); + scar_val_dst2->set_type(scar::val_type::VAR); + // Doing this so that we can use the same scar register to + // store the result of the second expression as well. + // We cannot simply use get_prev_reg_name() since we need to + // parse the second expression first and that will change the + // register counter + std::string result = get_reg_name(); + scar_val_dst2->set_reg_name(result); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(std::move(scar_instruction2)); + + // jump to the end + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_instruction3->set_type(scar::instruction_type::JUMP); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value(get_res_label_name()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(std::move(scar_instruction3)); + + // generate the intermediate label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_instruction4->set_type(scar::instruction_type::LABEL); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value(get_last_fr_label_name(true)); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(std::move(scar_instruction4)); + + // generate the second expression + gen_scar_exp(exp->get_right(), scar_function); + + // copy this result in a new register + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst5); + scar_instruction5->set_type(scar::instruction_type::COPY); + SETVARCONSTANTREG(scar_val_src5); + scar_instruction5->set_src1(std::move(scar_val_src5)); + scar_val_dst5->set_type(scar::val_type::VAR); + scar_val_dst5->set_reg_name(result); + scar_instruction5->set_dst(std::move(scar_val_dst5)); + scar_function->add_instruction(std::move(scar_instruction5)); + + // generate the final label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction6); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src6); + scar_instruction6->set_type(scar::instruction_type::LABEL); + scar_val_src6->set_type(scar::val_type::UNKNOWN); + scar_val_src6->set_value(get_last_res_label_name()); + scar_instruction6->set_src1(std::move(scar_val_src6)); + scar_function->add_instruction(std::move(scar_instruction6)); + + // early return + return; + } + gen_scar_exp(exp->get_right(), scar_function); + SETVARCONSTANTREG(scar_val_src2); + + if (short_circuit) { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + if (sc_binop == binop::BINOP::LAND) { + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); + } else { + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); + } + scar_instruction2->set_src1(std::move(scar_val_src2)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_val_dst2->set_type(scar::val_type::UNKNOWN); + scar_val_dst2->set_value(get_last_fr_label_name()); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(std::move(scar_instruction2)); + + // now copy 1(LAND) / 0(LOR) into a scar register + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst3); + scar_instruction3->set_type(scar::instruction_type::COPY); + scar_val_src3->set_type(scar::val_type::CONSTANT); + if (sc_binop == binop::BINOP::LAND) { + scar_val_src3->set_value(std::to_string(1)); + } else { + scar_val_src3->set_value(std::to_string(0)); + } + scar_val_dst3->set_type(scar::val_type::VAR); + scar_val_dst3->set_reg_name(get_reg_name()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_instruction3->set_dst(std::move(scar_val_dst3)); + scar_function->add_instruction(std::move(scar_instruction3)); + + // now jump to the end + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_instruction4->set_type(scar::instruction_type::JUMP); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value(get_res_label_name()); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(std::move(scar_instruction4)); + + // Now generate the intermediate label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); + scar_instruction5->set_type(scar::instruction_type::LABEL); + scar_val_src5->set_type(scar::val_type::UNKNOWN); + scar_val_src5->set_value(get_last_fr_label_name(true)); + scar_instruction5->set_src1(std::move(scar_val_src5)); + scar_function->add_instruction(std::move(scar_instruction5)); + + // now copy 0(LAND) / 1(LOR) into a scar register + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction6); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src6); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst6); + scar_instruction6->set_type(scar::instruction_type::COPY); + scar_val_src6->set_type(scar::val_type::CONSTANT); + if (sc_binop == binop::BINOP::LAND) { + scar_val_src6->set_value(std::to_string(0)); + } else { + scar_val_src6->set_value(std::to_string(1)); + } + scar_val_dst6->set_type(scar::val_type::VAR); + scar_val_dst6->set_reg_name(get_prev_reg_name()); + scar_instruction6->set_src1(std::move(scar_val_src6)); + scar_instruction6->set_dst(std::move(scar_val_dst6)); + scar_function->add_instruction(std::move(scar_instruction6)); + + // now generate the final label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction7); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src7); + scar_instruction7->set_type(scar::instruction_type::LABEL); + scar_val_src7->set_type(scar::val_type::UNKNOWN); + scar_val_src7->set_value(get_last_res_label_name()); + scar_instruction7->set_src1(std::move(scar_val_src7)); + scar_function->add_instruction(std::move(scar_instruction7)); + } else { + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_dst->set_type(scar::val_type::VAR); + if (binop::is_compound(compound_binop)) { + scar_val_dst->set_reg_name( + exp->get_factor_node()->get_identifier_node()->get_value()); + reg_name = scar_val_dst->get_reg(); + } else { + scar_val_dst->set_reg_name(get_reg_name()); + } + scar_instruction->set_src2(std::move(scar_val_src2)); + scar_instruction->set_dst(std::move(scar_val_dst)); + + scar_function->add_instruction(std::move(scar_instruction)); + } + } else { + // When we do not have a binary operator, so only parse the factor node + gen_scar_factor(exp->get_factor_node(), scar_function); + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_factor.cc b/codegen/scargen/scar_factor.cc new file mode 100644 index 0000000..f7871ef --- /dev/null +++ b/codegen/scargen/scar_factor.cc @@ -0,0 +1,181 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar_factor( + std::shared_ptr factor, + std::shared_ptr scar_function) { + // firstly put all the unops (if they exist) in the unop buffer + for (auto it : factor->get_unop_nodes()) { + unop_buffer[curr_buff].emplace_back(it->get_op()); + } + // if exp exists, parse that. If exp is null, it will simply return + if (factor->get_exp_node() != nullptr) { + curr_buff++; + if (curr_buff >= (int)unop_buffer.size()) + unop_buffer.resize(curr_buff + 1); + gen_scar_exp(factor->get_exp_node(), scar_function); + curr_buff--; + } + // If we have an integer node and unops to operate on, proceed... + if (!unop_buffer[curr_buff].empty()) { + int num_unpos = unop_buffer[curr_buff].size(); + for (int i = num_unpos - 1; i >= 0; i--) { + // SPECIAL CASE WHEN WE HAVE INCREMENT OR DECREMENT OPERATOR + unop::UNOP op = unop_buffer[curr_buff][i]; + if (op == unop::UNOP::PREINCREMENT or op == unop::UNOP::PREDECREMENT) { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::BINARY); + if (op == unop::UNOP::PREINCREMENT) { + scar_instruction->set_binop(binop::BINOP::ADD); + } else { + scar_instruction->set_binop(binop::BINOP::SUB); + } + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + + scar_val_dst->set_type(scar::val_type::VAR); + // The destination will always be a variable + if (!variable_buffer.empty()) { + scar_val_dst->set_reg_name(variable_buffer); + variable_buffer.clear(); + } else { + scar_val_dst->set_reg_name( + factor->get_identifier_node()->get_value()); + } + + reg_name = scar_val_dst->get_reg(); + scar_instruction->set_dst(std::move(scar_val_dst)); + + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name(reg_name); + scar_instruction->set_src1(std::move(scar_val_src)); + + scar_val_src2->set_type(scar::val_type::CONSTANT); + scar_val_src2->set_value("1"); + scar_instruction->set_src2(std::move(scar_val_src2)); + + scar_function->add_instruction(std::move(scar_instruction)); + continue; + } else if (op == unop::UNOP::POSTINCREMENT or + op == unop::UNOP::POSTDECREMENT) { + // SPECIAL CASE WHEN WE HAVE POST INCREMENT OR DECREMENT + // Since these return the original value and then increment or decrement + // We first make a copy of the original value and then increment or + // decrement + + // COPY THE ORIGINAL VALUE INTO A NEW SCAR REGISTER + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::COPY); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_src->set_type(scar::val_type::VAR); + if (!variable_buffer.empty()) { + scar_val_src->set_reg_name(variable_buffer); + variable_buffer.clear(); + } else { + scar_val_src->set_reg_name( + factor->get_identifier_node()->get_value()); + } + std::string _variable = scar_val_src->get_reg(); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_val_dst->set_type(scar::val_type::VAR); + scar_val_dst->set_reg_name(get_reg_name()); + scar_instruction->set_dst(std::move(scar_val_dst)); + scar_function->add_instruction(std::move(scar_instruction)); + + // NOW DO THE BINARY OPERATION + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::BINARY); + if (op == unop::UNOP::POSTINCREMENT) { + scar_instruction2->set_binop(binop::BINOP::ADD); + } else { + scar_instruction2->set_binop(binop::BINOP::SUB); + } + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + + scar_val_src2->set_type(scar::val_type::VAR); + scar_val_src2->set_reg_name(_variable); + scar_instruction2->set_src1(std::move(scar_val_src2)); + + scar_val_src3->set_type(scar::val_type::CONSTANT); + scar_val_src3->set_value("1"); + scar_instruction2->set_src2(std::move(scar_val_src3)); + + scar_val_dst2->set_type(scar::val_type::VAR); + scar_val_dst2->set_reg_name(_variable); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + + scar_function->add_instruction(std::move(scar_instruction2)); + continue; + } + // scar::scar_Instruction_Node scar_instruction; + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::UNARY); + scar_instruction->set_unop(op); + + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + + // deal with the source + if (i == num_unpos - 1) { + if (factor->get_int_node() != nullptr and + !factor->get_int_node()->get_value().empty()) { + scar_val_src->set_type(scar::val_type::CONSTANT); + scar_val_src->set_value(factor->get_int_node()->get_value()); + } else if (factor->get_identifier_node() != nullptr and + !factor->get_identifier_node()->get_value().empty()) { + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name( + factor->get_identifier_node()->get_value()); + } else if (!constant_buffer.empty()) { + scar_val_src->set_type(scar::val_type::CONSTANT); + scar_val_src->set_value(constant_buffer); + constant_buffer.clear(); + } else if (!variable_buffer.empty()) { + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name(variable_buffer); + variable_buffer.clear(); + } else { + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name(get_prev_reg_name()); + } + } else { + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name(get_prev_reg_name()); + } + scar_instruction->set_src1(std::move(scar_val_src)); + + // deal with the destination + scar_val_dst->set_type(scar::val_type::VAR); + scar_val_dst->set_reg_name(get_reg_name()); + scar_instruction->set_dst(std::move(scar_val_dst)); + + scar_function->add_instruction(std::move(scar_instruction)); + } + // empty the unop buffer + unop_buffer[curr_buff].clear(); + } else { + // NOTE: It is guaranteed that the factor node will have either an int node + // or an identifier node + + // save constant for later use + if (factor->get_int_node() != nullptr and + !factor->get_int_node()->get_value().empty()) { + constant_buffer = factor->get_int_node()->get_value(); + } + + // save variable for later use + if (factor->get_identifier_node() != nullptr and + !factor->get_identifier_node()->get_value().empty()) { + variable_buffer = factor->get_identifier_node()->get_value(); + } + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_statement.cc b/codegen/scargen/scar_statement.cc new file mode 100644 index 0000000..b821209 --- /dev/null +++ b/codegen/scargen/scar_statement.cc @@ -0,0 +1,332 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar_statement( + std::shared_ptr statement, + std::shared_ptr scar_function) { + switch (statement->get_type()) { + case ast::statementType::NULLSTMT: + break; + case ast::statementType::RETURN: { + gen_scar_exp(statement->get_exps(), scar_function); + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::RETURN); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(scar_val_src); + scar_function->add_instruction(scar_instruction); + } break; + case ast::statementType::EXP: { + gen_scar_exp(statement->get_exps(), scar_function); + } break; + case ast::statementType::IF: { + // (stored in exps) + // c = + // JumpIfZero(c, end) + // (handled in the next iteration) + // Label(end) (Added during the end of if statement) + auto if_statement = + std::static_pointer_cast(statement); + gen_scar_exp(if_statement->get_exps(), scar_function); + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(std::move(scar_val_src)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_dst->set_type(scar::val_type::UNKNOWN); + scar_val_dst->set_value(if_statement->get_labels().first->get_value()); + scar_instruction->set_dst(std::move(scar_val_dst)); + scar_function->add_instruction(std::move(scar_instruction)); + + // generate scar for the statement + gen_scar_statement(if_statement->get_stmt1(), scar_function); + + // generate the end label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + scar_val_src2->set_type(scar::val_type::UNKNOWN); + scar_val_src2->set_value(if_statement->get_labels().first->get_value()); + scar_instruction2->set_src1(std::move(scar_val_src2)); + scar_function->add_instruction(std::move(scar_instruction2)); + } break; + case ast::statementType::IFELSE: { + // + // c = + // JumpIfZero(c, else_label) + // + // Jump(end) + // Label(else_label) + // + // Label(end) + + auto if_else_statement = + std::static_pointer_cast(statement); + gen_scar_exp(if_else_statement->get_exps(), scar_function); + + // Jump if zero to else statement + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(std::move(scar_val_src)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_dst->set_type(scar::val_type::UNKNOWN); + scar_val_dst->set_value(if_else_statement->get_labels().first->get_value()); + scar_instruction->set_dst(std::move(scar_val_dst)); + scar_function->add_instruction(std::move(scar_instruction)); + + // generate scar for the if statement + gen_scar_statement(if_else_statement->get_stmt1(), scar_function); + + // jump to the end + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::JUMP); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + scar_val_src2->set_type(scar::val_type::UNKNOWN); + scar_val_src2->set_value( + if_else_statement->get_labels().second->get_value()); + scar_instruction2->set_src1(std::move(scar_val_src2)); + scar_function->add_instruction(std::move(scar_instruction2)); + + // generate the else label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + scar_instruction3->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value( + if_else_statement->get_labels().first->get_value()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(std::move(scar_instruction3)); + + // generate scar for the else statement + gen_scar_statement(if_else_statement->get_stmt2(), scar_function); + + // generate the end label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + scar_instruction4->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value( + if_else_statement->get_labels().second->get_value()); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(std::move(scar_instruction4)); + } break; + + case ast::statementType::GOTO: + case ast::statementType::BREAK: + case ast::statementType::CONTINUE: { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::JUMP); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(statement->get_labels().first->get_value()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + } break; + + case ast::statementType::LABEL: { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(statement->get_labels().first->get_value()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + } break; + + case ast::statementType::BLOCK: { + auto block_statement = + std::static_pointer_cast(statement); + gen_scar_block(block_statement->get_block(), scar_function); + } break; + + case ast::statementType::WHILE: { + auto while_statement = + std::static_pointer_cast(statement); + + // Label(start) + // + // c = + // JumpIfZero(c, end) + // + // Jump(start) + // Label(end) + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(while_statement->get_labels().first->get_value()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + + gen_scar_exp(while_statement->get_exps(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + SETVARCONSTANTREG(scar_val_src2); + scar_instruction2->set_src1(std::move(scar_val_src2)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_val_dst2->set_type(scar::val_type::UNKNOWN); + scar_val_dst2->set_value(while_statement->get_labels().second->get_value()); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(scar_instruction2); + + gen_scar_statement(while_statement->get_stmt(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + scar_instruction3->set_type(scar::instruction_type::JUMP); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value(while_statement->get_labels().first->get_value()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(scar_instruction3); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + scar_instruction4->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value(while_statement->get_labels().second->get_value()); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(scar_instruction4); + } break; + + case ast::statementType::DO_WHILE: { + auto do_while_statement = + std::static_pointer_cast(statement); + + // Label(start) + // + // Label(continue) + // + // c = + // JumpIfNotZero(c, start) + // Label(end) + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(do_while_statement->get_start_label()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + + gen_scar_statement(do_while_statement->get_stmt(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction1); + scar_instruction1->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src1); + scar_val_src1->set_type(scar::val_type::UNKNOWN); + scar_val_src1->set_value( + do_while_statement->get_labels().first->get_value()); + scar_instruction1->set_src1(std::move(scar_val_src1)); + scar_function->add_instruction(scar_instruction1); + + gen_scar_exp(do_while_statement->get_exps(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + SETVARCONSTANTREG(scar_val_src2); + scar_instruction2->set_src1(std::move(scar_val_src2)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_val_dst2->set_type(scar::val_type::UNKNOWN); + scar_val_dst2->set_value(do_while_statement->get_start_label()); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(scar_instruction2); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + scar_instruction3->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value( + do_while_statement->get_labels().second->get_value()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(scar_instruction3); + } break; + + case ast::statementType::FOR: { + auto for_statement = + std::static_pointer_cast(statement); + + // + // Label(Forstart) + // + // c = + // JumpIfZero(c, end) + // + // Label(continue) + // + // Jump(Forstart) + // Label(end) + + if (for_statement->get_for_init() != nullptr) { + if (for_statement->get_for_init()->get_declaration() != nullptr) { + gen_scar_declaration(for_statement->get_for_init()->get_declaration(), + scar_function); + } else { + gen_scar_exp(for_statement->get_for_init()->get_exp(), scar_function); + } + } + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(for_statement->get_start_label()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + + gen_scar_exp(for_statement->get_exps(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + SETVARCONSTANTREG(scar_val_src2); + scar_instruction2->set_src1(std::move(scar_val_src2)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_val_dst2->set_type(scar::val_type::UNKNOWN); + scar_val_dst2->set_value(for_statement->get_labels().second->get_value()); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(scar_instruction2); + + gen_scar_statement(for_statement->get_stmt(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + scar_instruction3->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value(for_statement->get_labels().first->get_value()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(scar_instruction3); + + gen_scar_exp(for_statement->get_exp2(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + scar_instruction4->set_type(scar::instruction_type::JUMP); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value(for_statement->get_start_label()); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(scar_instruction4); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); + scar_instruction5->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); + scar_val_src5->set_type(scar::val_type::UNKNOWN); + scar_val_src5->set_value(for_statement->get_labels().second->get_value()); + scar_instruction5->set_src1(std::move(scar_val_src5)); + scar_function->add_instruction(scar_instruction5); + } break; + case ast::statementType::UNKNOWN: + UNREACHABLE() + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scasmgen/fix_instructions.cc b/codegen/scasmgen/fix_instructions.cc new file mode 100644 index 0000000..69f4cc4 --- /dev/null +++ b/codegen/scasmgen/fix_instructions.cc @@ -0,0 +1,117 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::fix_instructions() { + MAKE_SHARED(scasm::scasm_instruction, scasm_stack_instr); + scasm_stack_instr->set_type(scasm::instruction_type::ALLOCATE_STACK); + MAKE_SHARED(scasm::scasm_operand, val); + val->set_type(scasm::operand_type::IMM); + val->set_imm(stack_offset); + scasm_stack_instr->set_src(std::move(val)); + + scasm.get_functions()[0]->get_instructions().insert( + scasm.get_functions()[0]->get_instructions().begin(), + std::move(scasm_stack_instr)); + + for (auto &funcs : scasm.get_functions()) { + for (auto it = funcs->get_instructions().begin(); + it != funcs->get_instructions().end(); it++) { + if (NOTNULL((*it)->get_src()) && NOTNULL((*it)->get_dst()) && + (*it)->get_src()->get_type() == scasm::operand_type::STACK && + (*it)->get_dst()->get_type() == scasm::operand_type::STACK) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + scasm_inst->set_src((*it)->get_src()); + + // fixing up stack to stack move + MAKE_SHARED(scasm::scasm_operand, dst); + dst->set_type(scasm::operand_type::REG); + dst->set_reg(scasm::register_type::R10); + scasm_inst->set_dst(dst); + + (*it)->set_src(std::move(dst)); + it = funcs->get_instructions().insert(it, std::move(scasm_inst)); + it++; + } + } + } + + // case when DIV uses a constant as an operand + // case when MUL have dst as a stack value + for (auto &funcs : scasm.get_functions()) { + for (auto it = funcs->get_instructions().begin(); + it != funcs->get_instructions().end(); it++) { + + if ((*it)->get_type() == scasm::instruction_type::CMP and + (*it)->get_dst()->get_type() == scasm::operand_type::IMM) { + // cmpl stack/reg, $5 + // | + // v + // movl $5, %r11d + // cmpl stack/reg, %r11d + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + scasm_inst->set_src((*it)->get_dst()); + MAKE_SHARED(scasm::scasm_operand, dst); + dst->set_type(scasm::operand_type::REG); + dst->set_reg(scasm::register_type::R11); + scasm_inst->set_dst(dst); + (*it)->set_dst(std::move(dst)); + it = funcs->get_instructions().insert(it, std::move(scasm_inst)); + it++; + } + if ((*it)->get_type() == scasm::instruction_type::IDIV and + (*it)->get_src()->get_type() == scasm::operand_type::IMM) { + // idivl $3 + // | + // v + // movl $3, %r10d + // idivl %r10d + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + scasm_inst->set_src((*it)->get_src()); + MAKE_SHARED(scasm::scasm_operand, dst); + dst->set_type(scasm::operand_type::REG); + dst->set_reg(scasm::register_type::R10); + scasm_inst->set_dst(dst); + (*it)->set_src(std::move(dst)); + it = funcs->get_instructions().insert(it, std::move(scasm_inst)); + it++; + } else if ((*it)->get_type() == scasm::instruction_type::BINARY and + (*it)->get_binop() == scasm::Binop::MUL and + (*it)->get_dst()->get_type() == scasm::operand_type::STACK) { + // imull $3, STACK + // | + // v + // movl STACK, %r11d + // imull $3, %r11d + // movl %r11d, STACK + + MAKE_SHARED(scasm::scasm_operand, dst); + dst->set_type(scasm::operand_type::REG); + dst->set_reg(scasm::register_type::R11); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + scasm_inst->set_src((*it)->get_dst()); + scasm_inst->set_dst(dst); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::MOV); + scasm_inst2->set_src(dst); + scasm_inst2->set_dst((*it)->get_dst()); + + (*it)->set_dst(std::move(dst)); + + it = funcs->get_instructions().insert(it, std::move(scasm_inst)); + it++; + it = funcs->get_instructions().insert(it + 1, std::move(scasm_inst2)); + } + } + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scasmgen/fix_pseudo_registers.cc b/codegen/scasmgen/fix_pseudo_registers.cc new file mode 100644 index 0000000..474383d --- /dev/null +++ b/codegen/scasmgen/fix_pseudo_registers.cc @@ -0,0 +1,35 @@ +#include + +namespace scarlet { +namespace codegen { + +#define FIX_PSEUDO(target) \ + if (NOTNULL(inst->get_##target()) && \ + inst->get_##target()->get_type() == scasm::operand_type::PSEUDO) { \ + if (pseduo_registers.find(inst->get_##target()->get_identifier_stack()) != \ + pseduo_registers.end()) { \ + inst->get_##target()->set_identifier_stack( \ + pseduo_registers[inst->get_##target()->get_identifier_stack()]); \ + } else { \ + std::string temp = inst->get_##target()->get_identifier_stack(); \ + inst->get_##target()->set_identifier_stack( \ + "-" + std::to_string(offset * 4) + "(%rbp)"); \ + pseduo_registers[temp] = inst->get_##target()->get_identifier_stack(); \ + offset++; \ + } \ + inst->get_##target()->set_type(scasm::operand_type::STACK); \ + } + +void Codegen::fix_pseudo_registers() { + int offset = 1; + for (auto &funcs : scasm.get_functions()) { + for (auto &inst : funcs->get_instructions()) { + FIX_PSEUDO(src); + FIX_PSEUDO(dst); + } + } + stack_offset = 4 * (offset - 1); +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scasmgen/scasm_generation.cc b/codegen/scasmgen/scasm_generation.cc new file mode 100644 index 0000000..3c5697b --- /dev/null +++ b/codegen/scasmgen/scasm_generation.cc @@ -0,0 +1,424 @@ +#include + +namespace scarlet { +namespace codegen { + +#define SET_MOV_SOURCE() \ + switch (inst->get_src1()->get_type()) { \ + case scar::val_type::VAR: \ + scasm_src->set_type(scasm::operand_type::PSEUDO); \ + scasm_src->set_identifier_stack(inst->get_src1()->get_reg()); \ + break; \ + case scar::val_type::CONSTANT: \ + scasm_src->set_type(scasm::operand_type::IMM); \ + scasm_src->set_imm(stoi(inst->get_src1()->get_value())); \ + break; \ + default: \ + break; \ + } \ + scasm_inst->set_src(std::move(scasm_src)) + +#define SET_DST(dst) \ + switch (inst->get_dst()->get_type()) { \ + case scar::val_type::VAR: \ + dst->set_type(scasm::operand_type::PSEUDO); \ + dst->set_identifier_stack(inst->get_dst()->get_reg()); \ + break; \ + default: \ + break; \ + } + +void Codegen::gen_scasm() { + scasm::scasm_program scasm_program{}; + for (auto func : scar.get_functions()) { + MAKE_SHARED(scasm::scasm_function, scasm_func); + scasm_func->set_name(func->get_identifier()->get_value()); + for (auto inst : func->get_instructions()) { + if (inst->get_type() == scar::instruction_type::RETURN) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + scasm_dst->set_type(scasm::operand_type::REG); + scasm_dst->set_reg(scasm::register_type::AX); + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::RET); + scasm_func->add_instruction(std::move(scasm_inst2)); + + } else if (inst->get_type() == scar::instruction_type::UNARY) { + if (inst->get_unop() == unop::UNOP::NOT) { + // Cmp(Imm(0), src) + // Mov(Imm(0), dst) + // SetCC(E, dst) + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::CMP); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + scasm_src->set_type(scasm::operand_type::IMM); + scasm_src->set_imm(0); + scasm_inst->set_src(std::move(scasm_src)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + switch (inst->get_src1()->get_type()) { + case scar::val_type::VAR: + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); + break; + case scar::val_type::CONSTANT: + scasm_dst->set_type(scasm::operand_type::IMM); + scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); + break; + default: + break; + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(0); + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + SET_DST(scasm_dst2); + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); + scasm_inst3->set_type(scasm::instruction_type::SETCC); + MAKE_SHARED(scasm::scasm_operand, scasm_src3); + scasm_src3->set_type(scasm::operand_type::COND); + scasm_src3->set_cond(scasm::cond_code::E); + scasm_inst3->set_src(std::move(scasm_src3)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst3); + switch (inst->get_dst()->get_type()) { + case scar::val_type::VAR: + scasm_dst3->set_type(scasm::operand_type::PSEUDO); + scasm_dst3->set_identifier_stack(inst->get_dst()->get_reg()); + break; + default: + break; + } + scasm_inst3->set_dst(std::move(scasm_dst3)); + scasm_func->add_instruction(std::move(scasm_inst3)); + } else { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst->set_dst(std::move(scasm_dst)); + + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::UNARY); + scasm_inst2->set_unop(inst->get_unop()); + + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst2->set_type(scasm::operand_type::PSEUDO); + scasm_dst2->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst2->set_dst(std::move(scasm_dst2)); + + scasm_func->add_instruction(std::move(scasm_inst2)); + } + } else if (inst->get_type() == scar::instruction_type::BINARY) { + if (binop::is_relational(inst->get_binop())) { + // Cmp(src2, src1) + // Mov(Imm(0), dst) + // SetCC(conditional, dst) + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::CMP); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + switch (inst->get_src2()->get_type()) { + case scar::val_type::VAR: + scasm_src->set_type(scasm::operand_type::PSEUDO); + scasm_src->set_identifier_stack(inst->get_src2()->get_reg()); + break; + case scar::val_type::CONSTANT: + scasm_src->set_type(scasm::operand_type::IMM); + scasm_src->set_imm(stoi(inst->get_src2()->get_value())); + break; + default: + break; + } + scasm_inst->set_src(std::move(scasm_src)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + switch (inst->get_src1()->get_type()) { + case scar::val_type::VAR: + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); + break; + case scar::val_type::CONSTANT: + scasm_dst->set_type(scasm::operand_type::IMM); + scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); + break; + default: + break; + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(0); + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + SET_DST(scasm_dst2); + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); + scasm_inst3->set_type(scasm::instruction_type::SETCC); + MAKE_SHARED(scasm::scasm_operand, scasm_src3); + scasm_src3->set_type(scasm::operand_type::COND); + switch (inst->get_binop()) { + case binop::BINOP::EQUAL: + scasm_src3->set_cond(scasm::cond_code::E); + break; + case binop::BINOP::NOTEQUAL: + scasm_src3->set_cond(scasm::cond_code::NE); + break; + case binop::BINOP::LESSTHAN: + scasm_src3->set_cond(scasm::cond_code::L); + break; + case binop::BINOP::LESSTHANEQUAL: + scasm_src3->set_cond(scasm::cond_code::LE); + break; + case binop::BINOP::GREATERTHAN: + scasm_src3->set_cond(scasm::cond_code::G); + break; + case binop::BINOP::GREATERTHANEQUAL: + scasm_src3->set_cond(scasm::cond_code::GE); + break; + default: + break; + } + scasm_inst3->set_src(std::move(scasm_src3)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst3); + SET_DST(scasm_dst3); + scasm_inst3->set_dst(std::move(scasm_dst3)); + scasm_func->add_instruction(std::move(scasm_inst3)); + } else if (inst->get_binop() == binop::BINOP::DIV or + inst->get_binop() == binop::BINOP::MOD) { + // Mov(src1, Reg(AX)) + // Cdq + // Idiv(src2) + // Mov(Reg(AX), dst) | Mov(Reg(DX), dst) + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + scasm_dst->set_type(scasm::operand_type::REG); + scasm_dst->set_reg(scasm::register_type::AX); + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::CDQ); + scasm_func->add_instruction(std::move(scasm_inst2)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); + scasm_inst3->set_type(scasm::instruction_type::IDIV); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + if (inst->get_src2()->get_type() == scar::val_type::VAR) { + scasm_src2->set_type(scasm::operand_type::PSEUDO); + scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); + } else if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); + } + scasm_inst3->set_src(std::move(scasm_src2)); + scasm_func->add_instruction(std::move(scasm_inst3)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst4); + scasm_inst4->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + SET_DST(scasm_dst2); + scasm_inst4->set_dst(std::move(scasm_dst2)); + MAKE_SHARED(scasm::scasm_operand, scasm_src3); + scasm_src3->set_type(scasm::operand_type::REG); + if (inst->get_binop() == binop::BINOP::DIV) { + scasm_src3->set_reg(scasm::register_type::AX); + } else { + scasm_src3->set_reg(scasm::register_type::DX); + } + scasm_inst4->set_src(std::move(scasm_src3)); + scasm_func->add_instruction(std::move(scasm_inst4)); + } else if (inst->get_binop() == binop::BINOP::LEFT_SHIFT or + inst->get_binop() == binop::BINOP::RIGHT_SHIFT) { + // Mov(src1,dst) + // Mov(src2, Reg(CX)) + // Binary(binary operand, CL, dst) + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); + } else if (inst->get_src2()->get_type() == scar::val_type::VAR) { + scasm_src2->set_type(scasm::operand_type::PSEUDO); + scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); + } + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + scasm_dst2->set_type(scasm::operand_type::REG); + scasm_dst2->set_reg(scasm::register_type::CX); + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); + scasm_inst3->set_type(scasm::instruction_type::BINARY); + scasm_inst3->set_binop( + scasm::scar_binop_to_scasm_binop(inst->get_binop())); + MAKE_SHARED(scasm::scasm_operand, scasm_src3); + scasm_src3->set_type(scasm::operand_type::REG); + scasm_src3->set_reg(scasm::register_type::CL); + scasm_inst3->set_src(std::move(scasm_src3)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst3); + scasm_dst3->set_type(scasm::operand_type::PSEUDO); + scasm_dst3->set_identifier_stack(inst->get_dst()->get_reg()); + scasm_inst3->set_dst(std::move(scasm_dst3)); + scasm_func->add_instruction(std::move(scasm_inst3)); + + } else { + // Mov(src1, dst) + // Binary(binary_operator, src2, dst) + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::BINARY); + scasm_inst2->set_binop( + scasm::scar_binop_to_scasm_binop(inst->get_binop())); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + if (inst->get_src2()->get_type() == scar::val_type::VAR) { + scasm_src2->set_type(scasm::operand_type::PSEUDO); + scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); + } else if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); + } + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst2->set_type(scasm::operand_type::PSEUDO); + scasm_dst2->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + } + } else if (inst->get_type() == scar::instruction_type::COPY) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + SET_DST(scasm_dst); + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + } else if (inst->get_type() == scar::instruction_type::LABEL) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::LABEL); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + scasm_src->set_type(scasm::operand_type::LABEL); + scasm_src->set_identifier_stack(inst->get_src1()->get_value()); + scasm_inst->set_src(std::move(scasm_src)); + scasm_func->add_instruction(std::move(scasm_inst)); + } else if (inst->get_type() == scar::instruction_type::JUMP) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::JMP); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + scasm_src->set_type(scasm::operand_type::LABEL); + scasm_src->set_identifier_stack(inst->get_src1()->get_value()); + scasm_inst->set_src(std::move(scasm_src)); + scasm_func->add_instruction(std::move(scasm_inst)); + } else if (inst->get_type() == scar::instruction_type::JUMP_IF_ZERO or + inst->get_type() == scar::instruction_type::JUMP_IF_NOT_ZERO) { + // Cmp(Imm(0), condition) + // JmpCC(E, label) | JmpCC(NE, label) + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::CMP); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + scasm_src->set_type(scasm::operand_type::IMM); + scasm_src->set_imm(0); + scasm_inst->set_src(std::move(scasm_src)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + switch (inst->get_src1()->get_type()) { + case scar::val_type::VAR: + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); + break; + case scar::val_type::CONSTANT: + scasm_dst->set_type(scasm::operand_type::IMM); + scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); + break; + default: + break; + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::JMPCC); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + scasm_src2->set_type(scasm::operand_type::COND); + if (inst->get_type() == scar::instruction_type::JUMP_IF_ZERO) { + scasm_src2->set_cond(scasm::cond_code::E); + } else { + scasm_src2->set_cond(scasm::cond_code::NE); + } + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + scasm_dst2->set_type(scasm::operand_type::LABEL); + scasm_dst2->set_identifier_stack(inst->get_dst()->get_value()); + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + } + } + scasm_program.add_function(std::move(scasm_func)); + } + + this->scasm = scasm_program; +} + +} // namespace codegen +} // namespace scarlet