brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.3 KiB · a42e675 Raw
184 lines · cpp
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-exception6//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 now19// ./BrainF -jit -abc prog.bf          #Run program now safely20// ./BrainF           prog.bf          #Write as BitCode21//22// lli prog.bf.bc                      #Run generated BitCode23//24//===----------------------------------------------------------------------===//25 26#include "BrainF.h"27#include "llvm/ADT/APInt.h"28#include "llvm/Bitcode/BitcodeWriter.h"29#include "llvm/ExecutionEngine/ExecutionEngine.h"30#include "llvm/ExecutionEngine/GenericValue.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/CommandLine.h"41#include "llvm/Support/FileSystem.h"42#include "llvm/Support/ManagedStatic.h"43#include "llvm/Support/TargetSelect.h"44#include "llvm/Support/raw_ostream.h"45#include <cstdlib>46#include <fstream>47#include <iostream>48#include <memory>49#include <string>50#include <system_error>51#include <vector>52 53using namespace llvm;54 55//Command line options56 57static cl::opt<std::string>58InputFilename(cl::Positional, cl::desc("<input brainf>"));59 60static cl::opt<std::string>61OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));62 63static cl::opt<bool>64ArrayBoundsChecking("abc", cl::desc("Enable array bounds checking"));65 66static cl::opt<bool>67JIT("jit", cl::desc("Run program Just-In-Time"));68 69//Add main function so can be fully compiled70void addMainFunction(Module *mod) {71  //define i32 @main(i32 %argc, i8 **%argv)72  FunctionType *main_func_fty = FunctionType::get(73      Type::getInt32Ty(mod->getContext()),74      {Type::getInt32Ty(mod->getContext()),75       PointerType::getUnqual(mod->getContext())},76      false);77  Function *main_func =78      Function::Create(main_func_fty, Function::ExternalLinkage, "main", mod);79 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 099  ReturnInst::Create(mod->getContext(),100                     ConstantInt::get(mod->getContext(), APInt(32, 0)), bb);101}102 103int 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 stream115  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::OF_None);127    }128  }129 130  //Get the input stream131  std::istream *in = &std::cin;132  if (InputFilename != "-")133    in = new std::ifstream(InputFilename.c_str());134 135  //Gather the compile flags136  BrainF::CompileFlags cf = BrainF::flag_off;137  if (ArrayBoundsChecking)138    cf = BrainF::CompileFlags(cf | BrainF::flag_arraybounds);139 140  //Read the BrainF program141  BrainF bf;142  std::unique_ptr<Module> Mod(bf.parse(in, 65536, cf, Context)); // 64 KiB143  if (in != &std::cin)144    delete in;145  addMainFunction(Mod.get());146 147  //Verify generated code148  if (verifyModule(*Mod)) {149    errs() << "Error: module failed verification.  This shouldn't happen.\n";150    abort();151  }152 153  //Write it out154  if (JIT) {155    InitializeNativeTarget();156    InitializeNativeTargetAsmPrinter();157 158    outs() << "------- Running JIT -------\n";159    Module &M = *Mod;160    ExecutionEngine *ee = EngineBuilder(std::move(Mod)).create();161    if (!ee) {162      errs() << "Error: execution engine creation failed.\n";163      abort();164    }165    std::vector<GenericValue> args;166    Function *brainf_func = M.getFunction("brainf");167    GenericValue gv = ee->runFunction(brainf_func, args);168    // Genereated code calls putchar, and output is not guaranteed without fflush.169    // The better place for fflush(stdout) call would be the generated code, but it170    // is unmanageable because stdout linkage name depends on stdlib implementation.171    fflush(stdout);172  } else {173    WriteBitcodeToFile(*Mod, *out);174  }175 176  //Clean up177  if (out != &outs())178    delete out;179 180  llvm_shutdown();181 182  return 0;183}184