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