1 //===-- BrainFDriver.cpp - BrainF compiler driver -----------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===--------------------------------------------------------------------===//
10 // This program converts the BrainF language into LLVM assembly,
11 // which it can then run using the JIT or output as BitCode.
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.
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
23 // lli prog.bf.bc #Run generated BitCode
24 // llvm-ld -native -o=prog prog.bf.bc #Compile BitCode into native executable
26 //===--------------------------------------------------------------------===//
29 #include "llvm/Constants.h"
30 #include "llvm/ModuleProvider.h"
31 #include "llvm/Analysis/Verifier.h"
32 #include "llvm/Bitcode/ReaderWriter.h"
33 #include "llvm/ExecutionEngine/GenericValue.h"
34 #include "llvm/ExecutionEngine/JIT.h"
35 #include "llvm/Target/TargetSelect.h"
36 #include "llvm/Support/CommandLine.h"
37 #include "llvm/Support/ManagedStatic.h"
38 #include "llvm/Support/raw_ostream.h"
43 //Command line options
45 static cl::opt
<std::string
>
46 InputFilename(cl::Positional
, cl::desc("<input brainf>"));
48 static cl::opt
<std::string
>
49 OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
52 ArrayBoundsChecking("abc", cl::desc("Enable array bounds checking"));
55 JIT("jit", cl::desc("Run program Just-In-Time"));
58 //Add main function so can be fully compiled
59 void addMainFunction(Module
*mod
) {
60 //define i32 @main(i32 %argc, i8 **%argv)
61 Function
*main_func
= cast
<Function
>(mod
->
62 getOrInsertFunction("main", IntegerType::getInt32Ty(mod
->getContext()),
63 IntegerType::getInt32Ty(mod
->getContext()),
64 PointerType::getUnqual(PointerType::getUnqual(
65 IntegerType::getInt8Ty(mod
->getContext()))), NULL
));
67 Function::arg_iterator args
= main_func
->arg_begin();
68 Value
*arg_0
= args
++;
69 arg_0
->setName("argc");
70 Value
*arg_1
= args
++;
71 arg_1
->setName("argv");
75 BasicBlock
*bb
= BasicBlock::Create(mod
->getContext(), "main.0", main_func
);
79 CallInst
*brainf_call
= CallInst::Create(mod
->getFunction("brainf"),
81 brainf_call
->setTailCall(false);
85 ReturnInst::Create(mod
->getContext(),
86 ConstantInt::get(mod
->getContext(), APInt(32, 0)), bb
);
89 int main(int argc
, char **argv
) {
90 cl::ParseCommandLineOptions(argc
, argv
, " BrainF compiler\n");
92 LLVMContext
&Context
= getGlobalContext();
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";
100 //Get the output stream
101 raw_ostream
*out
= &outs();
103 if (OutputFilename
== "") {
104 std::string base
= InputFilename
;
105 if (InputFilename
== "-") { base
= "a"; }
107 // Use default filename.
108 OutputFilename
= base
+".bc";
110 if (OutputFilename
!= "-") {
112 out
= new raw_fd_ostream(OutputFilename
.c_str(), ErrInfo
,
113 raw_fd_ostream::F_Binary
);
117 //Get the input stream
118 std::istream
*in
= &std::cin
;
119 if (InputFilename
!= "-")
120 in
= new std::ifstream(InputFilename
.c_str());
122 //Gather the compile flags
123 BrainF::CompileFlags cf
= BrainF::flag_off
;
124 if (ArrayBoundsChecking
)
125 cf
= BrainF::CompileFlags(cf
| BrainF::flag_arraybounds
);
127 //Read the BrainF program
129 Module
*mod
= bf
.parse(in
, 65536, cf
, Context
); //64 KiB
132 addMainFunction(mod
);
134 //Verify generated code
135 if (verifyModule(*mod
)) {
136 errs() << "Error: module failed verification. This shouldn't happen.\n";
142 InitializeNativeTarget();
144 outs() << "------- Running JIT -------\n";
145 ExecutionEngine
*ee
= EngineBuilder(mod
).create();
146 std::vector
<GenericValue
> args
;
147 Function
*brainf_func
= mod
->getFunction("brainf");
148 GenericValue gv
= ee
->runFunction(brainf_func
, args
);
150 WriteBitcodeToFile(mod
, *out
);