From e5de4b1adeb14d94d55573553f9043f0f12423cb Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 16 Jun 2024 16:01:26 +0800 Subject: [PATCH 01/84] Set up initial testing configuration for llvm --- main.cpp | 51 ++++++++++++++++++++++++++++------------- test/codegen/turnt.toml | 5 ++++ 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/main.cpp b/main.cpp index 55aadb5c..65054833 100644 --- a/main.cpp +++ b/main.cpp @@ -22,6 +22,12 @@ extern FILE* extern void yylex_destroy(); // NOLINT(readability-identifier-naming): extern // from flex generated code. +int QbeBuilder(std::unique_ptr program, std::string& input_basename, + std::string& output_name); + +int LlvmBuilder(std::unique_ptr program, std::string& input_basename, + std::string& output_name); + int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to // catch all exceptions isn't reasonable. int argc, char** argv) @@ -37,7 +43,7 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to ("o, output", "Write output to ", cxxopts::value()->default_value("a.out"), "") ("d, dump", "Dump the abstract syntax tree", cxxopts::value()->default_value("false")) // TODO: support LLVM IR - ("t, target", "Specify target IR", cxxopts::value()->default_value("qbe"), "[qbe]") + ("t, target", "Specify target IR", cxxopts::value()->default_value("qbe"), "[qbe|llvm]") ("h, help", "Display available options") ; // clang-format on @@ -93,8 +99,23 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to trans_unit->Accept(ast_dumper); } - // generate intermediate representation auto input_basename = input_path.stem().string(); + auto output = opts["output"].as(); + // generate intermediate representation based on target option + if (opts["target"].as() == "qbe") { + return QbeBuilder(std::move(program), input_basename, output); + } else if (opts["target"].as() == "llvm") { + return LlvmBuilder(std::move(program), input_basename, output); + } else { + std::cerr << "unknown target" << '\n'; + std::exit(0); + } + + return 0; +} + +int QbeBuilder(std::unique_ptr program, std::string& input_basename, + std::string& output_name) { auto output_ir = std::ofstream{fmt::format("{}.ssa", input_basename)}; QbeIrGenerator code_generator{output_ir}; trans_unit->Accept(code_generator); @@ -102,22 +123,15 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to output_ir.close(); // generate assembly - if (opts["target"].as() == "qbe") { - std::string qbe_command = - fmt::format("qbe -o {0}.s {0}.ssa", input_basename); - auto qbe_ret = std::system(qbe_command.c_str()); - // 0 on success, 1 otherwise - if (qbe_ret) { - return qbe_ret; - } - } else { - std::cerr << "unknown target" << '\n'; - std::exit(0); + std::string qbe_command = fmt::format("qbe -o {0}.s {0}.ssa", input_basename); + auto qbe_ret = std::system(qbe_command.c_str()); + // 0 on success, 1 otherwise + if (qbe_ret) { + return qbe_ret; } - // generate executable - auto output = opts["output"].as(); - std::string cc_command = fmt::format("cc -o {} {}.s", output, input_basename); + std::string cc_command = + fmt::format("cc -o {} {}.s", output_name, input_basename); auto cc_ret = std::system(cc_command.c_str()); // 0 on success, 1 otherwise if (cc_ret) { @@ -126,3 +140,8 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to return 0; } + +int LlvmBuilder(std::unique_ptr program, std::string& input_basename, + std::string& output_name) { + return 0; +} \ No newline at end of file diff --git a/test/codegen/turnt.toml b/test/codegen/turnt.toml index 4b19fcfc..8151219a 100644 --- a/test/codegen/turnt.toml +++ b/test/codegen/turnt.toml @@ -1,2 +1,7 @@ +[envs.qbe] command = """../../vitaminc -o {filename}.o {filename} && ./{filename}.o""" output.exp = "-" + +[envs.llvm] +command = """../../vitaminc --target llvm {filename}""" +return_code = 0 From 490766ba429b99fd049114016579618e9822f051 Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 16 Jun 2024 16:14:37 +0800 Subject: [PATCH 02/84] Create llvm IR generator --- include/llvm_ir_generator.hpp | 53 ++++++++++++++++++++++++ src/llvm_ir_generator.cpp | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 include/llvm_ir_generator.hpp create mode 100644 src/llvm_ir_generator.cpp diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp new file mode 100644 index 00000000..00cb996d --- /dev/null +++ b/include/llvm_ir_generator.hpp @@ -0,0 +1,53 @@ +#ifndef LLVM_IR_GENERATOR_HPP_ +#define LLVM_IR_GENERATOR_HPP_ + +#include "ast.hpp" +#include "visitor.hpp" + +class LLVMIRGenerator : public NonModifyingVisitor { + public: + void Visit(const DeclStmtNode&) override; + void Visit(const LoopInitNode&) override; + void Visit(const VarDeclNode&) override; + void Visit(const ArrDeclNode&) override; + void Visit(const RecordDeclNode&) override; + void Visit(const FieldNode&) override; + void Visit(const RecordVarDeclNode&) override; + void Visit(const ParamNode&) override; + void Visit(const FuncDefNode&) override; + void Visit(const CompoundStmtNode&) override; + void Visit(const ProgramNode&) override; + void Visit(const IfStmtNode&) override; + void Visit(const WhileStmtNode&) override; + void Visit(const ForStmtNode&) override; + void Visit(const ReturnStmtNode&) override; + void Visit(const GotoStmtNode&) override; + void Visit(const BreakStmtNode&) override; + void Visit(const ContinueStmtNode&) override; + void Visit(const SwitchStmtNode&) override; + void Visit(const IdLabeledStmtNode&) override; + void Visit(const CaseStmtNode&) override; + void Visit(const DefaultStmtNode&) override; + void Visit(const ExprStmtNode&) override; + void Visit(const InitExprNode&) override; + void Visit(const ArrDesNode&) override; + void Visit(const IdDesNode&) override; + void Visit(const NullExprNode&) override; + void Visit(const IdExprNode&) override; + void Visit(const IntConstExprNode&) override; + void Visit(const ArgExprNode&) override; + void Visit(const ArrSubExprNode&) override; + void Visit(const CondExprNode&) override; + void Visit(const FuncCallExprNode&) override; + void Visit(const PostfixArithExprNode&) override; + void Visit(const UnaryExprNode&) override; + void Visit(const BinaryExprNode&) override; + void Visit(const SimpleAssignmentExprNode&) override; + + LLVMIRGenerator(std::ostream& output) : output_{output} {} + + private: + std::ostream& output_; +}; + +#endif // LLVM_IR_GENERATOR_HPP_ \ No newline at end of file diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp new file mode 100644 index 00000000..d8afbc47 --- /dev/null +++ b/src/llvm_ir_generator.cpp @@ -0,0 +1,78 @@ +#include "llvm_ir_generator.hpp" + +#include "ast.hpp" +#include "llvm/builder.hpp" + +void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) {} + +void LLVMIRGenerator::Visit(const VarDeclNode& decl) {} + +void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) {} + +void LLVMIRGenerator::Visit(const RecordDeclNode& struct_def) {} + +void LLVMIRGenerator::Visit(const FieldNode& field) {} + +void LLVMIRGenerator::Visit(const RecordVarDeclNode& struct_def) {} + +void LLVMIRGenerator::Visit(const ParamNode& parameter) {} + +void LLVMIRGenerator::Visit(const FuncDefNode& func_def) {} + +void LLVMIRGenerator::Visit(const LoopInitNode& loop_init) {} + +void LLVMIRGenerator::Visit(const CompoundStmtNode& compound_stmt) {} + +void LLVMIRGenerator::Visit(const ProgramNode& program) {} + +void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) {} + +void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) {} + +void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) {} + +void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) {} + +void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) {} + +void LLVMIRGenerator::Visit(const BreakStmtNode& break_stmt) {} + +void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) {} + +void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) {} + +void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) {} + +void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) {} + +void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) {} + +void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) {} + +void LLVMIRGenerator::Visit(const InitExprNode& init_expr) {} + +void LLVMIRGenerator::Visit(const ArrDesNode& arr_des) {} + +void LLVMIRGenerator::Visit(const IdDesNode& id_des) {} + +void LLVMIRGenerator::Visit(const NullExprNode& null_expr) {} + +void LLVMIRGenerator::Visit(const IdExprNode& id_expr) {} + +void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) {} + +void LLVMIRGenerator::Visit(const ArgExprNode& arg_expr) {} + +void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) {} + +void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) {} + +void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) {} + +void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) {} + +void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) {} + +void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) {} + +void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) {} From c312c58165d300c4b595a4810a0bf8d4b8faf837 Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 16 Jun 2024 20:51:21 +0800 Subject: [PATCH 03/84] Write LLVM IR to files --- .gitignore | 3 +++ Makefile | 6 +++--- include/llvm_ir_generator.hpp | 27 +++++++++++++++++++++++++-- main.cpp | 15 ++++++++++++--- src/llvm_ir_generator.cpp | 28 +++++++++++++++++++++++++--- test/Makefile | 2 +- 6 files changed, 69 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index f87af72a..1502847e 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,9 @@ lex.yy.* # QBE IR files *.ssa +# LLVM IR files +*.ll + # Python environments .env .venv diff --git a/Makefile b/Makefile index 08432335..f58578a2 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ TARGET := vitaminc CXX := g++ CC = $(CXX) CLANG_TIDY ?= clang-tidy -CXXFLAGS = -g3 -std=c++17 -Wall -MMD -Iinclude -Werror +CXXFLAGS = -g3 -std=c++17 -Wall -MMD -Iinclude $(llvm-config --cxxflags) -I/usr/lib/llvm-18/include -Werror CFLAGS = $(CXXFLAGS) -LDLIBS = -lfmt +LDLIBS = -lfmt -lLLVM-18 LEX = lex # C++ features are used, yacc doesn't suffice YACC = bison @@ -87,7 +87,7 @@ coverage-report: coverage @echo "Open $(COVERAGE_DIR)/index.html in your browser to view the coverage report." clean: - $(RM) -r *.s *.o lex.yy.* y.tab.* *.output *.ssa *.out $(TARGET) $(OBJS) $(DEPS) \ + $(RM) -r *.s *.o lex.yy.* y.tab.* *.output *.ssa *.out *.ll $(TARGET) $(OBJS) $(DEPS) \ $(OBJS:.o=.gcda) $(OBJS:.o=.gcno) *.gcov $(COVERAGE_DIR) cd test/ && $(MAKE) clean diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 00cb996d..c6f3c5ef 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -1,6 +1,13 @@ #ifndef LLVM_IR_GENERATOR_HPP_ #define LLVM_IR_GENERATOR_HPP_ +#include +#include + +#include +#include +#include + #include "ast.hpp" #include "visitor.hpp" @@ -44,10 +51,26 @@ class LLVMIRGenerator : public NonModifyingVisitor { void Visit(const BinaryExprNode&) override; void Visit(const SimpleAssignmentExprNode&) override; - LLVMIRGenerator(std::ostream& output) : output_{output} {} + LLVMIRGenerator(std::ostream& output, std::string& filename) + : output_{output}, + context_{std::make_unique()}, + builder_{llvm::IRBuilder<>(*context_)}, + module_{std::make_unique(filename, *context_)} {} + + /// @brief Print LLVM IR to output_. + void PrintIR() { + module_->print(output_, nullptr); + } private: - std::ostream& output_; + /// @brief A LLVM ostream wrapper for writing to output. + llvm::raw_os_ostream output_; + /// @brief A LLVM core object. + std::unique_ptr context_; + /// @brief Provides LLVM Builder API for constructing IR. + llvm::IRBuilder<> builder_; + /// @brief Stores LLVM related information, including the constructed IR. + std::unique_ptr module_; }; #endif // LLVM_IR_GENERATOR_HPP_ \ No newline at end of file diff --git a/main.cpp b/main.cpp index 65054833..a32b202e 100644 --- a/main.cpp +++ b/main.cpp @@ -10,6 +10,7 @@ #include "ast.hpp" #include "ast_dumper.hpp" +#include "llvm_ir_generator.hpp" #include "qbe_ir_generator.hpp" #include "scope.hpp" #include "type_checker.hpp" @@ -25,7 +26,7 @@ extern void yylex_destroy(); // NOLINT(readability-identifier-naming): extern int QbeBuilder(std::unique_ptr program, std::string& input_basename, std::string& output_name); -int LlvmBuilder(std::unique_ptr program, std::string& input_basename, +int LLVMBuilder(std::unique_ptr program, std::string& input_basename, std::string& output_name); int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to @@ -105,7 +106,7 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to if (opts["target"].as() == "qbe") { return QbeBuilder(std::move(program), input_basename, output); } else if (opts["target"].as() == "llvm") { - return LlvmBuilder(std::move(program), input_basename, output); + return LLVMBuilder(std::move(program), input_basename, output); } else { std::cerr << "unknown target" << '\n'; std::exit(0); @@ -141,7 +142,15 @@ int QbeBuilder(std::unique_ptr program, std::string& input_basename, return 0; } -int LlvmBuilder(std::unique_ptr program, std::string& input_basename, +int LLVMBuilder(std::unique_ptr program, std::string& input_basename, std::string& output_name) { + auto output_ir = std::ofstream{fmt::format("{}.ll", input_basename)}; + LLVMIRGenerator code_generator{output_ir, input_basename}; + program->Accept(code_generator); + // TODO: Write to stdout based on cxxopts. + // Write LLVM IR to output file "*.ll". + code_generator.PrintIR(); + + output_ir.close(); return 0; } \ No newline at end of file diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index d8afbc47..51d9dfa0 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -1,7 +1,10 @@ #include "llvm_ir_generator.hpp" +#include + #include "ast.hpp" -#include "llvm/builder.hpp" + +using namespace llvm; void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) {} @@ -17,13 +20,32 @@ void LLVMIRGenerator::Visit(const RecordVarDeclNode& struct_def) {} void LLVMIRGenerator::Visit(const ParamNode& parameter) {} -void LLVMIRGenerator::Visit(const FuncDefNode& func_def) {} +void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { + auto i32 = builder_.getInt32Ty(); + auto prototype = FunctionType::get(i32, false); + Function* fn = Function::Create(prototype, Function::ExternalLinkage, + func_def.id, module_.get()); + BasicBlock* body = BasicBlock::Create(*context_, "body", fn); + builder_.SetInsertPoint(body); +} void LLVMIRGenerator::Visit(const LoopInitNode& loop_init) {} void LLVMIRGenerator::Visit(const CompoundStmtNode& compound_stmt) {} -void LLVMIRGenerator::Visit(const ProgramNode& program) {} +void LLVMIRGenerator::Visit(const ProgramNode& program) { + // Generate builtin print function. + auto i32 = builder_.getInt32Ty(); + auto prototype = FunctionType::get(i32, false); + Function* main_fn = Function::Create(prototype, Function::ExternalLinkage, + "__builtin_print__", module_.get()); + BasicBlock* body = BasicBlock::Create(*context_, "body", main_fn); + builder_.SetInsertPoint(body); + + for (const auto& func_def : program.func_def_list) { + func_def->Accept(*this); + } +} void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) {} diff --git a/test/Makefile b/test/Makefile index 3213094e..b0473c3f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -14,4 +14,4 @@ test: clean: - rm -f *.s **/*.s *.o **/*.o *.ssa **/*.ssa + rm -f *.s **/*.s *.o **/*.o *.ssa **/*.ssa **/*.ll From 3e90edce3899a7e0d29c3e280c591ff5ea8e0078 Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 18 Jun 2024 17:12:06 +0800 Subject: [PATCH 04/84] Generate return statement and constant expression LLVM IR --- src/llvm_ir_generator.cpp | 72 +++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 51d9dfa0..7728e26e 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -2,11 +2,42 @@ #include +#include + #include "ast.hpp" +namespace { + +/// @brief Store LLVM Value class at the bottom level of AST node. Upper level +/// AST node can use the information in Value directly. +class PrevValueRecorder { + public: + void Record(llvm::Value* val) { + prev_val_ = val; + } + + llvm::Value* ValOfPrevExpr() { + return prev_val_; + } + + private: + llvm::Value* prev_val_; +}; + +auto + val_recorder // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): + // Accessible only within this translation unit; declaring as + // a data member introduces unnecessary dependency. + = PrevValueRecorder{}; +} // namespace + using namespace llvm; -void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) {} +void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { + for (const auto& decl : decl_stmt.decls) { + decl->Accept(*this); + } +} void LLVMIRGenerator::Visit(const VarDeclNode& decl) {} @@ -23,24 +54,33 @@ void LLVMIRGenerator::Visit(const ParamNode& parameter) {} void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { auto i32 = builder_.getInt32Ty(); auto prototype = FunctionType::get(i32, false); - Function* fn = Function::Create(prototype, Function::ExternalLinkage, - func_def.id, module_.get()); - BasicBlock* body = BasicBlock::Create(*context_, "body", fn); + auto* fn = Function::Create(prototype, + func_def.id == "main" ? Function::ExternalLinkage + : Function::InternalLinkage, + func_def.id, module_.get()); + auto* body = BasicBlock::Create(*context_, "body", fn); builder_.SetInsertPoint(body); + func_def.body->Accept(*this); } void LLVMIRGenerator::Visit(const LoopInitNode& loop_init) {} -void LLVMIRGenerator::Visit(const CompoundStmtNode& compound_stmt) {} +void LLVMIRGenerator::Visit(const CompoundStmtNode& compound_stmt) { + for (const auto& stmt : compound_stmt.stmts) { + stmt->Accept(*this); + } +} void LLVMIRGenerator::Visit(const ProgramNode& program) { // Generate builtin print function. auto i32 = builder_.getInt32Ty(); auto prototype = FunctionType::get(i32, false); - Function* main_fn = Function::Create(prototype, Function::ExternalLinkage, - "__builtin_print__", module_.get()); - BasicBlock* body = BasicBlock::Create(*context_, "body", main_fn); + auto* main_fn = Function::Create(prototype, Function::ExternalLinkage, + "__builtin_print__", module_.get()); + auto* body = BasicBlock::Create(*context_, "body", main_fn); builder_.SetInsertPoint(body); + // Every basic block must have terminator instruction. + builder_.CreateUnreachable(); for (const auto& func_def : program.func_def_list) { func_def->Accept(*this); @@ -53,7 +93,13 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) {} void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) {} -void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) {} +void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { + ret_stmt.expr->Accept(*this); + auto i32 = builder_.getInt32Ty(); + auto* expr = val_recorder.ValOfPrevExpr(); + auto* ret = builder_.CreateLoad(i32, expr); + builder_.CreateRet(ret); +} void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) {} @@ -81,7 +127,13 @@ void LLVMIRGenerator::Visit(const NullExprNode& null_expr) {} void LLVMIRGenerator::Visit(const IdExprNode& id_expr) {} -void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) {} +void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { + auto i32 = builder_.getInt32Ty(); + auto* addr = builder_.CreateAlloca(i32); + auto* val = ConstantInt::get(i32, int_expr.val, true); + builder_.CreateStore(val, addr); + val_recorder.Record(addr); +} void LLVMIRGenerator::Visit(const ArgExprNode& arg_expr) {} From ef1879cc59a9f2bac7c7bb3945c5564a79007d70 Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 18 Jun 2024 17:48:35 +0800 Subject: [PATCH 05/84] Integrate lli for testing LLVM IR --- .gitignore | 3 +++ src/llvm_ir_generator.cpp | 7 ++++--- src/type_checker.cpp | 10 ++++++++++ test/Makefile | 2 +- test/codegen/turnt.toml | 2 +- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 1502847e..c3a45a7e 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,9 @@ lex.yy.* # QBE IR files *.ssa +# LLVM test source files +*_llvm.c + # LLVM IR files *.ll diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 7728e26e..cd285071 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -75,9 +75,10 @@ void LLVMIRGenerator::Visit(const ProgramNode& program) { // Generate builtin print function. auto i32 = builder_.getInt32Ty(); auto prototype = FunctionType::get(i32, false); - auto* main_fn = Function::Create(prototype, Function::ExternalLinkage, - "__builtin_print__", module_.get()); - auto* body = BasicBlock::Create(*context_, "body", main_fn); + auto* printf_fn = Function::Create(prototype, Function::ExternalLinkage, + "printf", module_.get()); + + auto* body = BasicBlock::Create(*context_, "body", printf_fn); builder_.SetInsertPoint(body); // Every basic block must have terminator instruction. builder_.CreateUnreachable(); diff --git a/src/type_checker.cpp b/src/type_checker.cpp index 792adbf5..d21006c0 100644 --- a/src/type_checker.cpp +++ b/src/type_checker.cpp @@ -236,6 +236,7 @@ void TypeChecker::Visit(CompoundStmtNode& compound_stmt) { void TypeChecker::InstallBuiltins_(ScopeStack& env) { // The supported builtins are: // - int __builtin_print(int) + // - int printf(int) auto param_types = std::vector>{}; param_types.emplace_back(std::make_unique(PrimitiveType::kInt)); @@ -244,6 +245,15 @@ void TypeChecker::InstallBuiltins_(ScopeStack& env) { std::make_unique(PrimitiveType::kInt), std::move(param_types))); env.AddSymbol(std::move(symbol), ScopeKind::kFile); + + auto param_types_printf = std::vector>{}; + param_types_printf.emplace_back( + std::make_unique(PrimitiveType::kInt)); + auto symbol_printf = std::make_unique( + "printf", std::make_unique( + std::make_unique(PrimitiveType::kInt), + std::move(param_types_printf))); + env.AddSymbol(std::move(symbol_printf), ScopeKind::kFile); } void TypeChecker::Visit(ExternDeclNode& extern_decl) { diff --git a/test/Makefile b/test/Makefile index b0473c3f..72062717 100644 --- a/test/Makefile +++ b/test/Makefile @@ -14,4 +14,4 @@ test: clean: - rm -f *.s **/*.s *.o **/*.o *.ssa **/*.ssa **/*.ll + rm -f *.s **/*.s *.o **/*.o *.ssa **/*.ssa **/*.ll **/*_llvm.c diff --git a/test/codegen/turnt.toml b/test/codegen/turnt.toml index 8151219a..5962eacf 100644 --- a/test/codegen/turnt.toml +++ b/test/codegen/turnt.toml @@ -3,5 +3,5 @@ command = """../../vitaminc -o {filename}.o {filename} && ./{filename}.o""" output.exp = "-" [envs.llvm] -command = """../../vitaminc --target llvm {filename}""" +command = """sed 's/__builtin_print/printf/g' {filename} > {filename}_llvm.c ; ../../vitaminc --target llvm {filename}_llvm.c && lli-18 {filename}.ll""" return_code = 0 From eca3d05add490c2ecb33a82ccf54a646e887246a Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 22 Jun 2024 15:33:57 +0800 Subject: [PATCH 06/84] Update turnt config file and printf with parameter --- src/llvm_ir_generator.cpp | 15 +++++++-------- test/codegen/turnt.toml | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index cd285071..f875cbe4 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -74,14 +74,13 @@ void LLVMIRGenerator::Visit(const CompoundStmtNode& compound_stmt) { void LLVMIRGenerator::Visit(const ProgramNode& program) { // Generate builtin print function. auto i32 = builder_.getInt32Ty(); - auto prototype = FunctionType::get(i32, false); - auto* printf_fn = Function::Create(prototype, Function::ExternalLinkage, - "printf", module_.get()); - - auto* body = BasicBlock::Create(*context_, "body", printf_fn); - builder_.SetInsertPoint(body); - // Every basic block must have terminator instruction. - builder_.CreateUnreachable(); + // pointer to char + auto ptr = builder_.getPtrTy(); + std::vector params; + params.push_back(ptr); + auto prototype = FunctionType::get(i32, params, true); + Function::Create(prototype, Function::ExternalLinkage, "printf", + module_.get()); for (const auto& func_def : program.func_def_list) { func_def->Accept(*this); diff --git a/test/codegen/turnt.toml b/test/codegen/turnt.toml index 5962eacf..c3baf00d 100644 --- a/test/codegen/turnt.toml +++ b/test/codegen/turnt.toml @@ -1,7 +1,7 @@ [envs.qbe] -command = """../../vitaminc -o {filename}.o {filename} && ./{filename}.o""" +command = """../../vitaminc -o {base}.o {filename} && ./{base}.o""" output.exp = "-" [envs.llvm] -command = """sed 's/__builtin_print/printf/g' {filename} > {filename}_llvm.c ; ../../vitaminc --target llvm {filename}_llvm.c && lli-18 {filename}.ll""" +command = """sed 's/__builtin_print/printf/g' {filename} > {base}_llvm.c ; ../../vitaminc --target llvm {base}_llvm.c && lli-18 {base}.ll""" return_code = 0 From fcc58384f5d25688c799752fb5e08bfc451c5de0 Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 22 Jun 2024 16:02:26 +0800 Subject: [PATCH 07/84] Handle simple binary expression --- src/llvm_ir_generator.cpp | 89 ++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 16 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index f875cbe4..3473b862 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -8,6 +8,30 @@ namespace { +llvm::Instruction::BinaryOps GetBinaryOperator(BinaryOperator op) { + switch (op) { + case BinaryOperator::kAdd: + return llvm::BinaryOperator::Add; + case BinaryOperator::kSub: + return llvm::BinaryOperator::Sub; + case BinaryOperator::kMul: + return llvm::BinaryOperator::Mul; + case BinaryOperator::kDiv: + return llvm::BinaryOperator::SDiv; + case BinaryOperator::kMod: + return llvm::BinaryOperator::SRem; + case BinaryOperator::kAnd: + return llvm::BinaryOperator::And; + case BinaryOperator::kXor: + return llvm::BinaryOperator::Xor; + case BinaryOperator::kOr: + return llvm::BinaryOperator::Or; + default: + // TODO + return llvm::BinaryOperator::Xor; + } +} + /// @brief Store LLVM Value class at the bottom level of AST node. Upper level /// AST node can use the information in Value directly. class PrevValueRecorder { @@ -31,8 +55,6 @@ auto = PrevValueRecorder{}; } // namespace -using namespace llvm; - void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { for (const auto& decl : decl_stmt.decls) { decl->Accept(*this); @@ -53,12 +75,13 @@ void LLVMIRGenerator::Visit(const ParamNode& parameter) {} void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { auto i32 = builder_.getInt32Ty(); - auto prototype = FunctionType::get(i32, false); - auto* fn = Function::Create(prototype, - func_def.id == "main" ? Function::ExternalLinkage - : Function::InternalLinkage, - func_def.id, module_.get()); - auto* body = BasicBlock::Create(*context_, "body", fn); + auto prototype = llvm::FunctionType::get(i32, false); + auto* fn = llvm::Function::Create(prototype, + func_def.id == "main" + ? llvm::Function::ExternalLinkage + : llvm::Function::InternalLinkage, + func_def.id, module_.get()); + auto* body = llvm::BasicBlock::Create(*context_, "body", fn); builder_.SetInsertPoint(body); func_def.body->Accept(*this); } @@ -78,9 +101,9 @@ void LLVMIRGenerator::Visit(const ProgramNode& program) { auto ptr = builder_.getPtrTy(); std::vector params; params.push_back(ptr); - auto prototype = FunctionType::get(i32, params, true); - Function::Create(prototype, Function::ExternalLinkage, "printf", - module_.get()); + auto prototype = llvm::FunctionType::get(i32, params, true); + llvm::Function::Create(prototype, llvm::Function::ExternalLinkage, "printf", + module_.get()); for (const auto& func_def : program.func_def_list) { func_def->Accept(*this); @@ -115,7 +138,9 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) {} void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) {} -void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) {} +void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) { + expr_stmt.expr->Accept(*this); +} void LLVMIRGenerator::Visit(const InitExprNode& init_expr) {} @@ -130,23 +155,55 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) {} void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { auto i32 = builder_.getInt32Ty(); auto* addr = builder_.CreateAlloca(i32); - auto* val = ConstantInt::get(i32, int_expr.val, true); + auto* val = llvm::ConstantInt::get(i32, int_expr.val, true); builder_.CreateStore(val, addr); val_recorder.Record(addr); } -void LLVMIRGenerator::Visit(const ArgExprNode& arg_expr) {} +void LLVMIRGenerator::Visit(const ArgExprNode& arg_expr) { + arg_expr.arg->Accept(*this); +} void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) {} void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) {} -void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) {} +void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { + call_expr.func_expr->Accept(*this); + + // Evaluate the arguments. + std::vector arg_vals{}; + for (const auto& arg : call_expr.args) { + arg->Accept(*this); + auto* arg_val = val_recorder.ValOfPrevExpr(); + arg_vals.push_back(arg_val); + } +} void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) {} void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) {} -void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) {} +void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { + bin_expr.lhs->Accept(*this); + auto* lhs = val_recorder.ValOfPrevExpr(); + + if (bin_expr.op == BinaryOperator::kComma) { + // For the comma operator, the value of its left operand is not used and can + // be eliminated if it has no side effects or if its definition is + // immediately dead. However, we leave these optimizations to QBE. + bin_expr.rhs->Accept(*this); + auto* rhs = val_recorder.ValOfPrevExpr(); + val_recorder.Record(rhs); + return; + } + if (bin_expr.op == BinaryOperator::kLand || + bin_expr.op == BinaryOperator::kLor) { + // TODO + } else { + auto* rhs = val_recorder.ValOfPrevExpr(); + builder_.CreateBinOp(GetBinaryOperator(bin_expr.op), lhs, rhs); + } +} void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) {} From 2975b36b8d535c3529c42c523ddd42d765a6c5e5 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 24 Jun 2024 16:30:05 +0800 Subject: [PATCH 08/84] Update TransUnitNode and ExternDeclNode --- include/llvm_ir_generator.hpp | 3 ++- main.cpp | 12 ++++++------ src/llvm_ir_generator.cpp | 10 +++++++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index c6f3c5ef..8c06e6d5 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -23,7 +23,8 @@ class LLVMIRGenerator : public NonModifyingVisitor { void Visit(const ParamNode&) override; void Visit(const FuncDefNode&) override; void Visit(const CompoundStmtNode&) override; - void Visit(const ProgramNode&) override; + void Visit(const TransUnitNode&) override; + void Visit(const ExternDeclNode&) override; void Visit(const IfStmtNode&) override; void Visit(const WhileStmtNode&) override; void Visit(const ForStmtNode&) override; diff --git a/main.cpp b/main.cpp index a32b202e..664f025c 100644 --- a/main.cpp +++ b/main.cpp @@ -104,9 +104,9 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to auto output = opts["output"].as(); // generate intermediate representation based on target option if (opts["target"].as() == "qbe") { - return QbeBuilder(std::move(program), input_basename, output); + return QbeBuilder(std::move(trans_unit), input_basename, output); } else if (opts["target"].as() == "llvm") { - return LLVMBuilder(std::move(program), input_basename, output); + return LLVMBuilder(std::move(trans_unit), input_basename, output); } else { std::cerr << "unknown target" << '\n'; std::exit(0); @@ -115,7 +115,7 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to return 0; } -int QbeBuilder(std::unique_ptr program, std::string& input_basename, +int QbeBuilder(std::unique_ptr trans_unit, std::string& input_basename, std::string& output_name) { auto output_ir = std::ofstream{fmt::format("{}.ssa", input_basename)}; QbeIrGenerator code_generator{output_ir}; @@ -142,11 +142,11 @@ int QbeBuilder(std::unique_ptr program, std::string& input_basename, return 0; } -int LLVMBuilder(std::unique_ptr program, std::string& input_basename, - std::string& output_name) { +int LLVMBuilder(std::unique_ptr trans_unit, + std::string& input_basename, std::string& output_name) { auto output_ir = std::ofstream{fmt::format("{}.ll", input_basename)}; LLVMIRGenerator code_generator{output_ir, input_basename}; - program->Accept(code_generator); + trans_unit->Accept(code_generator); // TODO: Write to stdout based on cxxopts. // Write LLVM IR to output file "*.ll". code_generator.PrintIR(); diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 3473b862..17159884 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -93,8 +93,12 @@ void LLVMIRGenerator::Visit(const CompoundStmtNode& compound_stmt) { stmt->Accept(*this); } } +void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { + std::visit([this](auto&& extern_decl) { extern_decl->Accept(*this); }, + extern_decl.decl); +} -void LLVMIRGenerator::Visit(const ProgramNode& program) { +void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. auto i32 = builder_.getInt32Ty(); // pointer to char @@ -105,8 +109,8 @@ void LLVMIRGenerator::Visit(const ProgramNode& program) { llvm::Function::Create(prototype, llvm::Function::ExternalLinkage, "printf", module_.get()); - for (const auto& func_def : program.func_def_list) { - func_def->Accept(*this); + for (const auto& extern_decl : trans_unit.extern_decls) { + extern_decl->Accept(*this); } } From c3603aad92b0e62d2c35c588062d583d1185d44a Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 24 Jun 2024 17:48:02 +0800 Subject: [PATCH 09/84] Insert __builtin_print_format global variable --- include/llvm_ir_generator.hpp | 6 +++--- src/llvm_ir_generator.cpp | 11 ++--------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 8c06e6d5..924cfcca 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -56,11 +56,11 @@ class LLVMIRGenerator : public NonModifyingVisitor { : output_{output}, context_{std::make_unique()}, builder_{llvm::IRBuilder<>(*context_)}, - module_{std::make_unique(filename, *context_)} {} + module_{llvm::Module(filename, *context_)} {} /// @brief Print LLVM IR to output_. void PrintIR() { - module_->print(output_, nullptr); + module_.print(output_, nullptr); } private: @@ -71,7 +71,7 @@ class LLVMIRGenerator : public NonModifyingVisitor { /// @brief Provides LLVM Builder API for constructing IR. llvm::IRBuilder<> builder_; /// @brief Stores LLVM related information, including the constructed IR. - std::unique_ptr module_; + llvm::Module module_; }; #endif // LLVM_IR_GENERATOR_HPP_ \ No newline at end of file diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 17159884..1057b6cf 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -80,7 +80,7 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { func_def.id == "main" ? llvm::Function::ExternalLinkage : llvm::Function::InternalLinkage, - func_def.id, module_.get()); + func_def.id, &module_); auto* body = llvm::BasicBlock::Create(*context_, "body", fn); builder_.SetInsertPoint(body); func_def.body->Accept(*this); @@ -100,14 +100,7 @@ void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. - auto i32 = builder_.getInt32Ty(); - // pointer to char - auto ptr = builder_.getPtrTy(); - std::vector params; - params.push_back(ptr); - auto prototype = llvm::FunctionType::get(i32, params, true); - llvm::Function::Create(prototype, llvm::Function::ExternalLinkage, "printf", - module_.get()); + builder_.CreateGlobalStringPtr("%d\n", "__builtin_print_format", 0, &module_); for (const auto& extern_decl : trans_unit.extern_decls) { extern_decl->Accept(*this); From 9e85f46af4595fd5cf0cb02ae3e07d8399481b07 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 24 Jun 2024 22:04:26 +0800 Subject: [PATCH 10/84] Print output with llvm interpreter --- include/llvm_ir_generator.hpp | 6 +-- src/llvm_ir_generator.cpp | 79 +++++++++++++++++++++++++++++------ test/codegen/turnt.toml | 4 +- 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 924cfcca..d156c619 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -56,11 +56,11 @@ class LLVMIRGenerator : public NonModifyingVisitor { : output_{output}, context_{std::make_unique()}, builder_{llvm::IRBuilder<>(*context_)}, - module_{llvm::Module(filename, *context_)} {} + module_{new llvm::Module(filename, *context_)} {} /// @brief Print LLVM IR to output_. void PrintIR() { - module_.print(output_, nullptr); + module_->print(output_, nullptr); } private: @@ -71,7 +71,7 @@ class LLVMIRGenerator : public NonModifyingVisitor { /// @brief Provides LLVM Builder API for constructing IR. llvm::IRBuilder<> builder_; /// @brief Stores LLVM related information, including the constructed IR. - llvm::Module module_; + llvm::Module* module_; }; #endif // LLVM_IR_GENERATOR_HPP_ \ No newline at end of file diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 1057b6cf..6359e9da 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -1,6 +1,8 @@ #include "llvm_ir_generator.hpp" +#include #include +#include #include @@ -80,7 +82,7 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { func_def.id == "main" ? llvm::Function::ExternalLinkage : llvm::Function::InternalLinkage, - func_def.id, &module_); + func_def.id, module_); auto* body = llvm::BasicBlock::Create(*context_, "body", fn); builder_.SetInsertPoint(body); func_def.body->Accept(*this); @@ -100,7 +102,19 @@ void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. - builder_.CreateGlobalStringPtr("%d\n", "__builtin_print_format", 0, &module_); + auto i32 = builder_.getInt32Ty(); + auto arg = llvm::ArrayRef{i32}; + auto builtin_print = llvm::FunctionType::get(i32, arg, false); + llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, + "__builtin_print", module_); + + auto ptrTy = builder_.getPtrTy(); + auto args = llvm::ArrayRef{ptrTy, i32}; + auto printf = llvm::FunctionType::get(i32, args, false); + llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", + module_); + + builder_.CreateGlobalString("%d\n", "__builtin_print_format", 0, module_); for (const auto& extern_decl : trans_unit.extern_decls) { extern_decl->Accept(*this); @@ -115,10 +129,8 @@ void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) {} void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { ret_stmt.expr->Accept(*this); - auto i32 = builder_.getInt32Ty(); - auto* expr = val_recorder.ValOfPrevExpr(); - auto* ret = builder_.CreateLoad(i32, expr); - builder_.CreateRet(ret); + auto expr = val_recorder.ValOfPrevExpr(); + builder_.CreateRet(expr); } void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) {} @@ -147,16 +159,25 @@ void LLVMIRGenerator::Visit(const IdDesNode& id_des) {} void LLVMIRGenerator::Visit(const NullExprNode& null_expr) {} -void LLVMIRGenerator::Visit(const IdExprNode& id_expr) {} +void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { + if (id_expr.type->IsFunc()) { + auto* func = module_->getFunction(id_expr.id); + assert(func); + val_recorder.Record(func); + return; + } +} void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { auto i32 = builder_.getInt32Ty(); - auto* addr = builder_.CreateAlloca(i32); - auto* val = llvm::ConstantInt::get(i32, int_expr.val, true); - builder_.CreateStore(val, addr); - val_recorder.Record(addr); + auto addr = builder_.CreateAlloca(i32); + auto constant = llvm::ConstantInt::get(i32, int_expr.val, true); + builder_.CreateStore(constant, addr); + auto val = builder_.CreateLoad(i32, addr); + val_recorder.Record(val); } +// builtin_print call void LLVMIRGenerator::Visit(const ArgExprNode& arg_expr) { arg_expr.arg->Accept(*this); } @@ -167,19 +188,53 @@ void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) {} void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { call_expr.func_expr->Accept(*this); + auto val = val_recorder.ValOfPrevExpr(); + auto func = llvm::dyn_cast(val); + assert(func); // Evaluate the arguments. std::vector arg_vals{}; for (const auto& arg : call_expr.args) { arg->Accept(*this); auto* arg_val = val_recorder.ValOfPrevExpr(); + llvm::outs() << arg_val->getName(); arg_vals.push_back(arg_val); } + if (func->getName() == "__builtin_print") { + // builtin_print call + auto printf = module_->getFunction("printf"); + assert(printf); + std::vector print_args{}; + // NOTE: set AllowInternal as true to get internal linkage global variable + auto print_format = + module_->getGlobalVariable("__builtin_print_format", true); + assert(print_format); + print_args.push_back(print_format); + print_args.insert(print_args.end(), arg_vals.begin(), arg_vals.end()); + builder_.CreateCall(printf, print_args); + } else { + } } void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) {} -void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) {} +void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { + unary_expr.operand->Accept(*this); + switch (unary_expr.op) { + case UnaryOperator::kPos: + /* Do nothing. */ + break; + case UnaryOperator::kNeg: { + auto val = val_recorder.ValOfPrevExpr(); + auto i32 = builder_.getInt32Ty(); + auto zero = llvm::ConstantInt::get(i32, 0, true); + auto res = builder_.CreateBinOp(llvm::BinaryOperator::Sub, zero, val); + val_recorder.Record(res); + } break; + default: + break; + } +} void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { bin_expr.lhs->Accept(*this); diff --git a/test/codegen/turnt.toml b/test/codegen/turnt.toml index c3baf00d..6e0e9899 100644 --- a/test/codegen/turnt.toml +++ b/test/codegen/turnt.toml @@ -3,5 +3,5 @@ command = """../../vitaminc -o {base}.o {filename} && ./{base}.o""" output.exp = "-" [envs.llvm] -command = """sed 's/__builtin_print/printf/g' {filename} > {base}_llvm.c ; ../../vitaminc --target llvm {base}_llvm.c && lli-18 {base}.ll""" -return_code = 0 +command = """../../vitaminc --target llvm {filename} && lli-18 {base}.ll""" +output.exp = "-" From c903cc96778a193db9317995b3fb4b1c786c31fd Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 24 Jun 2024 22:28:26 +0800 Subject: [PATCH 11/84] Simplify IntConstExprNode by returning integer const directly --- src/llvm_ir_generator.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 6359e9da..1de51a20 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -170,10 +170,7 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { auto i32 = builder_.getInt32Ty(); - auto addr = builder_.CreateAlloca(i32); - auto constant = llvm::ConstantInt::get(i32, int_expr.val, true); - builder_.CreateStore(constant, addr); - auto val = builder_.CreateLoad(i32, addr); + auto val = llvm::ConstantInt::get(i32, int_expr.val, true); val_recorder.Record(val); } From df0f59a5999459f27e9e73ca92d176ce5f961a34 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 24 Jun 2024 22:32:43 +0800 Subject: [PATCH 12/84] Code generation for variable declaration and id expression --- src/llvm_ir_generator.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 1de51a20..fdc08310 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -34,6 +34,11 @@ llvm::Instruction::BinaryOps GetBinaryOperator(BinaryOperator op) { } } +auto id_to_val // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): + // Accessible only within this translation unit; declaring as a + // data member introduces unnecessary dependency. + = std::map{}; + /// @brief Store LLVM Value class at the bottom level of AST node. Upper level /// AST node can use the information in Value directly. class PrevValueRecorder { @@ -63,7 +68,16 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { } } -void LLVMIRGenerator::Visit(const VarDeclNode& decl) {} +void LLVMIRGenerator::Visit(const VarDeclNode& decl) { + auto i32 = builder_.getInt32Ty(); + auto addr = builder_.CreateAlloca(i32); + if (decl.init) { + decl.init->Accept(*this); + auto val = val_recorder.ValOfPrevExpr(); + builder_.CreateStore(val, addr); + } + id_to_val[decl.id] = addr; +} void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) {} @@ -166,6 +180,16 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { val_recorder.Record(func); return; } + assert(id_to_val.count(id_expr.id) != 0); + auto id_val = id_to_val.at(id_expr.id); + + if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { + // TODO + } else { + auto i32 = builder_.getInt32Ty(); + auto res = builder_.CreateLoad(i32, id_val); + val_recorder.Record(res); + } } void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { From 2d46738744d072b864a22c2935b99d81227ac7e9 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 24 Jun 2024 22:49:40 +0800 Subject: [PATCH 13/84] Refactor i32Ty with Util class --- include/llvm/util.hpp | 36 +++++++++++++++++++++++++ include/llvm_ir_generator.hpp | 10 ++++--- src/llvm_ir_generator.cpp | 51 +++++++++++++++++------------------ 3 files changed, 68 insertions(+), 29 deletions(-) create mode 100644 include/llvm/util.hpp diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp new file mode 100644 index 00000000..2b65108a --- /dev/null +++ b/include/llvm/util.hpp @@ -0,0 +1,36 @@ +#ifndef LLVM_UTIL_HPP_ +#define LLVM_UTIL_HPP_ + +#include + +namespace util { + +/// @brief A collection of wrappers of LLVM types and functions. +class Util { + public: + /// @brief Integer type + llvm::IntegerType* i32Ty; + + /// @brief NOT operation wrapper since LLVM doesn't provide NOT operator. + /// @return + llvm::Value* NotOperation(llvm::Value* val) { + // Is 0 if the value of its operand compares unequal to 0, 1 if the value + // of its operand compares equal to 0. + auto zero = llvm::ConstantInt::get(val->getType(), 0, true); + auto one = llvm::ConstantInt::get(val->getType(), 1, true); + auto* isZero = builder_->CreateICmpEQ(val, zero, "isZero"); + return builder_->CreateSelect(isZero, one, zero, "notResult"); + }; + + Util(std::unique_ptr>& builder) : builder_{builder} { + i32Ty = builder_->getInt32Ty(); + } + + private: + /// @brief Stores a refernce from the original builder. + std::unique_ptr>& builder_; +}; + +} // namespace util + +#endif // LLVM_UTIL_HPP_ \ No newline at end of file diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index d156c619..a6b29aba 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -9,6 +9,7 @@ #include #include "ast.hpp" +#include "llvm/util.hpp" #include "visitor.hpp" class LLVMIRGenerator : public NonModifyingVisitor { @@ -55,8 +56,9 @@ class LLVMIRGenerator : public NonModifyingVisitor { LLVMIRGenerator(std::ostream& output, std::string& filename) : output_{output}, context_{std::make_unique()}, - builder_{llvm::IRBuilder<>(*context_)}, - module_{new llvm::Module(filename, *context_)} {} + builder_{std::make_unique>(*context_)}, + module_{new llvm::Module(filename, *context_)}, + util_{util::Util(builder_)} {} /// @brief Print LLVM IR to output_. void PrintIR() { @@ -69,9 +71,11 @@ class LLVMIRGenerator : public NonModifyingVisitor { /// @brief A LLVM core object. std::unique_ptr context_; /// @brief Provides LLVM Builder API for constructing IR. - llvm::IRBuilder<> builder_; + std::unique_ptr> builder_; /// @brief Stores LLVM related information, including the constructed IR. llvm::Module* module_; + /// @brief Handy LLVM types and functions for code generation. + util::Util util_; }; #endif // LLVM_IR_GENERATOR_HPP_ \ No newline at end of file diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index fdc08310..d0acb818 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -69,12 +69,11 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { } void LLVMIRGenerator::Visit(const VarDeclNode& decl) { - auto i32 = builder_.getInt32Ty(); - auto addr = builder_.CreateAlloca(i32); + auto addr = builder_->CreateAlloca(util_.i32Ty); if (decl.init) { decl.init->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); - builder_.CreateStore(val, addr); + builder_->CreateStore(val, addr); } id_to_val[decl.id] = addr; } @@ -90,15 +89,14 @@ void LLVMIRGenerator::Visit(const RecordVarDeclNode& struct_def) {} void LLVMIRGenerator::Visit(const ParamNode& parameter) {} void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { - auto i32 = builder_.getInt32Ty(); - auto prototype = llvm::FunctionType::get(i32, false); + auto prototype = llvm::FunctionType::get(util_.i32Ty, false); auto* fn = llvm::Function::Create(prototype, func_def.id == "main" ? llvm::Function::ExternalLinkage : llvm::Function::InternalLinkage, func_def.id, module_); auto* body = llvm::BasicBlock::Create(*context_, "body", fn); - builder_.SetInsertPoint(body); + builder_->SetInsertPoint(body); func_def.body->Accept(*this); } @@ -116,19 +114,18 @@ void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. - auto i32 = builder_.getInt32Ty(); - auto arg = llvm::ArrayRef{i32}; - auto builtin_print = llvm::FunctionType::get(i32, arg, false); + auto arg = llvm::ArrayRef{util_.i32Ty}; + auto builtin_print = llvm::FunctionType::get(util_.i32Ty, arg, false); llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, "__builtin_print", module_); - auto ptrTy = builder_.getPtrTy(); - auto args = llvm::ArrayRef{ptrTy, i32}; - auto printf = llvm::FunctionType::get(i32, args, false); + auto ptrTy = builder_->getPtrTy(); + auto args = llvm::ArrayRef{ptrTy, util_.i32Ty}; + auto printf = llvm::FunctionType::get(util_.i32Ty, args, false); llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", module_); - builder_.CreateGlobalString("%d\n", "__builtin_print_format", 0, module_); + builder_->CreateGlobalString("%d\n", "__builtin_print_format", 0, module_); for (const auto& extern_decl : trans_unit.extern_decls) { extern_decl->Accept(*this); @@ -144,7 +141,7 @@ void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) {} void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { ret_stmt.expr->Accept(*this); auto expr = val_recorder.ValOfPrevExpr(); - builder_.CreateRet(expr); + builder_->CreateRet(expr); } void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) {} @@ -186,15 +183,14 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { // TODO } else { - auto i32 = builder_.getInt32Ty(); - auto res = builder_.CreateLoad(i32, id_val); + auto res = builder_->CreateLoad(util_.i32Ty, id_val, id_expr.id); val_recorder.Record(res); } } void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { - auto i32 = builder_.getInt32Ty(); - auto val = llvm::ConstantInt::get(i32, int_expr.val, true); + // NOTE: LLVM Constant does not generate IR code, it can be used directly. + auto val = llvm::ConstantInt::get(util_.i32Ty, int_expr.val, true); val_recorder.Record(val); } @@ -218,7 +214,6 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { for (const auto& arg : call_expr.args) { arg->Accept(*this); auto* arg_val = val_recorder.ValOfPrevExpr(); - llvm::outs() << arg_val->getName(); arg_vals.push_back(arg_val); } if (func->getName() == "__builtin_print") { @@ -232,7 +227,7 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { assert(print_format); print_args.push_back(print_format); print_args.insert(print_args.end(), arg_vals.begin(), arg_vals.end()); - builder_.CreateCall(printf, print_args); + builder_->CreateCall(printf, print_args); } else { } } @@ -242,14 +237,18 @@ void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) {} void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { unary_expr.operand->Accept(*this); switch (unary_expr.op) { - case UnaryOperator::kPos: + case UnaryOperator::kPos: { /* Do nothing. */ - break; + } break; case UnaryOperator::kNeg: { auto val = val_recorder.ValOfPrevExpr(); - auto i32 = builder_.getInt32Ty(); - auto zero = llvm::ConstantInt::get(i32, 0, true); - auto res = builder_.CreateBinOp(llvm::BinaryOperator::Sub, zero, val); + auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); + auto res = builder_->CreateBinOp(llvm::BinaryOperator::Sub, zero, val); + val_recorder.Record(res); + } break; + case UnaryOperator::kNot: { + auto val = val_recorder.ValOfPrevExpr(); + auto res = util_.NotOperation(val); val_recorder.Record(res); } break; default: @@ -275,7 +274,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { // TODO } else { auto* rhs = val_recorder.ValOfPrevExpr(); - builder_.CreateBinOp(GetBinaryOperator(bin_expr.op), lhs, rhs); + builder_->CreateBinOp(GetBinaryOperator(bin_expr.op), lhs, rhs); } } From af47ebd59653077fb383cc92ba14e844e71992ce Mon Sep 17 00:00:00 2001 From: Lee Date: Thu, 27 Jun 2024 23:17:18 +0800 Subject: [PATCH 14/84] Binary and comparison operator code generation --- include/llvm/util.hpp | 2 +- src/llvm_ir_generator.cpp | 70 ++++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 2b65108a..e3539659 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -27,7 +27,7 @@ class Util { } private: - /// @brief Stores a refernce from the original builder. + /// @brief Stores a reference from the original builder. std::unique_ptr>& builder_; }; diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index d0acb818..027bbcd5 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -28,12 +28,59 @@ llvm::Instruction::BinaryOps GetBinaryOperator(BinaryOperator op) { return llvm::BinaryOperator::Xor; case BinaryOperator::kOr: return llvm::BinaryOperator::Or; + case BinaryOperator::kShl: + return llvm::BinaryOperator::Shl; + // NOTE: Arithmetic shift right (sar) is akin to dividing by a power of two + // for non-negative numbers. For negatives, it's implementation-defined, so + // we opt for arithmetic shifting. + case BinaryOperator::kShr: + return llvm::BinaryOperator::AShr; default: - // TODO + // TODO: unreachable return llvm::BinaryOperator::Xor; } } +llvm::CmpInst::Predicate GetCmpOperator(BinaryOperator op) { + switch (op) { + case BinaryOperator::kGt: { + return llvm::CmpInst::Predicate::ICMP_SGT; + } break; + case BinaryOperator::kGte: { + return llvm::CmpInst::Predicate::ICMP_SGE; + } break; + case BinaryOperator::kLt: { + return llvm::CmpInst::Predicate::ICMP_SLT; + } break; + case BinaryOperator::kLte: { + return llvm::CmpInst::Predicate::ICMP_SLE; + } break; + case BinaryOperator::kEq: { + return llvm::CmpInst::Predicate::ICMP_EQ; + } break; + case BinaryOperator::kNeq: { + return llvm::CmpInst::Predicate::ICMP_NE; + } break; + default: + return llvm::CmpInst::Predicate::BAD_ICMP_PREDICATE; + } +} + +bool isCmpInst(BinaryOperator op) { + switch (op) { + case BinaryOperator::kGt: + case BinaryOperator::kGte: + case BinaryOperator::kLt: + case BinaryOperator::kLte: + case BinaryOperator::kEq: + case BinaryOperator::kNeq: { + return true; + } break; + default: + return false; + } +} + auto id_to_val // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): // Accessible only within this translation unit; declaring as a // data member introduces unnecessary dependency. @@ -258,23 +305,28 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { bin_expr.lhs->Accept(*this); - auto* lhs = val_recorder.ValOfPrevExpr(); + auto lhs = val_recorder.ValOfPrevExpr(); if (bin_expr.op == BinaryOperator::kComma) { - // For the comma operator, the value of its left operand is not used and can - // be eliminated if it has no side effects or if its definition is - // immediately dead. However, we leave these optimizations to QBE. + // For the comma operator, the value of its left operand is not used, so we + // passed right hand side operand to the upper level. bin_expr.rhs->Accept(*this); - auto* rhs = val_recorder.ValOfPrevExpr(); - val_recorder.Record(rhs); return; } if (bin_expr.op == BinaryOperator::kLand || bin_expr.op == BinaryOperator::kLor) { // TODO + bin_expr.rhs->Accept(*this); + } else if (isCmpInst(bin_expr.op)) { + bin_expr.rhs->Accept(*this); + auto rhs = val_recorder.ValOfPrevExpr(); + auto res = builder_->CreateCmp(GetCmpOperator(bin_expr.op), lhs, rhs); + val_recorder.Record(res); } else { - auto* rhs = val_recorder.ValOfPrevExpr(); - builder_->CreateBinOp(GetBinaryOperator(bin_expr.op), lhs, rhs); + bin_expr.rhs->Accept(*this); + auto rhs = val_recorder.ValOfPrevExpr(); + auto res = builder_->CreateBinOp(GetBinaryOperator(bin_expr.op), lhs, rhs); + val_recorder.Record(res); } } From ada573d56fcfc9b299171fe8ff9cc703d15aef70 Mon Sep 17 00:00:00 2001 From: Lee Date: Thu, 27 Jun 2024 23:54:47 +0800 Subject: [PATCH 15/84] Implement simple assignment expression code generation --- src/llvm_ir_generator.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 027bbcd5..1bb07cde 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -86,6 +86,12 @@ auto id_to_val // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): // data member introduces unnecessary dependency. = std::map{}; +auto + val_to_id_addr // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): + // Accessible only within this translation unit; declaring + // as a data member introduces unnecessary dependency. + = std::map{}; + /// @brief Store LLVM Value class at the bottom level of AST node. Upper level /// AST node can use the information in Value directly. class PrevValueRecorder { @@ -230,8 +236,9 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { // TODO } else { - auto res = builder_->CreateLoad(util_.i32Ty, id_val, id_expr.id); + auto res = builder_->CreateLoad(util_.i32Ty, id_val); val_recorder.Record(res); + val_to_id_addr[res] = id_val; } } @@ -330,4 +337,15 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { } } -void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) {} +void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) { + assign_expr.lhs->Accept(*this); + auto lhs = val_recorder.ValOfPrevExpr(); + assign_expr.rhs->Accept(*this); + auto rhs = val_recorder.ValOfPrevExpr(); + if (assign_expr.lhs->type->IsPtr()) { + // TODO + } else { + builder_->CreateStore(rhs, val_to_id_addr.at(lhs)); + } + val_recorder.Record(rhs); +} From 690db76095463cfb7b256262a697ad2239eabed9 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 28 Jun 2024 09:59:46 +0800 Subject: [PATCH 16/84] Implement prefix increment and decrement code generation --- src/llvm_ir_generator.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 1bb07cde..efe05e52 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -286,23 +286,39 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { } } -void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) {} +void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) { + // TODO +} void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { unary_expr.operand->Accept(*this); switch (unary_expr.op) { + case UnaryOperator::kIncr: + case UnaryOperator::kDecr: { + // Equivalent to i += 1 or i -= 1. + auto operand = val_recorder.ValOfPrevExpr(); + auto arith_op = unary_expr.op == UnaryOperator::kIncr + ? BinaryOperator::kAdd + : BinaryOperator::kSub; + auto one = llvm::ConstantInt::get(util_.i32Ty, 1, true); + auto res = + builder_->CreateBinOp(GetBinaryOperator(arith_op), operand, one); + builder_->CreateStore(res, val_to_id_addr.at(operand)); + val_recorder.Record(res); + } break; case UnaryOperator::kPos: { /* Do nothing. */ } break; case UnaryOperator::kNeg: { - auto val = val_recorder.ValOfPrevExpr(); + auto operand = val_recorder.ValOfPrevExpr(); auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); - auto res = builder_->CreateBinOp(llvm::BinaryOperator::Sub, zero, val); + auto res = + builder_->CreateBinOp(llvm::BinaryOperator::Sub, zero, operand); val_recorder.Record(res); } break; case UnaryOperator::kNot: { - auto val = val_recorder.ValOfPrevExpr(); - auto res = util_.NotOperation(val); + auto operand = val_recorder.ValOfPrevExpr(); + auto res = util_.NotOperation(operand); val_recorder.Record(res); } break; default: @@ -322,7 +338,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { } if (bin_expr.op == BinaryOperator::kLand || bin_expr.op == BinaryOperator::kLor) { - // TODO + // TODO: 6/28 bin_expr.rhs->Accept(*this); } else if (isCmpInst(bin_expr.op)) { bin_expr.rhs->Accept(*this); From af5678e0b3e7f80f0eea879020521ef598b7ae0f Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 28 Jun 2024 22:51:42 +0800 Subject: [PATCH 17/84] Implement logical AND and OR operation code generation --- src/llvm_ir_generator.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index efe05e52..0cc1c262 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -334,12 +334,42 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { // For the comma operator, the value of its left operand is not used, so we // passed right hand side operand to the upper level. bin_expr.rhs->Accept(*this); + auto rhs = val_recorder.ValOfPrevExpr(); + val_recorder.Record(rhs); return; } if (bin_expr.op == BinaryOperator::kLand || bin_expr.op == BinaryOperator::kLor) { - // TODO: 6/28 + // Get the current function we are in. + auto func = builder_->GetInsertBlock()->getParent(); + auto rhs_BB = llvm::BasicBlock::Create(*context_, "logic_rhs", func); + auto short_circuit_BB = + llvm::BasicBlock::Create(*context_, "short_circuit", func); + auto end_BB = llvm::BasicBlock::Create(*context_, "logic_end", func); + auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); + auto lhs_res = builder_->CreateCmp(bin_expr.op == BinaryOperator::kLand + ? llvm::CmpInst::Predicate::ICMP_NE + : llvm::CmpInst::Predicate::ICMP_EQ, + lhs, zero); + builder_->CreateCondBr(lhs_res, rhs_BB, short_circuit_BB); + builder_->SetInsertPoint(rhs_BB); bin_expr.rhs->Accept(*this); + auto res = val_recorder.ValOfPrevExpr(); + auto rhs_res = + builder_->CreateCmp(llvm::CmpInst::Predicate::ICMP_NE, res, zero); + builder_->CreateBr(end_BB); + builder_->SetInsertPoint(short_circuit_BB); + auto false_val = llvm::ConstantInt::getFalse(*context_); + auto true_val = llvm::ConstantInt::getTrue(*context_); + auto short_circuit_res = + bin_expr.op == BinaryOperator::kLand ? false_val : true_val; + builder_->CreateBr(end_BB); + builder_->SetInsertPoint(end_BB); + // Merge results from rhs and short_circuit_res + auto phi_res = builder_->CreatePHI(builder_->getInt1Ty(), 2); + phi_res->addIncoming(rhs_res, rhs_BB); + phi_res->addIncoming(short_circuit_res, short_circuit_BB); + val_recorder.Record(phi_res); } else if (isCmpInst(bin_expr.op)) { bin_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); From b4a9c168007ac088ea610bede5430d1814950427 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 28 Jun 2024 23:00:46 +0800 Subject: [PATCH 18/84] Implement Bitwise complement operator code generation --- include/llvm/util.hpp | 11 ----------- src/llvm_ir_generator.cpp | 13 ++++++++++--- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index e3539659..d596dda3 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -11,17 +11,6 @@ class Util { /// @brief Integer type llvm::IntegerType* i32Ty; - /// @brief NOT operation wrapper since LLVM doesn't provide NOT operator. - /// @return - llvm::Value* NotOperation(llvm::Value* val) { - // Is 0 if the value of its operand compares unequal to 0, 1 if the value - // of its operand compares equal to 0. - auto zero = llvm::ConstantInt::get(val->getType(), 0, true); - auto one = llvm::ConstantInt::get(val->getType(), 1, true); - auto* isZero = builder_->CreateICmpEQ(val, zero, "isZero"); - return builder_->CreateSelect(isZero, one, zero, "notResult"); - }; - Util(std::unique_ptr>& builder) : builder_{builder} { i32Ty = builder_->getInt32Ty(); } diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 0cc1c262..5c80463c 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -318,7 +318,15 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { } break; case UnaryOperator::kNot: { auto operand = val_recorder.ValOfPrevExpr(); - auto res = util_.NotOperation(operand); + auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); + auto res = builder_->CreateICmpEQ(operand, zero); + val_recorder.Record(res); + } break; + case UnaryOperator::kBitComp: { + auto operand = val_recorder.ValOfPrevExpr(); + auto all_ones = llvm::ConstantInt::get(util_.i32Ty, -1, true); + auto res = + builder_->CreateBinOp(llvm::BinaryOperator::Xor, operand, all_ones); val_recorder.Record(res); } break; default: @@ -355,8 +363,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { builder_->SetInsertPoint(rhs_BB); bin_expr.rhs->Accept(*this); auto res = val_recorder.ValOfPrevExpr(); - auto rhs_res = - builder_->CreateCmp(llvm::CmpInst::Predicate::ICMP_NE, res, zero); + auto rhs_res = builder_->CreateICmpNE(res, zero); builder_->CreateBr(end_BB); builder_->SetInsertPoint(short_circuit_BB); auto false_val = llvm::ConstantInt::getFalse(*context_); From 4b250f1757b07c33bdd7d425693c2b71288a2218 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 28 Jun 2024 23:13:00 +0800 Subject: [PATCH 19/84] Implement postfix increment and decrement operator code generation --- src/llvm_ir_generator.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 5c80463c..5bb38229 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -287,7 +287,19 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { } void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) { - // TODO + postfix_expr.operand->Accept(*this); + auto val = val_recorder.ValOfPrevExpr(); + val_recorder.Record(val); + + auto arith_op = postfix_expr.op == PostfixOperator::kIncr + ? llvm::BinaryOperator::Add + : llvm::BinaryOperator::Sub; + + auto one = llvm::ConstantInt::get(util_.i32Ty, 1, true); + auto res = builder_->CreateBinOp(arith_op, val, one); + const auto* id_expr = dynamic_cast((postfix_expr.operand).get()); + assert(id_expr); + builder_->CreateStore(res, id_to_val.at(id_expr->id)); } void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { @@ -329,6 +341,10 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { builder_->CreateBinOp(llvm::BinaryOperator::Xor, operand, all_ones); val_recorder.Record(res); } break; + case UnaryOperator::kAddr: { + } break; + case UnaryOperator::kDeref: { + } break; default: break; } From e9836173d773a01cd465239c1aab505e8c21a5d8 Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 29 Jun 2024 13:33:14 +0800 Subject: [PATCH 20/84] Implement if else statement code generation --- src/llvm_ir_generator.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 5bb38229..a2e81e8d 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -185,7 +185,30 @@ void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { } } -void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) {} +void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { + if_stmt.predicate->Accept(*this); + auto predicate_val = val_recorder.ValOfPrevExpr(); + auto func = builder_->GetInsertBlock()->getParent(); + auto then_BB = llvm::BasicBlock::Create(*context_, "if_then", func); + auto else_BB = if_stmt.or_else != nullptr + ? llvm::BasicBlock::Create(*context_, "if_else", func) + : nullptr; + auto end_BB = llvm::BasicBlock::Create(*context_, "if_end", func); + + auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); + auto predicate = builder_->CreateICmpNE(predicate_val, zero); + builder_->CreateCondBr(predicate, then_BB, + if_stmt.or_else != nullptr ? else_BB : end_BB); + builder_->SetInsertPoint(then_BB); + if_stmt.then->Accept(*this); + builder_->CreateBr(end_BB); + if (if_stmt.or_else) { + builder_->SetInsertPoint(else_BB); + if_stmt.or_else->Accept(*this); + builder_->CreateBr(end_BB); + } + builder_->SetInsertPoint(end_BB); +} void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) {} @@ -221,7 +244,9 @@ void LLVMIRGenerator::Visit(const ArrDesNode& arr_des) {} void LLVMIRGenerator::Visit(const IdDesNode& id_des) {} -void LLVMIRGenerator::Visit(const NullExprNode& null_expr) {} +void LLVMIRGenerator::Visit(const NullExprNode& null_expr) { + /* do nothing */ +} void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { if (id_expr.type->IsFunc()) { From 7ccc800d6fe16936a17e1527e7010b369b0a278d Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 29 Jun 2024 14:14:13 +0800 Subject: [PATCH 21/84] Implement while and do while statement code generation --- src/llvm_ir_generator.cpp | 44 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index a2e81e8d..70f1dc0b 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -210,7 +210,45 @@ void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { builder_->SetInsertPoint(end_BB); } -void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) {} +void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { + auto label_prefix = std::string{while_stmt.is_do_while ? "do_" : "while_"}; + auto func = builder_->GetInsertBlock()->getParent(); + auto body_BB = + llvm::BasicBlock::Create(*context_, label_prefix + "body", func); + auto pred_BB = + llvm::BasicBlock::Create(*context_, label_prefix + "pred", func); + auto end_BB = llvm::BasicBlock::Create(*context_, label_prefix + "end", func); + + // A while statement's predicate is evaluated "before" the body statement, + // whereas a do-while statement's predicate is evaluated "after" the body + // statement. In the generated code for a while statement, there is an + // unconditional jump at the end of the body to jump back to the predicate. + // For a do-while statement, it only needs one conditional jump. + if (!while_stmt.is_do_while) { + builder_->CreateBr(pred_BB); + builder_->SetInsertPoint(pred_BB); + while_stmt.predicate->Accept(*this); + auto predicate = val_recorder.ValOfPrevExpr(); + builder_->CreateCondBr(predicate, body_BB, end_BB); + } + + // Connect entry basic block to body basic block. + if (while_stmt.is_do_while) { + builder_->CreateBr(body_BB); + } + builder_->SetInsertPoint(body_BB); + // TODO: break label + while_stmt.loop_body->Accept(*this); + builder_->CreateBr(pred_BB); + + if (while_stmt.is_do_while) { + builder_->SetInsertPoint(pred_BB); + while_stmt.predicate->Accept(*this); + auto predicate = val_recorder.ValOfPrevExpr(); + builder_->CreateCondBr(predicate, body_BB, end_BB); + } + builder_->SetInsertPoint(end_BB); +} void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) {} @@ -380,8 +418,8 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { auto lhs = val_recorder.ValOfPrevExpr(); if (bin_expr.op == BinaryOperator::kComma) { - // For the comma operator, the value of its left operand is not used, so we - // passed right hand side operand to the upper level. + // For the comma operator, the value of its left operand is not used, so + // we passed right hand side operand to the upper level. bin_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); val_recorder.Record(rhs); From bc5c7a52349945ea2e337b1e6159ffacf8cd2737 Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 29 Jun 2024 14:27:47 +0800 Subject: [PATCH 22/84] Implement for statement code generation --- src/llvm_ir_generator.cpp | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 70f1dc0b..4112967a 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -153,7 +153,10 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { func_def.body->Accept(*this); } -void LLVMIRGenerator::Visit(const LoopInitNode& loop_init) {} +void LLVMIRGenerator::Visit(const LoopInitNode& loop_init) { + std::visit([this](auto&& clause) { clause->Accept(*this); }, + loop_init.clause); +} void LLVMIRGenerator::Visit(const CompoundStmtNode& compound_stmt) { for (const auto& stmt : compound_stmt.stmts) { @@ -237,7 +240,7 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { builder_->CreateBr(body_BB); } builder_->SetInsertPoint(body_BB); - // TODO: break label + // TODO: break, continue label while_stmt.loop_body->Accept(*this); builder_->CreateBr(pred_BB); @@ -250,7 +253,32 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { builder_->SetInsertPoint(end_BB); } -void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) {} +void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { + auto func = builder_->GetInsertBlock()->getParent(); + auto pred_BB = llvm::BasicBlock::Create(*context_, "for_pred", func); + auto body_BB = llvm::BasicBlock::Create(*context_, "for_body", func); + auto step_BB = llvm::BasicBlock::Create(*context_, "for_step", func); + auto end_BB = llvm::BasicBlock::Create(*context_, "for_end", func); + + for_stmt.loop_init->Accept(*this); + builder_->CreateBr(pred_BB); + builder_->SetInsertPoint(pred_BB); + for_stmt.predicate->Accept(*this); + if (!dynamic_cast((for_stmt.predicate).get())) { + auto predicate = val_recorder.ValOfPrevExpr(); + builder_->CreateCondBr(predicate, body_BB, end_BB); + } + + builder_->SetInsertPoint(body_BB); + // TODO: break, continue label + for_stmt.loop_body->Accept(*this); + builder_->CreateBr(step_BB); + + builder_->SetInsertPoint(step_BB); + for_stmt.step->Accept(*this); + builder_->CreateBr(pred_BB); + builder_->SetInsertPoint(end_BB); +} void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { ret_stmt.expr->Accept(*this); From 6bfb6d03902b68a6e2728f6d4cc364e05d73b5b7 Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 29 Jun 2024 16:11:05 +0800 Subject: [PATCH 23/84] Implement break and continue statement code generation --- include/llvm/util.hpp | 21 +++++++++++++++++++++ src/llvm_ir_generator.cpp | 34 ++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index d596dda3..abbd651a 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -11,6 +11,27 @@ class Util { /// @brief Integer type llvm::IntegerType* i32Ty; + /// @brief Every LLVM basic block can only have one terminator instruction. + /// This function can check if there are terminator instructions before the + /// current insert point. If yes, then it will create an unconditional branch. + /// If no, then it will not create branch instruction. + void CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB) { + auto BB = builder_->GetInsertBlock(); + bool has_terminator = false; + for (auto it = BB->begin(); it != BB->end();) { + if (it->isTerminator()) { + has_terminator = true; + break; + } else { + ++it; + } + } + + if (!has_terminator) { + builder_->CreateBr(next_BB); + } + } + Util(std::unique_ptr>& builder) : builder_{builder} { i32Ty = builder_->getInt32Ty(); } diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 4112967a..e5d3e509 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -113,6 +113,18 @@ auto // Accessible only within this translation unit; declaring as // a data member introduces unnecessary dependency. = PrevValueRecorder{}; + +struct LabelViewPair { + llvm::BasicBlock* entry; + llvm::BasicBlock* exit; +}; + +/// @note Blocks that allows jumping within or out of it should add its labels +/// to this list +auto + label_views_of_jumpable_blocks // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + = std::vector{}; + } // namespace void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { @@ -198,13 +210,14 @@ void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { : nullptr; auto end_BB = llvm::BasicBlock::Create(*context_, "if_end", func); - auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); + auto zero = llvm::ConstantInt::get(predicate_val->getType(), 0, true); auto predicate = builder_->CreateICmpNE(predicate_val, zero); builder_->CreateCondBr(predicate, then_BB, if_stmt.or_else != nullptr ? else_BB : end_BB); builder_->SetInsertPoint(then_BB); if_stmt.then->Accept(*this); - builder_->CreateBr(end_BB); + util_.CreateBrIfNoBrBefore(end_BB); + if (if_stmt.or_else) { builder_->SetInsertPoint(else_BB); if_stmt.or_else->Accept(*this); @@ -240,8 +253,9 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { builder_->CreateBr(body_BB); } builder_->SetInsertPoint(body_BB); - // TODO: break, continue label + label_views_of_jumpable_blocks.push_back({.entry = pred_BB, .exit = end_BB}); while_stmt.loop_body->Accept(*this); + label_views_of_jumpable_blocks.pop_back(); builder_->CreateBr(pred_BB); if (while_stmt.is_do_while) { @@ -271,7 +285,9 @@ void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { builder_->SetInsertPoint(body_BB); // TODO: break, continue label + label_views_of_jumpable_blocks.push_back({.entry = step_BB, .exit = end_BB}); for_stmt.loop_body->Accept(*this); + label_views_of_jumpable_blocks.pop_back(); builder_->CreateBr(step_BB); builder_->SetInsertPoint(step_BB); @@ -288,9 +304,15 @@ void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) {} -void LLVMIRGenerator::Visit(const BreakStmtNode& break_stmt) {} +void LLVMIRGenerator::Visit(const BreakStmtNode& break_stmt) { + assert(!label_views_of_jumpable_blocks.empty()); + builder_->CreateBr(label_views_of_jumpable_blocks.back().exit); +} -void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) {} +void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { + assert(!label_views_of_jumpable_blocks.empty()); + builder_->CreateBr(label_views_of_jumpable_blocks.back().entry); +} void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) {} @@ -461,7 +483,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { auto short_circuit_BB = llvm::BasicBlock::Create(*context_, "short_circuit", func); auto end_BB = llvm::BasicBlock::Create(*context_, "logic_end", func); - auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); + auto zero = llvm::ConstantInt::get(lhs->getType(), 0, true); auto lhs_res = builder_->CreateCmp(bin_expr.op == BinaryOperator::kLand ? llvm::CmpInst::Predicate::ICMP_NE : llvm::CmpInst::Predicate::ICMP_EQ, From 65b7af077bdb204ee8e3ea402476448a53d51474 Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 29 Jun 2024 17:42:19 +0800 Subject: [PATCH 24/84] Rename integer type name --- include/llvm/util.hpp | 8 ++++++-- src/llvm_ir_generator.cpp | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index abbd651a..887d131c 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -9,7 +9,9 @@ namespace util { class Util { public: /// @brief Integer type - llvm::IntegerType* i32Ty; + llvm::IntegerType* intTy; + /// @brief Pointer type + llvm::PointerType* intPtrTy; /// @brief Every LLVM basic block can only have one terminator instruction. /// This function can check if there are terminator instructions before the @@ -33,7 +35,9 @@ class Util { } Util(std::unique_ptr>& builder) : builder_{builder} { - i32Ty = builder_->getInt32Ty(); + intTy = builder_->getInt32Ty(); + // FIXME: hardcode 32 bits + intPtrTy = builder_->getPtrTy(32); } private: diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index e5d3e509..edb6dbe9 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -154,7 +154,7 @@ void LLVMIRGenerator::Visit(const RecordVarDeclNode& struct_def) {} void LLVMIRGenerator::Visit(const ParamNode& parameter) {} void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { - auto prototype = llvm::FunctionType::get(util_.i32Ty, false); + auto prototype = llvm::FunctionType::get(util_.intTy, false); auto* fn = llvm::Function::Create(prototype, func_def.id == "main" ? llvm::Function::ExternalLinkage @@ -182,14 +182,14 @@ void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. - auto arg = llvm::ArrayRef{util_.i32Ty}; - auto builtin_print = llvm::FunctionType::get(util_.i32Ty, arg, false); + auto arg = llvm::ArrayRef{util_.intTy}; + auto builtin_print = llvm::FunctionType::get(util_.intTy, arg, false); llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, "__builtin_print", module_); auto ptrTy = builder_->getPtrTy(); - auto args = llvm::ArrayRef{ptrTy, util_.i32Ty}; - auto printf = llvm::FunctionType::get(util_.i32Ty, args, false); + auto args = llvm::ArrayRef{ptrTy, util_.intTy}; + auto printf = llvm::FunctionType::get(util_.intTy, args, false); llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", module_); @@ -349,7 +349,7 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { // TODO } else { - auto res = builder_->CreateLoad(util_.i32Ty, id_val); + auto res = builder_->CreateLoad(util_.intTy, id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } @@ -357,7 +357,7 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { // NOTE: LLVM Constant does not generate IR code, it can be used directly. - auto val = llvm::ConstantInt::get(util_.i32Ty, int_expr.val, true); + auto val = llvm::ConstantInt::get(util_.intTy, int_expr.val, true); val_recorder.Record(val); } @@ -408,7 +408,7 @@ void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) { ? llvm::BinaryOperator::Add : llvm::BinaryOperator::Sub; - auto one = llvm::ConstantInt::get(util_.i32Ty, 1, true); + auto one = llvm::ConstantInt::get(util_.intTy, 1, true); auto res = builder_->CreateBinOp(arith_op, val, one); const auto* id_expr = dynamic_cast((postfix_expr.operand).get()); assert(id_expr); @@ -425,7 +425,7 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { auto arith_op = unary_expr.op == UnaryOperator::kIncr ? BinaryOperator::kAdd : BinaryOperator::kSub; - auto one = llvm::ConstantInt::get(util_.i32Ty, 1, true); + auto one = llvm::ConstantInt::get(util_.intTy, 1, true); auto res = builder_->CreateBinOp(GetBinaryOperator(arith_op), operand, one); builder_->CreateStore(res, val_to_id_addr.at(operand)); @@ -436,20 +436,20 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { } break; case UnaryOperator::kNeg: { auto operand = val_recorder.ValOfPrevExpr(); - auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); + auto zero = llvm::ConstantInt::get(util_.intTy, 0, true); auto res = builder_->CreateBinOp(llvm::BinaryOperator::Sub, zero, operand); val_recorder.Record(res); } break; case UnaryOperator::kNot: { auto operand = val_recorder.ValOfPrevExpr(); - auto zero = llvm::ConstantInt::get(util_.i32Ty, 0, true); + auto zero = llvm::ConstantInt::get(util_.intTy, 0, true); auto res = builder_->CreateICmpEQ(operand, zero); val_recorder.Record(res); } break; case UnaryOperator::kBitComp: { auto operand = val_recorder.ValOfPrevExpr(); - auto all_ones = llvm::ConstantInt::get(util_.i32Ty, -1, true); + auto all_ones = llvm::ConstantInt::get(util_.intTy, -1, true); auto res = builder_->CreateBinOp(llvm::BinaryOperator::Xor, operand, all_ones); val_recorder.Record(res); From 563fba5a3f53d8bb99685ecbc1249118507ec91b Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 29 Jun 2024 18:41:56 +0800 Subject: [PATCH 25/84] Implement pointer code generation --- src/llvm_ir_generator.cpp | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index edb6dbe9..fb9540e7 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -134,7 +134,9 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { } void LLVMIRGenerator::Visit(const VarDeclNode& decl) { - auto addr = builder_->CreateAlloca(util_.i32Ty); + auto addr = builder_->CreateAlloca(decl.type->IsPtr() == true + ? (llvm::Type*)util_.intPtrTy + : (llvm::Type*)util_.intTy); if (decl.init) { decl.init->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); @@ -347,7 +349,9 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { auto id_val = id_to_val.at(id_expr.id); if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { - // TODO + auto res = builder_->CreateLoad(util_.intPtrTy, id_val); + val_recorder.Record(res); + val_to_id_addr[res] = id_val; } else { auto res = builder_->CreateLoad(util_.intTy, id_val); val_recorder.Record(res); @@ -455,8 +459,31 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { val_recorder.Record(res); } break; case UnaryOperator::kAddr: { + if (unary_expr.operand->type->IsFunc()) { + // No-op; the function itself already evaluates to the address. + break; + } + auto operand = val_recorder.ValOfPrevExpr(); + auto operand_addr = val_to_id_addr.at(operand); + val_recorder.Record(operand_addr); } break; case UnaryOperator::kDeref: { + // Is function pointer. + if (unary_expr.operand->type->IsPtr() && + dynamic_cast((unary_expr.operand->type).get()) + ->base_type() + .IsFunc()) { + // No-op; the function itself also evaluates to the address. + break; + } + + auto operand = val_recorder.ValOfPrevExpr(); + auto res = builder_->CreateLoad(unary_expr.type->IsPtr() == true + ? (llvm::Type*)util_.intPtrTy + : (llvm::Type*)util_.intTy, + operand); + val_recorder.Record(res); + val_to_id_addr[res] = operand; } break; default: break; @@ -524,10 +551,6 @@ void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) { auto lhs = val_recorder.ValOfPrevExpr(); assign_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); - if (assign_expr.lhs->type->IsPtr()) { - // TODO - } else { - builder_->CreateStore(rhs, val_to_id_addr.at(lhs)); - } + builder_->CreateStore(rhs, val_to_id_addr.at(lhs)); val_recorder.Record(rhs); } From fc9f7d42105ddbf13c34a5b3ea295eb186e1defc Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 29 Jun 2024 18:54:57 +0800 Subject: [PATCH 26/84] Remove hardcode pointer size --- include/llvm/util.hpp | 3 +-- src/llvm_ir_generator.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 887d131c..df424989 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -36,8 +36,7 @@ class Util { Util(std::unique_ptr>& builder) : builder_{builder} { intTy = builder_->getInt32Ty(); - // FIXME: hardcode 32 bits - intPtrTy = builder_->getPtrTy(32); + intPtrTy = builder_->getPtrTy(); } private: diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index fb9540e7..949ba1f7 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -189,8 +189,7 @@ void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, "__builtin_print", module_); - auto ptrTy = builder_->getPtrTy(); - auto args = llvm::ArrayRef{ptrTy, util_.intTy}; + auto args = llvm::ArrayRef{util_.intPtrTy, util_.intTy}; auto printf = llvm::FunctionType::get(util_.intTy, args, false); llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", module_); From 158ac6e74756e8ef8f3e60b2953e6b8cd45942b4 Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 29 Jun 2024 21:35:13 +0800 Subject: [PATCH 27/84] Implement function call expression code generation --- src/llvm_ir_generator.cpp | 47 ++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 949ba1f7..df20478c 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -153,17 +153,44 @@ void LLVMIRGenerator::Visit(const FieldNode& field) {} void LLVMIRGenerator::Visit(const RecordVarDeclNode& struct_def) {} -void LLVMIRGenerator::Visit(const ParamNode& parameter) {} +void LLVMIRGenerator::Visit(const ParamNode& parameter) { + /* Do nothing */ +} void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { - auto prototype = llvm::FunctionType::get(util_.intTy, false); - auto* fn = llvm::Function::Create(prototype, - func_def.id == "main" - ? llvm::Function::ExternalLinkage - : llvm::Function::InternalLinkage, - func_def.id, module_); - auto* body = llvm::BasicBlock::Create(*context_, "body", fn); + std::vector params; + for (auto& parameter : func_def.parameters) { + parameter->Accept(*this); + // Initiate first + id_to_val[parameter->id] = nullptr; + // TODO: support multiple data types. + if (parameter->type->IsPtr()) { + params.push_back(util_.intPtrTy); + } else { + params.push_back(util_.intTy); + } + } + + auto prototype = llvm::FunctionType::get(util_.intTy, params, false); + auto func = llvm::Function::Create(prototype, + func_def.id == "main" + ? llvm::Function::ExternalLinkage + : llvm::Function::InternalLinkage, + func_def.id, module_); + + auto body = llvm::BasicBlock::Create(*context_, "body", func); builder_->SetInsertPoint(body); + // Allocate space for parameters. + auto args_iter = func->arg_begin(); + for (auto& parameter : func_def.parameters) { + parameter->Accept(*this); + args_iter->setName(parameter->id); + auto addr = builder_->CreateAlloca(args_iter->getType()); + builder_->CreateStore(args_iter, addr); + id_to_val.at(parameter->id) = addr; + ++args_iter; + } + func_def.body->Accept(*this); } @@ -386,6 +413,7 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { auto* arg_val = val_recorder.ValOfPrevExpr(); arg_vals.push_back(arg_val); } + if (func->getName() == "__builtin_print") { // builtin_print call auto printf = module_->getFunction("printf"); @@ -399,6 +427,9 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { print_args.insert(print_args.end(), arg_vals.begin(), arg_vals.end()); builder_->CreateCall(printf, print_args); } else { + auto called_func = module_->getFunction(func->getName()); + auto return_res = builder_->CreateCall(called_func, arg_vals); + val_recorder.Record(return_res); } } From 07706ec3337bbdb75fc269b7a0e6abb247fa29a2 Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 30 Jun 2024 01:28:44 +0800 Subject: [PATCH 28/84] Implement condition expression code generation --- src/llvm_ir_generator.cpp | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index df20478c..59560677 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -398,14 +398,40 @@ void LLVMIRGenerator::Visit(const ArgExprNode& arg_expr) { void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) {} -void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) {} +void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { + cond_expr.predicate->Accept(*this); + auto predicate_val = val_recorder.ValOfPrevExpr(); + auto func = builder_->GetInsertBlock()->getParent(); + // The second operand is evaluated only if the first compares unequal to + // 0; the third operand is evaluated only if the first compares equal to + // 0; the result is the value of the second or third operand (whichever is + // evaluated). + auto second_BB = llvm::BasicBlock::Create(*context_, "cond_second", func); + auto third_BB = llvm::BasicBlock::Create(*context_, "cond_third", func); + auto end_BB = llvm::BasicBlock::Create(*context_, "cond_end", func); -void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { - call_expr.func_expr->Accept(*this); - auto val = val_recorder.ValOfPrevExpr(); - auto func = llvm::dyn_cast(val); - assert(func); + auto zero = llvm::ConstantInt::get(predicate_val->getType(), 0, true); + auto predicate = builder_->CreateICmpNE(predicate_val, zero); + builder_->CreateCondBr(predicate, second_BB, third_BB); + builder_->SetInsertPoint(second_BB); + cond_expr.then->Accept(*this); + auto second_val = val_recorder.ValOfPrevExpr(); + builder_->CreateBr(end_BB); + + builder_->SetInsertPoint(third_BB); + cond_expr.or_else->Accept(*this); + auto third_val = val_recorder.ValOfPrevExpr(); + builder_->CreateBr(end_BB); + + builder_->SetInsertPoint(end_BB); + auto phi_res = builder_->CreatePHI(util_.intTy, 2); + phi_res->addIncoming(second_val, second_BB); + phi_res->addIncoming(third_val, third_BB); + val_recorder.Record(phi_res); +} + +void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { // Evaluate the arguments. std::vector arg_vals{}; for (const auto& arg : call_expr.args) { From c93394b0b9ad7c948ce43be93f58e8b44c107069 Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 30 Jun 2024 14:49:47 +0800 Subject: [PATCH 29/84] Implement array code generation --- src/llvm_ir_generator.cpp | 55 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 59560677..65ba83ec 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -92,6 +92,11 @@ auto // as a data member introduces unnecessary dependency. = std::map{}; +auto val_to_type // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): + // Accessible only within this translation unit; declaring + // as a data member introduces unnecessary dependency. + = std::map{}; + /// @brief Store LLVM Value class at the bottom level of AST node. Upper level /// AST node can use the information in Value directly. class PrevValueRecorder { @@ -145,7 +150,34 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { id_to_val[decl.id] = addr; } -void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) {} +void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { + auto arr_decl_type = dynamic_cast((arr_decl.type).get()); + auto arr_type = llvm::ArrayType::get( + util_.intTy, + arr_decl_type->size() / arr_decl_type->element_type().size()); + auto base_addr = builder_->CreateAlloca(arr_type, nullptr); + id_to_val[arr_decl.id] = base_addr; + val_to_type[base_addr] = arr_type; + + for (auto i = std::size_t{0}, e = arr_decl_type->len(); i < e; ++i) { + if (i < arr_decl.init_list.size()) { + auto& arr_init = arr_decl.init_list.at(i); + arr_init->Accept(*this); + } + + auto res_addr = + builder_->CreateConstInBoundsGEP2_32(arr_type, base_addr, 0, i); + + if (i < arr_decl.init_list.size()) { + auto init_val = val_recorder.ValOfPrevExpr(); + builder_->CreateStore(init_val, res_addr); + } else { + // set remaining elements as 0 + auto zero = llvm::ConstantInt::get(util_.intTy, 0, true); + builder_->CreateStore(zero, res_addr); + } + } +} void LLVMIRGenerator::Visit(const RecordDeclNode& struct_def) {} @@ -354,7 +386,9 @@ void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) { expr_stmt.expr->Accept(*this); } -void LLVMIRGenerator::Visit(const InitExprNode& init_expr) {} +void LLVMIRGenerator::Visit(const InitExprNode& init_expr) { + init_expr.expr->Accept(*this); +} void LLVMIRGenerator::Visit(const ArrDesNode& arr_des) {} @@ -396,7 +430,22 @@ void LLVMIRGenerator::Visit(const ArgExprNode& arg_expr) { arg_expr.arg->Accept(*this); } -void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) {} +void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) { + arr_sub_expr.arr->Accept(*this); + auto val_num = val_recorder.ValOfPrevExpr(); + auto base_addr = val_to_id_addr.at(val_num); + auto arr_type = val_to_type.at(base_addr); + arr_sub_expr.index->Accept(*this); + auto index = dynamic_cast(arr_sub_expr.index.get()); + assert(index); + + auto res_addr = builder_->CreateConstInBoundsGEP2_32( + arr_type, base_addr, 0, (unsigned int)index->val); + auto res_val = + builder_->CreateLoad(arr_type->getArrayElementType(), res_addr); + val_to_id_addr[res_val] = res_addr; + val_recorder.Record(res_val); +} void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { cond_expr.predicate->Accept(*this); From fd78532d07c847031af8de4c4a5c9bbc665347df Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 30 Jun 2024 15:54:10 +0800 Subject: [PATCH 30/84] Implement function pointer code generation --- src/llvm_ir_generator.cpp | 56 +++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 65ba83ec..ae8e8869 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -139,15 +139,16 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { } void LLVMIRGenerator::Visit(const VarDeclNode& decl) { - auto addr = builder_->CreateAlloca(decl.type->IsPtr() == true - ? (llvm::Type*)util_.intPtrTy - : (llvm::Type*)util_.intTy); + auto var_type = decl.type->IsPtr() == true ? (llvm::Type*)util_.intPtrTy + : (llvm::Type*)util_.intTy; + auto addr = builder_->CreateAlloca(var_type); if (decl.init) { decl.init->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); builder_->CreateStore(val, addr); } id_to_val[decl.id] = addr; + val_to_type[addr] = var_type; } void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { @@ -203,8 +204,8 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { } } - auto prototype = llvm::FunctionType::get(util_.intTy, params, false); - auto func = llvm::Function::Create(prototype, + auto func_type = llvm::FunctionType::get(util_.intTy, params, false); + auto func = llvm::Function::Create(func_type, func_def.id == "main" ? llvm::Function::ExternalLinkage : llvm::Function::InternalLinkage, @@ -220,6 +221,7 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { auto addr = builder_->CreateAlloca(args_iter->getType()); builder_->CreateStore(args_iter, addr); id_to_val.at(parameter->id) = addr; + val_to_type[addr] = args_iter->getType(); ++args_iter; } @@ -489,21 +491,32 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { arg_vals.push_back(arg_val); } - if (func->getName() == "__builtin_print") { - // builtin_print call - auto printf = module_->getFunction("printf"); - assert(printf); - std::vector print_args{}; - // NOTE: set AllowInternal as true to get internal linkage global variable - auto print_format = - module_->getGlobalVariable("__builtin_print_format", true); - assert(print_format); - print_args.push_back(print_format); - print_args.insert(print_args.end(), arg_vals.begin(), arg_vals.end()); - builder_->CreateCall(printf, print_args); - } else { - auto called_func = module_->getFunction(func->getName()); - auto return_res = builder_->CreateCall(called_func, arg_vals); + call_expr.func_expr->Accept(*this); + auto val = val_recorder.ValOfPrevExpr(); + if (auto func = llvm::dyn_cast(val)) { + if (func->getName() == "__builtin_print") { + // builtin_print call + auto printf = module_->getFunction("printf"); + std::vector print_args{}; + // NOTE: set AllowInternal as true to get internal linkage global variable + auto print_format = + module_->getGlobalVariable("__builtin_print_format", true); + assert(print_format); + print_args.push_back(print_format); + print_args.insert(print_args.end(), arg_vals.begin(), arg_vals.end()); + builder_->CreateCall(printf, print_args); + } else { + auto called_func = module_->getFunction(func->getName()); + auto return_res = builder_->CreateCall(called_func, arg_vals); + val_recorder.Record(return_res); + } + } else if (llvm::dyn_cast(val->getType())) { + auto func_ptr = val_to_id_addr.at(val); + assert(func_ptr); + auto type = val_to_type.at(func_ptr); + auto func_type = llvm::dyn_cast(type); + assert(func_type); + auto return_res = builder_->CreateCall(func_type, val, arg_vals); val_recorder.Record(return_res); } } @@ -657,5 +670,8 @@ void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) { assign_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); builder_->CreateStore(rhs, val_to_id_addr.at(lhs)); + if (auto func = llvm::dyn_cast(rhs)) { + val_to_type[val_to_id_addr.at(lhs)] = func->getFunctionType(); + } val_recorder.Record(rhs); } From ceede3e1350c80efe51a37fa59e63626bab9ac56 Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 30 Jun 2024 15:54:40 +0800 Subject: [PATCH 31/84] Implement Record type declaration code generation --- src/llvm_ir_generator.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index ae8e8869..e82c6873 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -180,9 +180,13 @@ void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { } } -void LLVMIRGenerator::Visit(const RecordDeclNode& struct_def) {} +void LLVMIRGenerator::Visit(const RecordDeclNode& struct_def) { + /* Do nothing because this node only declares a type. */ +} -void LLVMIRGenerator::Visit(const FieldNode& field) {} +void LLVMIRGenerator::Visit(const FieldNode& field) { + /* Do nothing because this node only declares a member type in a record. */ +} void LLVMIRGenerator::Visit(const RecordVarDeclNode& struct_def) {} From f5aecb67cb03a537979869e2e5cd4ff90412cf8c Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 30 Jun 2024 22:47:17 +0800 Subject: [PATCH 32/84] Implement function pointer parameter code generation --- include/llvm_ir_generator.hpp | 2 + src/llvm_ir_generator.cpp | 77 +++++++++++++++++++++++++---------- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index a6b29aba..72c27d28 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -76,6 +76,8 @@ class LLVMIRGenerator : public NonModifyingVisitor { llvm::Module* module_; /// @brief Handy LLVM types and functions for code generation. util::Util util_; + /// @brief Get LLVM type from function parameter + llvm::Type* GetParamType_(const std::unique_ptr& parameter); }; #endif // LLVM_IR_GENERATOR_HPP_ \ No newline at end of file diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index e82c6873..9cfc9bbb 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -145,6 +145,9 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { if (decl.init) { decl.init->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); + if (auto func = llvm::dyn_cast(val)) { + var_type = func->getFunctionType(); + } builder_->CreateStore(val, addr); } id_to_val[decl.id] = addr; @@ -194,21 +197,37 @@ void LLVMIRGenerator::Visit(const ParamNode& parameter) { /* Do nothing */ } -void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { - std::vector params; - for (auto& parameter : func_def.parameters) { - parameter->Accept(*this); - // Initiate first - id_to_val[parameter->id] = nullptr; - // TODO: support multiple data types. - if (parameter->type->IsPtr()) { - params.push_back(util_.intPtrTy); +llvm::Type* LLVMIRGenerator::GetParamType_( + const std::unique_ptr& parameter) { + llvm::Type* param_type; + if (auto ptr_type = dynamic_cast(parameter->type.get())) { + auto base_type = ptr_type->base_type().Clone(); + if (auto func_type = dynamic_cast(base_type.get())) { + auto return_type = func_type->return_type().IsPtr() == true + ? (llvm::Type*)util_.intPtrTy + : (llvm::Type*)util_.intTy; + std::vector func_params; + for (auto& func_param : func_type->param_types()) { + func_params.push_back(func_param->IsPtr() == true + ? (llvm::Type*)util_.intPtrTy + : (llvm::Type*)util_.intTy); + } + auto func_ptr_type = + llvm::FunctionType::get(return_type, func_params, false); + param_type = func_ptr_type; } else { - params.push_back(util_.intTy); + param_type = util_.intPtrTy; } + } else { + param_type = util_.intTy; } - auto func_type = llvm::FunctionType::get(util_.intTy, params, false); + return param_type; +} + +void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { + std::vector param_types(func_def.parameters.size(), util_.intTy); + auto func_type = llvm::FunctionType::get(util_.intTy, param_types, false); auto func = llvm::Function::Create(func_type, func_def.id == "main" ? llvm::Function::ExternalLinkage @@ -222,10 +241,24 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { for (auto& parameter : func_def.parameters) { parameter->Accept(*this); args_iter->setName(parameter->id); - auto addr = builder_->CreateAlloca(args_iter->getType()); - builder_->CreateStore(args_iter, addr); - id_to_val.at(parameter->id) = addr; - val_to_type[addr] = args_iter->getType(); + + llvm::Type* param_type = GetParamType_(parameter); + // TODO: refactor + if (param_type->isFunctionTy()) { + auto func_type = param_type; + param_type = param_type->getPointerTo(); + args_iter->mutateType(param_type); + auto addr = builder_->CreateAlloca(param_type); + builder_->CreateStore(args_iter, addr); + id_to_val[parameter->id] = addr; + val_to_type[addr] = func_type; + } else { + args_iter->mutateType(param_type); + auto addr = builder_->CreateAlloca(param_type); + builder_->CreateStore(args_iter, addr); + id_to_val[parameter->id] = addr; + val_to_type[addr] = param_type; + } ++args_iter; } @@ -514,14 +547,16 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { auto return_res = builder_->CreateCall(called_func, arg_vals); val_recorder.Record(return_res); } - } else if (llvm::dyn_cast(val->getType())) { + } else if (val->getType()->isPointerTy()) { auto func_ptr = val_to_id_addr.at(val); - assert(func_ptr); auto type = val_to_type.at(func_ptr); - auto func_type = llvm::dyn_cast(type); - assert(func_type); - auto return_res = builder_->CreateCall(func_type, val, arg_vals); - val_recorder.Record(return_res); + if (auto func_type = llvm::dyn_cast(type)) { + auto return_res = builder_->CreateCall(func_type, val, arg_vals); + val_recorder.Record(return_res); + } else { + // TODO: unreachable + assert(false); + } } } From 2dfce85ae043a7c706147d16795350860ad510ea Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 30 Jun 2024 23:28:31 +0800 Subject: [PATCH 33/84] Implement goto and id label statement code generation --- src/llvm_ir_generator.cpp | 42 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 9cfc9bbb..6a444740 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -401,7 +401,24 @@ void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { builder_->CreateRet(expr); } -void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) {} +void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { + auto func = builder_->GetInsertBlock()->getParent(); + llvm::BasicBlock* target_BB = nullptr; + for (auto b = func->begin(), be = func->end(); b != be; ++b) { + auto& BB = b; + if (BB->getName() == goto_stmt.label) { + target_BB = &(*BB); + break; + } + } + + if (target_BB) { + builder_->CreateBr(target_BB); + } else { + auto label_BB = llvm::BasicBlock::Create(*context_, goto_stmt.label, func); + builder_->CreateBr(label_BB); + } +} void LLVMIRGenerator::Visit(const BreakStmtNode& break_stmt) { assert(!label_views_of_jumpable_blocks.empty()); @@ -415,7 +432,26 @@ void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) {} -void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) {} +void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { + auto func = builder_->GetInsertBlock()->getParent(); + llvm::BasicBlock* target_BB = nullptr; + for (auto b = func->begin(), be = func->end(); b != be; ++b) { + auto& BB = b; + if (BB->getName() == id_labeled_stmt.label) { + target_BB = &(*BB); + builder_->SetInsertPoint(target_BB); + break; + } + } + + if (!target_BB) { + auto label_BB = + llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, func); + builder_->SetInsertPoint(label_BB); + } + + id_labeled_stmt.stmt->Accept(*this); +} void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) {} @@ -535,7 +571,7 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { // builtin_print call auto printf = module_->getFunction("printf"); std::vector print_args{}; - // NOTE: set AllowInternal as true to get internal linkage global variable + // NOTE: set AllowInternal true to get internal linkage global variable auto print_format = module_->getGlobalVariable("__builtin_print_format", true); assert(print_format); From 98a05f307709310ec848d56e5d752611aff71516 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 01:28:46 +0800 Subject: [PATCH 34/84] Add newline at the end of the file --- include/llvm/util.hpp | 2 +- include/llvm_ir_generator.hpp | 2 +- main.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index df424989..8564e937 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -46,4 +46,4 @@ class Util { } // namespace util -#endif // LLVM_UTIL_HPP_ \ No newline at end of file +#endif // LLVM_UTIL_HPP_ diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 72c27d28..82046543 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -80,4 +80,4 @@ class LLVMIRGenerator : public NonModifyingVisitor { llvm::Type* GetParamType_(const std::unique_ptr& parameter); }; -#endif // LLVM_IR_GENERATOR_HPP_ \ No newline at end of file +#endif // LLVM_IR_GENERATOR_HPP_ diff --git a/main.cpp b/main.cpp index 664f025c..5b2dd1cb 100644 --- a/main.cpp +++ b/main.cpp @@ -153,4 +153,4 @@ int LLVMBuilder(std::unique_ptr trans_unit, output_ir.close(); return 0; -} \ No newline at end of file +} From 99b707329ac2deefc1604056ed7a573c9a207528 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 01:56:34 +0800 Subject: [PATCH 35/84] Implement switch, case, default statement code generation --- include/llvm/util.hpp | 20 +++++++++++ src/llvm_ir_generator.cpp | 70 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 8564e937..78d58f6a 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -34,6 +34,26 @@ class Util { } } + /// @brief Create a branch instruction to the next basic block. + void CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, + llvm::BasicBlock* next_BB) { + auto BB = curr_BB; + bool has_terminator = false; + for (auto it = BB->begin(); it != BB->end();) { + if (it->isTerminator()) { + has_terminator = true; + break; + } else { + ++it; + } + } + + if (!has_terminator) { + builder_->SetInsertPoint(curr_BB); + builder_->CreateBr(next_BB); + } + } + Util(std::unique_ptr>& builder) : builder_{builder} { intTy = builder_->getInt32Ty(); intPtrTy = builder_->getPtrTy(); diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 6a444740..be77874d 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -122,6 +122,7 @@ auto struct LabelViewPair { llvm::BasicBlock* entry; llvm::BasicBlock* exit; + std::vector> cases{}; }; /// @note Blocks that allows jumping within or out of it should add its labels @@ -404,6 +405,7 @@ void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { auto func = builder_->GetInsertBlock()->getParent(); llvm::BasicBlock* target_BB = nullptr; + // TODO: refactor for (auto b = func->begin(), be = func->end(); b != be; ++b) { auto& BB = b; if (BB->getName() == goto_stmt.label) { @@ -422,19 +424,54 @@ void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { void LLVMIRGenerator::Visit(const BreakStmtNode& break_stmt) { assert(!label_views_of_jumpable_blocks.empty()); - builder_->CreateBr(label_views_of_jumpable_blocks.back().exit); + util_.CreateBrIfNoBrBefore(label_views_of_jumpable_blocks.back().exit); } void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { assert(!label_views_of_jumpable_blocks.empty()); - builder_->CreateBr(label_views_of_jumpable_blocks.back().entry); + util_.CreateBrIfNoBrBefore(label_views_of_jumpable_blocks.back().entry); } -void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) {} +void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { + switch_stmt.ctrl->Accept(*this); + auto ctrl = val_recorder.ValOfPrevExpr(); + + auto func = builder_->GetInsertBlock()->getParent(); + auto end_BB = llvm::BasicBlock::Create(*context_, "switch_end", func); + auto sw = builder_->CreateSwitch(ctrl, nullptr); + label_views_of_jumpable_blocks.push_back({.entry = end_BB, .exit = end_BB}); + switch_stmt.stmt->Accept(*this); + // Update cases and default + auto switch_infos = label_views_of_jumpable_blocks.back(); + for (auto i = std::size_t{0}, e = switch_infos.cases.size(); i < e; ++i) { + auto case_info = switch_infos.cases.at(i); + auto curr_BB = case_info.second; + if (!case_info.first) { // default case + sw->setDefaultDest(curr_BB); + } else { + auto const_val = llvm::dyn_cast(case_info.first); + assert(const_val); + sw->addCase(const_val, curr_BB); + } + + // NOTE: if BB has no terminator, add one branch to next BB + // if BB is the last BB, then branch to switch_infos.exit + if (i + 1 != e) { + auto next_BB = switch_infos.cases.at(i + 1).second; + util_.CurrBBFallThroughNextBB(curr_BB, next_BB); + } else { + util_.CurrBBFallThroughNextBB(curr_BB, switch_infos.exit); + } + } + label_views_of_jumpable_blocks.pop_back(); + util_.CreateBrIfNoBrBefore(end_BB); + builder_->SetInsertPoint(end_BB); +} void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { auto func = builder_->GetInsertBlock()->getParent(); llvm::BasicBlock* target_BB = nullptr; + // TODO: refactor for (auto b = func->begin(), be = func->end(); b != be; ++b) { auto& BB = b; if (BB->getName() == id_labeled_stmt.label) { @@ -453,9 +490,32 @@ void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { id_labeled_stmt.stmt->Accept(*this); } -void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) {} +void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { + case_stmt.expr->Accept(*this); + auto val = val_recorder.ValOfPrevExpr(); + auto int_expr = dynamic_cast(case_stmt.expr.get()); + assert(int_expr); + + auto func = builder_->GetInsertBlock()->getParent(); + auto case_BB = llvm::BasicBlock::Create( + *context_, "case" + std::to_string(int_expr->val), func); -void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) {} + builder_->SetInsertPoint(case_BB); + case_stmt.stmt->Accept(*this); + + assert(!label_views_of_jumpable_blocks.empty()); + label_views_of_jumpable_blocks.back().cases.push_back({val, case_BB}); +} + +void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { + auto func = builder_->GetInsertBlock()->getParent(); + auto default_BB = llvm::BasicBlock::Create(*context_, "default", func); + builder_->SetInsertPoint(default_BB); + default_stmt.stmt->Accept(*this); + + assert(!label_views_of_jumpable_blocks.empty()); + label_views_of_jumpable_blocks.back().cases.push_back({nullptr, default_BB}); +} void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) { expr_stmt.expr->Accept(*this); From 5de045d3b125966e719b47d70cedf1979748cf6e Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 02:06:10 +0800 Subject: [PATCH 36/84] Use simpler builder function --- src/llvm_ir_generator.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index be77874d..3f8954dc 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -694,8 +694,7 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { case UnaryOperator::kNeg: { auto operand = val_recorder.ValOfPrevExpr(); auto zero = llvm::ConstantInt::get(util_.intTy, 0, true); - auto res = - builder_->CreateBinOp(llvm::BinaryOperator::Sub, zero, operand); + auto res = builder_->CreateSub(zero, operand); val_recorder.Record(res); } break; case UnaryOperator::kNot: { @@ -707,8 +706,7 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { case UnaryOperator::kBitComp: { auto operand = val_recorder.ValOfPrevExpr(); auto all_ones = llvm::ConstantInt::get(util_.intTy, -1, true); - auto res = - builder_->CreateBinOp(llvm::BinaryOperator::Xor, operand, all_ones); + auto res = builder_->CreateXor(operand, all_ones); val_recorder.Record(res); } break; case UnaryOperator::kAddr: { From 4730d88c8779987558ea734f15fa3dd9ee1d7945 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 15:20:30 +0800 Subject: [PATCH 37/84] Add GetFieldTypes to get field types of record type variable --- include/llvm_ir_generator.hpp | 5 ++++- include/type.hpp | 10 ++++++++++ src/llvm_ir_generator.cpp | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 82046543..6077f901 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -76,8 +76,11 @@ class LLVMIRGenerator : public NonModifyingVisitor { llvm::Module* module_; /// @brief Handy LLVM types and functions for code generation. util::Util util_; - /// @brief Get LLVM type from function parameter + /// @brief Get LLVM type from function parameter. llvm::Type* GetParamType_(const std::unique_ptr& parameter); + /// @brief Get LLVM types from record fields. + std::vector GetFieldTypes_( + const std::vector>& fields); }; #endif // LLVM_IR_GENERATOR_HPP_ diff --git a/include/type.hpp b/include/type.hpp index 35f96721..a455b638 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -188,6 +188,10 @@ class RecordType : public Type { /// @return The type id. virtual std::string id() // NOLINT(readability-identifier-naming) const noexcept = 0; + /// @return The fields of a record type. + virtual const std::vector>& + fields() // NOLINT(readability-identifier-naming) + const noexcept = 0; /// @brief Checks if `id` is a member of the record type. virtual bool IsMember(const std::string& id) const noexcept = 0; /// @return The type of a member in struct or union. The unknown type if the @@ -214,6 +218,9 @@ class StructType : public RecordType { StructType(std::string id, std::vector> fields) : id_{std::move(id)}, fields_{std::move(fields)} {} + const std::vector>& fields() const noexcept override { + return fields_; + } std::string id() const noexcept override; bool IsMember(const std::string& id) const noexcept override; std::unique_ptr MemberType( @@ -243,6 +250,9 @@ class UnionType : public RecordType { UnionType(std::string id, std::vector> fields) : id_{std::move(id)}, fields_{std::move(fields)} {} + const std::vector>& fields() const noexcept override { + return fields_; + } std::string id() const noexcept override; bool IsMember(const std::string& id) const noexcept override; std::unique_ptr MemberType( diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 3f8954dc..0ef8dcb0 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -184,7 +184,7 @@ void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { } } -void LLVMIRGenerator::Visit(const RecordDeclNode& struct_def) { +void LLVMIRGenerator::Visit(const RecordDeclNode& record_decl) { /* Do nothing because this node only declares a type. */ } @@ -192,7 +192,35 @@ void LLVMIRGenerator::Visit(const FieldNode& field) { /* Do nothing because this node only declares a member type in a record. */ } -void LLVMIRGenerator::Visit(const RecordVarDeclNode& struct_def) {} +std::vector LLVMIRGenerator::GetFieldTypes_( + const std::vector>& fields) { + std::vector field_types; + // TODO: support nested record. + // TODO: refactor to support multiple data types + for (auto& field : fields) { + if (field->type->IsPtr()) { + field_types.push_back(util_.intPtrTy); + } else { + field_types.push_back(util_.intTy); + } + } + + return field_types; +} + +void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { + // Define Record fields + auto* record_type = dynamic_cast(record_var_decl.type.get()); + assert(record_type); + auto field_types = GetFieldTypes_(record_type->fields()); + auto struct_type = llvm::StructType::create(*context_, field_types, + "struct_" + record_type->id()); + auto res = builder_->CreateAlloca(struct_type, nullptr); + + assert(res); + // Define Struct or Union type + // Allocate memory for the struct instance +} void LLVMIRGenerator::Visit(const ParamNode& parameter) { /* Do nothing */ From d7c92a88eb14b5bba667fdf716c57de7a76eacc5 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 16:29:58 +0800 Subject: [PATCH 38/84] Implement Struct and Union variable declaration code generation --- include/llvm_ir_generator.hpp | 1 + include/type.hpp | 6 +++++ src/llvm_ir_generator.cpp | 47 ++++++++++++++++++++++++++++++----- src/type.cpp | 22 ++++++++++++++++ 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 6077f901..2a455fd6 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -48,6 +48,7 @@ class LLVMIRGenerator : public NonModifyingVisitor { void Visit(const ArrSubExprNode&) override; void Visit(const CondExprNode&) override; void Visit(const FuncCallExprNode&) override; + void Visit(const RecordMemExprNode&) override; void Visit(const PostfixArithExprNode&) override; void Visit(const UnaryExprNode&) override; void Visit(const BinaryExprNode&) override; diff --git a/include/type.hpp b/include/type.hpp index a455b638..4380aa1b 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -198,6 +198,10 @@ class RecordType : public Type { /// `id` is not a member of the record type. virtual std::unique_ptr MemberType( const std::string& id) const noexcept = 0; + /// @note Every member in union shares the same index 0. + /// @return The index of a member in struct or union. + /// @throw `std::runtime_error` if the `id` is not a member of the record. + virtual std::size_t MemberIndex(const std::string& id) const = 0; /// @note Every member in union shares the same offset 0. /// @return The type offset in the record based on `id`. /// @throw `std::runtime_error` if the `id` is not a member of the record. @@ -225,6 +229,7 @@ class StructType : public RecordType { bool IsMember(const std::string& id) const noexcept override; std::unique_ptr MemberType( const std::string& id) const noexcept override; + std::size_t MemberIndex(const std::string& id) const override; std::size_t OffsetOf(const std::string& id) const override; std::size_t OffsetOf(std::size_t index) const override; std::size_t SlotCount() const noexcept override; @@ -257,6 +262,7 @@ class UnionType : public RecordType { bool IsMember(const std::string& id) const noexcept override; std::unique_ptr MemberType( const std::string& id) const noexcept override; + std::size_t MemberIndex(const std::string& id) const override; std::size_t OffsetOf(const std::string& id) const override; std::size_t OffsetOf(std::size_t index) const override; std::size_t SlotCount() const noexcept override; diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 0ef8dcb0..123d9208 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -213,13 +213,32 @@ void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { auto* record_type = dynamic_cast(record_var_decl.type.get()); assert(record_type); auto field_types = GetFieldTypes_(record_type->fields()); - auto struct_type = llvm::StructType::create(*context_, field_types, - "struct_" + record_type->id()); - auto res = builder_->CreateAlloca(struct_type, nullptr); + std::string record_prefix = ""; + if (record_type->IsStruct()) { + record_prefix += "struct_"; + } else { + record_prefix += "union_"; + } - assert(res); - // Define Struct or Union type - // Allocate memory for the struct instance + auto type = llvm::StructType::create(*context_, field_types, + record_prefix + record_type->id()); + auto base_addr = builder_->CreateAlloca(type, nullptr); + id_to_val[record_var_decl.id] = base_addr; + val_to_type[base_addr] = type; + + // NOTE: This predicate will make sure that we don't initialize members that + // exceed the total number of members in a record. Also, it gurantees + // that accessing element in the initializers will not go out of bound. + for (auto i = std::size_t{0}, e = record_var_decl.inits.size(), + slot_count = record_type->SlotCount(); + i < slot_count && i < e; ++i) { + auto& init = record_var_decl.inits.at(i); + init->Accept(*this); + auto init_val = val_recorder.ValOfPrevExpr(); + + auto res_addr = builder_->CreateStructGEP(type, base_addr, i); + builder_->CreateStore(init_val, res_addr); + } } void LLVMIRGenerator::Visit(const ParamNode& parameter) { @@ -700,6 +719,22 @@ void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) { builder_->CreateStore(res, id_to_val.at(id_expr->id)); } +void LLVMIRGenerator::Visit(const RecordMemExprNode& mem_expr) { + mem_expr.expr->Accept(*this); + auto val = val_recorder.ValOfPrevExpr(); + auto base_addr = val_to_id_addr.at(val); + auto struct_type = val_to_type.at(base_addr); + auto* record_type = dynamic_cast(mem_expr.expr->type.get()); + assert(record_type); + + auto res_addr = builder_->CreateStructGEP( + struct_type, base_addr, record_type->MemberIndex(mem_expr.id)); + // TODO: get type + auto res_val = builder_->CreateLoad(util_.intTy, res_addr); + val_to_id_addr[res_val] = res_addr; + val_recorder.Record(res_val); +} + void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { unary_expr.operand->Accept(*this); switch (unary_expr.op) { diff --git a/src/type.cpp b/src/type.cpp index e15ea014..4eea5d59 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -182,6 +182,17 @@ std::unique_ptr StructType::MemberType( return std::make_unique(PrimitiveType::kUnknown); } +std::size_t StructType::MemberIndex(const std::string& id) const { + for (auto i = std::size_t{0}, e = fields_.size(); i < e; ++i) { + const auto& field = fields_.at(i); + if (field->id == id) { + return i; + } + } + + throw std::runtime_error{"member not found in struct!"}; +} + std::size_t StructType::OffsetOf(const std::string& id) const { std::size_t offset = 0; for (auto i = std::size_t{0}, e = fields_.size(); i < e; ++i) { @@ -277,6 +288,17 @@ std::unique_ptr UnionType::MemberType( return std::make_unique(PrimitiveType::kUnknown); } +std::size_t UnionType::MemberIndex(const std::string& id) const { + for (auto i = std::size_t{0}, e = fields_.size(); i < e; ++i) { + const auto& field = fields_.at(i); + if (field->id == id) { + return 0; + } + } + + throw std::runtime_error{"member not found in struct!"}; +} + std::size_t UnionType::OffsetOf(const std::string& id) const { return 0; } From e3043061c5e888f1935cfe79caca41963ccfa37d Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 16:53:53 +0800 Subject: [PATCH 39/84] Add comments and use smart pointers for module --- include/llvm_ir_generator.hpp | 12 +++++++----- src/llvm_ir_generator.cpp | 9 +++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 2a455fd6..51e9694d 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -58,7 +58,7 @@ class LLVMIRGenerator : public NonModifyingVisitor { : output_{output}, context_{std::make_unique()}, builder_{std::make_unique>(*context_)}, - module_{new llvm::Module(filename, *context_)}, + module_{std::make_unique(filename, *context_)}, util_{util::Util(builder_)} {} /// @brief Print LLVM IR to output_. @@ -69,12 +69,14 @@ class LLVMIRGenerator : public NonModifyingVisitor { private: /// @brief A LLVM ostream wrapper for writing to output. llvm::raw_os_ostream output_; - /// @brief A LLVM core object. + /// @brief A LLVM object that includes core LLVM infrastructure. std::unique_ptr context_; - /// @brief Provides LLVM Builder API for constructing IR. + /// @brief Provides LLVM Builder API for constructing IR. By default, Constant + /// folding is enabled and we have more flexibility for inserting + /// instructions. std::unique_ptr> builder_; - /// @brief Stores LLVM related information, including the constructed IR. - llvm::Module* module_; + /// @brief Stores global variables, function lists, and the constructed IR. + std::unique_ptr module_; /// @brief Handy LLVM types and functions for code generation. util::Util util_; /// @brief Get LLVM type from function parameter. diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 123d9208..56c7ffd1 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -280,7 +280,7 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { func_def.id == "main" ? llvm::Function::ExternalLinkage : llvm::Function::InternalLinkage, - func_def.id, module_); + func_def.id, *module_); auto body = llvm::BasicBlock::Create(*context_, "body", func); builder_->SetInsertPoint(body); @@ -333,14 +333,15 @@ void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { auto arg = llvm::ArrayRef{util_.intTy}; auto builtin_print = llvm::FunctionType::get(util_.intTy, arg, false); llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, - "__builtin_print", module_); + "__builtin_print", *module_); auto args = llvm::ArrayRef{util_.intPtrTy, util_.intTy}; auto printf = llvm::FunctionType::get(util_.intTy, args, false); llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", - module_); + *module_); - builder_->CreateGlobalString("%d\n", "__builtin_print_format", 0, module_); + builder_->CreateGlobalString("%d\n", "__builtin_print_format", 0, + module_.get()); for (const auto& extern_decl : trans_unit.extern_decls) { extern_decl->Accept(*this); From 6cc3e4059528b8b15deb37185e8c86f1e13e9c23 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 17:07:09 +0800 Subject: [PATCH 40/84] Update binary operator helper functions --- src/llvm_ir_generator.cpp | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 56c7ffd1..6a0d737d 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -10,6 +10,7 @@ namespace { +/// @throw `std::runtime_error` if there's unrecognize binary operator llvm::Instruction::BinaryOps GetBinaryOperator(BinaryOperator op) { switch (op) { case BinaryOperator::kAdd: @@ -30,37 +31,32 @@ llvm::Instruction::BinaryOps GetBinaryOperator(BinaryOperator op) { return llvm::BinaryOperator::Or; case BinaryOperator::kShl: return llvm::BinaryOperator::Shl; - // NOTE: Arithmetic shift right (sar) is akin to dividing by a power of two + // NOTE: Arithmetic shift right (AShr) is akin to dividing by a power of two // for non-negative numbers. For negatives, it's implementation-defined, so // we opt for arithmetic shifting. case BinaryOperator::kShr: return llvm::BinaryOperator::AShr; default: - // TODO: unreachable - return llvm::BinaryOperator::Xor; + throw std::runtime_error{"unrecognize binary operator!"}; } } -llvm::CmpInst::Predicate GetCmpOperator(BinaryOperator op) { +/// @note Comparison operators are not categorized as operator in LLVM. Thus, we +/// have this helper function to get the predicate of our comparison operator. +llvm::CmpInst::Predicate GetCmpPredicate(BinaryOperator op) { switch (op) { - case BinaryOperator::kGt: { + case BinaryOperator::kGt: return llvm::CmpInst::Predicate::ICMP_SGT; - } break; - case BinaryOperator::kGte: { + case BinaryOperator::kGte: return llvm::CmpInst::Predicate::ICMP_SGE; - } break; - case BinaryOperator::kLt: { + case BinaryOperator::kLt: return llvm::CmpInst::Predicate::ICMP_SLT; - } break; - case BinaryOperator::kLte: { + case BinaryOperator::kLte: return llvm::CmpInst::Predicate::ICMP_SLE; - } break; - case BinaryOperator::kEq: { + case BinaryOperator::kEq: return llvm::CmpInst::Predicate::ICMP_EQ; - } break; - case BinaryOperator::kNeq: { + case BinaryOperator::kNeq: return llvm::CmpInst::Predicate::ICMP_NE; - } break; default: return llvm::CmpInst::Predicate::BAD_ICMP_PREDICATE; } @@ -73,9 +69,8 @@ bool isCmpInst(BinaryOperator op) { case BinaryOperator::kLt: case BinaryOperator::kLte: case BinaryOperator::kEq: - case BinaryOperator::kNeq: { + case BinaryOperator::kNeq: return true; - } break; default: return false; } @@ -851,7 +846,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { } else if (isCmpInst(bin_expr.op)) { bin_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); - auto res = builder_->CreateCmp(GetCmpOperator(bin_expr.op), lhs, rhs); + auto res = builder_->CreateCmp(GetCmpPredicate(bin_expr.op), lhs, rhs); val_recorder.Record(res); } else { bin_expr.rhs->Accept(*this); From 70f5a48ee0071c370c4526f11439f5c26ae30189 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 17:24:22 +0800 Subject: [PATCH 41/84] Rename struct and update comments --- src/llvm_ir_generator.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 6a0d737d..ee59549e 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -87,13 +87,14 @@ auto // as a data member introduces unnecessary dependency. = std::map{}; +// TODO: replaced this with GetType auto val_to_type // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): // Accessible only within this translation unit; declaring // as a data member introduces unnecessary dependency. = std::map{}; -/// @brief Store LLVM Value class at the bottom level of AST node. Upper level -/// AST node can use the information in Value directly. +/// @brief Every expression generates a LLVM object that is the subclass of +/// `llvm::Value`. This object is stored, so we can propagate to later use. class PrevValueRecorder { public: void Record(llvm::Value* val) { @@ -101,11 +102,12 @@ class PrevValueRecorder { } llvm::Value* ValOfPrevExpr() { + assert(prev_val_); return prev_val_; } private: - llvm::Value* prev_val_; + llvm::Value* prev_val_ = nullptr; }; auto @@ -114,17 +116,22 @@ auto // a data member introduces unnecessary dependency. = PrevValueRecorder{}; -struct LabelViewPair { +struct LabelViewInfo { llvm::BasicBlock* entry; llvm::BasicBlock* exit; + /// @brief This vector stores every `case` and `default` basic blocks of + /// a switch case. + /// This first element of a pair is the expression value + /// of a case statement. + /// This second element of a pair is the label's basic block. std::vector> cases{}; }; /// @note Blocks that allows jumping within or out of it should add its labels -/// to this list +/// to this list. auto label_views_of_jumpable_blocks // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - = std::vector{}; + = std::vector{}; } // namespace From afef598e8c5e5ee405c2ada0ab2a5e41a89ce8be Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 17:35:59 +0800 Subject: [PATCH 42/84] Separate LLVM util class header and source file --- include/llvm/util.hpp | 40 +++++----------------------------------- src/llvm/util.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 35 deletions(-) create mode 100644 src/llvm/util.cpp diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 78d58f6a..bd03efcd 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -15,44 +15,14 @@ class Util { /// @brief Every LLVM basic block can only have one terminator instruction. /// This function can check if there are terminator instructions before the - /// current insert point. If yes, then it will create an unconditional branch. - /// If no, then it will not create branch instruction. - void CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB) { - auto BB = builder_->GetInsertBlock(); - bool has_terminator = false; - for (auto it = BB->begin(); it != BB->end();) { - if (it->isTerminator()) { - has_terminator = true; - break; - } else { - ++it; - } - } - - if (!has_terminator) { - builder_->CreateBr(next_BB); - } - } + /// current insert point. If no, then it will create an unconditional branch + /// to the next basic block. If yes, then it will not create branch + /// instruction. + void CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB); /// @brief Create a branch instruction to the next basic block. void CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, - llvm::BasicBlock* next_BB) { - auto BB = curr_BB; - bool has_terminator = false; - for (auto it = BB->begin(); it != BB->end();) { - if (it->isTerminator()) { - has_terminator = true; - break; - } else { - ++it; - } - } - - if (!has_terminator) { - builder_->SetInsertPoint(curr_BB); - builder_->CreateBr(next_BB); - } - } + llvm::BasicBlock* next_BB); Util(std::unique_ptr>& builder) : builder_{builder} { intTy = builder_->getInt32Ty(); diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp new file mode 100644 index 00000000..b34749d7 --- /dev/null +++ b/src/llvm/util.cpp @@ -0,0 +1,41 @@ +#include "llvm/util.hpp" + +#include + +using namespace util; + +void Util::CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB) { + auto BB = builder_->GetInsertBlock(); + bool has_terminator = false; + for (auto it = BB->begin(); it != BB->end();) { + if (it->isTerminator()) { + has_terminator = true; + break; + } else { + ++it; + } + } + + if (!has_terminator) { + builder_->CreateBr(next_BB); + } +} + +void Util::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, + llvm::BasicBlock* next_BB) { + auto BB = curr_BB; + bool has_terminator = false; + for (auto it = BB->begin(); it != BB->end();) { + if (it->isTerminator()) { + has_terminator = true; + break; + } else { + ++it; + } + } + + if (!has_terminator) { + builder_->SetInsertPoint(curr_BB); + builder_->CreateBr(next_BB); + } +} \ No newline at end of file From 605ad92093291b20d2ead4c323d4e0475b14d45c Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 17:46:52 +0800 Subject: [PATCH 43/84] Rename util and type names --- include/llvm/util.hpp | 18 +++++---- include/llvm_ir_generator.hpp | 4 +- src/llvm/util.cpp | 8 ++-- src/llvm_ir_generator.cpp | 76 ++++++++++++++++++----------------- 4 files changed, 57 insertions(+), 49 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index bd03efcd..0551482a 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -3,15 +3,17 @@ #include +#include "type.hpp" + namespace util { /// @brief A collection of wrappers of LLVM types and functions. -class Util { +class LLVMIRUtil { public: - /// @brief Integer type - llvm::IntegerType* intTy; - /// @brief Pointer type - llvm::PointerType* intPtrTy; + /// @brief LLVM Integer type + llvm::IntegerType* IntType; + /// @brief LLVM Pointer type + llvm::PointerType* IntPtrType; /// @brief Every LLVM basic block can only have one terminator instruction. /// This function can check if there are terminator instructions before the @@ -24,9 +26,9 @@ class Util { void CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, llvm::BasicBlock* next_BB); - Util(std::unique_ptr>& builder) : builder_{builder} { - intTy = builder_->getInt32Ty(); - intPtrTy = builder_->getPtrTy(); + LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} { + IntType = builder_->getInt32Ty(); + IntPtrType = builder_->getPtrTy(); } private: diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 51e9694d..1f3f4124 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -59,7 +59,7 @@ class LLVMIRGenerator : public NonModifyingVisitor { context_{std::make_unique()}, builder_{std::make_unique>(*context_)}, module_{std::make_unique(filename, *context_)}, - util_{util::Util(builder_)} {} + llvm_util_{util::LLVMIRUtil(builder_)} {} /// @brief Print LLVM IR to output_. void PrintIR() { @@ -78,7 +78,7 @@ class LLVMIRGenerator : public NonModifyingVisitor { /// @brief Stores global variables, function lists, and the constructed IR. std::unique_ptr module_; /// @brief Handy LLVM types and functions for code generation. - util::Util util_; + util::LLVMIRUtil llvm_util_; /// @brief Get LLVM type from function parameter. llvm::Type* GetParamType_(const std::unique_ptr& parameter); /// @brief Get LLVM types from record fields. diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index b34749d7..a43be4f0 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -2,9 +2,11 @@ #include +#include "type.hpp" + using namespace util; -void Util::CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB) { +void LLVMIRUtil::CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB) { auto BB = builder_->GetInsertBlock(); bool has_terminator = false; for (auto it = BB->begin(); it != BB->end();) { @@ -21,8 +23,8 @@ void Util::CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB) { } } -void Util::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, - llvm::BasicBlock* next_BB) { +void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, + llvm::BasicBlock* next_BB) { auto BB = curr_BB; bool has_terminator = false; for (auto it = BB->begin(); it != BB->end();) { diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index ee59549e..8f2a8f2e 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -142,8 +142,9 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { } void LLVMIRGenerator::Visit(const VarDeclNode& decl) { - auto var_type = decl.type->IsPtr() == true ? (llvm::Type*)util_.intPtrTy - : (llvm::Type*)util_.intTy; + auto var_type = decl.type->IsPtr() == true + ? (llvm::Type*)llvm_util_.IntPtrType + : (llvm::Type*)llvm_util_.IntType; auto addr = builder_->CreateAlloca(var_type); if (decl.init) { decl.init->Accept(*this); @@ -160,7 +161,7 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { auto arr_decl_type = dynamic_cast((arr_decl.type).get()); auto arr_type = llvm::ArrayType::get( - util_.intTy, + llvm_util_.IntType, arr_decl_type->size() / arr_decl_type->element_type().size()); auto base_addr = builder_->CreateAlloca(arr_type, nullptr); id_to_val[arr_decl.id] = base_addr; @@ -180,7 +181,7 @@ void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { builder_->CreateStore(init_val, res_addr); } else { // set remaining elements as 0 - auto zero = llvm::ConstantInt::get(util_.intTy, 0, true); + auto zero = llvm::ConstantInt::get(llvm_util_.IntType, 0, true); builder_->CreateStore(zero, res_addr); } } @@ -201,9 +202,9 @@ std::vector LLVMIRGenerator::GetFieldTypes_( // TODO: refactor to support multiple data types for (auto& field : fields) { if (field->type->IsPtr()) { - field_types.push_back(util_.intPtrTy); + field_types.push_back(llvm_util_.IntPtrType); } else { - field_types.push_back(util_.intTy); + field_types.push_back(llvm_util_.IntType); } } @@ -254,30 +255,32 @@ llvm::Type* LLVMIRGenerator::GetParamType_( auto base_type = ptr_type->base_type().Clone(); if (auto func_type = dynamic_cast(base_type.get())) { auto return_type = func_type->return_type().IsPtr() == true - ? (llvm::Type*)util_.intPtrTy - : (llvm::Type*)util_.intTy; + ? (llvm::Type*)llvm_util_.IntPtrType + : (llvm::Type*)llvm_util_.IntType; std::vector func_params; for (auto& func_param : func_type->param_types()) { func_params.push_back(func_param->IsPtr() == true - ? (llvm::Type*)util_.intPtrTy - : (llvm::Type*)util_.intTy); + ? (llvm::Type*)llvm_util_.IntPtrType + : (llvm::Type*)llvm_util_.IntType); } auto func_ptr_type = llvm::FunctionType::get(return_type, func_params, false); param_type = func_ptr_type; } else { - param_type = util_.intPtrTy; + param_type = llvm_util_.IntPtrType; } } else { - param_type = util_.intTy; + param_type = llvm_util_.IntType; } return param_type; } void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { - std::vector param_types(func_def.parameters.size(), util_.intTy); - auto func_type = llvm::FunctionType::get(util_.intTy, param_types, false); + std::vector param_types(func_def.parameters.size(), + llvm_util_.IntType); + auto func_type = + llvm::FunctionType::get(llvm_util_.IntType, param_types, false); auto func = llvm::Function::Create(func_type, func_def.id == "main" ? llvm::Function::ExternalLinkage @@ -332,13 +335,14 @@ void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. - auto arg = llvm::ArrayRef{util_.intTy}; - auto builtin_print = llvm::FunctionType::get(util_.intTy, arg, false); + auto arg = llvm::ArrayRef{llvm_util_.IntType}; + auto builtin_print = llvm::FunctionType::get(llvm_util_.IntType, arg, false); llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, "__builtin_print", *module_); - auto args = llvm::ArrayRef{util_.intPtrTy, util_.intTy}; - auto printf = llvm::FunctionType::get(util_.intTy, args, false); + auto args = + llvm::ArrayRef{llvm_util_.IntPtrType, llvm_util_.IntType}; + auto printf = llvm::FunctionType::get(llvm_util_.IntType, args, false); llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", *module_); @@ -366,7 +370,7 @@ void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { if_stmt.or_else != nullptr ? else_BB : end_BB); builder_->SetInsertPoint(then_BB); if_stmt.then->Accept(*this); - util_.CreateBrIfNoBrBefore(end_BB); + llvm_util_.CreateBrIfNoBrBefore(end_BB); if (if_stmt.or_else) { builder_->SetInsertPoint(else_BB); @@ -474,12 +478,12 @@ void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { void LLVMIRGenerator::Visit(const BreakStmtNode& break_stmt) { assert(!label_views_of_jumpable_blocks.empty()); - util_.CreateBrIfNoBrBefore(label_views_of_jumpable_blocks.back().exit); + llvm_util_.CreateBrIfNoBrBefore(label_views_of_jumpable_blocks.back().exit); } void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { assert(!label_views_of_jumpable_blocks.empty()); - util_.CreateBrIfNoBrBefore(label_views_of_jumpable_blocks.back().entry); + llvm_util_.CreateBrIfNoBrBefore(label_views_of_jumpable_blocks.back().entry); } void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { @@ -508,13 +512,13 @@ void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { // if BB is the last BB, then branch to switch_infos.exit if (i + 1 != e) { auto next_BB = switch_infos.cases.at(i + 1).second; - util_.CurrBBFallThroughNextBB(curr_BB, next_BB); + llvm_util_.CurrBBFallThroughNextBB(curr_BB, next_BB); } else { - util_.CurrBBFallThroughNextBB(curr_BB, switch_infos.exit); + llvm_util_.CurrBBFallThroughNextBB(curr_BB, switch_infos.exit); } } label_views_of_jumpable_blocks.pop_back(); - util_.CreateBrIfNoBrBefore(end_BB); + llvm_util_.CreateBrIfNoBrBefore(end_BB); builder_->SetInsertPoint(end_BB); } @@ -594,11 +598,11 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { auto id_val = id_to_val.at(id_expr.id); if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { - auto res = builder_->CreateLoad(util_.intPtrTy, id_val); + auto res = builder_->CreateLoad(llvm_util_.IntPtrType, id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } else { - auto res = builder_->CreateLoad(util_.intTy, id_val); + auto res = builder_->CreateLoad(llvm_util_.IntType, id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } @@ -606,7 +610,7 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { // NOTE: LLVM Constant does not generate IR code, it can be used directly. - auto val = llvm::ConstantInt::get(util_.intTy, int_expr.val, true); + auto val = llvm::ConstantInt::get(llvm_util_.IntType, int_expr.val, true); val_recorder.Record(val); } @@ -659,7 +663,7 @@ void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { builder_->CreateBr(end_BB); builder_->SetInsertPoint(end_BB); - auto phi_res = builder_->CreatePHI(util_.intTy, 2); + auto phi_res = builder_->CreatePHI(llvm_util_.IntType, 2); phi_res->addIncoming(second_val, second_BB); phi_res->addIncoming(third_val, third_BB); val_recorder.Record(phi_res); @@ -715,7 +719,7 @@ void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) { ? llvm::BinaryOperator::Add : llvm::BinaryOperator::Sub; - auto one = llvm::ConstantInt::get(util_.intTy, 1, true); + auto one = llvm::ConstantInt::get(llvm_util_.IntType, 1, true); auto res = builder_->CreateBinOp(arith_op, val, one); const auto* id_expr = dynamic_cast((postfix_expr.operand).get()); assert(id_expr); @@ -733,7 +737,7 @@ void LLVMIRGenerator::Visit(const RecordMemExprNode& mem_expr) { auto res_addr = builder_->CreateStructGEP( struct_type, base_addr, record_type->MemberIndex(mem_expr.id)); // TODO: get type - auto res_val = builder_->CreateLoad(util_.intTy, res_addr); + auto res_val = builder_->CreateLoad(llvm_util_.IntType, res_addr); val_to_id_addr[res_val] = res_addr; val_recorder.Record(res_val); } @@ -748,7 +752,7 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { auto arith_op = unary_expr.op == UnaryOperator::kIncr ? BinaryOperator::kAdd : BinaryOperator::kSub; - auto one = llvm::ConstantInt::get(util_.intTy, 1, true); + auto one = llvm::ConstantInt::get(llvm_util_.IntType, 1, true); auto res = builder_->CreateBinOp(GetBinaryOperator(arith_op), operand, one); builder_->CreateStore(res, val_to_id_addr.at(operand)); @@ -759,19 +763,19 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { } break; case UnaryOperator::kNeg: { auto operand = val_recorder.ValOfPrevExpr(); - auto zero = llvm::ConstantInt::get(util_.intTy, 0, true); + auto zero = llvm::ConstantInt::get(llvm_util_.IntType, 0, true); auto res = builder_->CreateSub(zero, operand); val_recorder.Record(res); } break; case UnaryOperator::kNot: { auto operand = val_recorder.ValOfPrevExpr(); - auto zero = llvm::ConstantInt::get(util_.intTy, 0, true); + auto zero = llvm::ConstantInt::get(llvm_util_.IntType, 0, true); auto res = builder_->CreateICmpEQ(operand, zero); val_recorder.Record(res); } break; case UnaryOperator::kBitComp: { auto operand = val_recorder.ValOfPrevExpr(); - auto all_ones = llvm::ConstantInt::get(util_.intTy, -1, true); + auto all_ones = llvm::ConstantInt::get(llvm_util_.IntType, -1, true); auto res = builder_->CreateXor(operand, all_ones); val_recorder.Record(res); } break; @@ -796,8 +800,8 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { auto operand = val_recorder.ValOfPrevExpr(); auto res = builder_->CreateLoad(unary_expr.type->IsPtr() == true - ? (llvm::Type*)util_.intPtrTy - : (llvm::Type*)util_.intTy, + ? (llvm::Type*)llvm_util_.IntPtrType + : (llvm::Type*)llvm_util_.IntType, operand); val_recorder.Record(res); val_to_id_addr[res] = operand; From 0e589221cb3e4ec63106902c632c710feee8c920 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 18:19:50 +0800 Subject: [PATCH 44/84] Refactor VarDeclNode with GetLLVMType --- include/llvm/util.hpp | 4 ++++ src/llvm/util.cpp | 9 +++++++++ src/llvm_ir_generator.cpp | 4 +--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 0551482a..246facb7 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -2,6 +2,7 @@ #define LLVM_UTIL_HPP_ #include +#include #include "type.hpp" @@ -26,6 +27,9 @@ class LLVMIRUtil { void CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, llvm::BasicBlock* next_BB); + /// @brief Get the corresponding LLVM type from our type. + llvm::Type* GetLLVMType(const std::unique_ptr& type); + LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} { IntType = builder_->getInt32Ty(); IntPtrType = builder_->getPtrTy(); diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index a43be4f0..7bd3177e 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -1,6 +1,7 @@ #include "llvm/util.hpp" #include +#include #include "type.hpp" @@ -40,4 +41,12 @@ void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, builder_->SetInsertPoint(curr_BB); builder_->CreateBr(next_BB); } +} + +llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { + if (type->IsPtr()) { + return IntPtrType; + } + + return IntType; } \ No newline at end of file diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 8f2a8f2e..1320597e 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -142,9 +142,7 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { } void LLVMIRGenerator::Visit(const VarDeclNode& decl) { - auto var_type = decl.type->IsPtr() == true - ? (llvm::Type*)llvm_util_.IntPtrType - : (llvm::Type*)llvm_util_.IntType; + auto var_type = llvm_util_.GetLLVMType(decl.type); auto addr = builder_->CreateAlloca(var_type); if (decl.init) { decl.init->Accept(*this); From 0e2ed543a41678f34ac035e994b2b8f46974125b Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 18:36:17 +0800 Subject: [PATCH 45/84] Refactor ArrDeclNode and RecordVarDeclNode with GetLLVMType --- include/llvm_ir_generator.hpp | 3 --- src/llvm/util.cpp | 13 +++++++++++++ src/llvm_ir_generator.cpp | 34 +++------------------------------- 3 files changed, 16 insertions(+), 34 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 1f3f4124..2065d0dc 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -81,9 +81,6 @@ class LLVMIRGenerator : public NonModifyingVisitor { util::LLVMIRUtil llvm_util_; /// @brief Get LLVM type from function parameter. llvm::Type* GetParamType_(const std::unique_ptr& parameter); - /// @brief Get LLVM types from record fields. - std::vector GetFieldTypes_( - const std::vector>& fields); }; #endif // LLVM_IR_GENERATOR_HPP_ diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 7bd3177e..a30a9ef0 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -46,6 +46,19 @@ void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { if (type->IsPtr()) { return IntPtrType; + } else if (type->IsArr()) { + auto arr_type = dynamic_cast(type.get()); + return llvm::ArrayType::get(IntType, arr_type->len()); + } else if (type->IsStruct() || type->IsUnion()) { + std::string record_prefix = type->IsStruct() ? "struct_" : "union_"; + auto record_type = dynamic_cast(type.get()); + std::vector field_types; + for (auto& field : record_type->fields()) { + field_types.push_back(GetLLVMType(field->type)); + } + + return llvm::StructType::create(builder_->getContext(), field_types, + record_prefix + record_type->id()); } return IntType; diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 1320597e..63d2eb76 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -157,14 +157,12 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { } void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { - auto arr_decl_type = dynamic_cast((arr_decl.type).get()); - auto arr_type = llvm::ArrayType::get( - llvm_util_.IntType, - arr_decl_type->size() / arr_decl_type->element_type().size()); + auto arr_type = llvm_util_.GetLLVMType(arr_decl.type); auto base_addr = builder_->CreateAlloca(arr_type, nullptr); id_to_val[arr_decl.id] = base_addr; val_to_type[base_addr] = arr_type; + auto arr_decl_type = dynamic_cast(arr_decl.type.get()); for (auto i = std::size_t{0}, e = arr_decl_type->len(); i < e; ++i) { if (i < arr_decl.init_list.size()) { auto& arr_init = arr_decl.init_list.at(i); @@ -193,36 +191,10 @@ void LLVMIRGenerator::Visit(const FieldNode& field) { /* Do nothing because this node only declares a member type in a record. */ } -std::vector LLVMIRGenerator::GetFieldTypes_( - const std::vector>& fields) { - std::vector field_types; - // TODO: support nested record. - // TODO: refactor to support multiple data types - for (auto& field : fields) { - if (field->type->IsPtr()) { - field_types.push_back(llvm_util_.IntPtrType); - } else { - field_types.push_back(llvm_util_.IntType); - } - } - - return field_types; -} - void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { - // Define Record fields auto* record_type = dynamic_cast(record_var_decl.type.get()); assert(record_type); - auto field_types = GetFieldTypes_(record_type->fields()); - std::string record_prefix = ""; - if (record_type->IsStruct()) { - record_prefix += "struct_"; - } else { - record_prefix += "union_"; - } - - auto type = llvm::StructType::create(*context_, field_types, - record_prefix + record_type->id()); + auto type = llvm_util_.GetLLVMType(record_var_decl.type); auto base_addr = builder_->CreateAlloca(type, nullptr); id_to_val[record_var_decl.id] = base_addr; val_to_type[base_addr] = type; From 566765974c99912cc03915aabdd37d4b65dd4790 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 19:22:20 +0800 Subject: [PATCH 46/84] Change return_type() of FuncType to unique_ptr --- include/type.hpp | 5 +++-- parser.y | 4 ++-- src/llvm/util.cpp | 11 +++++++++++ src/llvm_ir_generator.cpp | 10 ++++++---- src/type.cpp | 2 +- src/type_checker.cpp | 4 ++-- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/include/type.hpp b/include/type.hpp index 4380aa1b..2ea8dc48 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -146,9 +146,10 @@ class FuncType : public Type { : return_type_{std::move(return_type)}, param_types_{std::move(param_types)} {} - const Type& return_type() // NOLINT(readability-identifier-naming) + const std::unique_ptr& + return_type() // NOLINT(readability-identifier-naming) const noexcept { - return *return_type_; + return return_type_; } // XXX: Consider exposing iterators for constness. diff --git a/parser.y b/parser.y index b5a3637c..5192f656 100644 --- a/parser.y +++ b/parser.y @@ -186,7 +186,7 @@ func_def: declaration_specifiers declarator compound_stmt { assert(func_def->type->IsFunc()); const auto* func_type = static_cast(func_def->type.get()); auto type = std::get>($1); - auto resolved_return_type = ResolveType(std::move(type), func_type->return_type().Clone()); + auto resolved_return_type = ResolveType(std::move(type), func_type->return_type()->Clone()); auto param_types = std::vector>{}; for (auto& param : func_type->param_types()) { param_types.push_back(param->Clone()); @@ -813,7 +813,7 @@ std::unique_ptr ResolveType(std::unique_ptr resolved_type, if (unknown_type->IsFunc()) { // NOTE: Due to the structure of the grammar, the return type of a function is to be resolved. auto func_type = static_cast(unknown_type.get()); - resolved_type = ResolveType(std::move(resolved_type), func_type->return_type().Clone()); + resolved_type = ResolveType(std::move(resolved_type), func_type->return_type()->Clone()); auto param_types = std::vector>{}; for (const auto& param : func_type->param_types()) { param_types.push_back(param->Clone()); diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index a30a9ef0..bc7724ab 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -45,6 +45,7 @@ void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { if (type->IsPtr()) { + // TODO recursive return IntPtrType; } else if (type->IsArr()) { auto arr_type = dynamic_cast(type.get()); @@ -59,6 +60,16 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { return llvm::StructType::create(builder_->getContext(), field_types, record_prefix + record_type->id()); + } else if (type->IsFunc()) { + auto func_type = dynamic_cast(type.get()); + auto return_type = GetLLVMType(func_type->return_type()); + + std::vector param_types; + for (auto& param_type : func_type->param_types()) { + param_types.push_back(GetLLVMType(param_type)); + } + + return llvm::FunctionType::get(return_type, param_types, false); } return IntType; diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 63d2eb76..28933d59 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -224,7 +224,7 @@ llvm::Type* LLVMIRGenerator::GetParamType_( if (auto ptr_type = dynamic_cast(parameter->type.get())) { auto base_type = ptr_type->base_type().Clone(); if (auto func_type = dynamic_cast(base_type.get())) { - auto return_type = func_type->return_type().IsPtr() == true + auto return_type = func_type->return_type()->IsPtr() == true ? (llvm::Type*)llvm_util_.IntPtrType : (llvm::Type*)llvm_util_.IntType; std::vector func_params; @@ -247,10 +247,11 @@ llvm::Type* LLVMIRGenerator::GetParamType_( } void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { - std::vector param_types(func_def.parameters.size(), - llvm_util_.IntType); + // Explicit cast to FunctionType or else it would get an error. auto func_type = - llvm::FunctionType::get(llvm_util_.IntType, param_types, false); + llvm::dyn_cast(llvm_util_.GetLLVMType(func_def.type)); + assert(func_type); + auto func = llvm::Function::Create(func_type, func_def.id == "main" ? llvm::Function::ExternalLinkage @@ -265,6 +266,7 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { parameter->Accept(*this); args_iter->setName(parameter->id); + // llvm::Type* param_type = GetParamType_(parameter); llvm::Type* param_type = GetParamType_(parameter); // TODO: refactor if (param_type->isFunctionTy()) { diff --git a/src/type.cpp b/src/type.cpp index 4eea5d59..eca30e5e 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -57,7 +57,7 @@ std::string PtrType::ToString() const { // For function pointer types, the '*' is placed between the return type and // the parameter list. if (const auto* base_func = dynamic_cast(base_type_.get())) { - auto str = base_func->return_type().ToString() + " (*)("; + auto str = base_func->return_type()->ToString() + " (*)("; for (auto i = std::size_t{0}, e = base_func->param_types().size(); i < e; ++i) { str += base_func->param_types().at(i)->ToString(); diff --git a/src/type_checker.cpp b/src/type_checker.cpp index d21006c0..bd3eb84a 100644 --- a/src/type_checker.cpp +++ b/src/type_checker.cpp @@ -200,7 +200,7 @@ void TypeChecker::Visit(FuncDefNode& func_def) { decayed_param_types.push_back(parameter->type->Clone()); } auto return_type = - dynamic_cast(func_def.type.get())->return_type().Clone(); + dynamic_cast(func_def.type.get())->return_type()->Clone(); func_def.type = std::make_unique(std::move(return_type), std::move(decayed_param_types)); auto symbol = @@ -474,7 +474,7 @@ void TypeChecker::Visit(FuncCallExprNode& call_expr) { // TODO: called object type 'type' is not a function or function pointer assert(false); } - call_expr.type = func_type->return_type().Clone(); + call_expr.type = func_type->return_type()->Clone(); auto& param_types = func_type->param_types(); auto& args = call_expr.args; From c5c10d851cf840df9a04d4e589756c82232044cb Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 19:52:06 +0800 Subject: [PATCH 47/84] Refactor goto and id label statement with find basic block function --- include/llvm/util.hpp | 5 +++++ src/llvm/util.cpp | 12 ++++++++++++ src/llvm_ir_generator.cpp | 38 ++++++++++++-------------------------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 246facb7..c54796cb 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -30,6 +30,11 @@ class LLVMIRUtil { /// @brief Get the corresponding LLVM type from our type. llvm::Type* GetLLVMType(const std::unique_ptr& type); + /// @brief Find the basic block with the same name as `id` within the current + /// function. + /// @return A pointer to basic block if found. `nullptr` if not found. + llvm::BasicBlock* FindBBWithNameOf(const std::string& id); + LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} { IntType = builder_->getInt32Ty(); IntPtrType = builder_->getPtrTy(); diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index bc7724ab..3f2cdc73 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -43,6 +43,18 @@ void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, } } +llvm::BasicBlock* LLVMIRUtil::FindBBWithNameOf(const std::string& id) { + auto func = builder_->GetInsertBlock()->getParent(); + for (auto BB_iter = func->begin(), BB_end = func->end(); BB_iter != BB_end; + ++BB_iter) { + if (BB_iter->getName() == id) { + return &(*BB_iter); + } + } + + return nullptr; +} + llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { if (type->IsPtr()) { // TODO recursive diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 28933d59..23d284d9 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -312,6 +312,7 @@ void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, "__builtin_print", *module_); + // Generate printf function for LLVM interpreter. auto args = llvm::ArrayRef{llvm_util_.IntPtrType, llvm_util_.IntType}; auto printf = llvm::FunctionType::get(llvm_util_.IntType, args, false); @@ -382,7 +383,7 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { label_views_of_jumpable_blocks.push_back({.entry = pred_BB, .exit = end_BB}); while_stmt.loop_body->Accept(*this); label_views_of_jumpable_blocks.pop_back(); - builder_->CreateBr(pred_BB); + llvm_util_.CreateBrIfNoBrBefore(pred_BB); if (while_stmt.is_do_while) { builder_->SetInsertPoint(pred_BB); @@ -410,11 +411,10 @@ void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { } builder_->SetInsertPoint(body_BB); - // TODO: break, continue label label_views_of_jumpable_blocks.push_back({.entry = step_BB, .exit = end_BB}); for_stmt.loop_body->Accept(*this); label_views_of_jumpable_blocks.pop_back(); - builder_->CreateBr(step_BB); + llvm_util_.CreateBrIfNoBrBefore(step_BB); builder_->SetInsertPoint(step_BB); for_stmt.step->Accept(*this); @@ -429,21 +429,13 @@ void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { } void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { - auto func = builder_->GetInsertBlock()->getParent(); - llvm::BasicBlock* target_BB = nullptr; - // TODO: refactor - for (auto b = func->begin(), be = func->end(); b != be; ++b) { - auto& BB = b; - if (BB->getName() == goto_stmt.label) { - target_BB = &(*BB); - break; - } - } + llvm::BasicBlock* target_BB = llvm_util_.FindBBWithNameOf(goto_stmt.label); if (target_BB) { builder_->CreateBr(target_BB); } else { - auto label_BB = llvm::BasicBlock::Create(*context_, goto_stmt.label, func); + auto label_BB = llvm::BasicBlock::Create( + *context_, goto_stmt.label, builder_->GetInsertBlock()->getParent()); builder_->CreateBr(label_BB); } } @@ -495,22 +487,16 @@ void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { } void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { - auto func = builder_->GetInsertBlock()->getParent(); - llvm::BasicBlock* target_BB = nullptr; - // TODO: refactor - for (auto b = func->begin(), be = func->end(); b != be; ++b) { - auto& BB = b; - if (BB->getName() == id_labeled_stmt.label) { - target_BB = &(*BB); - builder_->SetInsertPoint(target_BB); - break; - } - } + llvm::BasicBlock* target_BB = + llvm_util_.FindBBWithNameOf(id_labeled_stmt.label); if (!target_BB) { auto label_BB = - llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, func); + llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, + builder_->GetInsertBlock()->getParent()); builder_->SetInsertPoint(label_BB); + } else { + builder_->SetInsertPoint(target_BB); } id_labeled_stmt.stmt->Accept(*this); From 25d215fa425aa1e85bf79ee04138f4ce656bc91e Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 20:02:42 +0800 Subject: [PATCH 48/84] Refactor with CurrFunc to get the current inserting function --- include/llvm/util.hpp | 11 ++++++++--- src/llvm/util.cpp | 4 ++++ src/llvm_ir_generator.cpp | 37 +++++++++++++++++-------------------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index c54796cb..43dfede6 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -27,14 +27,19 @@ class LLVMIRUtil { void CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, llvm::BasicBlock* next_BB); - /// @brief Get the corresponding LLVM type from our type. - llvm::Type* GetLLVMType(const std::unique_ptr& type); - /// @brief Find the basic block with the same name as `id` within the current /// function. + /// @param id The name of the target basic block. /// @return A pointer to basic block if found. `nullptr` if not found. llvm::BasicBlock* FindBBWithNameOf(const std::string& id); + /// @brief Get the current function. + /// @return A pointer to the current function. + llvm::Function* CurrFunc(); + + /// @brief Get the corresponding LLVM type from our type. + llvm::Type* GetLLVMType(const std::unique_ptr& type); + LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} { IntType = builder_->getInt32Ty(); IntPtrType = builder_->getPtrTy(); diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 3f2cdc73..757b7566 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -55,6 +55,10 @@ llvm::BasicBlock* LLVMIRUtil::FindBBWithNameOf(const std::string& id) { return nullptr; } +llvm::Function* LLVMIRUtil::CurrFunc() { + return builder_->GetInsertBlock()->getParent(); +} + llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { if (type->IsPtr()) { // TODO recursive diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 23d284d9..c1b33098 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -330,7 +330,7 @@ void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { if_stmt.predicate->Accept(*this); auto predicate_val = val_recorder.ValOfPrevExpr(); - auto func = builder_->GetInsertBlock()->getParent(); + auto func = llvm_util_.CurrFunc(); auto then_BB = llvm::BasicBlock::Create(*context_, "if_then", func); auto else_BB = if_stmt.or_else != nullptr ? llvm::BasicBlock::Create(*context_, "if_else", func) @@ -355,7 +355,7 @@ void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { auto label_prefix = std::string{while_stmt.is_do_while ? "do_" : "while_"}; - auto func = builder_->GetInsertBlock()->getParent(); + auto func = llvm_util_.CurrFunc(); auto body_BB = llvm::BasicBlock::Create(*context_, label_prefix + "body", func); auto pred_BB = @@ -395,7 +395,7 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { } void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { - auto func = builder_->GetInsertBlock()->getParent(); + auto func = llvm_util_.CurrFunc(); auto pred_BB = llvm::BasicBlock::Create(*context_, "for_pred", func); auto body_BB = llvm::BasicBlock::Create(*context_, "for_body", func); auto step_BB = llvm::BasicBlock::Create(*context_, "for_step", func); @@ -434,8 +434,8 @@ void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { if (target_BB) { builder_->CreateBr(target_BB); } else { - auto label_BB = llvm::BasicBlock::Create( - *context_, goto_stmt.label, builder_->GetInsertBlock()->getParent()); + auto label_BB = llvm::BasicBlock::Create(*context_, goto_stmt.label, + llvm_util_.CurrFunc()); builder_->CreateBr(label_BB); } } @@ -453,13 +453,12 @@ void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { switch_stmt.ctrl->Accept(*this); auto ctrl = val_recorder.ValOfPrevExpr(); - - auto func = builder_->GetInsertBlock()->getParent(); - auto end_BB = llvm::BasicBlock::Create(*context_, "switch_end", func); + auto end_BB = + llvm::BasicBlock::Create(*context_, "switch_end", llvm_util_.CurrFunc()); auto sw = builder_->CreateSwitch(ctrl, nullptr); label_views_of_jumpable_blocks.push_back({.entry = end_BB, .exit = end_BB}); switch_stmt.stmt->Accept(*this); - // Update cases and default + // Update cases and default label. auto switch_infos = label_views_of_jumpable_blocks.back(); for (auto i = std::size_t{0}, e = switch_infos.cases.size(); i < e; ++i) { auto case_info = switch_infos.cases.at(i); @@ -472,8 +471,8 @@ void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { sw->addCase(const_val, curr_BB); } - // NOTE: if BB has no terminator, add one branch to next BB - // if BB is the last BB, then branch to switch_infos.exit + // NOTE: If BB has no terminator and has a next BB, add one branch to next + // BB. If BB is the last BB, then branch to switch exit. if (i + 1 != e) { auto next_BB = switch_infos.cases.at(i + 1).second; llvm_util_.CurrBBFallThroughNextBB(curr_BB, next_BB); @@ -491,9 +490,8 @@ void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { llvm_util_.FindBBWithNameOf(id_labeled_stmt.label); if (!target_BB) { - auto label_BB = - llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, - builder_->GetInsertBlock()->getParent()); + auto label_BB = llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, + llvm_util_.CurrFunc()); builder_->SetInsertPoint(label_BB); } else { builder_->SetInsertPoint(target_BB); @@ -508,9 +506,8 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { auto int_expr = dynamic_cast(case_stmt.expr.get()); assert(int_expr); - auto func = builder_->GetInsertBlock()->getParent(); auto case_BB = llvm::BasicBlock::Create( - *context_, "case" + std::to_string(int_expr->val), func); + *context_, "case" + std::to_string(int_expr->val), llvm_util_.CurrFunc()); builder_->SetInsertPoint(case_BB); case_stmt.stmt->Accept(*this); @@ -520,8 +517,8 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { } void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { - auto func = builder_->GetInsertBlock()->getParent(); - auto default_BB = llvm::BasicBlock::Create(*context_, "default", func); + auto default_BB = + llvm::BasicBlock::Create(*context_, "default", llvm_util_.CurrFunc()); builder_->SetInsertPoint(default_BB); default_stmt.stmt->Accept(*this); @@ -597,7 +594,7 @@ void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) { void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { cond_expr.predicate->Accept(*this); auto predicate_val = val_recorder.ValOfPrevExpr(); - auto func = builder_->GetInsertBlock()->getParent(); + auto func = llvm_util_.CurrFunc(); // The second operand is evaluated only if the first compares unequal to // 0; the third operand is evaluated only if the first compares equal to // 0; the result is the value of the second or third operand (whichever is @@ -784,7 +781,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { if (bin_expr.op == BinaryOperator::kLand || bin_expr.op == BinaryOperator::kLor) { // Get the current function we are in. - auto func = builder_->GetInsertBlock()->getParent(); + auto func = llvm_util_.CurrFunc(); auto rhs_BB = llvm::BasicBlock::Create(*context_, "logic_rhs", func); auto short_circuit_BB = llvm::BasicBlock::Create(*context_, "short_circuit", func); From 65a6b01c7683b23b701a5cc75e66de8f1c063efb Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 20:18:57 +0800 Subject: [PATCH 49/84] Small refactor and remove unused statements --- src/llvm_ir_generator.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index c1b33098..97953afa 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -160,7 +160,6 @@ void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { auto arr_type = llvm_util_.GetLLVMType(arr_decl.type); auto base_addr = builder_->CreateAlloca(arr_type, nullptr); id_to_val[arr_decl.id] = base_addr; - val_to_type[base_addr] = arr_type; auto arr_decl_type = dynamic_cast(arr_decl.type.get()); for (auto i = std::size_t{0}, e = arr_decl_type->len(); i < e; ++i) { @@ -197,7 +196,6 @@ void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { auto type = llvm_util_.GetLLVMType(record_var_decl.type); auto base_addr = builder_->CreateAlloca(type, nullptr); id_to_val[record_var_decl.id] = base_addr; - val_to_type[base_addr] = type; // NOTE: This predicate will make sure that we don't initialize members that // exceed the total number of members in a record. Also, it gurantees @@ -576,9 +574,9 @@ void LLVMIRGenerator::Visit(const ArgExprNode& arg_expr) { void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) { arr_sub_expr.arr->Accept(*this); - auto val_num = val_recorder.ValOfPrevExpr(); - auto base_addr = val_to_id_addr.at(val_num); - auto arr_type = val_to_type.at(base_addr); + auto val = val_recorder.ValOfPrevExpr(); + auto base_addr = val_to_id_addr.at(val); + auto arr_type = llvm_util_.GetLLVMType(arr_sub_expr.arr->type); arr_sub_expr.index->Accept(*this); auto index = dynamic_cast(arr_sub_expr.index.get()); assert(index); @@ -618,6 +616,8 @@ void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { builder_->CreateBr(end_BB); builder_->SetInsertPoint(end_BB); + // NOTE: Since we do not know which operand will be executed in runtime, we + // create a Phi node to merge both values. auto phi_res = builder_->CreatePHI(llvm_util_.IntType, 2); phi_res->addIncoming(second_val, second_BB); phi_res->addIncoming(third_val, third_BB); @@ -685,14 +685,14 @@ void LLVMIRGenerator::Visit(const RecordMemExprNode& mem_expr) { mem_expr.expr->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); auto base_addr = val_to_id_addr.at(val); - auto struct_type = val_to_type.at(base_addr); + auto struct_type = llvm_util_.GetLLVMType(mem_expr.expr->type); auto* record_type = dynamic_cast(mem_expr.expr->type.get()); assert(record_type); auto res_addr = builder_->CreateStructGEP( struct_type, base_addr, record_type->MemberIndex(mem_expr.id)); - // TODO: get type - auto res_val = builder_->CreateLoad(llvm_util_.IntType, res_addr); + auto res_val = builder_->CreateLoad( + llvm_util_.GetLLVMType(record_type->MemberType(mem_expr.id)), res_addr); val_to_id_addr[res_val] = res_addr; val_recorder.Record(res_val); } @@ -707,7 +707,7 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { auto arith_op = unary_expr.op == UnaryOperator::kIncr ? BinaryOperator::kAdd : BinaryOperator::kSub; - auto one = llvm::ConstantInt::get(llvm_util_.IntType, 1, true); + auto one = llvm::ConstantInt::get(operand->getType(), 1, true); auto res = builder_->CreateBinOp(GetBinaryOperator(arith_op), operand, one); builder_->CreateStore(res, val_to_id_addr.at(operand)); @@ -718,19 +718,19 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { } break; case UnaryOperator::kNeg: { auto operand = val_recorder.ValOfPrevExpr(); - auto zero = llvm::ConstantInt::get(llvm_util_.IntType, 0, true); + auto zero = llvm::ConstantInt::get(operand->getType(), 0, true); auto res = builder_->CreateSub(zero, operand); val_recorder.Record(res); } break; case UnaryOperator::kNot: { auto operand = val_recorder.ValOfPrevExpr(); - auto zero = llvm::ConstantInt::get(llvm_util_.IntType, 0, true); + auto zero = llvm::ConstantInt::get(operand->getType(), 0, true); auto res = builder_->CreateICmpEQ(operand, zero); val_recorder.Record(res); } break; case UnaryOperator::kBitComp: { auto operand = val_recorder.ValOfPrevExpr(); - auto all_ones = llvm::ConstantInt::get(llvm_util_.IntType, -1, true); + auto all_ones = llvm::ConstantInt::get(operand->getType(), -1, true); auto res = builder_->CreateXor(operand, all_ones); val_recorder.Record(res); } break; @@ -780,7 +780,6 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { } if (bin_expr.op == BinaryOperator::kLand || bin_expr.op == BinaryOperator::kLor) { - // Get the current function we are in. auto func = llvm_util_.CurrFunc(); auto rhs_BB = llvm::BasicBlock::Create(*context_, "logic_rhs", func); auto short_circuit_BB = @@ -804,7 +803,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { bin_expr.op == BinaryOperator::kLand ? false_val : true_val; builder_->CreateBr(end_BB); builder_->SetInsertPoint(end_BB); - // Merge results from rhs and short_circuit_res + // Merge results from rhs and short_circuit_res. auto phi_res = builder_->CreatePHI(builder_->getInt1Ty(), 2); phi_res->addIncoming(rhs_res, rhs_BB); phi_res->addIncoming(short_circuit_res, short_circuit_BB); From ff2722956208ba060ef042dac13dd6e9e267dc3f Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 20:31:36 +0800 Subject: [PATCH 50/84] Update TODOs in makefile and main.cpp --- Makefile | 2 ++ main.cpp | 1 - src/llvm/util.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f58578a2..6d63e9f1 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,10 @@ TARGET := vitaminc CXX := g++ CC = $(CXX) CLANG_TIDY ?= clang-tidy +# TODO: replace with llvm-config CXXFLAGS = -g3 -std=c++17 -Wall -MMD -Iinclude $(llvm-config --cxxflags) -I/usr/lib/llvm-18/include -Werror CFLAGS = $(CXXFLAGS) +# TODO: replace with llvm-config LDLIBS = -lfmt -lLLVM-18 LEX = lex # C++ features are used, yacc doesn't suffice diff --git a/main.cpp b/main.cpp index 5b2dd1cb..40bf4c98 100644 --- a/main.cpp +++ b/main.cpp @@ -43,7 +43,6 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to cmd_options.add_options() ("o, output", "Write output to ", cxxopts::value()->default_value("a.out"), "") ("d, dump", "Dump the abstract syntax tree", cxxopts::value()->default_value("false")) - // TODO: support LLVM IR ("t, target", "Specify target IR", cxxopts::value()->default_value("qbe"), "[qbe|llvm]") ("h, help", "Display available options") ; diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 757b7566..f8887dd4 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -89,4 +89,4 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { } return IntType; -} \ No newline at end of file +} From 28d90870ccf248d4a22f35a091a2e765691fcb34 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 20:46:35 +0800 Subject: [PATCH 51/84] Update Makefile with llvm-config flags and CI --- .github/workflows/ci.yml | 3 +++ Makefile | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adff422d..a988f368 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,6 +50,9 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v3 + - name: Install LLVM + run: | + sudo apt-get install -q -y llvm - name: Install QBE run: scripts/install-qbe.sh - name: Install cxxopts diff --git a/Makefile b/Makefile index 6d63e9f1..dd7115ab 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,9 @@ TARGET := vitaminc CXX := g++ CC = $(CXX) CLANG_TIDY ?= clang-tidy -# TODO: replace with llvm-config -CXXFLAGS = -g3 -std=c++17 -Wall -MMD -Iinclude $(llvm-config --cxxflags) -I/usr/lib/llvm-18/include -Werror +CXXFLAGS = -g3 -std=c++17 -Wall -MMD -Iinclude -I$(shell llvm-config --includedir) -Werror CFLAGS = $(CXXFLAGS) -# TODO: replace with llvm-config -LDLIBS = -lfmt -lLLVM-18 +LDLIBS = -lfmt $(shell llvm-config --libs core) LEX = lex # C++ features are used, yacc doesn't suffice YACC = bison From 9f5ee56e9dc4d68f427b209080ace5fd8dfaa66b Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 20:56:53 +0800 Subject: [PATCH 52/84] Update LLVM installed version --- .github/workflows/ci.yml | 5 ++++- Makefile | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a988f368..2b868a20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,10 @@ jobs: - uses: actions/setup-python@v3 - name: Install LLVM run: | - sudo apt-get install -q -y llvm + sudo add-apt-repository -y 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main' + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo apt-get update + sudo apt-get install -q -y llvm-18 lld-18 llvm-18-runtime - name: Install QBE run: scripts/install-qbe.sh - name: Install cxxopts diff --git a/Makefile b/Makefile index dd7115ab..08778e04 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ TARGET := vitaminc CXX := g++ CC = $(CXX) CLANG_TIDY ?= clang-tidy -CXXFLAGS = -g3 -std=c++17 -Wall -MMD -Iinclude -I$(shell llvm-config --includedir) -Werror +CXXFLAGS = -g3 -std=c++17 -Wall -MMD -Iinclude -I$(shell llvm-config-18 --includedir) -Werror CFLAGS = $(CXXFLAGS) -LDLIBS = -lfmt $(shell llvm-config --libs core) +LDLIBS = -lfmt $(shell llvm-config-18 --libs core) LEX = lex # C++ features are used, yacc doesn't suffice YACC = bison From 4061c19e350b2001daea2c6ee428ca6105e1c069 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 21:56:00 +0800 Subject: [PATCH 53/84] Include missing headers --- include/llvm/util.hpp | 3 +++ include/llvm_ir_generator.hpp | 3 +++ src/llvm/util.cpp | 5 +++++ src/llvm_ir_generator.cpp | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 43dfede6..e453398e 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -1,6 +1,9 @@ #ifndef LLVM_UTIL_HPP_ #define LLVM_UTIL_HPP_ +#include +#include +#include #include #include diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 2065d0dc..95d1c242 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -2,6 +2,9 @@ #define LLVM_IR_GENERATOR_HPP_ #include +#include +#include +#include #include #include diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index f8887dd4..e959c677 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -1,6 +1,11 @@ #include "llvm/util.hpp" +#include +#include +#include #include +#include +#include #include #include "type.hpp" diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 97953afa..1541d73c 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -1,8 +1,12 @@ #include "llvm_ir_generator.hpp" +#include +#include +#include #include #include #include +#include #include From eca43ddc82bcfda7e94a679d7fda5e32a60dd764 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 22:01:30 +0800 Subject: [PATCH 54/84] Rename basic block from BB to bb --- include/llvm/util.hpp | 6 +- src/llvm/util.cpp | 28 +++---- src/llvm_ir_generator.cpp | 168 +++++++++++++++++++------------------- 3 files changed, 101 insertions(+), 101 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index e453398e..bf2e25e8 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -24,11 +24,11 @@ class LLVMIRUtil { /// current insert point. If no, then it will create an unconditional branch /// to the next basic block. If yes, then it will not create branch /// instruction. - void CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB); + void CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb); /// @brief Create a branch instruction to the next basic block. - void CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, - llvm::BasicBlock* next_BB); + void CurrBBFallThroughNextBB(llvm::BasicBlock* curr_bb, + llvm::BasicBlock* next_bb); /// @brief Find the basic block with the same name as `id` within the current /// function. diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index e959c677..89721d82 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -12,10 +12,10 @@ using namespace util; -void LLVMIRUtil::CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB) { - auto BB = builder_->GetInsertBlock(); +void LLVMIRUtil::CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb) { + auto bb = builder_->GetInsertBlock(); bool has_terminator = false; - for (auto it = BB->begin(); it != BB->end();) { + for (auto it = bb->begin(); it != bb->end();) { if (it->isTerminator()) { has_terminator = true; break; @@ -25,15 +25,15 @@ void LLVMIRUtil::CreateBrIfNoBrBefore(llvm::BasicBlock* next_BB) { } if (!has_terminator) { - builder_->CreateBr(next_BB); + builder_->CreateBr(next_bb); } } -void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, - llvm::BasicBlock* next_BB) { - auto BB = curr_BB; +void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_bb, + llvm::BasicBlock* next_bb) { + auto bb = curr_bb; bool has_terminator = false; - for (auto it = BB->begin(); it != BB->end();) { + for (auto it = bb->begin(); it != bb->end();) { if (it->isTerminator()) { has_terminator = true; break; @@ -43,17 +43,17 @@ void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_BB, } if (!has_terminator) { - builder_->SetInsertPoint(curr_BB); - builder_->CreateBr(next_BB); + builder_->SetInsertPoint(curr_bb); + builder_->CreateBr(next_bb); } } llvm::BasicBlock* LLVMIRUtil::FindBBWithNameOf(const std::string& id) { auto func = builder_->GetInsertBlock()->getParent(); - for (auto BB_iter = func->begin(), BB_end = func->end(); BB_iter != BB_end; - ++BB_iter) { - if (BB_iter->getName() == id) { - return &(*BB_iter); + for (auto bb_iter = func->begin(), bb_end = func->end(); bb_iter != bb_end; + ++bb_iter) { + if (bb_iter->getName() == id) { + return &(*bb_iter); } } diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 1541d73c..c9477ff0 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -333,36 +333,36 @@ void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { if_stmt.predicate->Accept(*this); auto predicate_val = val_recorder.ValOfPrevExpr(); auto func = llvm_util_.CurrFunc(); - auto then_BB = llvm::BasicBlock::Create(*context_, "if_then", func); - auto else_BB = if_stmt.or_else != nullptr + auto then_bb = llvm::BasicBlock::Create(*context_, "if_then", func); + auto else_bb = if_stmt.or_else != nullptr ? llvm::BasicBlock::Create(*context_, "if_else", func) : nullptr; - auto end_BB = llvm::BasicBlock::Create(*context_, "if_end", func); + auto end_bb = llvm::BasicBlock::Create(*context_, "if_end", func); auto zero = llvm::ConstantInt::get(predicate_val->getType(), 0, true); auto predicate = builder_->CreateICmpNE(predicate_val, zero); - builder_->CreateCondBr(predicate, then_BB, - if_stmt.or_else != nullptr ? else_BB : end_BB); - builder_->SetInsertPoint(then_BB); + builder_->CreateCondBr(predicate, then_bb, + if_stmt.or_else != nullptr ? else_bb : end_bb); + builder_->SetInsertPoint(then_bb); if_stmt.then->Accept(*this); - llvm_util_.CreateBrIfNoBrBefore(end_BB); + llvm_util_.CreateBrIfNoBrBefore(end_bb); if (if_stmt.or_else) { - builder_->SetInsertPoint(else_BB); + builder_->SetInsertPoint(else_bb); if_stmt.or_else->Accept(*this); - builder_->CreateBr(end_BB); + builder_->CreateBr(end_bb); } - builder_->SetInsertPoint(end_BB); + builder_->SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { auto label_prefix = std::string{while_stmt.is_do_while ? "do_" : "while_"}; auto func = llvm_util_.CurrFunc(); - auto body_BB = + auto body_bb = llvm::BasicBlock::Create(*context_, label_prefix + "body", func); - auto pred_BB = + auto pred_bb = llvm::BasicBlock::Create(*context_, label_prefix + "pred", func); - auto end_BB = llvm::BasicBlock::Create(*context_, label_prefix + "end", func); + auto end_bb = llvm::BasicBlock::Create(*context_, label_prefix + "end", func); // A while statement's predicate is evaluated "before" the body statement, // whereas a do-while statement's predicate is evaluated "after" the body @@ -370,58 +370,58 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { // unconditional jump at the end of the body to jump back to the predicate. // For a do-while statement, it only needs one conditional jump. if (!while_stmt.is_do_while) { - builder_->CreateBr(pred_BB); - builder_->SetInsertPoint(pred_BB); + builder_->CreateBr(pred_bb); + builder_->SetInsertPoint(pred_bb); while_stmt.predicate->Accept(*this); auto predicate = val_recorder.ValOfPrevExpr(); - builder_->CreateCondBr(predicate, body_BB, end_BB); + builder_->CreateCondBr(predicate, body_bb, end_bb); } // Connect entry basic block to body basic block. if (while_stmt.is_do_while) { - builder_->CreateBr(body_BB); + builder_->CreateBr(body_bb); } - builder_->SetInsertPoint(body_BB); - label_views_of_jumpable_blocks.push_back({.entry = pred_BB, .exit = end_BB}); + builder_->SetInsertPoint(body_bb); + label_views_of_jumpable_blocks.push_back({.entry = pred_bb, .exit = end_bb}); while_stmt.loop_body->Accept(*this); label_views_of_jumpable_blocks.pop_back(); - llvm_util_.CreateBrIfNoBrBefore(pred_BB); + llvm_util_.CreateBrIfNoBrBefore(pred_bb); if (while_stmt.is_do_while) { - builder_->SetInsertPoint(pred_BB); + builder_->SetInsertPoint(pred_bb); while_stmt.predicate->Accept(*this); auto predicate = val_recorder.ValOfPrevExpr(); - builder_->CreateCondBr(predicate, body_BB, end_BB); + builder_->CreateCondBr(predicate, body_bb, end_bb); } - builder_->SetInsertPoint(end_BB); + builder_->SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { auto func = llvm_util_.CurrFunc(); - auto pred_BB = llvm::BasicBlock::Create(*context_, "for_pred", func); - auto body_BB = llvm::BasicBlock::Create(*context_, "for_body", func); - auto step_BB = llvm::BasicBlock::Create(*context_, "for_step", func); - auto end_BB = llvm::BasicBlock::Create(*context_, "for_end", func); + auto pred_bb = llvm::BasicBlock::Create(*context_, "for_pred", func); + auto body_bb = llvm::BasicBlock::Create(*context_, "for_body", func); + auto step_bb = llvm::BasicBlock::Create(*context_, "for_step", func); + auto end_bb = llvm::BasicBlock::Create(*context_, "for_end", func); for_stmt.loop_init->Accept(*this); - builder_->CreateBr(pred_BB); - builder_->SetInsertPoint(pred_BB); + builder_->CreateBr(pred_bb); + builder_->SetInsertPoint(pred_bb); for_stmt.predicate->Accept(*this); if (!dynamic_cast((for_stmt.predicate).get())) { auto predicate = val_recorder.ValOfPrevExpr(); - builder_->CreateCondBr(predicate, body_BB, end_BB); + builder_->CreateCondBr(predicate, body_bb, end_bb); } - builder_->SetInsertPoint(body_BB); - label_views_of_jumpable_blocks.push_back({.entry = step_BB, .exit = end_BB}); + builder_->SetInsertPoint(body_bb); + label_views_of_jumpable_blocks.push_back({.entry = step_bb, .exit = end_bb}); for_stmt.loop_body->Accept(*this); label_views_of_jumpable_blocks.pop_back(); - llvm_util_.CreateBrIfNoBrBefore(step_BB); + llvm_util_.CreateBrIfNoBrBefore(step_bb); - builder_->SetInsertPoint(step_BB); + builder_->SetInsertPoint(step_bb); for_stmt.step->Accept(*this); - builder_->CreateBr(pred_BB); - builder_->SetInsertPoint(end_BB); + builder_->CreateBr(pred_bb); + builder_->SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { @@ -431,14 +431,14 @@ void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { } void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { - llvm::BasicBlock* target_BB = llvm_util_.FindBBWithNameOf(goto_stmt.label); + llvm::BasicBlock* target_bb = llvm_util_.FindBBWithNameOf(goto_stmt.label); - if (target_BB) { - builder_->CreateBr(target_BB); + if (target_bb) { + builder_->CreateBr(target_bb); } else { - auto label_BB = llvm::BasicBlock::Create(*context_, goto_stmt.label, + auto label_bb = llvm::BasicBlock::Create(*context_, goto_stmt.label, llvm_util_.CurrFunc()); - builder_->CreateBr(label_BB); + builder_->CreateBr(label_bb); } } @@ -455,48 +455,48 @@ void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { switch_stmt.ctrl->Accept(*this); auto ctrl = val_recorder.ValOfPrevExpr(); - auto end_BB = + auto end_bb = llvm::BasicBlock::Create(*context_, "switch_end", llvm_util_.CurrFunc()); auto sw = builder_->CreateSwitch(ctrl, nullptr); - label_views_of_jumpable_blocks.push_back({.entry = end_BB, .exit = end_BB}); + label_views_of_jumpable_blocks.push_back({.entry = end_bb, .exit = end_bb}); switch_stmt.stmt->Accept(*this); // Update cases and default label. auto switch_infos = label_views_of_jumpable_blocks.back(); for (auto i = std::size_t{0}, e = switch_infos.cases.size(); i < e; ++i) { auto case_info = switch_infos.cases.at(i); - auto curr_BB = case_info.second; + auto curr_bb = case_info.second; if (!case_info.first) { // default case - sw->setDefaultDest(curr_BB); + sw->setDefaultDest(curr_bb); } else { auto const_val = llvm::dyn_cast(case_info.first); assert(const_val); - sw->addCase(const_val, curr_BB); + sw->addCase(const_val, curr_bb); } // NOTE: If BB has no terminator and has a next BB, add one branch to next // BB. If BB is the last BB, then branch to switch exit. if (i + 1 != e) { - auto next_BB = switch_infos.cases.at(i + 1).second; - llvm_util_.CurrBBFallThroughNextBB(curr_BB, next_BB); + auto next_bb = switch_infos.cases.at(i + 1).second; + llvm_util_.CurrBBFallThroughNextBB(curr_bb, next_bb); } else { - llvm_util_.CurrBBFallThroughNextBB(curr_BB, switch_infos.exit); + llvm_util_.CurrBBFallThroughNextBB(curr_bb, switch_infos.exit); } } label_views_of_jumpable_blocks.pop_back(); - llvm_util_.CreateBrIfNoBrBefore(end_BB); - builder_->SetInsertPoint(end_BB); + llvm_util_.CreateBrIfNoBrBefore(end_bb); + builder_->SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { - llvm::BasicBlock* target_BB = + llvm::BasicBlock* target_bb = llvm_util_.FindBBWithNameOf(id_labeled_stmt.label); - if (!target_BB) { - auto label_BB = llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, + if (!target_bb) { + auto label_bb = llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, llvm_util_.CurrFunc()); - builder_->SetInsertPoint(label_BB); + builder_->SetInsertPoint(label_bb); } else { - builder_->SetInsertPoint(target_BB); + builder_->SetInsertPoint(target_bb); } id_labeled_stmt.stmt->Accept(*this); @@ -508,24 +508,24 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { auto int_expr = dynamic_cast(case_stmt.expr.get()); assert(int_expr); - auto case_BB = llvm::BasicBlock::Create( + auto case_bb = llvm::BasicBlock::Create( *context_, "case" + std::to_string(int_expr->val), llvm_util_.CurrFunc()); - builder_->SetInsertPoint(case_BB); + builder_->SetInsertPoint(case_bb); case_stmt.stmt->Accept(*this); assert(!label_views_of_jumpable_blocks.empty()); - label_views_of_jumpable_blocks.back().cases.push_back({val, case_BB}); + label_views_of_jumpable_blocks.back().cases.push_back({val, case_bb}); } void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { - auto default_BB = + auto default_bb = llvm::BasicBlock::Create(*context_, "default", llvm_util_.CurrFunc()); - builder_->SetInsertPoint(default_BB); + builder_->SetInsertPoint(default_bb); default_stmt.stmt->Accept(*this); assert(!label_views_of_jumpable_blocks.empty()); - label_views_of_jumpable_blocks.back().cases.push_back({nullptr, default_BB}); + label_views_of_jumpable_blocks.back().cases.push_back({nullptr, default_bb}); } void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) { @@ -601,30 +601,30 @@ void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { // 0; the third operand is evaluated only if the first compares equal to // 0; the result is the value of the second or third operand (whichever is // evaluated). - auto second_BB = llvm::BasicBlock::Create(*context_, "cond_second", func); - auto third_BB = llvm::BasicBlock::Create(*context_, "cond_third", func); - auto end_BB = llvm::BasicBlock::Create(*context_, "cond_end", func); + auto second_bb = llvm::BasicBlock::Create(*context_, "cond_second", func); + auto third_bb = llvm::BasicBlock::Create(*context_, "cond_third", func); + auto end_bb = llvm::BasicBlock::Create(*context_, "cond_end", func); auto zero = llvm::ConstantInt::get(predicate_val->getType(), 0, true); auto predicate = builder_->CreateICmpNE(predicate_val, zero); - builder_->CreateCondBr(predicate, second_BB, third_BB); + builder_->CreateCondBr(predicate, second_bb, third_bb); - builder_->SetInsertPoint(second_BB); + builder_->SetInsertPoint(second_bb); cond_expr.then->Accept(*this); auto second_val = val_recorder.ValOfPrevExpr(); - builder_->CreateBr(end_BB); + builder_->CreateBr(end_bb); - builder_->SetInsertPoint(third_BB); + builder_->SetInsertPoint(third_bb); cond_expr.or_else->Accept(*this); auto third_val = val_recorder.ValOfPrevExpr(); - builder_->CreateBr(end_BB); + builder_->CreateBr(end_bb); - builder_->SetInsertPoint(end_BB); + builder_->SetInsertPoint(end_bb); // NOTE: Since we do not know which operand will be executed in runtime, we // create a Phi node to merge both values. auto phi_res = builder_->CreatePHI(llvm_util_.IntType, 2); - phi_res->addIncoming(second_val, second_BB); - phi_res->addIncoming(third_val, third_BB); + phi_res->addIncoming(second_val, second_bb); + phi_res->addIncoming(third_val, third_bb); val_recorder.Record(phi_res); } @@ -785,32 +785,32 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { if (bin_expr.op == BinaryOperator::kLand || bin_expr.op == BinaryOperator::kLor) { auto func = llvm_util_.CurrFunc(); - auto rhs_BB = llvm::BasicBlock::Create(*context_, "logic_rhs", func); - auto short_circuit_BB = + auto rhs_bb = llvm::BasicBlock::Create(*context_, "logic_rhs", func); + auto short_circuit_bb = llvm::BasicBlock::Create(*context_, "short_circuit", func); - auto end_BB = llvm::BasicBlock::Create(*context_, "logic_end", func); + auto end_bb = llvm::BasicBlock::Create(*context_, "logic_end", func); auto zero = llvm::ConstantInt::get(lhs->getType(), 0, true); auto lhs_res = builder_->CreateCmp(bin_expr.op == BinaryOperator::kLand ? llvm::CmpInst::Predicate::ICMP_NE : llvm::CmpInst::Predicate::ICMP_EQ, lhs, zero); - builder_->CreateCondBr(lhs_res, rhs_BB, short_circuit_BB); - builder_->SetInsertPoint(rhs_BB); + builder_->CreateCondBr(lhs_res, rhs_bb, short_circuit_bb); + builder_->SetInsertPoint(rhs_bb); bin_expr.rhs->Accept(*this); auto res = val_recorder.ValOfPrevExpr(); auto rhs_res = builder_->CreateICmpNE(res, zero); - builder_->CreateBr(end_BB); - builder_->SetInsertPoint(short_circuit_BB); + builder_->CreateBr(end_bb); + builder_->SetInsertPoint(short_circuit_bb); auto false_val = llvm::ConstantInt::getFalse(*context_); auto true_val = llvm::ConstantInt::getTrue(*context_); auto short_circuit_res = bin_expr.op == BinaryOperator::kLand ? false_val : true_val; - builder_->CreateBr(end_BB); - builder_->SetInsertPoint(end_BB); + builder_->CreateBr(end_bb); + builder_->SetInsertPoint(end_bb); // Merge results from rhs and short_circuit_res. auto phi_res = builder_->CreatePHI(builder_->getInt1Ty(), 2); - phi_res->addIncoming(rhs_res, rhs_BB); - phi_res->addIncoming(short_circuit_res, short_circuit_BB); + phi_res->addIncoming(rhs_res, rhs_bb); + phi_res->addIncoming(short_circuit_res, short_circuit_bb); val_recorder.Record(phi_res); } else if (isCmpInst(bin_expr.op)) { bin_expr.rhs->Accept(*this); From 4b8a5bd765d2de19520ba68ffa44b490192f70d3 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 23:23:45 +0800 Subject: [PATCH 55/84] Change public member to public functions --- include/llvm/util.hpp | 9 +++------ src/llvm/util.cpp | 18 ++++++++++++++---- src/llvm_ir_generator.cpp | 39 ++++++++++++++++++++------------------- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index bf2e25e8..d443beb5 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -15,9 +15,9 @@ namespace util { class LLVMIRUtil { public: /// @brief LLVM Integer type - llvm::IntegerType* IntType; + llvm::IntegerType* IntType(); /// @brief LLVM Pointer type - llvm::PointerType* IntPtrType; + llvm::PointerType* IntPtrType(); /// @brief Every LLVM basic block can only have one terminator instruction. /// This function can check if there are terminator instructions before the @@ -43,10 +43,7 @@ class LLVMIRUtil { /// @brief Get the corresponding LLVM type from our type. llvm::Type* GetLLVMType(const std::unique_ptr& type); - LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} { - IntType = builder_->getInt32Ty(); - IntPtrType = builder_->getPtrTy(); - } + LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} {} private: /// @brief Stores a reference from the original builder. diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 89721d82..f03b9575 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -12,6 +12,14 @@ using namespace util; +llvm::IntegerType* LLVMIRUtil::IntType() { + return builder_->getInt32Ty(); +} + +llvm::PointerType* LLVMIRUtil::IntPtrType() { + return builder_->getPtrTy(); +} + void LLVMIRUtil::CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb) { auto bb = builder_->GetInsertBlock(); bool has_terminator = false; @@ -66,11 +74,13 @@ llvm::Function* LLVMIRUtil::CurrFunc() { llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { if (type->IsPtr()) { - // TODO recursive - return IntPtrType; + // TODO: recursive + auto ptr_type = dynamic_cast(type.get()); + assert(ptr_type); + return IntPtrType(); } else if (type->IsArr()) { auto arr_type = dynamic_cast(type.get()); - return llvm::ArrayType::get(IntType, arr_type->len()); + return llvm::ArrayType::get(IntType(), arr_type->len()); } else if (type->IsStruct() || type->IsUnion()) { std::string record_prefix = type->IsStruct() ? "struct_" : "union_"; auto record_type = dynamic_cast(type.get()); @@ -93,5 +103,5 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { return llvm::FunctionType::get(return_type, param_types, false); } - return IntType; + return IntType(); } diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index c9477ff0..565d4238 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -180,7 +180,7 @@ void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { builder_->CreateStore(init_val, res_addr); } else { // set remaining elements as 0 - auto zero = llvm::ConstantInt::get(llvm_util_.IntType, 0, true); + auto zero = llvm::ConstantInt::get(llvm_util_.IntType(), 0, true); builder_->CreateStore(zero, res_addr); } } @@ -227,22 +227,22 @@ llvm::Type* LLVMIRGenerator::GetParamType_( auto base_type = ptr_type->base_type().Clone(); if (auto func_type = dynamic_cast(base_type.get())) { auto return_type = func_type->return_type()->IsPtr() == true - ? (llvm::Type*)llvm_util_.IntPtrType - : (llvm::Type*)llvm_util_.IntType; + ? (llvm::Type*)llvm_util_.IntPtrType() + : (llvm::Type*)llvm_util_.IntType(); std::vector func_params; for (auto& func_param : func_type->param_types()) { func_params.push_back(func_param->IsPtr() == true - ? (llvm::Type*)llvm_util_.IntPtrType - : (llvm::Type*)llvm_util_.IntType); + ? (llvm::Type*)llvm_util_.IntPtrType() + : (llvm::Type*)llvm_util_.IntType()); } auto func_ptr_type = llvm::FunctionType::get(return_type, func_params, false); param_type = func_ptr_type; } else { - param_type = llvm_util_.IntPtrType; + param_type = llvm_util_.IntPtrType(); } } else { - param_type = llvm_util_.IntType; + param_type = llvm_util_.IntType(); } return param_type; @@ -309,15 +309,16 @@ void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. - auto arg = llvm::ArrayRef{llvm_util_.IntType}; - auto builtin_print = llvm::FunctionType::get(llvm_util_.IntType, arg, false); + auto arg = llvm::ArrayRef{llvm_util_.IntType()}; + auto builtin_print = + llvm::FunctionType::get(llvm_util_.IntType(), arg, false); llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, "__builtin_print", *module_); // Generate printf function for LLVM interpreter. - auto args = - llvm::ArrayRef{llvm_util_.IntPtrType, llvm_util_.IntType}; - auto printf = llvm::FunctionType::get(llvm_util_.IntType, args, false); + auto args = llvm::ArrayRef{llvm_util_.IntPtrType(), + llvm_util_.IntType()}; + auto printf = llvm::FunctionType::get(llvm_util_.IntType(), args, false); llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", *module_); @@ -555,11 +556,11 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { auto id_val = id_to_val.at(id_expr.id); if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { - auto res = builder_->CreateLoad(llvm_util_.IntPtrType, id_val); + auto res = builder_->CreateLoad(llvm_util_.IntPtrType(), id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } else { - auto res = builder_->CreateLoad(llvm_util_.IntType, id_val); + auto res = builder_->CreateLoad(llvm_util_.IntType(), id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } @@ -567,7 +568,7 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { // NOTE: LLVM Constant does not generate IR code, it can be used directly. - auto val = llvm::ConstantInt::get(llvm_util_.IntType, int_expr.val, true); + auto val = llvm::ConstantInt::get(llvm_util_.IntType(), int_expr.val, true); val_recorder.Record(val); } @@ -622,7 +623,7 @@ void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { builder_->SetInsertPoint(end_bb); // NOTE: Since we do not know which operand will be executed in runtime, we // create a Phi node to merge both values. - auto phi_res = builder_->CreatePHI(llvm_util_.IntType, 2); + auto phi_res = builder_->CreatePHI(llvm_util_.IntType(), 2); phi_res->addIncoming(second_val, second_bb); phi_res->addIncoming(third_val, third_bb); val_recorder.Record(phi_res); @@ -678,7 +679,7 @@ void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) { ? llvm::BinaryOperator::Add : llvm::BinaryOperator::Sub; - auto one = llvm::ConstantInt::get(llvm_util_.IntType, 1, true); + auto one = llvm::ConstantInt::get(llvm_util_.IntType(), 1, true); auto res = builder_->CreateBinOp(arith_op, val, one); const auto* id_expr = dynamic_cast((postfix_expr.operand).get()); assert(id_expr); @@ -759,8 +760,8 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { auto operand = val_recorder.ValOfPrevExpr(); auto res = builder_->CreateLoad(unary_expr.type->IsPtr() == true - ? (llvm::Type*)llvm_util_.IntPtrType - : (llvm::Type*)llvm_util_.IntType, + ? (llvm::Type*)llvm_util_.IntPtrType() + : (llvm::Type*)llvm_util_.IntType(), operand); val_recorder.Record(res); val_to_id_addr[res] = operand; From 6c9f9c995fc2c4c65b968c88dd57f0f0114ea4a2 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 1 Jul 2024 23:40:03 +0800 Subject: [PATCH 56/84] Fix Clang tidy errors and ignore one check due to crash --- .clang-tidy | 8 ++++++++ include/llvm/util.hpp | 6 +++++- include/llvm_ir_generator.hpp | 4 ++-- main.cpp | 10 ++++++---- src/llvm/util.cpp | 12 ++++++++---- src/llvm_ir_generator.cpp | 33 +++++++++++++++++++++++++-------- 6 files changed, 54 insertions(+), 19 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index cad57e0e..98a6570c 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -8,6 +8,12 @@ # # -cppcoreguidelines-explicit-virtual-functions: # It's an alias of "modernize-use-override". +# +# -bugprone-unchecked-optional-access: +# Clang-tidy will crash due to unknown reasons. +# +# -bugprone-easily-swappable-parameters +# Nothing we can do about it. # Warnings are easily be overlooked when they are not treated as errors. WarningsAsErrors: "*" @@ -15,6 +21,8 @@ WarningsAsErrors: "*" Checks: > -*, bugprone-*, + -bugprone-unchecked-optional-access, + -bugprone-easily-swappable-parameters, performance-*, clang-analyzer-*, cppcoreguidelines-*, diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index d443beb5..7f6a9aca 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -7,6 +7,9 @@ #include #include +#include +#include + #include "type.hpp" namespace util { @@ -47,7 +50,8 @@ class LLVMIRUtil { private: /// @brief Stores a reference from the original builder. - std::unique_ptr>& builder_; + std::unique_ptr>& // XXX: Ignore check until refactor. + builder_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) }; } // namespace util diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 95d1c242..b8f5bb7b 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -8,8 +8,8 @@ #include #include -#include -#include +#include +#include #include "ast.hpp" #include "llvm/util.hpp" diff --git a/main.cpp b/main.cpp index 40bf4c98..ba130074 100644 --- a/main.cpp +++ b/main.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "ast.hpp" #include "ast_dumper.hpp" @@ -23,11 +25,11 @@ extern FILE* extern void yylex_destroy(); // NOLINT(readability-identifier-naming): extern // from flex generated code. -int QbeBuilder(std::unique_ptr program, std::string& input_basename, +int QbeBuilder(std::unique_ptr trans_unit, std::string& input_basename, std::string& output_name); -int LLVMBuilder(std::unique_ptr program, std::string& input_basename, - std::string& output_name); +int LLVMBuilder(std::unique_ptr trans_unit, + std::string& input_basename, std::string& output_name); int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to // catch all exceptions isn't reasonable. @@ -74,7 +76,7 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to std::exit(0); } - /// @brief The root node of the program. + /// @brief The root node of the trans_unit. auto trans_unit = std::unique_ptr{}; yy::parser parser{trans_unit}; int ret = parser.parse(); diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index f03b9575..6e29c6e7 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -8,6 +8,11 @@ #include #include +#include +#include +#include +#include + #include "type.hpp" using namespace util; @@ -58,10 +63,9 @@ void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_bb, llvm::BasicBlock* LLVMIRUtil::FindBBWithNameOf(const std::string& id) { auto func = builder_->GetInsertBlock()->getParent(); - for (auto bb_iter = func->begin(), bb_end = func->end(); bb_iter != bb_end; - ++bb_iter) { - if (bb_iter->getName() == id) { - return &(*bb_iter); + for (auto& bb_iter : *func) { + if (bb_iter.getName() == id) { + return &(bb_iter); } } diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 565d4238..83563ff4 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -1,16 +1,30 @@ #include "llvm_ir_generator.hpp" +#include #include +#include #include #include #include #include +#include +#include #include #include +#include +#include +#include #include +#include +#include +#include +#include +#include #include "ast.hpp" +#include "operator.hpp" +#include "type.hpp" namespace { @@ -66,7 +80,7 @@ llvm::CmpInst::Predicate GetCmpPredicate(BinaryOperator op) { } } -bool isCmpInst(BinaryOperator op) { +bool IsCmpInst(BinaryOperator op) { switch (op) { case BinaryOperator::kGt: case BinaryOperator::kGte: @@ -220,18 +234,19 @@ void LLVMIRGenerator::Visit(const ParamNode& parameter) { /* Do nothing */ } +// TODO: Remove this function after refactoring GetLLVMType llvm::Type* LLVMIRGenerator::GetParamType_( const std::unique_ptr& parameter) { - llvm::Type* param_type; + llvm::Type* param_type = nullptr; if (auto ptr_type = dynamic_cast(parameter->type.get())) { auto base_type = ptr_type->base_type().Clone(); if (auto func_type = dynamic_cast(base_type.get())) { - auto return_type = func_type->return_type()->IsPtr() == true + auto return_type = func_type->return_type()->IsPtr() ? (llvm::Type*)llvm_util_.IntPtrType() : (llvm::Type*)llvm_util_.IntType(); std::vector func_params; for (auto& func_param : func_type->param_types()) { - func_params.push_back(func_param->IsPtr() == true + func_params.push_back(func_param->IsPtr() ? (llvm::Type*)llvm_util_.IntPtrType() : (llvm::Type*)llvm_util_.IntType()); } @@ -516,7 +531,8 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { case_stmt.stmt->Accept(*this); assert(!label_views_of_jumpable_blocks.empty()); - label_views_of_jumpable_blocks.back().cases.push_back({val, case_bb}); + std::pair p{val, case_bb}; + label_views_of_jumpable_blocks.back().cases.push_back(p); } void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { @@ -526,7 +542,8 @@ void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { default_stmt.stmt->Accept(*this); assert(!label_views_of_jumpable_blocks.empty()); - label_views_of_jumpable_blocks.back().cases.push_back({nullptr, default_bb}); + std::pair p{nullptr, default_bb}; + label_views_of_jumpable_blocks.back().cases.push_back(p); } void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) { @@ -759,7 +776,7 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { } auto operand = val_recorder.ValOfPrevExpr(); - auto res = builder_->CreateLoad(unary_expr.type->IsPtr() == true + auto res = builder_->CreateLoad(unary_expr.type->IsPtr() ? (llvm::Type*)llvm_util_.IntPtrType() : (llvm::Type*)llvm_util_.IntType(), operand); @@ -813,7 +830,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { phi_res->addIncoming(rhs_res, rhs_bb); phi_res->addIncoming(short_circuit_res, short_circuit_bb); val_recorder.Record(phi_res); - } else if (isCmpInst(bin_expr.op)) { + } else if (IsCmpInst(bin_expr.op)) { bin_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); auto res = builder_->CreateCmp(GetCmpPredicate(bin_expr.op), lhs, rhs); From 09edb4716a07b8666620fa4f0cb06e185cccee1f Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 00:45:21 +0800 Subject: [PATCH 57/84] Remove unused code --- .gitignore | 3 --- src/type_checker.cpp | 10 ---------- test/Makefile | 2 +- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index c3a45a7e..1502847e 100644 --- a/.gitignore +++ b/.gitignore @@ -47,9 +47,6 @@ lex.yy.* # QBE IR files *.ssa -# LLVM test source files -*_llvm.c - # LLVM IR files *.ll diff --git a/src/type_checker.cpp b/src/type_checker.cpp index bd3eb84a..d767db24 100644 --- a/src/type_checker.cpp +++ b/src/type_checker.cpp @@ -236,7 +236,6 @@ void TypeChecker::Visit(CompoundStmtNode& compound_stmt) { void TypeChecker::InstallBuiltins_(ScopeStack& env) { // The supported builtins are: // - int __builtin_print(int) - // - int printf(int) auto param_types = std::vector>{}; param_types.emplace_back(std::make_unique(PrimitiveType::kInt)); @@ -245,15 +244,6 @@ void TypeChecker::InstallBuiltins_(ScopeStack& env) { std::make_unique(PrimitiveType::kInt), std::move(param_types))); env.AddSymbol(std::move(symbol), ScopeKind::kFile); - - auto param_types_printf = std::vector>{}; - param_types_printf.emplace_back( - std::make_unique(PrimitiveType::kInt)); - auto symbol_printf = std::make_unique( - "printf", std::make_unique( - std::make_unique(PrimitiveType::kInt), - std::move(param_types_printf))); - env.AddSymbol(std::move(symbol_printf), ScopeKind::kFile); } void TypeChecker::Visit(ExternDeclNode& extern_decl) { diff --git a/test/Makefile b/test/Makefile index 72062717..b0473c3f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -14,4 +14,4 @@ test: clean: - rm -f *.s **/*.s *.o **/*.o *.ssa **/*.ssa **/*.ll **/*_llvm.c + rm -f *.s **/*.s *.o **/*.o *.ssa **/*.ssa **/*.ll From d648869c5c189bfc233e497c6f8e6eea9c00fa8e Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 01:44:22 +0800 Subject: [PATCH 58/84] Update comments --- src/llvm/util.cpp | 3 ++- src/llvm_ir_generator.cpp | 12 +++++++++--- src/type.cpp | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 6e29c6e7..85a89b96 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -78,7 +78,8 @@ llvm::Function* LLVMIRUtil::CurrFunc() { llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { if (type->IsPtr()) { - // TODO: recursive + // TODO: If type's base_type() IsFunc(), then return + // GetLLVMType(base_type()). Otherwise, return pointer to base_type() type. auto ptr_type = dynamic_cast(type.get()); assert(ptr_type); return IntPtrType(); diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 83563ff4..83e1d928 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -105,7 +105,7 @@ auto // as a data member introduces unnecessary dependency. = std::map{}; -// TODO: replaced this with GetType +// TODO: Remove this after finishing LLVMGetType and remove all use of this map. auto val_to_type // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): // Accessible only within this translation unit; declaring // as a data member introduces unnecessary dependency. @@ -165,12 +165,14 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { if (decl.init) { decl.init->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); + // TODO: Remove this after finishing LLVMGetType if (auto func = llvm::dyn_cast(val)) { var_type = func->getFunctionType(); } builder_->CreateStore(val, addr); } id_to_val[decl.id] = addr; + // TODO: Remove this after finishing LLVMGetType val_to_type[addr] = var_type; } @@ -283,11 +285,12 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { parameter->Accept(*this); args_iter->setName(parameter->id); - // llvm::Type* param_type = GetParamType_(parameter); llvm::Type* param_type = GetParamType_(parameter); - // TODO: refactor + // TODO: Refactor this after finishing GetLLVMType + // Remove the need of storing val_to_type map if (param_type->isFunctionTy()) { auto func_type = param_type; + // function pointer param_type = param_type->getPointerTo(); args_iter->mutateType(param_type); auto addr = builder_->CreateAlloca(param_type); @@ -675,7 +678,9 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { val_recorder.Record(return_res); } } else if (val->getType()->isPointerTy()) { + // function pointer auto func_ptr = val_to_id_addr.at(val); + // TODO: get function type from call_expr.func_expr auto type = val_to_type.at(func_ptr); if (auto func_type = llvm::dyn_cast(type)) { auto return_res = builder_->CreateCall(func_type, val, arg_vals); @@ -849,6 +854,7 @@ void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) { assign_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); builder_->CreateStore(rhs, val_to_id_addr.at(lhs)); + // TODO: Remove this after finishing GetLLVMType if (auto func = llvm::dyn_cast(rhs)) { val_to_type[val_to_id_addr.at(lhs)] = func->getFunctionType(); } diff --git a/src/type.cpp b/src/type.cpp index eca30e5e..c1e6c187 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -296,7 +296,7 @@ std::size_t UnionType::MemberIndex(const std::string& id) const { } } - throw std::runtime_error{"member not found in struct!"}; + throw std::runtime_error{"member not found in union!"}; } std::size_t UnionType::OffsetOf(const std::string& id) const { From 4355ca5d28b1480385001d15bd22544002d70233 Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 13:09:15 +0800 Subject: [PATCH 59/84] Revert "Change return_type() of FuncType to unique_ptr" This reverts commit 566765974c99912cc03915aabdd37d4b65dd4790. --- include/type.hpp | 5 ++--- parser.y | 4 ++-- src/llvm/util.cpp | 14 -------------- src/llvm_ir_generator.cpp | 9 ++++----- src/type.cpp | 2 +- src/type_checker.cpp | 4 ++-- 6 files changed, 11 insertions(+), 27 deletions(-) diff --git a/include/type.hpp b/include/type.hpp index 2ea8dc48..4380aa1b 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -146,10 +146,9 @@ class FuncType : public Type { : return_type_{std::move(return_type)}, param_types_{std::move(param_types)} {} - const std::unique_ptr& - return_type() // NOLINT(readability-identifier-naming) + const Type& return_type() // NOLINT(readability-identifier-naming) const noexcept { - return return_type_; + return *return_type_; } // XXX: Consider exposing iterators for constness. diff --git a/parser.y b/parser.y index 5192f656..b5a3637c 100644 --- a/parser.y +++ b/parser.y @@ -186,7 +186,7 @@ func_def: declaration_specifiers declarator compound_stmt { assert(func_def->type->IsFunc()); const auto* func_type = static_cast(func_def->type.get()); auto type = std::get>($1); - auto resolved_return_type = ResolveType(std::move(type), func_type->return_type()->Clone()); + auto resolved_return_type = ResolveType(std::move(type), func_type->return_type().Clone()); auto param_types = std::vector>{}; for (auto& param : func_type->param_types()) { param_types.push_back(param->Clone()); @@ -813,7 +813,7 @@ std::unique_ptr ResolveType(std::unique_ptr resolved_type, if (unknown_type->IsFunc()) { // NOTE: Due to the structure of the grammar, the return type of a function is to be resolved. auto func_type = static_cast(unknown_type.get()); - resolved_type = ResolveType(std::move(resolved_type), func_type->return_type()->Clone()); + resolved_type = ResolveType(std::move(resolved_type), func_type->return_type().Clone()); auto param_types = std::vector>{}; for (const auto& param : func_type->param_types()) { param_types.push_back(param->Clone()); diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 85a89b96..906d5aec 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -78,10 +78,6 @@ llvm::Function* LLVMIRUtil::CurrFunc() { llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { if (type->IsPtr()) { - // TODO: If type's base_type() IsFunc(), then return - // GetLLVMType(base_type()). Otherwise, return pointer to base_type() type. - auto ptr_type = dynamic_cast(type.get()); - assert(ptr_type); return IntPtrType(); } else if (type->IsArr()) { auto arr_type = dynamic_cast(type.get()); @@ -96,16 +92,6 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { return llvm::StructType::create(builder_->getContext(), field_types, record_prefix + record_type->id()); - } else if (type->IsFunc()) { - auto func_type = dynamic_cast(type.get()); - auto return_type = GetLLVMType(func_type->return_type()); - - std::vector param_types; - for (auto& param_type : func_type->param_types()) { - param_types.push_back(GetLLVMType(param_type)); - } - - return llvm::FunctionType::get(return_type, param_types, false); } return IntType(); diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 83e1d928..000cbec6 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -243,7 +243,7 @@ llvm::Type* LLVMIRGenerator::GetParamType_( if (auto ptr_type = dynamic_cast(parameter->type.get())) { auto base_type = ptr_type->base_type().Clone(); if (auto func_type = dynamic_cast(base_type.get())) { - auto return_type = func_type->return_type()->IsPtr() + auto return_type = func_type->return_type().IsPtr() == true ? (llvm::Type*)llvm_util_.IntPtrType() : (llvm::Type*)llvm_util_.IntType(); std::vector func_params; @@ -266,11 +266,10 @@ llvm::Type* LLVMIRGenerator::GetParamType_( } void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { - // Explicit cast to FunctionType or else it would get an error. + std::vector param_types(func_def.parameters.size(), + llvm_util_.IntType()); auto func_type = - llvm::dyn_cast(llvm_util_.GetLLVMType(func_def.type)); - assert(func_type); - + llvm::FunctionType::get(llvm_util_.IntType(), param_types, false); auto func = llvm::Function::Create(func_type, func_def.id == "main" ? llvm::Function::ExternalLinkage diff --git a/src/type.cpp b/src/type.cpp index c1e6c187..f81c2574 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -57,7 +57,7 @@ std::string PtrType::ToString() const { // For function pointer types, the '*' is placed between the return type and // the parameter list. if (const auto* base_func = dynamic_cast(base_type_.get())) { - auto str = base_func->return_type()->ToString() + " (*)("; + auto str = base_func->return_type().ToString() + " (*)("; for (auto i = std::size_t{0}, e = base_func->param_types().size(); i < e; ++i) { str += base_func->param_types().at(i)->ToString(); diff --git a/src/type_checker.cpp b/src/type_checker.cpp index d767db24..792adbf5 100644 --- a/src/type_checker.cpp +++ b/src/type_checker.cpp @@ -200,7 +200,7 @@ void TypeChecker::Visit(FuncDefNode& func_def) { decayed_param_types.push_back(parameter->type->Clone()); } auto return_type = - dynamic_cast(func_def.type.get())->return_type()->Clone(); + dynamic_cast(func_def.type.get())->return_type().Clone(); func_def.type = std::make_unique(std::move(return_type), std::move(decayed_param_types)); auto symbol = @@ -464,7 +464,7 @@ void TypeChecker::Visit(FuncCallExprNode& call_expr) { // TODO: called object type 'type' is not a function or function pointer assert(false); } - call_expr.type = func_type->return_type()->Clone(); + call_expr.type = func_type->return_type().Clone(); auto& param_types = func_type->param_types(); auto& args = call_expr.args; From 7d70f29377ba735a5765f94e13048d4d0db0ea88 Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 13:28:40 +0800 Subject: [PATCH 60/84] Refactor GetLLVMType with Type reference --- include/llvm/util.hpp | 2 +- src/llvm/util.cpp | 21 +++++++++++---------- src/llvm_ir_generator.cpp | 13 +++++++------ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 7f6a9aca..bb896092 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -44,7 +44,7 @@ class LLVMIRUtil { llvm::Function* CurrFunc(); /// @brief Get the corresponding LLVM type from our type. - llvm::Type* GetLLVMType(const std::unique_ptr& type); + llvm::Type* GetLLVMType(const Type& type); LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} {} diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 906d5aec..4df13b89 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -76,23 +76,24 @@ llvm::Function* LLVMIRUtil::CurrFunc() { return builder_->GetInsertBlock()->getParent(); } -llvm::Type* LLVMIRUtil::GetLLVMType(const std::unique_ptr& type) { - if (type->IsPtr()) { +llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { + if (type.IsPtr()) { + // TODO: recursive get base type return IntPtrType(); - } else if (type->IsArr()) { - auto arr_type = dynamic_cast(type.get()); - return llvm::ArrayType::get(IntType(), arr_type->len()); - } else if (type->IsStruct() || type->IsUnion()) { - std::string record_prefix = type->IsStruct() ? "struct_" : "union_"; - auto record_type = dynamic_cast(type.get()); + } else if (type.IsArr()) { + auto arr_type = dynamic_cast(&type); + return llvm::ArrayType::get(GetLLVMType(arr_type->element_type()), + arr_type->len()); + } else if (type.IsStruct() || type.IsUnion()) { + std::string record_prefix = type.IsStruct() ? "struct_" : "union_"; + auto record_type = dynamic_cast(&type); std::vector field_types; for (auto& field : record_type->fields()) { - field_types.push_back(GetLLVMType(field->type)); + field_types.push_back(GetLLVMType(*(field->type))); } return llvm::StructType::create(builder_->getContext(), field_types, record_prefix + record_type->id()); } - return IntType(); } diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 000cbec6..b43f7ec0 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -160,7 +160,7 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { } void LLVMIRGenerator::Visit(const VarDeclNode& decl) { - auto var_type = llvm_util_.GetLLVMType(decl.type); + auto var_type = llvm_util_.GetLLVMType(*(decl.type)); auto addr = builder_->CreateAlloca(var_type); if (decl.init) { decl.init->Accept(*this); @@ -177,7 +177,7 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { } void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { - auto arr_type = llvm_util_.GetLLVMType(arr_decl.type); + auto arr_type = llvm_util_.GetLLVMType(*(arr_decl.type)); auto base_addr = builder_->CreateAlloca(arr_type, nullptr); id_to_val[arr_decl.id] = base_addr; @@ -213,7 +213,7 @@ void LLVMIRGenerator::Visit(const FieldNode& field) { void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { auto* record_type = dynamic_cast(record_var_decl.type.get()); assert(record_type); - auto type = llvm_util_.GetLLVMType(record_var_decl.type); + auto type = llvm_util_.GetLLVMType(*(record_var_decl.type)); auto base_addr = builder_->CreateAlloca(type, nullptr); id_to_val[record_var_decl.id] = base_addr; @@ -600,7 +600,7 @@ void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) { arr_sub_expr.arr->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); auto base_addr = val_to_id_addr.at(val); - auto arr_type = llvm_util_.GetLLVMType(arr_sub_expr.arr->type); + auto arr_type = llvm_util_.GetLLVMType(*(arr_sub_expr.arr->type)); arr_sub_expr.index->Accept(*this); auto index = dynamic_cast(arr_sub_expr.index.get()); assert(index); @@ -711,14 +711,15 @@ void LLVMIRGenerator::Visit(const RecordMemExprNode& mem_expr) { mem_expr.expr->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); auto base_addr = val_to_id_addr.at(val); - auto struct_type = llvm_util_.GetLLVMType(mem_expr.expr->type); + auto struct_type = llvm_util_.GetLLVMType(*(mem_expr.expr->type)); auto* record_type = dynamic_cast(mem_expr.expr->type.get()); assert(record_type); auto res_addr = builder_->CreateStructGEP( struct_type, base_addr, record_type->MemberIndex(mem_expr.id)); auto res_val = builder_->CreateLoad( - llvm_util_.GetLLVMType(record_type->MemberType(mem_expr.id)), res_addr); + llvm_util_.GetLLVMType(*(record_type->MemberType(mem_expr.id))), + res_addr); val_to_id_addr[res_val] = res_addr; val_recorder.Record(res_val); } From 3b87b3451fb50da74da36d378b1f1b3995e49ac2 Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 15:44:28 +0800 Subject: [PATCH 61/84] Refactor function signature and id expression with GetLLVMType --- src/llvm/util.cpp | 16 ++++++++++++++++ src/llvm_ir_generator.cpp | 15 +++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 4df13b89..a7200cc9 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -79,6 +79,13 @@ llvm::Function* LLVMIRUtil::CurrFunc() { llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { if (type.IsPtr()) { // TODO: recursive get base type + auto ptr_type = dynamic_cast(&type); + auto base_type = ptr_type->base_type().Clone(); + auto llvm_base_type = GetLLVMType(*base_type); + if (llvm_base_type->isFunctionTy()) { + return IntPtrType(); + } + return IntPtrType(); } else if (type.IsArr()) { auto arr_type = dynamic_cast(&type); @@ -94,6 +101,15 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { return llvm::StructType::create(builder_->getContext(), field_types, record_prefix + record_type->id()); + } else if (type.IsFunc()) { + auto func_type = dynamic_cast(&type); + auto return_type = GetLLVMType(func_type->return_type()); + std::vector param_types; + for (auto& param_type : func_type->param_types()) { + param_types.push_back(GetLLVMType(*param_type)); + } + + return llvm::FunctionType::get(return_type, param_types, false); } return IntType(); } diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index b43f7ec0..065ad0d1 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -266,10 +266,9 @@ llvm::Type* LLVMIRGenerator::GetParamType_( } void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { - std::vector param_types(func_def.parameters.size(), - llvm_util_.IntType()); - auto func_type = - llvm::FunctionType::get(llvm_util_.IntType(), param_types, false); + // Explicit cast to llvm::FunctionType to avoid compiler error. + auto func_type = llvm::dyn_cast( + llvm_util_.GetLLVMType(*(func_def.type))); auto func = llvm::Function::Create(func_type, func_def.id == "main" ? llvm::Function::ExternalLinkage @@ -574,12 +573,16 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { assert(id_to_val.count(id_expr.id) != 0); auto id_val = id_to_val.at(id_expr.id); + // TODO: Remove this if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { - auto res = builder_->CreateLoad(llvm_util_.IntPtrType(), id_val); + // auto res = builder_->CreateLoad(llvm_util_.IntPtrType(), id_val); + auto res = + builder_->CreateLoad(llvm_util_.GetLLVMType(*(id_expr.type)), id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } else { - auto res = builder_->CreateLoad(llvm_util_.IntType(), id_val); + auto res = + builder_->CreateLoad(llvm_util_.GetLLVMType(*(id_expr.type)), id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } From 2599d8a6e46af415aa9202fb7e29d8d8d8bcd086 Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 16:13:03 +0800 Subject: [PATCH 62/84] Remove redundant val_to_type map --- src/llvm/util.cpp | 3 +-- src/llvm_ir_generator.cpp | 36 ++++++++---------------------------- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index a7200cc9..bd71c1d7 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -78,12 +78,11 @@ llvm::Function* LLVMIRUtil::CurrFunc() { llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { if (type.IsPtr()) { - // TODO: recursive get base type auto ptr_type = dynamic_cast(&type); auto base_type = ptr_type->base_type().Clone(); auto llvm_base_type = GetLLVMType(*base_type); if (llvm_base_type->isFunctionTy()) { - return IntPtrType(); + return llvm_base_type; } return IntPtrType(); diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 065ad0d1..28ae0a9c 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -105,12 +105,6 @@ auto // as a data member introduces unnecessary dependency. = std::map{}; -// TODO: Remove this after finishing LLVMGetType and remove all use of this map. -auto val_to_type // NOLINT(cppcoreguidelines-avoid-non-const-global-variables): - // Accessible only within this translation unit; declaring - // as a data member introduces unnecessary dependency. - = std::map{}; - /// @brief Every expression generates a LLVM object that is the subclass of /// `llvm::Value`. This object is stored, so we can propagate to later use. class PrevValueRecorder { @@ -161,19 +155,15 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { void LLVMIRGenerator::Visit(const VarDeclNode& decl) { auto var_type = llvm_util_.GetLLVMType(*(decl.type)); + // For function pointer, we need to change from FunctionType to PointerType + var_type = var_type->isFunctionTy() ? var_type->getPointerTo() : var_type; auto addr = builder_->CreateAlloca(var_type); if (decl.init) { decl.init->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); - // TODO: Remove this after finishing LLVMGetType - if (auto func = llvm::dyn_cast(val)) { - var_type = func->getFunctionType(); - } builder_->CreateStore(val, addr); } id_to_val[decl.id] = addr; - // TODO: Remove this after finishing LLVMGetType - val_to_type[addr] = var_type; } void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { @@ -284,23 +274,22 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { args_iter->setName(parameter->id); llvm::Type* param_type = GetParamType_(parameter); - // TODO: Refactor this after finishing GetLLVMType - // Remove the need of storing val_to_type map + // Get FunctionType instead of Ptr type + // llvm::Type* param_type2 = llvm_util_.GetLLVMType(*(parameter->type)); + // TODO: Refactor this after finishing GetLLVMType if (param_type->isFunctionTy()) { - auto func_type = param_type; + // auto func_type = param_type; // function pointer param_type = param_type->getPointerTo(); args_iter->mutateType(param_type); auto addr = builder_->CreateAlloca(param_type); builder_->CreateStore(args_iter, addr); id_to_val[parameter->id] = addr; - val_to_type[addr] = func_type; } else { args_iter->mutateType(param_type); auto addr = builder_->CreateAlloca(param_type); builder_->CreateStore(args_iter, addr); id_to_val[parameter->id] = addr; - val_to_type[addr] = param_type; } ++args_iter; } @@ -573,11 +562,8 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { assert(id_to_val.count(id_expr.id) != 0); auto id_val = id_to_val.at(id_expr.id); - // TODO: Remove this if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { - // auto res = builder_->CreateLoad(llvm_util_.IntPtrType(), id_val); - auto res = - builder_->CreateLoad(llvm_util_.GetLLVMType(*(id_expr.type)), id_val); + auto res = builder_->CreateLoad(llvm_util_.IntPtrType(), id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } else { @@ -681,9 +667,7 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { } } else if (val->getType()->isPointerTy()) { // function pointer - auto func_ptr = val_to_id_addr.at(val); - // TODO: get function type from call_expr.func_expr - auto type = val_to_type.at(func_ptr); + auto type = llvm_util_.GetLLVMType(*(call_expr.func_expr->type)); if (auto func_type = llvm::dyn_cast(type)) { auto return_res = builder_->CreateCall(func_type, val, arg_vals); val_recorder.Record(return_res); @@ -857,9 +841,5 @@ void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) { assign_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); builder_->CreateStore(rhs, val_to_id_addr.at(lhs)); - // TODO: Remove this after finishing GetLLVMType - if (auto func = llvm::dyn_cast(rhs)) { - val_to_type[val_to_id_addr.at(lhs)] = func->getFunctionType(); - } val_recorder.Record(rhs); } From fdd8c9006c19cf44967743a93eea3c8e543f7857 Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 16:16:43 +0800 Subject: [PATCH 63/84] Throw exception if type is unknown --- include/llvm/util.hpp | 1 + src/llvm/util.cpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index bb896092..3534deff 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -44,6 +44,7 @@ class LLVMIRUtil { llvm::Function* CurrFunc(); /// @brief Get the corresponding LLVM type from our type. + /// @throw `std::runtime_error` if the `type` is not unknown. llvm::Type* GetLLVMType(const Type& type); LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} {} diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index bd71c1d7..38569ff8 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -77,7 +78,13 @@ llvm::Function* LLVMIRUtil::CurrFunc() { } llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { - if (type.IsPtr()) { + if (type.IsPrim()) { + if (type.IsEqual(PrimitiveType::kInt)) { + return IntType(); + } + + throw std::runtime_error{"unknown type in GetLLVMType!"}; + } else if (type.IsPtr()) { auto ptr_type = dynamic_cast(&type); auto base_type = ptr_type->base_type().Clone(); auto llvm_base_type = GetLLVMType(*base_type); @@ -110,5 +117,7 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { return llvm::FunctionType::get(return_type, param_types, false); } - return IntType(); + + assert(false); + return nullptr; } From 9e5384a8b31d70f7166053d818e59de240e18c1c Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 16:24:13 +0800 Subject: [PATCH 64/84] Refactor function parameters declaration code generation --- include/llvm_ir_generator.hpp | 2 -- src/llvm_ir_generator.cpp | 50 +++++------------------------------ 2 files changed, 6 insertions(+), 46 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index b8f5bb7b..18d91d4a 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -82,8 +82,6 @@ class LLVMIRGenerator : public NonModifyingVisitor { std::unique_ptr module_; /// @brief Handy LLVM types and functions for code generation. util::LLVMIRUtil llvm_util_; - /// @brief Get LLVM type from function parameter. - llvm::Type* GetParamType_(const std::unique_ptr& parameter); }; #endif // LLVM_IR_GENERATOR_HPP_ diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 28ae0a9c..546c1cfa 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -226,35 +226,6 @@ void LLVMIRGenerator::Visit(const ParamNode& parameter) { /* Do nothing */ } -// TODO: Remove this function after refactoring GetLLVMType -llvm::Type* LLVMIRGenerator::GetParamType_( - const std::unique_ptr& parameter) { - llvm::Type* param_type = nullptr; - if (auto ptr_type = dynamic_cast(parameter->type.get())) { - auto base_type = ptr_type->base_type().Clone(); - if (auto func_type = dynamic_cast(base_type.get())) { - auto return_type = func_type->return_type().IsPtr() == true - ? (llvm::Type*)llvm_util_.IntPtrType() - : (llvm::Type*)llvm_util_.IntType(); - std::vector func_params; - for (auto& func_param : func_type->param_types()) { - func_params.push_back(func_param->IsPtr() - ? (llvm::Type*)llvm_util_.IntPtrType() - : (llvm::Type*)llvm_util_.IntType()); - } - auto func_ptr_type = - llvm::FunctionType::get(return_type, func_params, false); - param_type = func_ptr_type; - } else { - param_type = llvm_util_.IntPtrType(); - } - } else { - param_type = llvm_util_.IntType(); - } - - return param_type; -} - void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { // Explicit cast to llvm::FunctionType to avoid compiler error. auto func_type = llvm::dyn_cast( @@ -273,24 +244,15 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { parameter->Accept(*this); args_iter->setName(parameter->id); - llvm::Type* param_type = GetParamType_(parameter); - // Get FunctionType instead of Ptr type - // llvm::Type* param_type2 = llvm_util_.GetLLVMType(*(parameter->type)); - // TODO: Refactor this after finishing GetLLVMType + llvm::Type* param_type = llvm_util_.GetLLVMType(*(parameter->type)); + // Update type from FunctionType to PointerType for function pointer. if (param_type->isFunctionTy()) { - // auto func_type = param_type; - // function pointer param_type = param_type->getPointerTo(); - args_iter->mutateType(param_type); - auto addr = builder_->CreateAlloca(param_type); - builder_->CreateStore(args_iter, addr); - id_to_val[parameter->id] = addr; - } else { - args_iter->mutateType(param_type); - auto addr = builder_->CreateAlloca(param_type); - builder_->CreateStore(args_iter, addr); - id_to_val[parameter->id] = addr; } + args_iter->mutateType(param_type); + auto addr = builder_->CreateAlloca(param_type); + builder_->CreateStore(args_iter, addr); + id_to_val[parameter->id] = addr; ++args_iter; } From 7886b4dde03d9511e047c8fa6313724b3730377f Mon Sep 17 00:00:00 2001 From: Lee Date: Tue, 2 Jul 2024 16:38:55 +0800 Subject: [PATCH 65/84] Update comments --- include/llvm/util.hpp | 3 +++ src/llvm/util.cpp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 3534deff..133ac9db 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -44,6 +44,9 @@ class LLVMIRUtil { llvm::Function* CurrFunc(); /// @brief Get the corresponding LLVM type from our type. + /// @note For Function Pointers, even though it is a pointer type, we return + /// `FunctionType` instead of `PointerType` because `FunctionType` is needed + /// for creating LLVM IR function call. /// @throw `std::runtime_error` if the `type` is not unknown. llvm::Type* GetLLVMType(const Type& type); diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 38569ff8..41a24a95 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -88,6 +88,7 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { auto ptr_type = dynamic_cast(&type); auto base_type = ptr_type->base_type().Clone(); auto llvm_base_type = GetLLVMType(*base_type); + // Function pointers if (llvm_base_type->isFunctionTy()) { return llvm_base_type; } @@ -98,6 +99,7 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { return llvm::ArrayType::get(GetLLVMType(arr_type->element_type()), arr_type->len()); } else if (type.IsStruct() || type.IsUnion()) { + // A prefix is needed to distinguish struct and union with the same name. std::string record_prefix = type.IsStruct() ? "struct_" : "union_"; auto record_type = dynamic_cast(&type); std::vector field_types; From 3099ea28cebac4c696874ccf7c9b68ab34f3f19e Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 14:10:35 +0800 Subject: [PATCH 66/84] Rename helper functions --- main.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/main.cpp b/main.cpp index ba130074..6dafab65 100644 --- a/main.cpp +++ b/main.cpp @@ -25,10 +25,10 @@ extern FILE* extern void yylex_destroy(); // NOLINT(readability-identifier-naming): extern // from flex generated code. -int QbeBuilder(std::unique_ptr trans_unit, std::string& input_basename, +int CompileQbe(std::unique_ptr trans_unit, std::string& input_basename, std::string& output_name); -int LLVMBuilder(std::unique_ptr trans_unit, +int CompileLLVM(std::unique_ptr trans_unit, std::string& input_basename, std::string& output_name); int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to @@ -76,7 +76,7 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to std::exit(0); } - /// @brief The root node of the trans_unit. + /// @brief The root node of the translation unit. auto trans_unit = std::unique_ptr{}; yy::parser parser{trans_unit}; int ret = parser.parse(); @@ -105,9 +105,9 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to auto output = opts["output"].as(); // generate intermediate representation based on target option if (opts["target"].as() == "qbe") { - return QbeBuilder(std::move(trans_unit), input_basename, output); + return CompileQbe(std::move(trans_unit), input_basename, output); } else if (opts["target"].as() == "llvm") { - return LLVMBuilder(std::move(trans_unit), input_basename, output); + return CompileLLVM(std::move(trans_unit), input_basename, output); } else { std::cerr << "unknown target" << '\n'; std::exit(0); @@ -116,7 +116,7 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to return 0; } -int QbeBuilder(std::unique_ptr trans_unit, std::string& input_basename, +int CompileQbe(std::unique_ptr trans_unit, std::string& input_basename, std::string& output_name) { auto output_ir = std::ofstream{fmt::format("{}.ssa", input_basename)}; QbeIrGenerator code_generator{output_ir}; @@ -143,7 +143,7 @@ int QbeBuilder(std::unique_ptr trans_unit, std::string& input_basename, return 0; } -int LLVMBuilder(std::unique_ptr trans_unit, +int CompileLLVM(std::unique_ptr trans_unit, std::string& input_basename, std::string& output_name) { auto output_ir = std::ofstream{fmt::format("{}.ll", input_basename)}; LLVMIRGenerator code_generator{output_ir, input_basename}; From 4e1b63485d9d4dd8cf71406b3380421636734102 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 14:24:19 +0800 Subject: [PATCH 67/84] Rename builder helper class and builder reference --- include/llvm/util.hpp | 6 +++--- include/llvm_ir_generator.hpp | 6 +++--- src/llvm/util.cpp | 34 +++++++++++++++++----------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 133ac9db..ec381312 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -15,7 +15,7 @@ namespace util { /// @brief A collection of wrappers of LLVM types and functions. -class LLVMIRUtil { +class LLVMIRBuilderHelper { public: /// @brief LLVM Integer type llvm::IntegerType* IntType(); @@ -50,11 +50,11 @@ class LLVMIRUtil { /// @throw `std::runtime_error` if the `type` is not unknown. llvm::Type* GetLLVMType(const Type& type); - LLVMIRUtil(std::unique_ptr>& builder) : builder_{builder} {} + LLVMIRBuilderHelper(llvm::IRBuilder<>& builder) : builder_{builder} {} private: /// @brief Stores a reference from the original builder. - std::unique_ptr>& // XXX: Ignore check until refactor. + llvm::IRBuilder<>& builder_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) }; diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 18d91d4a..9e9888bb 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -62,9 +62,9 @@ class LLVMIRGenerator : public NonModifyingVisitor { context_{std::make_unique()}, builder_{std::make_unique>(*context_)}, module_{std::make_unique(filename, *context_)}, - llvm_util_{util::LLVMIRUtil(builder_)} {} + llvm_util_{util::LLVMIRBuilderHelper(*builder_)} {} - /// @brief Print LLVM IR to output_. + /// @brief Print LLVM IR to output. void PrintIR() { module_->print(output_, nullptr); } @@ -81,7 +81,7 @@ class LLVMIRGenerator : public NonModifyingVisitor { /// @brief Stores global variables, function lists, and the constructed IR. std::unique_ptr module_; /// @brief Handy LLVM types and functions for code generation. - util::LLVMIRUtil llvm_util_; + util::LLVMIRBuilderHelper llvm_util_; }; #endif // LLVM_IR_GENERATOR_HPP_ diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 41a24a95..2c757594 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -18,16 +18,16 @@ using namespace util; -llvm::IntegerType* LLVMIRUtil::IntType() { - return builder_->getInt32Ty(); +llvm::IntegerType* LLVMIRBuilderHelper::IntType() { + return builder_.getInt32Ty(); } -llvm::PointerType* LLVMIRUtil::IntPtrType() { - return builder_->getPtrTy(); +llvm::PointerType* LLVMIRBuilderHelper::IntPtrType() { + return builder_.getPtrTy(); } -void LLVMIRUtil::CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb) { - auto bb = builder_->GetInsertBlock(); +void LLVMIRBuilderHelper::CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb) { + auto bb = builder_.GetInsertBlock(); bool has_terminator = false; for (auto it = bb->begin(); it != bb->end();) { if (it->isTerminator()) { @@ -39,12 +39,12 @@ void LLVMIRUtil::CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb) { } if (!has_terminator) { - builder_->CreateBr(next_bb); + builder_.CreateBr(next_bb); } } -void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_bb, - llvm::BasicBlock* next_bb) { +void LLVMIRBuilderHelper::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_bb, + llvm::BasicBlock* next_bb) { auto bb = curr_bb; bool has_terminator = false; for (auto it = bb->begin(); it != bb->end();) { @@ -57,13 +57,13 @@ void LLVMIRUtil::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_bb, } if (!has_terminator) { - builder_->SetInsertPoint(curr_bb); - builder_->CreateBr(next_bb); + builder_.SetInsertPoint(curr_bb); + builder_.CreateBr(next_bb); } } -llvm::BasicBlock* LLVMIRUtil::FindBBWithNameOf(const std::string& id) { - auto func = builder_->GetInsertBlock()->getParent(); +llvm::BasicBlock* LLVMIRBuilderHelper::FindBBWithNameOf(const std::string& id) { + auto func = builder_.GetInsertBlock()->getParent(); for (auto& bb_iter : *func) { if (bb_iter.getName() == id) { return &(bb_iter); @@ -73,11 +73,11 @@ llvm::BasicBlock* LLVMIRUtil::FindBBWithNameOf(const std::string& id) { return nullptr; } -llvm::Function* LLVMIRUtil::CurrFunc() { - return builder_->GetInsertBlock()->getParent(); +llvm::Function* LLVMIRBuilderHelper::CurrFunc() { + return builder_.GetInsertBlock()->getParent(); } -llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { +llvm::Type* LLVMIRBuilderHelper::GetLLVMType(const Type& type) { if (type.IsPrim()) { if (type.IsEqual(PrimitiveType::kInt)) { return IntType(); @@ -107,7 +107,7 @@ llvm::Type* LLVMIRUtil::GetLLVMType(const Type& type) { field_types.push_back(GetLLVMType(*(field->type))); } - return llvm::StructType::create(builder_->getContext(), field_types, + return llvm::StructType::create(builder_.getContext(), field_types, record_prefix + record_type->id()); } else if (type.IsFunc()) { auto func_type = dynamic_cast(&type); From f598de284977708a3d8eac204712c43d5ebb0b01 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 14:39:12 +0800 Subject: [PATCH 68/84] Inline builder integer and pointer type --- include/llvm/util.hpp | 5 ----- src/llvm/util.cpp | 15 ++------------- src/llvm_ir_generator.cpp | 24 ++++++++++++------------ 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index ec381312..96b0f197 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -17,11 +17,6 @@ namespace util { /// @brief A collection of wrappers of LLVM types and functions. class LLVMIRBuilderHelper { public: - /// @brief LLVM Integer type - llvm::IntegerType* IntType(); - /// @brief LLVM Pointer type - llvm::PointerType* IntPtrType(); - /// @brief Every LLVM basic block can only have one terminator instruction. /// This function can check if there are terminator instructions before the /// current insert point. If no, then it will create an unconditional branch diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 2c757594..763bb4b3 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include #include @@ -18,14 +16,6 @@ using namespace util; -llvm::IntegerType* LLVMIRBuilderHelper::IntType() { - return builder_.getInt32Ty(); -} - -llvm::PointerType* LLVMIRBuilderHelper::IntPtrType() { - return builder_.getPtrTy(); -} - void LLVMIRBuilderHelper::CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb) { auto bb = builder_.GetInsertBlock(); bool has_terminator = false; @@ -80,7 +70,7 @@ llvm::Function* LLVMIRBuilderHelper::CurrFunc() { llvm::Type* LLVMIRBuilderHelper::GetLLVMType(const Type& type) { if (type.IsPrim()) { if (type.IsEqual(PrimitiveType::kInt)) { - return IntType(); + return builder_.getInt32Ty(); } throw std::runtime_error{"unknown type in GetLLVMType!"}; @@ -92,8 +82,7 @@ llvm::Type* LLVMIRBuilderHelper::GetLLVMType(const Type& type) { if (llvm_base_type->isFunctionTy()) { return llvm_base_type; } - - return IntPtrType(); + return builder_.getPtrTy(); } else if (type.IsArr()) { auto arr_type = dynamic_cast(&type); return llvm::ArrayType::get(GetLLVMType(arr_type->element_type()), diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 546c1cfa..cfa71da2 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -186,7 +186,7 @@ void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { builder_->CreateStore(init_val, res_addr); } else { // set remaining elements as 0 - auto zero = llvm::ConstantInt::get(llvm_util_.IntType(), 0, true); + auto zero = llvm::ConstantInt::get(builder_->getInt32Ty(), 0, true); builder_->CreateStore(zero, res_addr); } } @@ -276,16 +276,16 @@ void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. - auto arg = llvm::ArrayRef{llvm_util_.IntType()}; + auto arg = llvm::ArrayRef{builder_->getInt32Ty()}; auto builtin_print = - llvm::FunctionType::get(llvm_util_.IntType(), arg, false); + llvm::FunctionType::get(builder_->getInt32Ty(), arg, false); llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, "__builtin_print", *module_); // Generate printf function for LLVM interpreter. - auto args = llvm::ArrayRef{llvm_util_.IntPtrType(), - llvm_util_.IntType()}; - auto printf = llvm::FunctionType::get(llvm_util_.IntType(), args, false); + auto args = + llvm::ArrayRef{builder_->getPtrTy(), builder_->getInt32Ty()}; + auto printf = llvm::FunctionType::get(builder_->getInt32Ty(), args, false); llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", *module_); @@ -525,7 +525,7 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { auto id_val = id_to_val.at(id_expr.id); if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { - auto res = builder_->CreateLoad(llvm_util_.IntPtrType(), id_val); + auto res = builder_->CreateLoad(builder_->getPtrTy(), id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } else { @@ -538,7 +538,7 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { // NOTE: LLVM Constant does not generate IR code, it can be used directly. - auto val = llvm::ConstantInt::get(llvm_util_.IntType(), int_expr.val, true); + auto val = llvm::ConstantInt::get(builder_->getInt32Ty(), int_expr.val, true); val_recorder.Record(val); } @@ -593,7 +593,7 @@ void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { builder_->SetInsertPoint(end_bb); // NOTE: Since we do not know which operand will be executed in runtime, we // create a Phi node to merge both values. - auto phi_res = builder_->CreatePHI(llvm_util_.IntType(), 2); + auto phi_res = builder_->CreatePHI(builder_->getInt32Ty(), 2); phi_res->addIncoming(second_val, second_bb); phi_res->addIncoming(third_val, third_bb); val_recorder.Record(phi_res); @@ -649,7 +649,7 @@ void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) { ? llvm::BinaryOperator::Add : llvm::BinaryOperator::Sub; - auto one = llvm::ConstantInt::get(llvm_util_.IntType(), 1, true); + auto one = llvm::ConstantInt::get(builder_->getInt32Ty(), 1, true); auto res = builder_->CreateBinOp(arith_op, val, one); const auto* id_expr = dynamic_cast((postfix_expr.operand).get()); assert(id_expr); @@ -731,8 +731,8 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { auto operand = val_recorder.ValOfPrevExpr(); auto res = builder_->CreateLoad(unary_expr.type->IsPtr() - ? (llvm::Type*)llvm_util_.IntPtrType() - : (llvm::Type*)llvm_util_.IntType(), + ? (llvm::Type*)builder_->getPtrTy() + : (llvm::Type*)builder_->getInt32Ty(), operand); val_recorder.Record(res); val_to_id_addr[res] = operand; From 1f8ca0a837cae8fe80b76d50394fade4bede181d Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 14:48:50 +0800 Subject: [PATCH 69/84] Refactor helper function for basic blocks --- include/llvm/util.hpp | 4 ++++ src/llvm/util.cpp | 38 +++++++++++--------------------------- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index 96b0f197..b7ed1da8 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -17,6 +17,10 @@ namespace util { /// @brief A collection of wrappers of LLVM types and functions. class LLVMIRBuilderHelper { public: + /// @brief Check if a basic block has a terminator instruction. + /// @return `true` if terminator instruction is found, `false` otherwise. + bool HasTerminator(llvm::BasicBlock* bb); + /// @brief Every LLVM basic block can only have one terminator instruction. /// This function can check if there are terminator instructions before the /// current insert point. If no, then it will create an unconditional branch diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 763bb4b3..cf2940fc 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -16,37 +16,25 @@ using namespace util; -void LLVMIRBuilderHelper::CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb) { - auto bb = builder_.GetInsertBlock(); - bool has_terminator = false; - for (auto it = bb->begin(); it != bb->end();) { +bool LLVMIRBuilderHelper::HasTerminator(llvm::BasicBlock* bb) { + for (auto it = bb->begin(); it != bb->end(); ++it) { if (it->isTerminator()) { - has_terminator = true; - break; - } else { - ++it; + return true; } } + return false; +} - if (!has_terminator) { +void LLVMIRBuilderHelper::CreateBrIfNoBrBefore(llvm::BasicBlock* next_bb) { + auto bb = builder_.GetInsertBlock(); + if (!HasTerminator(bb)) { builder_.CreateBr(next_bb); } } void LLVMIRBuilderHelper::CurrBBFallThroughNextBB(llvm::BasicBlock* curr_bb, llvm::BasicBlock* next_bb) { - auto bb = curr_bb; - bool has_terminator = false; - for (auto it = bb->begin(); it != bb->end();) { - if (it->isTerminator()) { - has_terminator = true; - break; - } else { - ++it; - } - } - - if (!has_terminator) { + if (!HasTerminator(curr_bb)) { builder_.SetInsertPoint(curr_bb); builder_.CreateBr(next_bb); } @@ -59,7 +47,6 @@ llvm::BasicBlock* LLVMIRBuilderHelper::FindBBWithNameOf(const std::string& id) { return &(bb_iter); } } - return nullptr; } @@ -72,7 +59,6 @@ llvm::Type* LLVMIRBuilderHelper::GetLLVMType(const Type& type) { if (type.IsEqual(PrimitiveType::kInt)) { return builder_.getInt32Ty(); } - throw std::runtime_error{"unknown type in GetLLVMType!"}; } else if (type.IsPtr()) { auto ptr_type = dynamic_cast(&type); @@ -88,14 +74,13 @@ llvm::Type* LLVMIRBuilderHelper::GetLLVMType(const Type& type) { return llvm::ArrayType::get(GetLLVMType(arr_type->element_type()), arr_type->len()); } else if (type.IsStruct() || type.IsUnion()) { - // A prefix is needed to distinguish struct and union with the same name. - std::string record_prefix = type.IsStruct() ? "struct_" : "union_"; auto record_type = dynamic_cast(&type); std::vector field_types; for (auto& field : record_type->fields()) { field_types.push_back(GetLLVMType(*(field->type))); } - + // A prefix is needed to distinguish struct and union with the same name. + std::string record_prefix = type.IsStruct() ? "struct_" : "union_"; return llvm::StructType::create(builder_.getContext(), field_types, record_prefix + record_type->id()); } else if (type.IsFunc()) { @@ -105,7 +90,6 @@ llvm::Type* LLVMIRBuilderHelper::GetLLVMType(const Type& type) { for (auto& param_type : func_type->param_types()) { param_types.push_back(GetLLVMType(*param_type)); } - return llvm::FunctionType::get(return_type, param_types, false); } From aa98013d2e5511ff069b5f01b372038bc3a644ce Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 14:56:45 +0800 Subject: [PATCH 70/84] Include missing headers --- src/llvm_ir_generator.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index cfa71da2..8a3bb0e2 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -1,22 +1,31 @@ #include "llvm_ir_generator.hpp" #include +#include +#include +#include #include +#include #include #include #include +#include #include #include #include #include +#include #include #include +#include #include +#include #include #include #include #include +#include #include #include #include From e22a12622b6b605081f4a4519d45dcc79321db0d Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 14:59:02 +0800 Subject: [PATCH 71/84] Throw errors for operator helper functions --- src/llvm_ir_generator.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 8a3bb0e2..bcc8d074 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -37,7 +37,7 @@ namespace { -/// @throw `std::runtime_error` if there's unrecognize binary operator +/// @throw `std::runtime_error` if there's unrecognized binary operator. llvm::Instruction::BinaryOps GetBinaryOperator(BinaryOperator op) { switch (op) { case BinaryOperator::kAdd: @@ -64,12 +64,13 @@ llvm::Instruction::BinaryOps GetBinaryOperator(BinaryOperator op) { case BinaryOperator::kShr: return llvm::BinaryOperator::AShr; default: - throw std::runtime_error{"unrecognize binary operator!"}; + throw std::runtime_error{"unrecognized binary operator!"}; } } /// @note Comparison operators are not categorized as operator in LLVM. Thus, we /// have this helper function to get the predicate of our comparison operator. +/// @throw `std::runtime_error` if there's unrecognized comparison operator. llvm::CmpInst::Predicate GetCmpPredicate(BinaryOperator op) { switch (op) { case BinaryOperator::kGt: @@ -85,7 +86,7 @@ llvm::CmpInst::Predicate GetCmpPredicate(BinaryOperator op) { case BinaryOperator::kNeq: return llvm::CmpInst::Predicate::ICMP_NE; default: - return llvm::CmpInst::Predicate::BAD_ICMP_PREDICATE; + throw std::runtime_error{"unrecognized comparison operator!"}; } } From 89b08d1e8d5863add0bec0ea696778d71972bc7e Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 15:04:36 +0800 Subject: [PATCH 72/84] Rename LabelInfo struct and vector --- src/llvm_ir_generator.cpp | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index bcc8d074..06e38b3c 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -138,22 +138,22 @@ auto // a data member introduces unnecessary dependency. = PrevValueRecorder{}; -struct LabelViewInfo { +struct LabelInfo { llvm::BasicBlock* entry; llvm::BasicBlock* exit; /// @brief This vector stores every `case` and `default` basic blocks of /// a switch case. - /// This first element of a pair is the expression value - /// of a case statement. - /// This second element of a pair is the label's basic block. + /// The first element of a pair is the expression value + /// of a case statement. It will be a `nullptr` if this is a default case. + /// The second element of a pair is the label's basic block. std::vector> cases{}; }; /// @note Blocks that allows jumping within or out of it should add its labels /// to this list. auto - label_views_of_jumpable_blocks // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - = std::vector{}; + labels_of_jumpable_blocks // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + = std::vector{}; } // namespace @@ -360,9 +360,9 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { builder_->CreateBr(body_bb); } builder_->SetInsertPoint(body_bb); - label_views_of_jumpable_blocks.push_back({.entry = pred_bb, .exit = end_bb}); + labels_of_jumpable_blocks.push_back({.entry = pred_bb, .exit = end_bb}); while_stmt.loop_body->Accept(*this); - label_views_of_jumpable_blocks.pop_back(); + labels_of_jumpable_blocks.pop_back(); llvm_util_.CreateBrIfNoBrBefore(pred_bb); if (while_stmt.is_do_while) { @@ -391,9 +391,9 @@ void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { } builder_->SetInsertPoint(body_bb); - label_views_of_jumpable_blocks.push_back({.entry = step_bb, .exit = end_bb}); + labels_of_jumpable_blocks.push_back({.entry = step_bb, .exit = end_bb}); for_stmt.loop_body->Accept(*this); - label_views_of_jumpable_blocks.pop_back(); + labels_of_jumpable_blocks.pop_back(); llvm_util_.CreateBrIfNoBrBefore(step_bb); builder_->SetInsertPoint(step_bb); @@ -421,13 +421,13 @@ void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { } void LLVMIRGenerator::Visit(const BreakStmtNode& break_stmt) { - assert(!label_views_of_jumpable_blocks.empty()); - llvm_util_.CreateBrIfNoBrBefore(label_views_of_jumpable_blocks.back().exit); + assert(!labels_of_jumpable_blocks.empty()); + llvm_util_.CreateBrIfNoBrBefore(labels_of_jumpable_blocks.back().exit); } void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { - assert(!label_views_of_jumpable_blocks.empty()); - llvm_util_.CreateBrIfNoBrBefore(label_views_of_jumpable_blocks.back().entry); + assert(!labels_of_jumpable_blocks.empty()); + llvm_util_.CreateBrIfNoBrBefore(labels_of_jumpable_blocks.back().entry); } void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { @@ -436,10 +436,10 @@ void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { auto end_bb = llvm::BasicBlock::Create(*context_, "switch_end", llvm_util_.CurrFunc()); auto sw = builder_->CreateSwitch(ctrl, nullptr); - label_views_of_jumpable_blocks.push_back({.entry = end_bb, .exit = end_bb}); + labels_of_jumpable_blocks.push_back({.entry = end_bb, .exit = end_bb}); switch_stmt.stmt->Accept(*this); // Update cases and default label. - auto switch_infos = label_views_of_jumpable_blocks.back(); + auto switch_infos = labels_of_jumpable_blocks.back(); for (auto i = std::size_t{0}, e = switch_infos.cases.size(); i < e; ++i) { auto case_info = switch_infos.cases.at(i); auto curr_bb = case_info.second; @@ -460,7 +460,7 @@ void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { llvm_util_.CurrBBFallThroughNextBB(curr_bb, switch_infos.exit); } } - label_views_of_jumpable_blocks.pop_back(); + labels_of_jumpable_blocks.pop_back(); llvm_util_.CreateBrIfNoBrBefore(end_bb); builder_->SetInsertPoint(end_bb); } @@ -492,9 +492,9 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { builder_->SetInsertPoint(case_bb); case_stmt.stmt->Accept(*this); - assert(!label_views_of_jumpable_blocks.empty()); + assert(!labels_of_jumpable_blocks.empty()); std::pair p{val, case_bb}; - label_views_of_jumpable_blocks.back().cases.push_back(p); + labels_of_jumpable_blocks.back().cases.push_back(p); } void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { @@ -503,9 +503,9 @@ void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { builder_->SetInsertPoint(default_bb); default_stmt.stmt->Accept(*this); - assert(!label_views_of_jumpable_blocks.empty()); + assert(!labels_of_jumpable_blocks.empty()); std::pair p{nullptr, default_bb}; - label_views_of_jumpable_blocks.back().cases.push_back(p); + labels_of_jumpable_blocks.back().cases.push_back(p); } void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) { From 6b8940568ae66baf61393767ed19145cd7168334 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 15:30:37 +0800 Subject: [PATCH 73/84] Update comments and remove redundant arguments --- src/llvm_ir_generator.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 06e38b3c..6459ddd4 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -178,7 +178,7 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { auto arr_type = llvm_util_.GetLLVMType(*(arr_decl.type)); - auto base_addr = builder_->CreateAlloca(arr_type, nullptr); + auto base_addr = builder_->CreateAlloca(arr_type); id_to_val[arr_decl.id] = base_addr; auto arr_decl_type = dynamic_cast(arr_decl.type.get()); @@ -214,11 +214,11 @@ void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { auto* record_type = dynamic_cast(record_var_decl.type.get()); assert(record_type); auto type = llvm_util_.GetLLVMType(*(record_var_decl.type)); - auto base_addr = builder_->CreateAlloca(type, nullptr); + auto base_addr = builder_->CreateAlloca(type); id_to_val[record_var_decl.id] = base_addr; // NOTE: This predicate will make sure that we don't initialize members that - // exceed the total number of members in a record. Also, it gurantees + // exceed the total number of members in a record. Also, it guarantees // that accessing element in the initializers will not go out of bound. for (auto i = std::size_t{0}, e = record_var_decl.inits.size(), slot_count = record_type->SlotCount(); @@ -240,11 +240,8 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { // Explicit cast to llvm::FunctionType to avoid compiler error. auto func_type = llvm::dyn_cast( llvm_util_.GetLLVMType(*(func_def.type))); - auto func = llvm::Function::Create(func_type, - func_def.id == "main" - ? llvm::Function::ExternalLinkage - : llvm::Function::InternalLinkage, - func_def.id, *module_); + auto func = llvm::Function::Create( + func_type, llvm::GlobalValue::ExternalLinkage, func_def.id, *module_); auto body = llvm::BasicBlock::Create(*context_, "body", func); builder_->SetInsertPoint(body); @@ -292,7 +289,7 @@ void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, "__builtin_print", *module_); - // Generate printf function for LLVM interpreter. + // Generate printf function. auto args = llvm::ArrayRef{builder_->getPtrTy(), builder_->getInt32Ty()}; auto printf = llvm::FunctionType::get(builder_->getInt32Ty(), args, false); From 49d3ab0567ab89db5b1baea13b53ef086e3abdb3 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 15:47:25 +0800 Subject: [PATCH 74/84] Refactor create basic block if not exist logic --- src/llvm_ir_generator.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 6459ddd4..63f2d455 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -411,9 +411,9 @@ void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { if (target_bb) { builder_->CreateBr(target_bb); } else { - auto label_bb = llvm::BasicBlock::Create(*context_, goto_stmt.label, - llvm_util_.CurrFunc()); - builder_->CreateBr(label_bb); + target_bb = llvm::BasicBlock::Create(*context_, goto_stmt.label, + llvm_util_.CurrFunc()); + builder_->CreateBr(target_bb); } } @@ -467,9 +467,9 @@ void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { llvm_util_.FindBBWithNameOf(id_labeled_stmt.label); if (!target_bb) { - auto label_bb = llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, - llvm_util_.CurrFunc()); - builder_->SetInsertPoint(label_bb); + target_bb = llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, + llvm_util_.CurrFunc()); + builder_->SetInsertPoint(target_bb); } else { builder_->SetInsertPoint(target_bb); } @@ -483,15 +483,15 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { auto int_expr = dynamic_cast(case_stmt.expr.get()); assert(int_expr); - auto case_bb = llvm::BasicBlock::Create( - *context_, "case" + std::to_string(int_expr->val), llvm_util_.CurrFunc()); + auto case_label = "case_" + std::to_string(int_expr->val); + auto case_bb = + llvm::BasicBlock::Create(*context_, case_label, llvm_util_.CurrFunc()); builder_->SetInsertPoint(case_bb); case_stmt.stmt->Accept(*this); assert(!labels_of_jumpable_blocks.empty()); - std::pair p{val, case_bb}; - labels_of_jumpable_blocks.back().cases.push_back(p); + labels_of_jumpable_blocks.back().cases.emplace_back(val, case_bb); } void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { @@ -501,8 +501,7 @@ void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { default_stmt.stmt->Accept(*this); assert(!labels_of_jumpable_blocks.empty()); - std::pair p{nullptr, default_bb}; - labels_of_jumpable_blocks.back().cases.push_back(p); + labels_of_jumpable_blocks.back().cases.emplace_back(nullptr, default_bb); } void LLVMIRGenerator::Visit(const ExprStmtNode& expr_stmt) { From 93dd326aa21981fb56e053ea6ba3e1fc94e40663 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 16:11:15 +0800 Subject: [PATCH 75/84] Refactor IdExprNode --- src/llvm_ir_generator.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 63f2d455..5ff5c5bc 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -530,16 +530,16 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { assert(id_to_val.count(id_expr.id) != 0); auto id_val = id_to_val.at(id_expr.id); + llvm::Type* id_type = nullptr; + // LLVM requires the function to have pointer type when being referenced. if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { - auto res = builder_->CreateLoad(builder_->getPtrTy(), id_val); - val_recorder.Record(res); - val_to_id_addr[res] = id_val; + id_type = builder_->getPtrTy(); } else { - auto res = - builder_->CreateLoad(llvm_util_.GetLLVMType(*(id_expr.type)), id_val); - val_recorder.Record(res); - val_to_id_addr[res] = id_val; + id_type = llvm_util_.GetLLVMType(*(id_expr.type)); } + auto res = builder_->CreateLoad(id_type, id_val); + val_recorder.Record(res); + val_to_id_addr[res] = id_val; } void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { From cd17d351ddace55d6a614db0cf284e45e9260bb4 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 16:23:06 +0800 Subject: [PATCH 76/84] Record return value of printf function --- src/llvm_ir_generator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 5ff5c5bc..fd834488 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -627,7 +627,8 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { assert(print_format); print_args.push_back(print_format); print_args.insert(print_args.end(), arg_vals.begin(), arg_vals.end()); - builder_->CreateCall(printf, print_args); + auto return_res = builder_->CreateCall(printf, print_args); + val_recorder.Record(return_res); } else { auto called_func = module_->getFunction(func->getName()); auto return_res = builder_->CreateCall(called_func, arg_vals); From bc6e89475e1f1fcb0b51b8ead3650512df8a52d7 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 16:29:01 +0800 Subject: [PATCH 77/84] Rename variable --- src/llvm_ir_generator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index fd834488..4143c37e 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -667,12 +667,12 @@ void LLVMIRGenerator::Visit(const RecordMemExprNode& mem_expr) { mem_expr.expr->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); auto base_addr = val_to_id_addr.at(val); - auto struct_type = llvm_util_.GetLLVMType(*(mem_expr.expr->type)); + auto llvm_type = llvm_util_.GetLLVMType(*(mem_expr.expr->type)); auto* record_type = dynamic_cast(mem_expr.expr->type.get()); assert(record_type); auto res_addr = builder_->CreateStructGEP( - struct_type, base_addr, record_type->MemberIndex(mem_expr.id)); + llvm_type, base_addr, record_type->MemberIndex(mem_expr.id)); auto res_val = builder_->CreateLoad( llvm_util_.GetLLVMType(*(record_type->MemberType(mem_expr.id))), res_addr); From 015682e01e7d2ecf558d1dc51bd12f29705930f4 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 16:31:28 +0800 Subject: [PATCH 78/84] Refactor with GetLLVMType --- src/llvm_ir_generator.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 4143c37e..cb764fa2 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -737,10 +737,8 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { } auto operand = val_recorder.ValOfPrevExpr(); - auto res = builder_->CreateLoad(unary_expr.type->IsPtr() - ? (llvm::Type*)builder_->getPtrTy() - : (llvm::Type*)builder_->getInt32Ty(), - operand); + auto res = builder_->CreateLoad( + llvm_util_.GetLLVMType(*(unary_expr.type)), operand); val_recorder.Record(res); val_to_id_addr[res] = operand; } break; From 3fa57004ef4b6a659a85ec5b181ef9c6d78eae68 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 16:53:09 +0800 Subject: [PATCH 79/84] Fix clang-tidy --- include/llvm/util.hpp | 2 -- src/llvm/util.cpp | 5 ++--- src/llvm_ir_generator.cpp | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index b7ed1da8..f893af9f 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -2,12 +2,10 @@ #define LLVM_UTIL_HPP_ #include -#include #include #include #include -#include #include #include "type.hpp" diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index cf2940fc..709eb44c 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -17,8 +16,8 @@ using namespace util; bool LLVMIRBuilderHelper::HasTerminator(llvm::BasicBlock* bb) { - for (auto it = bb->begin(); it != bb->end(); ++it) { - if (it->isTerminator()) { + for (auto& it : *bb) { + if (it.isTerminator()) { return true; } } diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index cb764fa2..0017e7ef 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -20,7 +19,6 @@ #include #include -#include #include #include #include From a2ce9e0ed062fc234c7447acf89bb29f3eedf5ed Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 22:34:02 +0800 Subject: [PATCH 80/84] Move HasTerminator outside of BuilderHelper class --- include/llvm/util.hpp | 8 ++++---- src/llvm/util.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/llvm/util.hpp b/include/llvm/util.hpp index f893af9f..4be88300 100644 --- a/include/llvm/util.hpp +++ b/include/llvm/util.hpp @@ -12,13 +12,13 @@ namespace util { +/// @brief Check if a basic block has a terminator instruction. +/// @return `true` if terminator instruction is found, `false` otherwise. +bool HasTerminator(llvm::BasicBlock* bb); + /// @brief A collection of wrappers of LLVM types and functions. class LLVMIRBuilderHelper { public: - /// @brief Check if a basic block has a terminator instruction. - /// @return `true` if terminator instruction is found, `false` otherwise. - bool HasTerminator(llvm::BasicBlock* bb); - /// @brief Every LLVM basic block can only have one terminator instruction. /// This function can check if there are terminator instructions before the /// current insert point. If no, then it will create an unconditional branch diff --git a/src/llvm/util.cpp b/src/llvm/util.cpp index 709eb44c..086dc26a 100644 --- a/src/llvm/util.cpp +++ b/src/llvm/util.cpp @@ -15,7 +15,7 @@ using namespace util; -bool LLVMIRBuilderHelper::HasTerminator(llvm::BasicBlock* bb) { +bool util::HasTerminator(llvm::BasicBlock* bb) { for (auto& it : *bb) { if (it.isTerminator()) { return true; From 9c0088f75cfbc9ba19598a3252bdd444c0cee6aa Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 22:36:32 +0800 Subject: [PATCH 81/84] Rename builder_helper_ member and update comments --- include/llvm_ir_generator.hpp | 9 +++-- src/llvm_ir_generator.cpp | 69 ++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 9e9888bb..7b793823 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -57,12 +57,12 @@ class LLVMIRGenerator : public NonModifyingVisitor { void Visit(const BinaryExprNode&) override; void Visit(const SimpleAssignmentExprNode&) override; - LLVMIRGenerator(std::ostream& output, std::string& filename) + LLVMIRGenerator(std::ostream& output, const std::string& filename) : output_{output}, context_{std::make_unique()}, builder_{std::make_unique>(*context_)}, module_{std::make_unique(filename, *context_)}, - llvm_util_{util::LLVMIRBuilderHelper(*builder_)} {} + builder_helper_{util::LLVMIRBuilderHelper(*builder_)} {} /// @brief Print LLVM IR to output. void PrintIR() { @@ -80,8 +80,9 @@ class LLVMIRGenerator : public NonModifyingVisitor { std::unique_ptr> builder_; /// @brief Stores global variables, function lists, and the constructed IR. std::unique_ptr module_; - /// @brief Handy LLVM types and functions for code generation. - util::LLVMIRBuilderHelper llvm_util_; + /// @brief Wrapping IR builder to provide handy LLVM types and functions for + /// IR generation. + util::LLVMIRBuilderHelper builder_helper_; }; #endif // LLVM_IR_GENERATOR_HPP_ diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 0017e7ef..974aca6d 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -162,7 +162,7 @@ void LLVMIRGenerator::Visit(const DeclStmtNode& decl_stmt) { } void LLVMIRGenerator::Visit(const VarDeclNode& decl) { - auto var_type = llvm_util_.GetLLVMType(*(decl.type)); + auto var_type = builder_helper_.GetLLVMType(*(decl.type)); // For function pointer, we need to change from FunctionType to PointerType var_type = var_type->isFunctionTy() ? var_type->getPointerTo() : var_type; auto addr = builder_->CreateAlloca(var_type); @@ -175,7 +175,7 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { } void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { - auto arr_type = llvm_util_.GetLLVMType(*(arr_decl.type)); + auto arr_type = builder_helper_.GetLLVMType(*(arr_decl.type)); auto base_addr = builder_->CreateAlloca(arr_type); id_to_val[arr_decl.id] = base_addr; @@ -211,7 +211,7 @@ void LLVMIRGenerator::Visit(const FieldNode& field) { void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { auto* record_type = dynamic_cast(record_var_decl.type.get()); assert(record_type); - auto type = llvm_util_.GetLLVMType(*(record_var_decl.type)); + auto type = builder_helper_.GetLLVMType(*(record_var_decl.type)); auto base_addr = builder_->CreateAlloca(type); id_to_val[record_var_decl.id] = base_addr; @@ -237,7 +237,7 @@ void LLVMIRGenerator::Visit(const ParamNode& parameter) { void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { // Explicit cast to llvm::FunctionType to avoid compiler error. auto func_type = llvm::dyn_cast( - llvm_util_.GetLLVMType(*(func_def.type))); + builder_helper_.GetLLVMType(*(func_def.type))); auto func = llvm::Function::Create( func_type, llvm::GlobalValue::ExternalLinkage, func_def.id, *module_); @@ -249,7 +249,7 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { parameter->Accept(*this); args_iter->setName(parameter->id); - llvm::Type* param_type = llvm_util_.GetLLVMType(*(parameter->type)); + llvm::Type* param_type = builder_helper_.GetLLVMType(*(parameter->type)); // Update type from FunctionType to PointerType for function pointer. if (param_type->isFunctionTy()) { param_type = param_type->getPointerTo(); @@ -305,7 +305,7 @@ void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { if_stmt.predicate->Accept(*this); auto predicate_val = val_recorder.ValOfPrevExpr(); - auto func = llvm_util_.CurrFunc(); + auto func = builder_helper_.CurrFunc(); auto then_bb = llvm::BasicBlock::Create(*context_, "if_then", func); auto else_bb = if_stmt.or_else != nullptr ? llvm::BasicBlock::Create(*context_, "if_else", func) @@ -318,7 +318,7 @@ void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { if_stmt.or_else != nullptr ? else_bb : end_bb); builder_->SetInsertPoint(then_bb); if_stmt.then->Accept(*this); - llvm_util_.CreateBrIfNoBrBefore(end_bb); + builder_helper_.CreateBrIfNoBrBefore(end_bb); if (if_stmt.or_else) { builder_->SetInsertPoint(else_bb); @@ -330,7 +330,7 @@ void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { auto label_prefix = std::string{while_stmt.is_do_while ? "do_" : "while_"}; - auto func = llvm_util_.CurrFunc(); + auto func = builder_helper_.CurrFunc(); auto body_bb = llvm::BasicBlock::Create(*context_, label_prefix + "body", func); auto pred_bb = @@ -358,7 +358,7 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { labels_of_jumpable_blocks.push_back({.entry = pred_bb, .exit = end_bb}); while_stmt.loop_body->Accept(*this); labels_of_jumpable_blocks.pop_back(); - llvm_util_.CreateBrIfNoBrBefore(pred_bb); + builder_helper_.CreateBrIfNoBrBefore(pred_bb); if (while_stmt.is_do_while) { builder_->SetInsertPoint(pred_bb); @@ -370,7 +370,7 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { } void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { - auto func = llvm_util_.CurrFunc(); + auto func = builder_helper_.CurrFunc(); auto pred_bb = llvm::BasicBlock::Create(*context_, "for_pred", func); auto body_bb = llvm::BasicBlock::Create(*context_, "for_body", func); auto step_bb = llvm::BasicBlock::Create(*context_, "for_step", func); @@ -389,7 +389,7 @@ void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { labels_of_jumpable_blocks.push_back({.entry = step_bb, .exit = end_bb}); for_stmt.loop_body->Accept(*this); labels_of_jumpable_blocks.pop_back(); - llvm_util_.CreateBrIfNoBrBefore(step_bb); + builder_helper_.CreateBrIfNoBrBefore(step_bb); builder_->SetInsertPoint(step_bb); for_stmt.step->Accept(*this); @@ -404,32 +404,33 @@ void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { } void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { - llvm::BasicBlock* target_bb = llvm_util_.FindBBWithNameOf(goto_stmt.label); + llvm::BasicBlock* target_bb = + builder_helper_.FindBBWithNameOf(goto_stmt.label); if (target_bb) { builder_->CreateBr(target_bb); } else { target_bb = llvm::BasicBlock::Create(*context_, goto_stmt.label, - llvm_util_.CurrFunc()); + builder_helper_.CurrFunc()); builder_->CreateBr(target_bb); } } void LLVMIRGenerator::Visit(const BreakStmtNode& break_stmt) { assert(!labels_of_jumpable_blocks.empty()); - llvm_util_.CreateBrIfNoBrBefore(labels_of_jumpable_blocks.back().exit); + builder_helper_.CreateBrIfNoBrBefore(labels_of_jumpable_blocks.back().exit); } void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { assert(!labels_of_jumpable_blocks.empty()); - llvm_util_.CreateBrIfNoBrBefore(labels_of_jumpable_blocks.back().entry); + builder_helper_.CreateBrIfNoBrBefore(labels_of_jumpable_blocks.back().entry); } void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { switch_stmt.ctrl->Accept(*this); auto ctrl = val_recorder.ValOfPrevExpr(); - auto end_bb = - llvm::BasicBlock::Create(*context_, "switch_end", llvm_util_.CurrFunc()); + auto end_bb = llvm::BasicBlock::Create(*context_, "switch_end", + builder_helper_.CurrFunc()); auto sw = builder_->CreateSwitch(ctrl, nullptr); labels_of_jumpable_blocks.push_back({.entry = end_bb, .exit = end_bb}); switch_stmt.stmt->Accept(*this); @@ -450,23 +451,23 @@ void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { // BB. If BB is the last BB, then branch to switch exit. if (i + 1 != e) { auto next_bb = switch_infos.cases.at(i + 1).second; - llvm_util_.CurrBBFallThroughNextBB(curr_bb, next_bb); + builder_helper_.CurrBBFallThroughNextBB(curr_bb, next_bb); } else { - llvm_util_.CurrBBFallThroughNextBB(curr_bb, switch_infos.exit); + builder_helper_.CurrBBFallThroughNextBB(curr_bb, switch_infos.exit); } } labels_of_jumpable_blocks.pop_back(); - llvm_util_.CreateBrIfNoBrBefore(end_bb); + builder_helper_.CreateBrIfNoBrBefore(end_bb); builder_->SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { llvm::BasicBlock* target_bb = - llvm_util_.FindBBWithNameOf(id_labeled_stmt.label); + builder_helper_.FindBBWithNameOf(id_labeled_stmt.label); if (!target_bb) { target_bb = llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, - llvm_util_.CurrFunc()); + builder_helper_.CurrFunc()); builder_->SetInsertPoint(target_bb); } else { builder_->SetInsertPoint(target_bb); @@ -482,8 +483,8 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { assert(int_expr); auto case_label = "case_" + std::to_string(int_expr->val); - auto case_bb = - llvm::BasicBlock::Create(*context_, case_label, llvm_util_.CurrFunc()); + auto case_bb = llvm::BasicBlock::Create(*context_, case_label, + builder_helper_.CurrFunc()); builder_->SetInsertPoint(case_bb); case_stmt.stmt->Accept(*this); @@ -493,8 +494,8 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { } void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { - auto default_bb = - llvm::BasicBlock::Create(*context_, "default", llvm_util_.CurrFunc()); + auto default_bb = llvm::BasicBlock::Create(*context_, "default", + builder_helper_.CurrFunc()); builder_->SetInsertPoint(default_bb); default_stmt.stmt->Accept(*this); @@ -533,7 +534,7 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { id_type = builder_->getPtrTy(); } else { - id_type = llvm_util_.GetLLVMType(*(id_expr.type)); + id_type = builder_helper_.GetLLVMType(*(id_expr.type)); } auto res = builder_->CreateLoad(id_type, id_val); val_recorder.Record(res); @@ -555,7 +556,7 @@ void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) { arr_sub_expr.arr->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); auto base_addr = val_to_id_addr.at(val); - auto arr_type = llvm_util_.GetLLVMType(*(arr_sub_expr.arr->type)); + auto arr_type = builder_helper_.GetLLVMType(*(arr_sub_expr.arr->type)); arr_sub_expr.index->Accept(*this); auto index = dynamic_cast(arr_sub_expr.index.get()); assert(index); @@ -571,7 +572,7 @@ void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) { void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { cond_expr.predicate->Accept(*this); auto predicate_val = val_recorder.ValOfPrevExpr(); - auto func = llvm_util_.CurrFunc(); + auto func = builder_helper_.CurrFunc(); // The second operand is evaluated only if the first compares unequal to // 0; the third operand is evaluated only if the first compares equal to // 0; the result is the value of the second or third operand (whichever is @@ -634,7 +635,7 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { } } else if (val->getType()->isPointerTy()) { // function pointer - auto type = llvm_util_.GetLLVMType(*(call_expr.func_expr->type)); + auto type = builder_helper_.GetLLVMType(*(call_expr.func_expr->type)); if (auto func_type = llvm::dyn_cast(type)) { auto return_res = builder_->CreateCall(func_type, val, arg_vals); val_recorder.Record(return_res); @@ -665,14 +666,14 @@ void LLVMIRGenerator::Visit(const RecordMemExprNode& mem_expr) { mem_expr.expr->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); auto base_addr = val_to_id_addr.at(val); - auto llvm_type = llvm_util_.GetLLVMType(*(mem_expr.expr->type)); + auto llvm_type = builder_helper_.GetLLVMType(*(mem_expr.expr->type)); auto* record_type = dynamic_cast(mem_expr.expr->type.get()); assert(record_type); auto res_addr = builder_->CreateStructGEP( llvm_type, base_addr, record_type->MemberIndex(mem_expr.id)); auto res_val = builder_->CreateLoad( - llvm_util_.GetLLVMType(*(record_type->MemberType(mem_expr.id))), + builder_helper_.GetLLVMType(*(record_type->MemberType(mem_expr.id))), res_addr); val_to_id_addr[res_val] = res_addr; val_recorder.Record(res_val); @@ -736,7 +737,7 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { auto operand = val_recorder.ValOfPrevExpr(); auto res = builder_->CreateLoad( - llvm_util_.GetLLVMType(*(unary_expr.type)), operand); + builder_helper_.GetLLVMType(*(unary_expr.type)), operand); val_recorder.Record(res); val_to_id_addr[res] = operand; } break; @@ -759,7 +760,7 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { } if (bin_expr.op == BinaryOperator::kLand || bin_expr.op == BinaryOperator::kLor) { - auto func = llvm_util_.CurrFunc(); + auto func = builder_helper_.CurrFunc(); auto rhs_bb = llvm::BasicBlock::Create(*context_, "logic_rhs", func); auto short_circuit_bb = llvm::BasicBlock::Create(*context_, "short_circuit", func); From 6e50cce8070db1425b6c202bb95507fff9331450 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 22:38:15 +0800 Subject: [PATCH 82/84] Pass constant string reference --- main.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/main.cpp b/main.cpp index 6dafab65..8ff5bc8e 100644 --- a/main.cpp +++ b/main.cpp @@ -25,11 +25,13 @@ extern FILE* extern void yylex_destroy(); // NOLINT(readability-identifier-naming): extern // from flex generated code. -int CompileQbe(std::unique_ptr trans_unit, std::string& input_basename, - std::string& output_name); +int CompileQbe(std::unique_ptr trans_unit, + const std::string& input_basename, + const std::string& output_name); int CompileLLVM(std::unique_ptr trans_unit, - std::string& input_basename, std::string& output_name); + const std::string& input_basename, + const std::string& output_name); int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to // catch all exceptions isn't reasonable. @@ -116,8 +118,9 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to return 0; } -int CompileQbe(std::unique_ptr trans_unit, std::string& input_basename, - std::string& output_name) { +int CompileQbe(std::unique_ptr trans_unit, + const std::string& input_basename, + const std::string& output_name) { auto output_ir = std::ofstream{fmt::format("{}.ssa", input_basename)}; QbeIrGenerator code_generator{output_ir}; trans_unit->Accept(code_generator); @@ -144,7 +147,8 @@ int CompileQbe(std::unique_ptr trans_unit, std::string& input_basename, } int CompileLLVM(std::unique_ptr trans_unit, - std::string& input_basename, std::string& output_name) { + const std::string& input_basename, + const std::string& output_name) { auto output_ir = std::ofstream{fmt::format("{}.ll", input_basename)}; LLVMIRGenerator code_generator{output_ir, input_basename}; trans_unit->Accept(code_generator); From c030086428b84f27d3c2873c14795106f625c438 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 23:06:47 +0800 Subject: [PATCH 83/84] Refactor LLVM IR generator data members --- include/llvm_ir_generator.hpp | 17 ++- src/llvm_ir_generator.cpp | 250 +++++++++++++++++----------------- 2 files changed, 132 insertions(+), 135 deletions(-) diff --git a/include/llvm_ir_generator.hpp b/include/llvm_ir_generator.hpp index 7b793823..423e3e45 100644 --- a/include/llvm_ir_generator.hpp +++ b/include/llvm_ir_generator.hpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -59,27 +58,27 @@ class LLVMIRGenerator : public NonModifyingVisitor { LLVMIRGenerator(std::ostream& output, const std::string& filename) : output_{output}, - context_{std::make_unique()}, - builder_{std::make_unique>(*context_)}, - module_{std::make_unique(filename, *context_)}, - builder_helper_{util::LLVMIRBuilderHelper(*builder_)} {} + context_{}, + builder_{llvm::IRBuilder<>(context_)}, + module_{llvm::Module(filename, context_)}, + builder_helper_{util::LLVMIRBuilderHelper(builder_)} {} /// @brief Print LLVM IR to output. void PrintIR() { - module_->print(output_, nullptr); + module_.print(output_, nullptr); } private: /// @brief A LLVM ostream wrapper for writing to output. llvm::raw_os_ostream output_; /// @brief A LLVM object that includes core LLVM infrastructure. - std::unique_ptr context_; + llvm::LLVMContext context_; /// @brief Provides LLVM Builder API for constructing IR. By default, Constant /// folding is enabled and we have more flexibility for inserting /// instructions. - std::unique_ptr> builder_; + llvm::IRBuilder<> builder_; /// @brief Stores global variables, function lists, and the constructed IR. - std::unique_ptr module_; + llvm::Module module_; /// @brief Wrapping IR builder to provide handy LLVM types and functions for /// IR generation. util::LLVMIRBuilderHelper builder_helper_; diff --git a/src/llvm_ir_generator.cpp b/src/llvm_ir_generator.cpp index 974aca6d..a26759aa 100644 --- a/src/llvm_ir_generator.cpp +++ b/src/llvm_ir_generator.cpp @@ -165,18 +165,18 @@ void LLVMIRGenerator::Visit(const VarDeclNode& decl) { auto var_type = builder_helper_.GetLLVMType(*(decl.type)); // For function pointer, we need to change from FunctionType to PointerType var_type = var_type->isFunctionTy() ? var_type->getPointerTo() : var_type; - auto addr = builder_->CreateAlloca(var_type); + auto addr = builder_.CreateAlloca(var_type); if (decl.init) { decl.init->Accept(*this); auto val = val_recorder.ValOfPrevExpr(); - builder_->CreateStore(val, addr); + builder_.CreateStore(val, addr); } id_to_val[decl.id] = addr; } void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { auto arr_type = builder_helper_.GetLLVMType(*(arr_decl.type)); - auto base_addr = builder_->CreateAlloca(arr_type); + auto base_addr = builder_.CreateAlloca(arr_type); id_to_val[arr_decl.id] = base_addr; auto arr_decl_type = dynamic_cast(arr_decl.type.get()); @@ -187,15 +187,15 @@ void LLVMIRGenerator::Visit(const ArrDeclNode& arr_decl) { } auto res_addr = - builder_->CreateConstInBoundsGEP2_32(arr_type, base_addr, 0, i); + builder_.CreateConstInBoundsGEP2_32(arr_type, base_addr, 0, i); if (i < arr_decl.init_list.size()) { auto init_val = val_recorder.ValOfPrevExpr(); - builder_->CreateStore(init_val, res_addr); + builder_.CreateStore(init_val, res_addr); } else { // set remaining elements as 0 - auto zero = llvm::ConstantInt::get(builder_->getInt32Ty(), 0, true); - builder_->CreateStore(zero, res_addr); + auto zero = llvm::ConstantInt::get(builder_.getInt32Ty(), 0, true); + builder_.CreateStore(zero, res_addr); } } } @@ -212,7 +212,7 @@ void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { auto* record_type = dynamic_cast(record_var_decl.type.get()); assert(record_type); auto type = builder_helper_.GetLLVMType(*(record_var_decl.type)); - auto base_addr = builder_->CreateAlloca(type); + auto base_addr = builder_.CreateAlloca(type); id_to_val[record_var_decl.id] = base_addr; // NOTE: This predicate will make sure that we don't initialize members that @@ -225,8 +225,8 @@ void LLVMIRGenerator::Visit(const RecordVarDeclNode& record_var_decl) { init->Accept(*this); auto init_val = val_recorder.ValOfPrevExpr(); - auto res_addr = builder_->CreateStructGEP(type, base_addr, i); - builder_->CreateStore(init_val, res_addr); + auto res_addr = builder_.CreateStructGEP(type, base_addr, i); + builder_.CreateStore(init_val, res_addr); } } @@ -239,10 +239,10 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { auto func_type = llvm::dyn_cast( builder_helper_.GetLLVMType(*(func_def.type))); auto func = llvm::Function::Create( - func_type, llvm::GlobalValue::ExternalLinkage, func_def.id, *module_); + func_type, llvm::GlobalValue::ExternalLinkage, func_def.id, module_); - auto body = llvm::BasicBlock::Create(*context_, "body", func); - builder_->SetInsertPoint(body); + auto body = llvm::BasicBlock::Create(context_, "body", func); + builder_.SetInsertPoint(body); // Allocate space for parameters. auto args_iter = func->arg_begin(); for (auto& parameter : func_def.parameters) { @@ -255,8 +255,8 @@ void LLVMIRGenerator::Visit(const FuncDefNode& func_def) { param_type = param_type->getPointerTo(); } args_iter->mutateType(param_type); - auto addr = builder_->CreateAlloca(param_type); - builder_->CreateStore(args_iter, addr); + auto addr = builder_.CreateAlloca(param_type); + builder_.CreateStore(args_iter, addr); id_to_val[parameter->id] = addr; ++args_iter; } @@ -281,21 +281,20 @@ void LLVMIRGenerator::Visit(const ExternDeclNode& extern_decl) { void LLVMIRGenerator::Visit(const TransUnitNode& trans_unit) { // Generate builtin print function. - auto arg = llvm::ArrayRef{builder_->getInt32Ty()}; + auto arg = llvm::ArrayRef{builder_.getInt32Ty()}; auto builtin_print = - llvm::FunctionType::get(builder_->getInt32Ty(), arg, false); + llvm::FunctionType::get(builder_.getInt32Ty(), arg, false); llvm::Function::Create(builtin_print, llvm::Function::ExternalLinkage, - "__builtin_print", *module_); + "__builtin_print", module_); // Generate printf function. auto args = - llvm::ArrayRef{builder_->getPtrTy(), builder_->getInt32Ty()}; - auto printf = llvm::FunctionType::get(builder_->getInt32Ty(), args, false); + llvm::ArrayRef{builder_.getPtrTy(), builder_.getInt32Ty()}; + auto printf = llvm::FunctionType::get(builder_.getInt32Ty(), args, false); llvm::Function::Create(printf, llvm::Function::ExternalLinkage, "printf", - *module_); + module_); - builder_->CreateGlobalString("%d\n", "__builtin_print_format", 0, - module_.get()); + builder_.CreateGlobalString("%d\n", "__builtin_print_format", 0, &module_); for (const auto& extern_decl : trans_unit.extern_decls) { extern_decl->Accept(*this); @@ -306,36 +305,36 @@ void LLVMIRGenerator::Visit(const IfStmtNode& if_stmt) { if_stmt.predicate->Accept(*this); auto predicate_val = val_recorder.ValOfPrevExpr(); auto func = builder_helper_.CurrFunc(); - auto then_bb = llvm::BasicBlock::Create(*context_, "if_then", func); + auto then_bb = llvm::BasicBlock::Create(context_, "if_then", func); auto else_bb = if_stmt.or_else != nullptr - ? llvm::BasicBlock::Create(*context_, "if_else", func) + ? llvm::BasicBlock::Create(context_, "if_else", func) : nullptr; - auto end_bb = llvm::BasicBlock::Create(*context_, "if_end", func); + auto end_bb = llvm::BasicBlock::Create(context_, "if_end", func); auto zero = llvm::ConstantInt::get(predicate_val->getType(), 0, true); - auto predicate = builder_->CreateICmpNE(predicate_val, zero); - builder_->CreateCondBr(predicate, then_bb, - if_stmt.or_else != nullptr ? else_bb : end_bb); - builder_->SetInsertPoint(then_bb); + auto predicate = builder_.CreateICmpNE(predicate_val, zero); + builder_.CreateCondBr(predicate, then_bb, + if_stmt.or_else != nullptr ? else_bb : end_bb); + builder_.SetInsertPoint(then_bb); if_stmt.then->Accept(*this); builder_helper_.CreateBrIfNoBrBefore(end_bb); if (if_stmt.or_else) { - builder_->SetInsertPoint(else_bb); + builder_.SetInsertPoint(else_bb); if_stmt.or_else->Accept(*this); - builder_->CreateBr(end_bb); + builder_.CreateBr(end_bb); } - builder_->SetInsertPoint(end_bb); + builder_.SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { auto label_prefix = std::string{while_stmt.is_do_while ? "do_" : "while_"}; auto func = builder_helper_.CurrFunc(); auto body_bb = - llvm::BasicBlock::Create(*context_, label_prefix + "body", func); + llvm::BasicBlock::Create(context_, label_prefix + "body", func); auto pred_bb = - llvm::BasicBlock::Create(*context_, label_prefix + "pred", func); - auto end_bb = llvm::BasicBlock::Create(*context_, label_prefix + "end", func); + llvm::BasicBlock::Create(context_, label_prefix + "pred", func); + auto end_bb = llvm::BasicBlock::Create(context_, label_prefix + "end", func); // A while statement's predicate is evaluated "before" the body statement, // whereas a do-while statement's predicate is evaluated "after" the body @@ -343,64 +342,64 @@ void LLVMIRGenerator::Visit(const WhileStmtNode& while_stmt) { // unconditional jump at the end of the body to jump back to the predicate. // For a do-while statement, it only needs one conditional jump. if (!while_stmt.is_do_while) { - builder_->CreateBr(pred_bb); - builder_->SetInsertPoint(pred_bb); + builder_.CreateBr(pred_bb); + builder_.SetInsertPoint(pred_bb); while_stmt.predicate->Accept(*this); auto predicate = val_recorder.ValOfPrevExpr(); - builder_->CreateCondBr(predicate, body_bb, end_bb); + builder_.CreateCondBr(predicate, body_bb, end_bb); } // Connect entry basic block to body basic block. if (while_stmt.is_do_while) { - builder_->CreateBr(body_bb); + builder_.CreateBr(body_bb); } - builder_->SetInsertPoint(body_bb); + builder_.SetInsertPoint(body_bb); labels_of_jumpable_blocks.push_back({.entry = pred_bb, .exit = end_bb}); while_stmt.loop_body->Accept(*this); labels_of_jumpable_blocks.pop_back(); builder_helper_.CreateBrIfNoBrBefore(pred_bb); if (while_stmt.is_do_while) { - builder_->SetInsertPoint(pred_bb); + builder_.SetInsertPoint(pred_bb); while_stmt.predicate->Accept(*this); auto predicate = val_recorder.ValOfPrevExpr(); - builder_->CreateCondBr(predicate, body_bb, end_bb); + builder_.CreateCondBr(predicate, body_bb, end_bb); } - builder_->SetInsertPoint(end_bb); + builder_.SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const ForStmtNode& for_stmt) { auto func = builder_helper_.CurrFunc(); - auto pred_bb = llvm::BasicBlock::Create(*context_, "for_pred", func); - auto body_bb = llvm::BasicBlock::Create(*context_, "for_body", func); - auto step_bb = llvm::BasicBlock::Create(*context_, "for_step", func); - auto end_bb = llvm::BasicBlock::Create(*context_, "for_end", func); + auto pred_bb = llvm::BasicBlock::Create(context_, "for_pred", func); + auto body_bb = llvm::BasicBlock::Create(context_, "for_body", func); + auto step_bb = llvm::BasicBlock::Create(context_, "for_step", func); + auto end_bb = llvm::BasicBlock::Create(context_, "for_end", func); for_stmt.loop_init->Accept(*this); - builder_->CreateBr(pred_bb); - builder_->SetInsertPoint(pred_bb); + builder_.CreateBr(pred_bb); + builder_.SetInsertPoint(pred_bb); for_stmt.predicate->Accept(*this); if (!dynamic_cast((for_stmt.predicate).get())) { auto predicate = val_recorder.ValOfPrevExpr(); - builder_->CreateCondBr(predicate, body_bb, end_bb); + builder_.CreateCondBr(predicate, body_bb, end_bb); } - builder_->SetInsertPoint(body_bb); + builder_.SetInsertPoint(body_bb); labels_of_jumpable_blocks.push_back({.entry = step_bb, .exit = end_bb}); for_stmt.loop_body->Accept(*this); labels_of_jumpable_blocks.pop_back(); builder_helper_.CreateBrIfNoBrBefore(step_bb); - builder_->SetInsertPoint(step_bb); + builder_.SetInsertPoint(step_bb); for_stmt.step->Accept(*this); - builder_->CreateBr(pred_bb); - builder_->SetInsertPoint(end_bb); + builder_.CreateBr(pred_bb); + builder_.SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const ReturnStmtNode& ret_stmt) { ret_stmt.expr->Accept(*this); auto expr = val_recorder.ValOfPrevExpr(); - builder_->CreateRet(expr); + builder_.CreateRet(expr); } void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { @@ -408,11 +407,11 @@ void LLVMIRGenerator::Visit(const GotoStmtNode& goto_stmt) { builder_helper_.FindBBWithNameOf(goto_stmt.label); if (target_bb) { - builder_->CreateBr(target_bb); + builder_.CreateBr(target_bb); } else { - target_bb = llvm::BasicBlock::Create(*context_, goto_stmt.label, + target_bb = llvm::BasicBlock::Create(context_, goto_stmt.label, builder_helper_.CurrFunc()); - builder_->CreateBr(target_bb); + builder_.CreateBr(target_bb); } } @@ -429,9 +428,9 @@ void LLVMIRGenerator::Visit(const ContinueStmtNode& continue_stmt) { void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { switch_stmt.ctrl->Accept(*this); auto ctrl = val_recorder.ValOfPrevExpr(); - auto end_bb = llvm::BasicBlock::Create(*context_, "switch_end", + auto end_bb = llvm::BasicBlock::Create(context_, "switch_end", builder_helper_.CurrFunc()); - auto sw = builder_->CreateSwitch(ctrl, nullptr); + auto sw = builder_.CreateSwitch(ctrl, nullptr); labels_of_jumpable_blocks.push_back({.entry = end_bb, .exit = end_bb}); switch_stmt.stmt->Accept(*this); // Update cases and default label. @@ -458,7 +457,7 @@ void LLVMIRGenerator::Visit(const SwitchStmtNode& switch_stmt) { } labels_of_jumpable_blocks.pop_back(); builder_helper_.CreateBrIfNoBrBefore(end_bb); - builder_->SetInsertPoint(end_bb); + builder_.SetInsertPoint(end_bb); } void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { @@ -466,11 +465,11 @@ void LLVMIRGenerator::Visit(const IdLabeledStmtNode& id_labeled_stmt) { builder_helper_.FindBBWithNameOf(id_labeled_stmt.label); if (!target_bb) { - target_bb = llvm::BasicBlock::Create(*context_, id_labeled_stmt.label, + target_bb = llvm::BasicBlock::Create(context_, id_labeled_stmt.label, builder_helper_.CurrFunc()); - builder_->SetInsertPoint(target_bb); + builder_.SetInsertPoint(target_bb); } else { - builder_->SetInsertPoint(target_bb); + builder_.SetInsertPoint(target_bb); } id_labeled_stmt.stmt->Accept(*this); @@ -483,10 +482,10 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { assert(int_expr); auto case_label = "case_" + std::to_string(int_expr->val); - auto case_bb = llvm::BasicBlock::Create(*context_, case_label, + auto case_bb = llvm::BasicBlock::Create(context_, case_label, builder_helper_.CurrFunc()); - builder_->SetInsertPoint(case_bb); + builder_.SetInsertPoint(case_bb); case_stmt.stmt->Accept(*this); assert(!labels_of_jumpable_blocks.empty()); @@ -494,9 +493,9 @@ void LLVMIRGenerator::Visit(const CaseStmtNode& case_stmt) { } void LLVMIRGenerator::Visit(const DefaultStmtNode& default_stmt) { - auto default_bb = llvm::BasicBlock::Create(*context_, "default", - builder_helper_.CurrFunc()); - builder_->SetInsertPoint(default_bb); + auto default_bb = + llvm::BasicBlock::Create(context_, "default", builder_helper_.CurrFunc()); + builder_.SetInsertPoint(default_bb); default_stmt.stmt->Accept(*this); assert(!labels_of_jumpable_blocks.empty()); @@ -521,7 +520,7 @@ void LLVMIRGenerator::Visit(const NullExprNode& null_expr) { void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { if (id_expr.type->IsFunc()) { - auto* func = module_->getFunction(id_expr.id); + auto* func = module_.getFunction(id_expr.id); assert(func); val_recorder.Record(func); return; @@ -532,18 +531,18 @@ void LLVMIRGenerator::Visit(const IdExprNode& id_expr) { llvm::Type* id_type = nullptr; // LLVM requires the function to have pointer type when being referenced. if (id_expr.type->IsPtr() || id_expr.type->IsFunc()) { - id_type = builder_->getPtrTy(); + id_type = builder_.getPtrTy(); } else { id_type = builder_helper_.GetLLVMType(*(id_expr.type)); } - auto res = builder_->CreateLoad(id_type, id_val); + auto res = builder_.CreateLoad(id_type, id_val); val_recorder.Record(res); val_to_id_addr[res] = id_val; } void LLVMIRGenerator::Visit(const IntConstExprNode& int_expr) { // NOTE: LLVM Constant does not generate IR code, it can be used directly. - auto val = llvm::ConstantInt::get(builder_->getInt32Ty(), int_expr.val, true); + auto val = llvm::ConstantInt::get(builder_.getInt32Ty(), int_expr.val, true); val_recorder.Record(val); } @@ -561,10 +560,9 @@ void LLVMIRGenerator::Visit(const ArrSubExprNode& arr_sub_expr) { auto index = dynamic_cast(arr_sub_expr.index.get()); assert(index); - auto res_addr = builder_->CreateConstInBoundsGEP2_32( - arr_type, base_addr, 0, (unsigned int)index->val); - auto res_val = - builder_->CreateLoad(arr_type->getArrayElementType(), res_addr); + auto res_addr = builder_.CreateConstInBoundsGEP2_32(arr_type, base_addr, 0, + (unsigned int)index->val); + auto res_val = builder_.CreateLoad(arr_type->getArrayElementType(), res_addr); val_to_id_addr[res_val] = res_addr; val_recorder.Record(res_val); } @@ -577,28 +575,28 @@ void LLVMIRGenerator::Visit(const CondExprNode& cond_expr) { // 0; the third operand is evaluated only if the first compares equal to // 0; the result is the value of the second or third operand (whichever is // evaluated). - auto second_bb = llvm::BasicBlock::Create(*context_, "cond_second", func); - auto third_bb = llvm::BasicBlock::Create(*context_, "cond_third", func); - auto end_bb = llvm::BasicBlock::Create(*context_, "cond_end", func); + auto second_bb = llvm::BasicBlock::Create(context_, "cond_second", func); + auto third_bb = llvm::BasicBlock::Create(context_, "cond_third", func); + auto end_bb = llvm::BasicBlock::Create(context_, "cond_end", func); auto zero = llvm::ConstantInt::get(predicate_val->getType(), 0, true); - auto predicate = builder_->CreateICmpNE(predicate_val, zero); - builder_->CreateCondBr(predicate, second_bb, third_bb); + auto predicate = builder_.CreateICmpNE(predicate_val, zero); + builder_.CreateCondBr(predicate, second_bb, third_bb); - builder_->SetInsertPoint(second_bb); + builder_.SetInsertPoint(second_bb); cond_expr.then->Accept(*this); auto second_val = val_recorder.ValOfPrevExpr(); - builder_->CreateBr(end_bb); + builder_.CreateBr(end_bb); - builder_->SetInsertPoint(third_bb); + builder_.SetInsertPoint(third_bb); cond_expr.or_else->Accept(*this); auto third_val = val_recorder.ValOfPrevExpr(); - builder_->CreateBr(end_bb); + builder_.CreateBr(end_bb); - builder_->SetInsertPoint(end_bb); + builder_.SetInsertPoint(end_bb); // NOTE: Since we do not know which operand will be executed in runtime, we // create a Phi node to merge both values. - auto phi_res = builder_->CreatePHI(builder_->getInt32Ty(), 2); + auto phi_res = builder_.CreatePHI(builder_.getInt32Ty(), 2); phi_res->addIncoming(second_val, second_bb); phi_res->addIncoming(third_val, third_bb); val_recorder.Record(phi_res); @@ -618,26 +616,26 @@ void LLVMIRGenerator::Visit(const FuncCallExprNode& call_expr) { if (auto func = llvm::dyn_cast(val)) { if (func->getName() == "__builtin_print") { // builtin_print call - auto printf = module_->getFunction("printf"); + auto printf = module_.getFunction("printf"); std::vector print_args{}; // NOTE: set AllowInternal true to get internal linkage global variable auto print_format = - module_->getGlobalVariable("__builtin_print_format", true); + module_.getGlobalVariable("__builtin_print_format", true); assert(print_format); print_args.push_back(print_format); print_args.insert(print_args.end(), arg_vals.begin(), arg_vals.end()); - auto return_res = builder_->CreateCall(printf, print_args); + auto return_res = builder_.CreateCall(printf, print_args); val_recorder.Record(return_res); } else { - auto called_func = module_->getFunction(func->getName()); - auto return_res = builder_->CreateCall(called_func, arg_vals); + auto called_func = module_.getFunction(func->getName()); + auto return_res = builder_.CreateCall(called_func, arg_vals); val_recorder.Record(return_res); } } else if (val->getType()->isPointerTy()) { // function pointer auto type = builder_helper_.GetLLVMType(*(call_expr.func_expr->type)); if (auto func_type = llvm::dyn_cast(type)) { - auto return_res = builder_->CreateCall(func_type, val, arg_vals); + auto return_res = builder_.CreateCall(func_type, val, arg_vals); val_recorder.Record(return_res); } else { // TODO: unreachable @@ -655,11 +653,11 @@ void LLVMIRGenerator::Visit(const PostfixArithExprNode& postfix_expr) { ? llvm::BinaryOperator::Add : llvm::BinaryOperator::Sub; - auto one = llvm::ConstantInt::get(builder_->getInt32Ty(), 1, true); - auto res = builder_->CreateBinOp(arith_op, val, one); + auto one = llvm::ConstantInt::get(builder_.getInt32Ty(), 1, true); + auto res = builder_.CreateBinOp(arith_op, val, one); const auto* id_expr = dynamic_cast((postfix_expr.operand).get()); assert(id_expr); - builder_->CreateStore(res, id_to_val.at(id_expr->id)); + builder_.CreateStore(res, id_to_val.at(id_expr->id)); } void LLVMIRGenerator::Visit(const RecordMemExprNode& mem_expr) { @@ -670,9 +668,9 @@ void LLVMIRGenerator::Visit(const RecordMemExprNode& mem_expr) { auto* record_type = dynamic_cast(mem_expr.expr->type.get()); assert(record_type); - auto res_addr = builder_->CreateStructGEP( + auto res_addr = builder_.CreateStructGEP( llvm_type, base_addr, record_type->MemberIndex(mem_expr.id)); - auto res_val = builder_->CreateLoad( + auto res_val = builder_.CreateLoad( builder_helper_.GetLLVMType(*(record_type->MemberType(mem_expr.id))), res_addr); val_to_id_addr[res_val] = res_addr; @@ -691,8 +689,8 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { : BinaryOperator::kSub; auto one = llvm::ConstantInt::get(operand->getType(), 1, true); auto res = - builder_->CreateBinOp(GetBinaryOperator(arith_op), operand, one); - builder_->CreateStore(res, val_to_id_addr.at(operand)); + builder_.CreateBinOp(GetBinaryOperator(arith_op), operand, one); + builder_.CreateStore(res, val_to_id_addr.at(operand)); val_recorder.Record(res); } break; case UnaryOperator::kPos: { @@ -701,19 +699,19 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { case UnaryOperator::kNeg: { auto operand = val_recorder.ValOfPrevExpr(); auto zero = llvm::ConstantInt::get(operand->getType(), 0, true); - auto res = builder_->CreateSub(zero, operand); + auto res = builder_.CreateSub(zero, operand); val_recorder.Record(res); } break; case UnaryOperator::kNot: { auto operand = val_recorder.ValOfPrevExpr(); auto zero = llvm::ConstantInt::get(operand->getType(), 0, true); - auto res = builder_->CreateICmpEQ(operand, zero); + auto res = builder_.CreateICmpEQ(operand, zero); val_recorder.Record(res); } break; case UnaryOperator::kBitComp: { auto operand = val_recorder.ValOfPrevExpr(); auto all_ones = llvm::ConstantInt::get(operand->getType(), -1, true); - auto res = builder_->CreateXor(operand, all_ones); + auto res = builder_.CreateXor(operand, all_ones); val_recorder.Record(res); } break; case UnaryOperator::kAddr: { @@ -736,7 +734,7 @@ void LLVMIRGenerator::Visit(const UnaryExprNode& unary_expr) { } auto operand = val_recorder.ValOfPrevExpr(); - auto res = builder_->CreateLoad( + auto res = builder_.CreateLoad( builder_helper_.GetLLVMType(*(unary_expr.type)), operand); val_recorder.Record(res); val_to_id_addr[res] = operand; @@ -761,42 +759,42 @@ void LLVMIRGenerator::Visit(const BinaryExprNode& bin_expr) { if (bin_expr.op == BinaryOperator::kLand || bin_expr.op == BinaryOperator::kLor) { auto func = builder_helper_.CurrFunc(); - auto rhs_bb = llvm::BasicBlock::Create(*context_, "logic_rhs", func); + auto rhs_bb = llvm::BasicBlock::Create(context_, "logic_rhs", func); auto short_circuit_bb = - llvm::BasicBlock::Create(*context_, "short_circuit", func); - auto end_bb = llvm::BasicBlock::Create(*context_, "logic_end", func); + llvm::BasicBlock::Create(context_, "short_circuit", func); + auto end_bb = llvm::BasicBlock::Create(context_, "logic_end", func); auto zero = llvm::ConstantInt::get(lhs->getType(), 0, true); - auto lhs_res = builder_->CreateCmp(bin_expr.op == BinaryOperator::kLand - ? llvm::CmpInst::Predicate::ICMP_NE - : llvm::CmpInst::Predicate::ICMP_EQ, - lhs, zero); - builder_->CreateCondBr(lhs_res, rhs_bb, short_circuit_bb); - builder_->SetInsertPoint(rhs_bb); + auto lhs_res = builder_.CreateCmp(bin_expr.op == BinaryOperator::kLand + ? llvm::CmpInst::Predicate::ICMP_NE + : llvm::CmpInst::Predicate::ICMP_EQ, + lhs, zero); + builder_.CreateCondBr(lhs_res, rhs_bb, short_circuit_bb); + builder_.SetInsertPoint(rhs_bb); bin_expr.rhs->Accept(*this); auto res = val_recorder.ValOfPrevExpr(); - auto rhs_res = builder_->CreateICmpNE(res, zero); - builder_->CreateBr(end_bb); - builder_->SetInsertPoint(short_circuit_bb); - auto false_val = llvm::ConstantInt::getFalse(*context_); - auto true_val = llvm::ConstantInt::getTrue(*context_); + auto rhs_res = builder_.CreateICmpNE(res, zero); + builder_.CreateBr(end_bb); + builder_.SetInsertPoint(short_circuit_bb); + auto false_val = llvm::ConstantInt::getFalse(context_); + auto true_val = llvm::ConstantInt::getTrue(context_); auto short_circuit_res = bin_expr.op == BinaryOperator::kLand ? false_val : true_val; - builder_->CreateBr(end_bb); - builder_->SetInsertPoint(end_bb); + builder_.CreateBr(end_bb); + builder_.SetInsertPoint(end_bb); // Merge results from rhs and short_circuit_res. - auto phi_res = builder_->CreatePHI(builder_->getInt1Ty(), 2); + auto phi_res = builder_.CreatePHI(builder_.getInt1Ty(), 2); phi_res->addIncoming(rhs_res, rhs_bb); phi_res->addIncoming(short_circuit_res, short_circuit_bb); val_recorder.Record(phi_res); } else if (IsCmpInst(bin_expr.op)) { bin_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); - auto res = builder_->CreateCmp(GetCmpPredicate(bin_expr.op), lhs, rhs); + auto res = builder_.CreateCmp(GetCmpPredicate(bin_expr.op), lhs, rhs); val_recorder.Record(res); } else { bin_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); - auto res = builder_->CreateBinOp(GetBinaryOperator(bin_expr.op), lhs, rhs); + auto res = builder_.CreateBinOp(GetBinaryOperator(bin_expr.op), lhs, rhs); val_recorder.Record(res); } } @@ -806,6 +804,6 @@ void LLVMIRGenerator::Visit(const SimpleAssignmentExprNode& assign_expr) { auto lhs = val_recorder.ValOfPrevExpr(); assign_expr.rhs->Accept(*this); auto rhs = val_recorder.ValOfPrevExpr(); - builder_->CreateStore(rhs, val_to_id_addr.at(lhs)); + builder_.CreateStore(rhs, val_to_id_addr.at(lhs)); val_recorder.Record(rhs); } From f2122317c72188903046278bc0eff6417951d642 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Jul 2024 23:15:10 +0800 Subject: [PATCH 84/84] Update README --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9dfee4f8..19aee0c1 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ VitaminC 🍋 is an educational C compiler frontend written in C++. As a fronten > [!WARNING] > This project is still under development. Many features are not yet implemented. Currently, we do not support preprocessor directives, and only the `int` type and its pointer, as well as object types, are supported. -The main goal of this project is to demonstrate how a compiler frontend works with [the LLVM compiler infrastructure](https://llvm.org/) and generates LLVM IR. However, we are not yet there. Currently, we generate [QBE](https://c9x.me/compile/) IR manually. +The main goal of this project is to demonstrate how a compiler frontend works with [the LLVM compiler infrastructure](https://llvm.org/) and generates LLVM IR. Currently, this compiler can generate [QBE](https://c9x.me/compile/) IR and [LLVM](https://llvm.org/docs/LangRef.html) IR. We are not aiming to be a fully compliant C compiler, although we strive to be as compliant as possible with C89 and support common C99 features. @@ -17,7 +17,8 @@ We are not aiming to be a fully compliant C compiler, although we strive to be a - A C++ compiler that supports C++17. - [GNU Make](https://www.gnu.org/software/make/): for building the project. -- [QBE](https://c9x.me/compile/releases.html): for compiling the QBE IR down to assembly. +- [QBE](https://c9x.me/compile/releases.html): for compiling QBE IR to assembly. +- [LLVM-18](https://releases.llvm.org/): for generating LLVM IR and compiling it to assembly. - [cxxopts](https://github.com/jarro2783/cxxopts): for command-line argument parsing. - [fmt](https://fmt.dev/latest/index.html): for modern C++ formatting. - (test-only) [turnt](https://github.com/cucapra/turnt): for snapshot testing. @@ -49,10 +50,10 @@ A simple C compiler. Usage: ./vitaminc [options] file - -o, --output Write output to (default: a.out) - -d, --dump Dump the abstract syntax tree - -t, --target [qbe] Specify target IR (default: qbe) - -h, --help Display available options + -o, --output Write output to (default: a.out) + -d, --dump Dump the abstract syntax tree + -t, --target [qbe|llvm] Specify target IR (default: qbe) + -h, --help Display available options ``` ## License