Home | History | Annotate | Download | only in BrainF
      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/ReaderWriter.h"
     30 #include "llvm/ExecutionEngine/ExecutionEngine.h"
     31 #include "llvm/ExecutionEngine/GenericValue.h"
     32 #include "llvm/IR/BasicBlock.h"
     33 #include "llvm/IR/Constants.h"
     34 #include "llvm/IR/DerivedTypes.h"
     35 #include "llvm/IR/Function.h"
     36 #include "llvm/IR/Instructions.h"
     37 #include "llvm/IR/LLVMContext.h"
     38 #include "llvm/IR/Module.h"
     39 #include "llvm/IR/Value.h"
     40 #include "llvm/IR/Verifier.h"
     41 #include "llvm/Support/Casting.h"
     42 #include "llvm/Support/CommandLine.h"
     43 #include "llvm/Support/FileSystem.h"
     44 #include "llvm/Support/ManagedStatic.h"
     45 #include "llvm/Support/TargetSelect.h"
     46 #include "llvm/Support/raw_ostream.h"
     47 #include <algorithm>
     48 #include <cstdlib>
     49 #include <fstream>
     50 #include <iostream>
     51 #include <memory>
     52 #include <string>
     53 #include <system_error>
     54 #include <vector>
     55 
     56 using namespace llvm;
     57 
     58 //Command line options
     59 
     60 static cl::opt<std::string>
     61 InputFilename(cl::Positional, cl::desc("<input brainf>"));
     62 
     63 static cl::opt<std::string>
     64 OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
     65 
     66 static cl::opt<bool>
     67 ArrayBoundsChecking("abc", cl::desc("Enable array bounds checking"));
     68 
     69 static cl::opt<bool>
     70 JIT("jit", cl::desc("Run program Just-In-Time"));
     71 
     72 //Add main function so can be fully compiled
     73 void addMainFunction(Module *mod) {
     74   //define i32 @main(i32 %argc, i8 **%argv)
     75   Function *main_func = cast<Function>(mod->
     76     getOrInsertFunction("main", IntegerType::getInt32Ty(mod->getContext()),
     77                         IntegerType::getInt32Ty(mod->getContext()),
     78                         PointerType::getUnqual(PointerType::getUnqual(
     79                           IntegerType::getInt8Ty(mod->getContext()))), NULL));
     80   {
     81     Function::arg_iterator args = main_func->arg_begin();
     82     Value *arg_0 = &*args++;
     83     arg_0->setName("argc");
     84     Value *arg_1 = &*args++;
     85     arg_1->setName("argv");
     86   }
     87 
     88   //main.0:
     89   BasicBlock *bb = BasicBlock::Create(mod->getContext(), "main.0", main_func);
     90 
     91   //call void @brainf()
     92   {
     93     CallInst *brainf_call = CallInst::Create(mod->getFunction("brainf"),
     94                                              "", bb);
     95     brainf_call->setTailCall(false);
     96   }
     97 
     98   //ret i32 0
     99   ReturnInst::Create(mod->getContext(),
    100                      ConstantInt::get(mod->getContext(), APInt(32, 0)), bb);
    101 }
    102 
    103 int main(int argc, char **argv) {
    104   cl::ParseCommandLineOptions(argc, argv, " BrainF compiler\n");
    105 
    106   LLVMContext Context;
    107 
    108   if (InputFilename == "") {
    109     errs() << "Error: You must specify the filename of the program to "
    110     "be compiled.  Use --help to see the options.\n";
    111     abort();
    112   }
    113 
    114   //Get the output stream
    115   raw_ostream *out = &outs();
    116   if (!JIT) {
    117     if (OutputFilename == "") {
    118       std::string base = InputFilename;
    119       if (InputFilename == "-") { base = "a"; }
    120 
    121       // Use default filename.
    122       OutputFilename = base+".bc";
    123     }
    124     if (OutputFilename != "-") {
    125       std::error_code EC;
    126       out = new raw_fd_ostream(OutputFilename, EC, sys::fs::F_None);
    127     }
    128   }
    129 
    130   //Get the input stream
    131   std::istream *in = &std::cin;
    132   if (InputFilename != "-")
    133     in = new std::ifstream(InputFilename.c_str());
    134 
    135   //Gather the compile flags
    136   BrainF::CompileFlags cf = BrainF::flag_off;
    137   if (ArrayBoundsChecking)
    138     cf = BrainF::CompileFlags(cf | BrainF::flag_arraybounds);
    139 
    140   //Read the BrainF program
    141   BrainF bf;
    142   std::unique_ptr<Module> Mod(bf.parse(in, 65536, cf, Context)); // 64 KiB
    143   if (in != &std::cin)
    144     delete in;
    145   addMainFunction(Mod.get());
    146 
    147   //Verify generated code
    148   if (verifyModule(*Mod)) {
    149     errs() << "Error: module failed verification.  This shouldn't happen.\n";
    150     abort();
    151   }
    152 
    153   //Write it out
    154   if (JIT) {
    155     InitializeNativeTarget();
    156 
    157     outs() << "------- Running JIT -------\n";
    158     Module &M = *Mod;
    159     ExecutionEngine *ee = EngineBuilder(std::move(Mod)).create();
    160     std::vector<GenericValue> args;
    161     Function *brainf_func = M.getFunction("brainf");
    162     GenericValue gv = ee->runFunction(brainf_func, args);
    163   } else {
    164     WriteBitcodeToFile(Mod.get(), *out);
    165   }
    166 
    167   //Clean up
    168   if (out != &outs())
    169     delete out;
    170 
    171   llvm_shutdown();
    172 
    173   return 0;
    174 }
    175