llvm.org GIT mirror llvm / bef8e0b
add a new BF->LLVM translator, contributed by Sterling Stein. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41881 91177308-0d34-0410-b5e6-96231b3b80d8 Chris Lattner 11 years ago
5 changed file(s) with 721 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
0 //===-- BrainF.cpp - BrainF compiler example ----------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file was developed by Sterling Stein and is distributed under the
5 // University of Illinois Open Source License. See LICENSE.TXT for details.
6 //
7 //===--------------------------------------------------------------------===//
8 //
9 // This class compiles the BrainF language into LLVM assembly.
10 //
11 // The BrainF language has 8 commands:
12 // Command Equivalent C Action
13 // ------- ------------ ------
14 // , *h=getchar(); Read a character from stdin, 255 on EOF
15 // . putchar(*h); Write a character to stdout
16 // - --*h; Decrement tape
17 // + ++*h; Increment tape
18 // < --h; Move head left
19 // > ++h; Move head right
20 // [ while(*h) { Start loop
21 // ] } End loop
22 //
23 //===--------------------------------------------------------------------===//
24
25 #include "BrainF.h"
26 #include "llvm/Constants.h"
27 #include "llvm/ADT/STLExtras.h"
28
29 using namespace llvm;
30
31 //Set the constants for naming
32 const char *BrainF::tapereg = "tape";
33 const char *BrainF::headreg = "head";
34 const char *BrainF::label = "brainf";
35 const char *BrainF::testreg = "test";
36
37 Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf) {
38 in = in1;
39 memtotal = mem;
40 comflag = cf;
41
42 header();
43 readloop(0, 0, 0);
44 delete builder;
45 return module;
46 }
47
48 void BrainF::header() {
49 module = new Module("BrainF");
50
51 //Function prototypes
52
53 //declare void @llvm.memset.i32(i8 *, i8, i32, i32)
54 Function *memset_func = cast(module->
55 getOrInsertFunction("llvm.memset.i32", Type::VoidTy,
56 PointerType::get(IntegerType::Int8Ty),
57 IntegerType::Int8Ty, IntegerType::Int32Ty,
58 IntegerType::Int32Ty, NULL));
59
60 //declare i32 @getchar()
61 getchar_func = cast(module->
62 getOrInsertFunction("getchar", IntegerType::Int32Ty, NULL));
63
64 //declare i32 @putchar(i32)
65 putchar_func = cast(module->
66 getOrInsertFunction("putchar", IntegerType::Int32Ty,
67 IntegerType::Int32Ty, NULL));
68
69
70 //Function header
71
72 //define void @brainf()
73 brainf_func = cast(module->
74 getOrInsertFunction("brainf", Type::VoidTy, NULL));
75
76 builder = new LLVMBuilder(new BasicBlock(label, brainf_func));
77
78 //%arr = malloc i8, i32 %d
79 ConstantInt *val_mem = ConstantInt::get(APInt(32, memtotal));
80 ptr_arr = builder->CreateMalloc(IntegerType::Int8Ty, val_mem, "arr");
81
82 //call void @llvm.memset.i32(i8 *%arr, i8 0, i32 %d, i32 1)
83 {
84 Value *memset_params[] = {
85 ptr_arr,
86 ConstantInt::get(APInt(8, 0)),
87 val_mem,
88 ConstantInt::get(APInt(32, 1))
89 };
90
91 CallInst *memset_call = builder->
92 CreateCall(memset_func, memset_params, array_endof(memset_params));
93 memset_call->setTailCall(false);
94 }
95
96 //%arrmax = getelementptr i8 *%arr, i32 %d
97 if (comflag & flag_arraybounds) {
98 ptr_arrmax = builder->
99 CreateGEP(ptr_arr, ConstantInt::get(APInt(32, memtotal)), "arrmax");
100 }
101
102 //%head.%d = getelementptr i8 *%arr, i32 %d
103 curhead = builder->CreateGEP(ptr_arr,
104 ConstantInt::get(APInt(32, memtotal/2)),
105 headreg);
106
107
108
109 //Function footer
110
111 //brainf.end:
112 endbb = new BasicBlock(label, brainf_func);
113
114 //free i8 *%arr
115 new FreeInst(ptr_arr, endbb);
116
117 //ret void
118 new ReturnInst(endbb);
119
120
121
122 //Error block for array out of bounds
123 if (comflag & flag_arraybounds)
124 {
125 //@aberrormsg = internal constant [%d x i8] c"\00"
126 Constant *msg_0 = ConstantArray::
127 get("Error: The head has left the tape.", true);
128
129 GlobalVariable *aberrormsg = new GlobalVariable(
130 msg_0->getType(),
131 true,
132 GlobalValue::InternalLinkage,
133 msg_0,
134 "aberrormsg",
135 module);
136
137 //declare i32 @puts(i8 *)
138 Function *puts_func = cast(module->
139 getOrInsertFunction("puts", IntegerType::Int32Ty,
140 PointerType::get(IntegerType::Int8Ty), NULL));
141
142 //brainf.aberror:
143 aberrorbb = new BasicBlock(label, brainf_func);
144
145 //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
146 {
147 Constant *zero_32 = Constant::getNullValue(IntegerType::Int32Ty);
148
149 Constant *gep_params[] = {
150 zero_32,
151 zero_32
152 };
153
154 Constant *msgptr = ConstantExpr::
155 getGetElementPtr(aberrormsg, gep_params,
156 array_lengthof(gep_params));
157
158 Value *puts_params[] = {
159 msgptr
160 };
161
162 CallInst *puts_call =
163 new CallInst(puts_func,
164 puts_params, array_endof(puts_params),
165 "", aberrorbb);
166 puts_call->setTailCall(false);
167 }
168
169 //br label %brainf.end
170 new BranchInst(endbb, aberrorbb);
171 }
172 }
173
174 void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb) {
175 Symbol cursym = SYM_NONE;
176 int curvalue = 0;
177 Symbol nextsym = SYM_NONE;
178 int nextvalue = 0;
179 char c;
180 int loop;
181 int direction;
182
183 while(cursym != SYM_EOF && cursym != SYM_ENDLOOP) {
184 // Write out commands
185 switch(cursym) {
186 case SYM_NONE:
187 // Do nothing
188 break;
189
190 case SYM_READ:
191 {
192 //%tape.%d = call i32 @getchar()
193 CallInst *getchar_call = builder->CreateCall(getchar_func, tapereg);
194 getchar_call->setTailCall(false);
195 Value *tape_0 = getchar_call;
196
197 //%tape.%d = trunc i32 %tape.%d to i8
198 TruncInst *tape_1 = builder->
199 CreateTrunc(tape_0, IntegerType::Int8Ty, tapereg);
200
201 //store i8 %tape.%d, i8 *%head.%d
202 builder->CreateStore(tape_1, curhead);
203 }
204 break;
205
206 case SYM_WRITE:
207 {
208 //%tape.%d = load i8 *%head.%d
209 LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);
210
211 //%tape.%d = sext i8 %tape.%d to i32
212 SExtInst *tape_1 = builder->
213 CreateSExt(tape_0, IntegerType::Int32Ty, tapereg);
214
215 //call i32 @putchar(i32 %tape.%d)
216 Value *putchar_params[] = {
217 tape_1
218 };
219 CallInst *putchar_call = builder->
220 CreateCall(putchar_func,
221 putchar_params, array_endof(putchar_params));
222 putchar_call->setTailCall(false);
223 }
224 break;
225
226 case SYM_MOVE:
227 {
228 //%head.%d = getelementptr i8 *%head.%d, i32 %d
229 curhead = builder->
230 CreateGEP(curhead, ConstantInt::get(APInt(32, curvalue)),
231 headreg);
232
233 //Error block for array out of bounds
234 if (comflag & flag_arraybounds)
235 {
236 //%test.%d = icmp uge i8 *%head.%d, %arrmax
237 ICmpInst *test_0 = builder->
238 CreateICmpUGE(curhead, ptr_arrmax, testreg);
239
240 //%test.%d = icmp ult i8 *%head.%d, %arr
241 ICmpInst *test_1 = builder->
242 CreateICmpULT(curhead, ptr_arr, testreg);
243
244 //%test.%d = or i1 %test.%d, %test.%d
245 BinaryOperator *test_2 = builder->
246 CreateOr(test_0, test_1, testreg);
247
248 //br i1 %test.%d, label %main.%d, label %main.%d
249 BasicBlock *nextbb = new BasicBlock(label, brainf_func);
250 builder->CreateCondBr(test_2, aberrorbb, nextbb);
251
252 //main.%d:
253 builder->SetInsertPoint(nextbb);
254 }
255 }
256 break;
257
258 case SYM_CHANGE:
259 {
260 //%tape.%d = load i8 *%head.%d
261 LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);
262
263 //%tape.%d = add i8 %tape.%d, %d
264 BinaryOperator *tape_1 = builder->
265 CreateAdd(tape_0, ConstantInt::get(APInt(8, curvalue)), tapereg);
266
267 //store i8 %tape.%d, i8 *%head.%d\n"
268 builder->CreateStore(tape_1, curhead);
269 }
270 break;
271
272 case SYM_LOOP:
273 {
274 //br label %main.%d
275 BasicBlock *testbb = new BasicBlock(label, brainf_func);
276 builder->CreateBr(testbb);
277
278 //main.%d:
279 BasicBlock *bb_0 = builder->GetInsertBlock();
280 BasicBlock *bb_1 = new BasicBlock(label, brainf_func);
281 builder->SetInsertPoint(bb_1);
282
283 //Make part of PHI instruction now, wait until end of loop to finish
284 PHINode *phi_0 = new PHINode(PointerType::get(IntegerType::Int8Ty),
285 headreg, testbb);
286 phi_0->reserveOperandSpace(2);
287 phi_0->addIncoming(curhead, bb_0);
288 curhead = phi_0;
289
290 readloop(phi_0, bb_1, testbb);
291 }
292 break;
293
294 default:
295 cerr<<"Error: Unknown symbol.\n";
296 abort();
297 break;
298 }
299
300 cursym = nextsym;
301 curvalue = nextvalue;
302 nextsym = SYM_NONE;
303
304 // Reading stdin loop
305 loop = (cursym == SYM_NONE)
306 || (cursym == SYM_MOVE)
307 || (cursym == SYM_CHANGE);
308 while(loop) {
309 *in>>c;
310 if (in->eof()) {
311 if (cursym == SYM_NONE) {
312 cursym = SYM_EOF;
313 } else {
314 nextsym = SYM_EOF;
315 }
316 loop = 0;
317 } else {
318 direction = 1;
319 switch(c) {
320 case '-':
321 direction = -1;
322 // Fall through
323
324 case '+':
325 if (cursym == SYM_CHANGE) {
326 curvalue += direction;
327 // loop = 1
328 } else {
329 if (cursym == SYM_NONE) {
330 cursym = SYM_CHANGE;
331 curvalue = direction;
332 // loop = 1
333 } else {
334 nextsym = SYM_CHANGE;
335 nextvalue = direction;
336 loop = 0;
337 }
338 }
339 break;
340
341 case '<':
342 direction = -1;
343 // Fall through
344
345 case '>':
346 if (cursym == SYM_MOVE) {
347 curvalue += direction;
348 // loop = 1
349 } else {
350 if (cursym == SYM_NONE) {
351 cursym = SYM_MOVE;
352 curvalue = direction;
353 // loop = 1
354 } else {
355 nextsym = SYM_MOVE;
356 nextvalue = direction;
357 loop = 0;
358 }
359 }
360 break;
361
362 case ',':
363 if (cursym == SYM_NONE) {
364 cursym = SYM_READ;
365 } else {
366 nextsym = SYM_READ;
367 }
368 loop = 0;
369 break;
370
371 case '.':
372 if (cursym == SYM_NONE) {
373 cursym = SYM_WRITE;
374 } else {
375 nextsym = SYM_WRITE;
376 }
377 loop = 0;
378 break;
379
380 case '[':
381 if (cursym == SYM_NONE) {
382 cursym = SYM_LOOP;
383 } else {
384 nextsym = SYM_LOOP;
385 }
386 loop = 0;
387 break;
388
389 case ']':
390 if (cursym == SYM_NONE) {
391 cursym = SYM_ENDLOOP;
392 } else {
393 nextsym = SYM_ENDLOOP;
394 }
395 loop = 0;
396 break;
397
398 // Ignore other characters
399 default:
400 break;
401 }
402 }
403 }
404 }
405
406 if (cursym == SYM_ENDLOOP) {
407 if (!phi) {
408 cerr<<"Error: Extra ']'\n";
409 abort();
410 }
411
412 // Write loop test
413 {
414 //br label %main.%d
415 builder->CreateBr(testbb);
416
417 //main.%d:
418
419 //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
420 //Finish phi made at beginning of loop
421 phi->addIncoming(curhead, builder->GetInsertBlock());
422 Value *head_0 = phi;
423
424 //%tape.%d = load i8 *%head.%d
425 LoadInst *tape_0 = new LoadInst(head_0, tapereg, testbb);
426
427 //%test.%d = icmp eq i8 %tape.%d, 0
428 ICmpInst *test_0 = new ICmpInst(ICmpInst::ICMP_EQ, tape_0,
429 ConstantInt::get(APInt(8, 0)), testreg,
430 testbb);
431
432 //br i1 %test.%d, label %main.%d, label %main.%d
433 BasicBlock *bb_0 = new BasicBlock(label, brainf_func);
434 new BranchInst(bb_0, oldbb, test_0, testbb);
435
436 //main.%d:
437 builder->SetInsertPoint(bb_0);
438
439 //%head.%d = phi i8 *[%head.%d, %main.%d]
440 PHINode *phi_1 = builder->
441 CreatePHI(PointerType::get(IntegerType::Int8Ty), headreg);
442 phi_1->reserveOperandSpace(1);
443 phi_1->addIncoming(head_0, testbb);
444 curhead = phi_1;
445 }
446
447 return;
448 }
449
450 //End of the program, so go to return block
451 builder->CreateBr(endbb);
452
453 if (phi) {
454 cerr<<"Error: Missing ']'\n";
455 abort();
456 }
457 }
0 //===-- BrainF.h - BrainF compiler class ----------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file was developed by Sterling Stein and is distributed under the
5 // University of Illinois Open Source License. See LICENSE.TXT for details.
6 //
7 //===--------------------------------------------------------------------===//
8 //
9 // This class stores the data for the BrainF compiler so it doesn't have
10 // to pass all of it around. The main method is parse.
11 //
12 //===--------------------------------------------------------------------===//
13
14 #ifndef BRAINF_H
15 #define BRAINF_H
16
17 #include "llvm/Module.h"
18 #include "llvm/Support/LLVMBuilder.h"
19
20 using namespace llvm;
21
22 /// This class provides a parser for the BrainF language.
23 /// The class itself is made to store values during
24 /// parsing so they don't have to be passed around
25 /// as much.
26 class BrainF {
27 public:
28 /// Options for how BrainF should compile
29 enum CompileFlags {
30 flag_off = 0,
31 flag_arraybounds = 1
32 };
33
34 /// This is the main method. It parses BrainF from in1
35 /// and returns the module with a function
36 /// void brainf()
37 /// containing the resulting code.
38 /// On error, it calls abort.
39 /// The caller must delete the returned module.
40 Module *parse(std::istream *in1, int mem, CompileFlags cf);
41
42 protected:
43 /// The different symbols in the BrainF language
44 enum Symbol {
45 SYM_NONE,
46 SYM_READ,
47 SYM_WRITE,
48 SYM_MOVE,
49 SYM_CHANGE,
50 SYM_LOOP,
51 SYM_ENDLOOP,
52 SYM_EOF
53 };
54
55 /// Names of the different parts of the language.
56 /// Tape is used for reading and writing the tape.
57 /// headreg is used for the position of the head.
58 /// label is used for the labels for the BasicBlocks.
59 /// testreg is used for testing the loop exit condition.
60 static const char *tapereg;
61 static const char *headreg;
62 static const char *label;
63 static const char *testreg;
64
65 /// Put the brainf function preamble and other fixed pieces of code
66 void header();
67
68 /// The main loop for parsing. It calls itself recursively
69 /// to handle the depth of nesting of "[]".
70 void readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb);
71
72 /// Constants during parsing
73 int memtotal;
74 CompileFlags comflag;
75 std::istream *in;
76 Module *module;
77 Function *brainf_func;
78 Function *getchar_func;
79 Function *putchar_func;
80 Value *ptr_arr;
81 Value *ptr_arrmax;
82 BasicBlock *endbb;
83 BasicBlock *aberrorbb;
84
85 /// Variables
86 LLVMBuilder *builder;
87 Value *curhead;
88 };
89
90 #endif
0 //===-- BrainFDriver.cpp - BrainF compiler driver -----------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file was developed by Sterling Stein and is distributed under the
5 // University of Illinois Open Source License. See LICENSE.TXT for details.
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 // llvm-ld -native -o=prog prog.bf.bc #Compile BitCode into native executable
24 //
25 //===--------------------------------------------------------------------===//
26
27 #include "BrainF.h"
28 #include "llvm/Constants.h"
29 #include "llvm/ModuleProvider.h"
30 #include "llvm/Analysis/Verifier.h"
31 #include "llvm/Bitcode/ReaderWriter.h"
32 #include "llvm/ExecutionEngine/GenericValue.h"
33 #include "llvm/ExecutionEngine/JIT.h"
34 #include "llvm/Support/CommandLine.h"
35 #include "llvm/Support/ManagedStatic.h"
36 #include
37 #include
38
39 using namespace llvm;
40
41 //Command line options
42
43 static cl::opt
44 InputFilename(cl::Positional, cl::desc(""));
45
46 static cl::opt
47 OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
48
49 static cl::opt
50 ArrayBoundsChecking("abc", cl::desc("Enable array bounds checking"));
51
52 static cl::opt
53 JIT("jit", cl::desc("Run program Just-In-Time"));
54
55
56 //Add main function so can be fully compiled
57 void addMainFunction(Module *mod) {
58 //define i32 @main(i32 %argc, i8 **%argv)
59 Function *main_func = cast(mod->
60 getOrInsertFunction("main", IntegerType::Int32Ty, IntegerType::Int32Ty,
61 PointerType::get(PointerType::get(
62 IntegerType::Int8Ty)), NULL));
63 {
64 Function::arg_iterator args = main_func->arg_begin();
65 Value *arg_0 = args++;
66 arg_0->setName("argc");
67 Value *arg_1 = args++;
68 arg_1->setName("argv");
69 }
70
71 //main.0:
72 BasicBlock *bb = new BasicBlock("main.0", main_func);
73
74 //call void @brainf()
75 {
76 CallInst *brainf_call = new CallInst(mod->getFunction("brainf"),
77 "", bb);
78 brainf_call->setTailCall(false);
79 }
80
81 //ret i32 0
82 new ReturnInst(ConstantInt::get(APInt(32, 0)), bb);
83 }
84
85 int main(int argc, char **argv) {
86 cl::ParseCommandLineOptions(argc, argv, " BrainF compiler\n");
87
88 if (InputFilename == "") {
89 cerr<<"Error: You must specify the filename of the program to "
90 "be compiled. Use --help to see the options.\n";
91 abort();
92 }
93
94 //Get the output stream
95 std::ostream *out = &std::cout;
96 if (!JIT) {
97 if (OutputFilename == "") {
98 std::string base = InputFilename;
99 if (InputFilename == "-") {base = "a";}
100
101 //Use default filename
102 const char *suffix = ".bc";
103 OutputFilename = base+suffix;
104 }
105 if (OutputFilename != "-") {
106 out = new std::
107 ofstream(OutputFilename.c_str(),
108 std::ios::out | std::ios::trunc | std::ios::binary);
109 }
110 }
111
112 //Get the input stream
113 std::istream *in = &std::cin;
114 if (InputFilename != "-") {
115 in = new std::ifstream(InputFilename.c_str());
116 }
117
118 //Gather the compile flags
119 BrainF::CompileFlags cf = BrainF::flag_off;
120 if (ArrayBoundsChecking) {
121 cf = BrainF::CompileFlags(cf | BrainF::flag_arraybounds);
122 }
123
124 //Read the BrainF program
125 BrainF bf;
126 Module *mod = bf.parse(in, 65536, cf); //64 KiB
127 if (in != &std::cin) {delete in;}
128 addMainFunction(mod);
129
130 //Verify generated code
131 if (verifyModule(*mod)) {
132 cerr<<"Error: module failed verification. This shouldn't happen.\n";
133 abort();
134 }
135
136 //Write it out
137 if (JIT) {
138 cout<<"------- Running JIT -------\n";
139 ExistingModuleProvider *mp = new ExistingModuleProvider(mod);
140 ExecutionEngine *ee = ExecutionEngine::create(mp, false);
141 std::vector args;
142 Function *brainf_func = mod->getFunction("brainf");
143 GenericValue gv = ee->runFunction(brainf_func, args);
144 } else {
145 WriteBitcodeToFile(mod, *out);
146 }
147
148 //Clean up
149 if (out != &std::cout) {delete out;}
150 delete mod;
151
152 llvm_shutdown();
153
154 return 0;
155 }
0 ##===- examples/BrainF/Makefile ----------------------------*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file was developed by Sterling Stein and is distributed under
5 # the University of Illinois Open Source License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8 LEVEL = ../..
9 TOOLNAME = BrainF
10 EXAMPLE_TOOL = 1
11
12 LINK_COMPONENTS := jit bitwriter native interpreter
13
14 include $(LEVEL)/Makefile.common
99
1010 include $(LEVEL)/Makefile.config
1111
12 PARALLEL_DIRS:= Fibonacci HowToUseJIT ModuleMaker
12 PARALLEL_DIRS:= BrainF Fibonacci HowToUseJIT ModuleMaker
1313
1414 ifeq ($(HAVE_PTHREAD),1)
1515 PARALLEL_DIRS += ParallelJIT