BrainFDriver.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. //===-- BrainFDriver.cpp - BrainF compiler driver -------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This program converts the BrainF language into LLVM assembly,
  10. // which it can then run using the JIT or output as BitCode.
  11. //
  12. // This implementation has a tape of 65536 bytes,
  13. // with the head starting in the middle.
  14. // Range checking is off by default, so be careful.
  15. // It can be enabled with -abc.
  16. //
  17. // Use:
  18. // ./BrainF -jit prog.bf #Run program now
  19. // ./BrainF -jit -abc prog.bf #Run program now safely
  20. // ./BrainF prog.bf #Write as BitCode
  21. //
  22. // lli prog.bf.bc #Run generated BitCode
  23. //
  24. //===----------------------------------------------------------------------===//
  25. #include "BrainF.h"
  26. #include "llvm/ADT/APInt.h"
  27. #include "llvm/Bitcode/BitcodeWriter.h"
  28. #include "llvm/ExecutionEngine/ExecutionEngine.h"
  29. #include "llvm/ExecutionEngine/GenericValue.h"
  30. #include "llvm/ExecutionEngine/MCJIT.h"
  31. #include "llvm/IR/BasicBlock.h"
  32. #include "llvm/IR/Constants.h"
  33. #include "llvm/IR/DerivedTypes.h"
  34. #include "llvm/IR/Function.h"
  35. #include "llvm/IR/Instructions.h"
  36. #include "llvm/IR/LLVMContext.h"
  37. #include "llvm/IR/Module.h"
  38. #include "llvm/IR/Value.h"
  39. #include "llvm/IR/Verifier.h"
  40. #include "llvm/Support/Casting.h"
  41. #include "llvm/Support/CommandLine.h"
  42. #include "llvm/Support/FileSystem.h"
  43. #include "llvm/Support/ManagedStatic.h"
  44. #include "llvm/Support/TargetSelect.h"
  45. #include "llvm/Support/raw_ostream.h"
  46. #include <algorithm>
  47. #include <cstdlib>
  48. #include <fstream>
  49. #include <iostream>
  50. #include <memory>
  51. #include <string>
  52. #include <system_error>
  53. #include <vector>
  54. using namespace llvm;
  55. //Command line options
  56. static cl::opt<std::string>
  57. InputFilename(cl::Positional, cl::desc("<input brainf>"));
  58. static cl::opt<std::string>
  59. OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
  60. static cl::opt<bool>
  61. ArrayBoundsChecking("abc", cl::desc("Enable array bounds checking"));
  62. static cl::opt<bool>
  63. JIT("jit", cl::desc("Run program Just-In-Time"));
  64. //Add main function so can be fully compiled
  65. void addMainFunction(Module *mod) {
  66. //define i32 @main(i32 %argc, i8 **%argv)
  67. Function *main_func = cast<Function>(mod->
  68. getOrInsertFunction("main", IntegerType::getInt32Ty(mod->getContext()),
  69. IntegerType::getInt32Ty(mod->getContext()),
  70. PointerType::getUnqual(PointerType::getUnqual(
  71. IntegerType::getInt8Ty(mod->getContext())))));
  72. {
  73. Function::arg_iterator args = main_func->arg_begin();
  74. Value *arg_0 = &*args++;
  75. arg_0->setName("argc");
  76. Value *arg_1 = &*args++;
  77. arg_1->setName("argv");
  78. }
  79. //main.0:
  80. BasicBlock *bb = BasicBlock::Create(mod->getContext(), "main.0", main_func);
  81. //call void @brainf()
  82. {
  83. CallInst *brainf_call = CallInst::Create(mod->getFunction("brainf"),
  84. "", bb);
  85. brainf_call->setTailCall(false);
  86. }
  87. //ret i32 0
  88. ReturnInst::Create(mod->getContext(),
  89. ConstantInt::get(mod->getContext(), APInt(32, 0)), bb);
  90. }
  91. int main(int argc, char **argv) {
  92. cl::ParseCommandLineOptions(argc, argv, " BrainF compiler\n");
  93. LLVMContext Context;
  94. if (InputFilename == "") {
  95. errs() << "Error: You must specify the filename of the program to "
  96. "be compiled. Use --help to see the options.\n";
  97. abort();
  98. }
  99. //Get the output stream
  100. raw_ostream *out = &outs();
  101. if (!JIT) {
  102. if (OutputFilename == "") {
  103. std::string base = InputFilename;
  104. if (InputFilename == "-") { base = "a"; }
  105. // Use default filename.
  106. OutputFilename = base+".bc";
  107. }
  108. if (OutputFilename != "-") {
  109. std::error_code EC;
  110. out = new raw_fd_ostream(OutputFilename, EC, sys::fs::F_None);
  111. }
  112. }
  113. //Get the input stream
  114. std::istream *in = &std::cin;
  115. if (InputFilename != "-")
  116. in = new std::ifstream(InputFilename.c_str());
  117. //Gather the compile flags
  118. BrainF::CompileFlags cf = BrainF::flag_off;
  119. if (ArrayBoundsChecking)
  120. cf = BrainF::CompileFlags(cf | BrainF::flag_arraybounds);
  121. //Read the BrainF program
  122. BrainF bf;
  123. std::unique_ptr<Module> Mod(bf.parse(in, 65536, cf, Context)); // 64 KiB
  124. if (in != &std::cin)
  125. delete in;
  126. addMainFunction(Mod.get());
  127. //Verify generated code
  128. if (verifyModule(*Mod)) {
  129. errs() << "Error: module failed verification. This shouldn't happen.\n";
  130. abort();
  131. }
  132. //Write it out
  133. if (JIT) {
  134. InitializeNativeTarget();
  135. InitializeNativeTargetAsmPrinter();
  136. outs() << "------- Running JIT -------\n";
  137. Module &M = *Mod;
  138. ExecutionEngine *ee = EngineBuilder(std::move(Mod)).create();
  139. if (!ee) {
  140. errs() << "Error: execution engine creation failed.\n";
  141. abort();
  142. }
  143. std::vector<GenericValue> args;
  144. Function *brainf_func = M.getFunction("brainf");
  145. GenericValue gv = ee->runFunction(brainf_func, args);
  146. // Genereated code calls putchar, and output is not guaranteed without fflush.
  147. // The better place for fflush(stdout) call would be the generated code, but it
  148. // is unmanageable because stdout linkage name depends on stdlib implementation.
  149. fflush(stdout);
  150. } else {
  151. WriteBitcodeToFile(*Mod, *out);
  152. }
  153. //Clean up
  154. if (out != &outs())
  155. delete out;
  156. llvm_shutdown();
  157. return 0;
  158. }