Skip to content

Commit

Permalink
[cpp] codegen intro. now ready for actual codegen logic
Browse files Browse the repository at this point in the history
  • Loading branch information
harrand committed May 17, 2024
1 parent e31bd01 commit db23eca
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 5 deletions.
85 changes: 83 additions & 2 deletions cpp/src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,93 @@ namespace code
diag::error(error_code::nyi, "writing to object file is not yet implemented. i was told to write to \"{}\"", object_filename);
}

output generate(const semal::output& input, std::string module_name)
// global state:
static std::unique_ptr<llvm::LLVMContext> ctx = nullptr;
static std::unique_ptr<llvm::Module> program = nullptr;
static std::unique_ptr<llvm::IRBuilder<>> builder = nullptr;
// global variables are RAII objects meaning we will have to deal with their lifetimes. to do that, we're just chucking them in there, and spreading the underlying ptr all around the place (as we're allocing we have pointer stability so its safe).
static std::vector<std::unique_ptr<llvm::GlobalVariable>> global_variable_storage = {};

void static_initialise()
{
ctx = std::make_unique<llvm::LLVMContext>();
}

void static_terminate()
{
diag::assert_that(program == nullptr, error_code::ice, "an LLVM Module was not destroyed prior to static terminate");
ctx = nullptr;
}

void cleanup()
{
// note: tearing down all this state is actually ridiculously error prone.
// cant unlink globals until the program stops referencing them.
// globals must all be destroyed before program itself dies.
// so:
// 1.) program stops referencing everything
if(program != nullptr)
{
program->dropAllReferences();
}
// 2.) unlink globals from parent (but doesnt erase them)
for(auto& glob_ptr : global_variable_storage)
{
glob_ptr->removeFromParent();
}
// 3.) kill globals and then program etc...

global_variable_storage.clear();
builder = nullptr;
program = nullptr;
}

struct data
{
return
const ast& tree;
const ast::node& node;
const ast::path_t& path;
const semal::output& semantic;

void error(std::string msg) const
{
diag::error(error_code::codegen, "at: {}: {}", node.meta.to_string(), msg);
}

void internal_error(std::string msg) const
{
diag::error(error_code::ice, "at: {}: {}", node.meta.to_string(), msg);
}

void warning(std::string msg) const
{
diag::warning("at: {}: {}", node.meta.to_string(), msg);
}

void assert_that(bool expr, std::string msg) const
{
if(!expr)
{
this->error(msg);
}
}
};

output generate(const ast& tree, const semal::output& input, std::string module_name)
{
diag::assert_that(program == nullptr && builder == nullptr, error_code::ice, "previous codegen state has not been erased and you want me to move onto codegening another file...");
output ret
{
.codegen_handle = nullptr,
.module_name = module_name
};
program = std::make_unique<llvm::Module>(module_name, *ctx);
builder = std::make_unique<llvm::IRBuilder<>>(*ctx);

// todo: codegen logic goes here.

llvm::verifyModule(*program);
ret.codegen_handle = program.get();
return ret;
}
}
8 changes: 7 additions & 1 deletion cpp/src/codegen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ namespace code
void write_to_object_file(std::filesystem::path output_dir);
};

output generate(const semal::output& input, std::string module_name = "<unnamed_module>");
// initialise and terminate *once*, at the beginning and end of the compiler program respectively.
void static_initialise();
void static_terminate();

void cleanup();
// perform code generation. `codegen_handle` member of the returned output remains valid until you invoke `code::cleanup()`. ideally, you generate, then dump-ir/write-object, cleanup and then codegen another file.
output generate(const ast& tree, const semal::output& input, std::string module_name = "<unnamed_module>");

struct state
{
Expand Down
4 changes: 3 additions & 1 deletion cpp/src/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum class error_code
parse,
type,
semal,
codegen,
_count
};

Expand All @@ -22,7 +23,8 @@ constexpr std::array<const char*, (int)error_code::_count> error_names
"lex",
"parse",
"type",
"semantic analysis"
"semantic analysis",
"code generation"
};

#endif // PSYC_ERROR_HPP
8 changes: 7 additions & 1 deletion cpp/src/psyc_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ int main(int argc, char** argv)
config::compiler_args args = parse_args(cli_args);
timers t;

code::static_initialise();

// lex
timer::start();
lex::state lex;
Expand Down Expand Up @@ -93,12 +95,14 @@ int main(int argc, char** argv)
code::state codegen;
for(const auto& [input_file, semantic_output] : semal.analysed_input_files)
{
codegen.codegend_input_files[input_file] = code::generate(semantic_output, input_file.stem().string());
codegen.codegend_input_files[input_file] = code::generate(parse.parsed_input_files[input_file], semantic_output, input_file.stem().string());
if(args.should_dump_ir)
{
std::cout << "==========================\n";
std::cout << "ir for " << input_file << ":\n";
std::cout << codegen.codegend_input_files[input_file].dump_ir();
code::cleanup();
codegen.codegend_input_files[input_file].codegen_handle = nullptr;
std::cout << "\n==========================\n\n";
}
}
Expand All @@ -107,6 +111,8 @@ int main(int argc, char** argv)
// link

t.print();

code::static_terminate();
return 0;
}

Expand Down

0 comments on commit db23eca

Please sign in to comment.