Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support LLVM backend #171

Merged
merged 84 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
e5de4b1
Set up initial testing configuration for llvm
leewei05 Jun 16, 2024
490766b
Create llvm IR generator
leewei05 Jun 16, 2024
c312c58
Write LLVM IR to files
leewei05 Jun 16, 2024
3e90edc
Generate return statement and constant expression LLVM IR
leewei05 Jun 18, 2024
ef1879c
Integrate lli for testing LLVM IR
leewei05 Jun 18, 2024
eca3d05
Update turnt config file and printf with parameter
leewei05 Jun 22, 2024
fcc5838
Handle simple binary expression
leewei05 Jun 22, 2024
2975b36
Update TransUnitNode and ExternDeclNode
leewei05 Jun 24, 2024
c3603aa
Insert __builtin_print_format global variable
leewei05 Jun 24, 2024
9e85f46
Print output with llvm interpreter
leewei05 Jun 24, 2024
c903cc9
Simplify IntConstExprNode by returning integer const directly
leewei05 Jun 24, 2024
df0f59a
Code generation for variable declaration and id expression
leewei05 Jun 24, 2024
2d46738
Refactor i32Ty with Util class
leewei05 Jun 24, 2024
af47ebd
Binary and comparison operator code generation
leewei05 Jun 27, 2024
ada573d
Implement simple assignment expression code generation
leewei05 Jun 27, 2024
690db76
Implement prefix increment and decrement code generation
leewei05 Jun 28, 2024
af5678e
Implement logical AND and OR operation code generation
leewei05 Jun 28, 2024
b4a9c16
Implement Bitwise complement operator code generation
leewei05 Jun 28, 2024
4b250f1
Implement postfix increment and decrement operator code generation
leewei05 Jun 28, 2024
e983617
Implement if else statement code generation
leewei05 Jun 29, 2024
7ccc800
Implement while and do while statement code generation
leewei05 Jun 29, 2024
bc5c7a5
Implement for statement code generation
leewei05 Jun 29, 2024
6bfb6d0
Implement break and continue statement code generation
leewei05 Jun 29, 2024
65b7af0
Rename integer type name
leewei05 Jun 29, 2024
563fba5
Implement pointer code generation
leewei05 Jun 29, 2024
fc9f7d4
Remove hardcode pointer size
leewei05 Jun 29, 2024
158ac6e
Implement function call expression code generation
leewei05 Jun 29, 2024
07706ec
Implement condition expression code generation
leewei05 Jun 29, 2024
c93394b
Implement array code generation
leewei05 Jun 30, 2024
fd78532
Implement function pointer code generation
leewei05 Jun 30, 2024
ceede3e
Implement Record type declaration code generation
leewei05 Jun 30, 2024
f5aecb6
Implement function pointer parameter code generation
leewei05 Jun 30, 2024
2dfce85
Implement goto and id label statement code generation
leewei05 Jun 30, 2024
98a05f3
Add newline at the end of the file
leewei05 Jun 30, 2024
99b7073
Implement switch, case, default statement code generation
leewei05 Jun 30, 2024
5de045d
Use simpler builder function
leewei05 Jun 30, 2024
4730d88
Add GetFieldTypes to get field types of record type variable
leewei05 Jul 1, 2024
d7c92a8
Implement Struct and Union variable declaration code generation
leewei05 Jul 1, 2024
e304306
Add comments and use smart pointers for module
leewei05 Jul 1, 2024
6cc3e40
Update binary operator helper functions
leewei05 Jul 1, 2024
70f5a48
Rename struct and update comments
leewei05 Jul 1, 2024
afef598
Separate LLVM util class header and source file
leewei05 Jul 1, 2024
605ad92
Rename util and type names
leewei05 Jul 1, 2024
0e58922
Refactor VarDeclNode with GetLLVMType
leewei05 Jul 1, 2024
0e2ed54
Refactor ArrDeclNode and RecordVarDeclNode with GetLLVMType
leewei05 Jul 1, 2024
5667659
Change return_type() of FuncType to unique_ptr
leewei05 Jul 1, 2024
c5c10d8
Refactor goto and id label statement with find basic block function
leewei05 Jul 1, 2024
25d215f
Refactor with CurrFunc to get the current inserting function
leewei05 Jul 1, 2024
65a6b01
Small refactor and remove unused statements
leewei05 Jul 1, 2024
ff27229
Update TODOs in makefile and main.cpp
leewei05 Jul 1, 2024
28d9087
Update Makefile with llvm-config flags and CI
leewei05 Jul 1, 2024
9f5ee56
Update LLVM installed version
leewei05 Jul 1, 2024
4061c19
Include missing headers
leewei05 Jul 1, 2024
eca43dd
Rename basic block from BB to bb
leewei05 Jul 1, 2024
4b8a5bd
Change public member to public functions
leewei05 Jul 1, 2024
6c9f9c9
Fix Clang tidy errors and ignore one check due to crash
leewei05 Jul 1, 2024
09edb47
Remove unused code
leewei05 Jul 1, 2024
d648869
Update comments
leewei05 Jul 1, 2024
4355ca5
Revert "Change return_type() of FuncType to unique_ptr"
leewei05 Jul 2, 2024
7d70f29
Refactor GetLLVMType with Type reference
leewei05 Jul 2, 2024
3b87b34
Refactor function signature and id expression with GetLLVMType
leewei05 Jul 2, 2024
2599d8a
Remove redundant val_to_type map
leewei05 Jul 2, 2024
fdd8c90
Throw exception if type is unknown
leewei05 Jul 2, 2024
9e5384a
Refactor function parameters declaration code generation
leewei05 Jul 2, 2024
7886b4d
Update comments
leewei05 Jul 2, 2024
3099ea2
Rename helper functions
leewei05 Jul 5, 2024
4e1b634
Rename builder helper class and builder reference
leewei05 Jul 5, 2024
f598de2
Inline builder integer and pointer type
leewei05 Jul 5, 2024
1f8ca0a
Refactor helper function for basic blocks
leewei05 Jul 5, 2024
aa98013
Include missing headers
leewei05 Jul 5, 2024
e22a126
Throw errors for operator helper functions
leewei05 Jul 5, 2024
89b08d1
Rename LabelInfo struct and vector
leewei05 Jul 5, 2024
6b89405
Update comments and remove redundant arguments
leewei05 Jul 5, 2024
49d3ab0
Refactor create basic block if not exist logic
leewei05 Jul 5, 2024
93dd326
Refactor IdExprNode
leewei05 Jul 5, 2024
cd17d35
Record return value of printf function
leewei05 Jul 5, 2024
bc6e894
Rename variable
leewei05 Jul 5, 2024
015682e
Refactor with GetLLVMType
leewei05 Jul 5, 2024
3fa5700
Fix clang-tidy
leewei05 Jul 5, 2024
a2ce9e0
Move HasTerminator outside of BuilderHelper class
leewei05 Jul 5, 2024
9c0088f
Rename builder_helper_ member and update comments
leewei05 Jul 5, 2024
6e50cce
Pass constant string reference
leewei05 Jul 5, 2024
c030086
Refactor LLVM IR generator data members
leewei05 Jul 5, 2024
f212231
Update README
leewei05 Jul 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@
#
# -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: "*"

Checks: >
-*,
bugprone-*,
-bugprone-unchecked-optional-access,
-bugprone-easily-swappable-parameters,
performance-*,
clang-analyzer-*,
cppcoreguidelines-*,
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- name: Install LLVM
run: |
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
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ lex.yy.*
# QBE IR files
*.ssa

# LLVM IR files
*.ll

# Python environments
.env
.venv
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 -I$(shell llvm-config-18 --includedir) -Werror
CFLAGS = $(CXXFLAGS)
LDLIBS = -lfmt
LDLIBS = -lfmt $(shell llvm-config-18 --libs core)
LEX = lex
# C++ features are used, yacc doesn't suffice
YACC = bison
Expand Down Expand Up @@ -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

Expand Down
63 changes: 63 additions & 0 deletions include/llvm/util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#ifndef LLVM_UTIL_HPP_
#define LLVM_UTIL_HPP_

#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Type.h>

#include <memory>
#include <string>

#include "type.hpp"

namespace util {

/// @brief A collection of wrappers of LLVM types and functions.
class LLVMIRUtil {
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
/// 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);

/// @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.
/// @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);

LLVMIRUtil(std::unique_ptr<llvm::IRBuilder<>>& builder) : builder_{builder} {}
leewei05 marked this conversation as resolved.
Show resolved Hide resolved

private:
/// @brief Stores a reference from the original builder.
std::unique_ptr<llvm::IRBuilder<>>& // XXX: Ignore check until refactor.
builder_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
leewei05 marked this conversation as resolved.
Show resolved Hide resolved
};

} // namespace util

#endif // LLVM_UTIL_HPP_
87 changes: 87 additions & 0 deletions include/llvm_ir_generator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#ifndef LLVM_IR_GENERATOR_HPP_
#define LLVM_IR_GENERATOR_HPP_

#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/Support/raw_os_ostream.h>

#include <memory>
#include <ostream>
#include <string>

#include "ast.hpp"
#include "llvm/util.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 TransUnitNode&) override;
void Visit(const ExternDeclNode&) 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 RecordMemExprNode&) 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, std::string& filename)
Lai-YT marked this conversation as resolved.
Show resolved Hide resolved
: output_{output},
context_{std::make_unique<llvm::LLVMContext>()},
builder_{std::make_unique<llvm::IRBuilder<>>(*context_)},
module_{std::make_unique<llvm::Module>(filename, *context_)},
llvm_util_{util::LLVMIRUtil(builder_)} {}

/// @brief Print LLVM IR to output_.
leewei05 marked this conversation as resolved.
Show resolved Hide resolved
void PrintIR() {
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<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<llvm::IRBuilder<>> builder_;
/// @brief Stores global variables, function lists, and the constructed IR.
std::unique_ptr<llvm::Module> module_;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any specific reason for storing these data members as unique pointers instead of values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I used unique pointers to store them is because these data members must be the same when generating LLVM IR. Or else, the builder will not generate the correct LLVM IR under the correct module_ and context_. Any suggestions?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They seem to be passed by reference when used, meaning they are not going to be copied. Furthermore, I believe these classes are not copyable, thus already unique within the code generator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unique pointers removed!

/// @brief Handy LLVM types and functions for code generation.
util::LLVMIRUtil llvm_util_;
};

#endif // LLVM_IR_GENERATOR_HPP_
16 changes: 16 additions & 0 deletions include/type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,20 @@ 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<std::unique_ptr<Field>>&
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
/// `id` is not a member of the record type.
virtual std::unique_ptr<Type> 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.
Expand All @@ -214,10 +222,14 @@ class StructType : public RecordType {
StructType(std::string id, std::vector<std::unique_ptr<Field>> fields)
: id_{std::move(id)}, fields_{std::move(fields)} {}

const std::vector<std::unique_ptr<Field>>& fields() const noexcept override {
return fields_;
}
std::string id() const noexcept override;
bool IsMember(const std::string& id) const noexcept override;
std::unique_ptr<Type> 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;
Expand All @@ -243,10 +255,14 @@ class UnionType : public RecordType {
UnionType(std::string id, std::vector<std::unique_ptr<Field>> fields)
: id_{std::move(id)}, fields_{std::move(fields)} {}

const std::vector<std::unique_ptr<Field>>& fields() const noexcept override {
return fields_;
}
std::string id() const noexcept override;
bool IsMember(const std::string& id) const noexcept override;
std::unique_ptr<Type> 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;
Expand Down
65 changes: 47 additions & 18 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <utility>

#include "ast.hpp"
#include "ast_dumper.hpp"
#include "llvm_ir_generator.hpp"
#include "qbe_ir_generator.hpp"
#include "scope.hpp"
#include "type_checker.hpp"
Expand All @@ -22,6 +25,12 @@ extern FILE*
extern void yylex_destroy(); // NOLINT(readability-identifier-naming): extern
// from flex generated code.

int QbeBuilder(std::unique_ptr<AstNode> trans_unit, std::string& input_basename,
std::string& output_name);

int LLVMBuilder(std::unique_ptr<AstNode> 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.
int argc, char** argv)
Expand All @@ -36,8 +45,7 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to
cmd_options.add_options()
("o, output", "Write output to <file>", cxxopts::value<std::string>()->default_value("a.out"), "<file>")
("d, dump", "Dump the abstract syntax tree", cxxopts::value<bool>()->default_value("false"))
// TODO: support LLVM IR
("t, target", "Specify target IR", cxxopts::value<std::string>()->default_value("qbe"), "[qbe]")
("t, target", "Specify target IR", cxxopts::value<std::string>()->default_value("qbe"), "[qbe|llvm]")
("h, help", "Display available options")
;
// clang-format on
Expand Down Expand Up @@ -68,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.
leewei05 marked this conversation as resolved.
Show resolved Hide resolved
auto trans_unit = std::unique_ptr<AstNode>{};
yy::parser parser{trans_unit};
int ret = parser.parse();
Expand All @@ -93,31 +101,39 @@ 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<std::string>();
// generate intermediate representation based on target option
if (opts["target"].as<std::string>() == "qbe") {
return QbeBuilder(std::move(trans_unit), input_basename, output);
} else if (opts["target"].as<std::string>() == "llvm") {
return LLVMBuilder(std::move(trans_unit), input_basename, output);
leewei05 marked this conversation as resolved.
Show resolved Hide resolved
} else {
std::cerr << "unknown target" << '\n';
std::exit(0);
}

return 0;
}

int QbeBuilder(std::unique_ptr<AstNode> 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};
trans_unit->Accept(code_generator);

output_ir.close();

// generate assembly
if (opts["target"].as<std::string>() == "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>();
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) {
Expand All @@ -126,3 +142,16 @@ int main( // NOLINT(bugprone-exception-escape): Using a big try-catch block to

return 0;
}

int LLVMBuilder(std::unique_ptr<AstNode> 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};
trans_unit->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;
}
Loading
Loading