A Hugo incarnation of the blog.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

compiler.cpp 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #include "compiler.hpp"
  2. #include "binop.hpp"
  3. #include "error.hpp"
  4. #include "global_scope.hpp"
  5. #include "parse_driver.hpp"
  6. #include "type.hpp"
  7. #include "type_env.hpp"
  8. #include "llvm/IR/LegacyPassManager.h"
  9. #include "llvm/IR/Verifier.h"
  10. #include "llvm/Support/TargetSelect.h"
  11. #include "llvm/Support/TargetRegistry.h"
  12. #include "llvm/Support/raw_ostream.h"
  13. #include "llvm/Support/FileSystem.h"
  14. #include "llvm/Target/TargetOptions.h"
  15. #include "llvm/Target/TargetMachine.h"
  16. void compiler::add_default_types() {
  17. global_env->bind_type("Int", type_ptr(new type_base("Int")));
  18. }
  19. void compiler::add_binop_type(binop op, type_ptr type) {
  20. auto name = mng.new_mangled_name(op_action(op));
  21. global_env->bind(op_name(op), std::move(type), visibility::global);
  22. global_env->set_mangled_name(op_name(op), name);
  23. }
  24. void compiler::add_default_function_types() {
  25. type_ptr int_type = global_env->lookup_type("Int");
  26. assert(int_type != nullptr);
  27. type_ptr int_type_app = type_ptr(new type_app(int_type));
  28. type_ptr closed_int_op_type(
  29. new type_arr(int_type_app, type_ptr(new type_arr(int_type_app, int_type_app))));
  30. constexpr binop closed_ops[] = { PLUS, MINUS, TIMES, DIVIDE };
  31. for(auto& op : closed_ops) add_binop_type(op, closed_int_op_type);
  32. }
  33. void compiler::parse() {
  34. if(!driver())
  35. throw compiler_error("failed to open file");
  36. }
  37. void compiler::typecheck() {
  38. std::set<std::string> free_variables;
  39. global_defs.find_free(free_variables);
  40. global_defs.typecheck(type_m, global_env);
  41. }
  42. void compiler::translate() {
  43. for(auto& data : global_defs.defs_data) {
  44. data.second->into_globals(global_scp);
  45. }
  46. for(auto& defn : global_defs.defs_defn) {
  47. auto& function = defn.second->into_global(global_scp);
  48. defn.second->env->set_mangled_name(defn.first, function.name);
  49. }
  50. }
  51. void compiler::compile() {
  52. global_scp.compile();
  53. }
  54. void compiler::create_llvm_binop(binop op) {
  55. auto new_function =
  56. ctx.create_custom_function(global_env->get_mangled_name(op_name(op)), 2);
  57. std::vector<instruction_ptr> instructions;
  58. instructions.push_back(instruction_ptr(new instruction_push(1)));
  59. instructions.push_back(instruction_ptr(new instruction_eval()));
  60. instructions.push_back(instruction_ptr(new instruction_push(1)));
  61. instructions.push_back(instruction_ptr(new instruction_eval()));
  62. instructions.push_back(instruction_ptr(new instruction_binop(op)));
  63. instructions.push_back(instruction_ptr(new instruction_update(2)));
  64. instructions.push_back(instruction_ptr(new instruction_pop(2)));
  65. ctx.get_builder().SetInsertPoint(&new_function->getEntryBlock());
  66. for(auto& instruction : instructions) {
  67. instruction->gen_llvm(ctx, new_function);
  68. }
  69. ctx.get_builder().CreateRetVoid();
  70. }
  71. void compiler::generate_llvm() {
  72. for(auto op : all_binops) {
  73. create_llvm_binop(op);
  74. }
  75. global_scp.generate_llvm(ctx);
  76. }
  77. void compiler::output_llvm(const std::string& into) {
  78. std::string targetTriple = llvm::sys::getDefaultTargetTriple();
  79. llvm::InitializeNativeTarget();
  80. llvm::InitializeNativeTargetAsmParser();
  81. llvm::InitializeNativeTargetAsmPrinter();
  82. std::string error;
  83. const llvm::Target* target =
  84. llvm::TargetRegistry::lookupTarget(targetTriple, error);
  85. if (!target) {
  86. std::cerr << error << std::endl;
  87. } else {
  88. std::string cpu = "generic";
  89. std::string features = "";
  90. llvm::TargetOptions options;
  91. std::unique_ptr<llvm::TargetMachine> targetMachine(
  92. target->createTargetMachine(targetTriple, cpu, features,
  93. options, llvm::Optional<llvm::Reloc::Model>()));
  94. ctx.get_module().setDataLayout(targetMachine->createDataLayout());
  95. ctx.get_module().setTargetTriple(targetTriple);
  96. std::error_code ec;
  97. llvm::raw_fd_ostream file(into, ec, llvm::sys::fs::F_None);
  98. if (ec) {
  99. throw compiler_error("failed to open object file for writing");
  100. } else {
  101. llvm::CodeGenFileType type = llvm::CGFT_ObjectFile;
  102. llvm::legacy::PassManager pm;
  103. if (targetMachine->addPassesToEmitFile(pm, file, NULL, type)) {
  104. throw compiler_error("failed to add passes to pass manager");
  105. } else {
  106. pm.run(ctx.get_module());
  107. file.close();
  108. }
  109. }
  110. }
  111. }
  112. compiler::compiler(const std::string& filename)
  113. : file_m(), global_defs(), driver(file_m, global_defs, filename),
  114. global_env(new type_env), type_m(), mng(), global_scp(mng), ctx() {
  115. add_default_types();
  116. add_default_function_types();
  117. }
  118. void compiler::operator()(const std::string& into) {
  119. parse();
  120. typecheck();
  121. translate();
  122. compile();
  123. generate_llvm();
  124. output_llvm(into);
  125. }
  126. file_mgr& compiler::get_file_manager() {
  127. return file_m;
  128. }
  129. type_mgr& compiler::get_type_manager() {
  130. return type_m;
  131. }