1 //===-- BrainF.cpp - BrainF compiler example ------------------------------===//
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 class compiles the BrainF language into LLVM assembly.
12 // The BrainF language has 8 commands:
13 // Command Equivalent C Action
14 // ------- ------------ ------
15 // , *h=getchar(); Read a character from stdin, 255 on EOF
16 // . putchar(*h); Write a character to stdout
17 // - --*h; Decrement tape
18 // + ++*h; Increment tape
19 // < --h; Move head left
20 // > ++h; Move head right
21 // [ while(*h) { Start loop
24 //===----------------------------------------------------------------------===//
27 #include "llvm/ADT/APInt.h"
28 #include "llvm/IR/BasicBlock.h"
29 #include "llvm/IR/Constant.h"
30 #include "llvm/IR/Constants.h"
31 #include "llvm/IR/DerivedTypes.h"
32 #include "llvm/IR/Function.h"
33 #include "llvm/IR/GlobalValue.h"
34 #include "llvm/IR/GlobalVariable.h"
35 #include "llvm/IR/InstrTypes.h"
36 #include "llvm/IR/Instruction.h"
37 #include "llvm/IR/Instructions.h"
38 #include "llvm/IR/Intrinsics.h"
39 #include "llvm/IR/Module.h"
40 #include "llvm/IR/Type.h"
41 #include "llvm/Support/Casting.h"
47 //Set the constants for naming
48 const char *BrainF::tapereg
= "tape";
49 const char *BrainF::headreg
= "head";
50 const char *BrainF::label
= "brainf";
51 const char *BrainF::testreg
= "test";
53 Module
*BrainF::parse(std::istream
*in1
, int mem
, CompileFlags cf
,
54 LLVMContext
& Context
) {
60 readloop(nullptr, nullptr, nullptr, Context
);
65 void BrainF::header(LLVMContext
& C
) {
66 module
= new Module("BrainF", C
);
70 //declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i32, i1)
71 Type
*Tys
[] = { Type::getInt8PtrTy(C
), Type::getInt32Ty(C
) };
72 Function
*memset_func
= Intrinsic::getDeclaration(module
, Intrinsic::memset
,
75 //declare i32 @getchar()
76 getchar_func
= cast
<Function
>(module
->
77 getOrInsertFunction("getchar", IntegerType::getInt32Ty(C
)));
79 //declare i32 @putchar(i32)
80 putchar_func
= cast
<Function
>(module
->
81 getOrInsertFunction("putchar", IntegerType::getInt32Ty(C
),
82 IntegerType::getInt32Ty(C
)));
86 //define void @brainf()
87 brainf_func
= cast
<Function
>(module
->
88 getOrInsertFunction("brainf", Type::getVoidTy(C
)));
90 builder
= new IRBuilder
<>(BasicBlock::Create(C
, label
, brainf_func
));
92 //%arr = malloc i8, i32 %d
93 ConstantInt
*val_mem
= ConstantInt::get(C
, APInt(32, memtotal
));
94 BasicBlock
* BB
= builder
->GetInsertBlock();
95 Type
* IntPtrTy
= IntegerType::getInt32Ty(C
);
96 Type
* Int8Ty
= IntegerType::getInt8Ty(C
);
97 Constant
* allocsize
= ConstantExpr::getSizeOf(Int8Ty
);
98 allocsize
= ConstantExpr::getTruncOrBitCast(allocsize
, IntPtrTy
);
99 ptr_arr
= CallInst::CreateMalloc(BB
, IntPtrTy
, Int8Ty
, allocsize
, val_mem
,
101 BB
->getInstList().push_back(cast
<Instruction
>(ptr_arr
));
103 //call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i32 1, i1 0)
105 Value
*memset_params
[] = {
107 ConstantInt::get(C
, APInt(8, 0)),
109 ConstantInt::get(C
, APInt(32, 1)),
110 ConstantInt::get(C
, APInt(1, 0))
113 CallInst
*memset_call
= builder
->
114 CreateCall(memset_func
, memset_params
);
115 memset_call
->setTailCall(false);
118 //%arrmax = getelementptr i8 *%arr, i32 %d
119 if (comflag
& flag_arraybounds
) {
120 ptr_arrmax
= builder
->
121 CreateGEP(ptr_arr
, ConstantInt::get(C
, APInt(32, memtotal
)), "arrmax");
124 //%head.%d = getelementptr i8 *%arr, i32 %d
125 curhead
= builder
->CreateGEP(ptr_arr
,
126 ConstantInt::get(C
, APInt(32, memtotal
/2)),
132 endbb
= BasicBlock::Create(C
, label
, brainf_func
);
134 //call free(i8 *%arr)
135 endbb
->getInstList().push_back(CallInst::CreateFree(ptr_arr
, endbb
));
138 ReturnInst::Create(C
, endbb
);
140 //Error block for array out of bounds
141 if (comflag
& flag_arraybounds
)
143 //@aberrormsg = internal constant [%d x i8] c"\00"
145 ConstantDataArray::getString(C
, "Error: The head has left the tape.",
148 GlobalVariable
*aberrormsg
= new GlobalVariable(
152 GlobalValue::InternalLinkage
,
156 //declare i32 @puts(i8 *)
157 Function
*puts_func
= cast
<Function
>(module
->
158 getOrInsertFunction("puts", IntegerType::getInt32Ty(C
),
159 PointerType::getUnqual(IntegerType::getInt8Ty(C
))));
162 aberrorbb
= BasicBlock::Create(C
, label
, brainf_func
);
164 //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
166 Constant
*zero_32
= Constant::getNullValue(IntegerType::getInt32Ty(C
));
168 Constant
*gep_params
[] = {
173 Constant
*msgptr
= ConstantExpr::
174 getGetElementPtr(aberrormsg
->getValueType(), aberrormsg
, gep_params
);
176 Value
*puts_params
[] = {
180 CallInst
*puts_call
=
181 CallInst::Create(puts_func
,
184 puts_call
->setTailCall(false);
187 //br label %brainf.end
188 BranchInst::Create(endbb
, aberrorbb
);
192 void BrainF::readloop(PHINode
*phi
, BasicBlock
*oldbb
, BasicBlock
*testbb
,
194 Symbol cursym
= SYM_NONE
;
196 Symbol nextsym
= SYM_NONE
;
202 while(cursym
!= SYM_EOF
&& cursym
!= SYM_ENDLOOP
) {
203 // Write out commands
211 //%tape.%d = call i32 @getchar()
212 CallInst
*getchar_call
=
213 builder
->CreateCall(getchar_func
, {}, tapereg
);
214 getchar_call
->setTailCall(false);
215 Value
*tape_0
= getchar_call
;
217 //%tape.%d = trunc i32 %tape.%d to i8
218 Value
*tape_1
= builder
->
219 CreateTrunc(tape_0
, IntegerType::getInt8Ty(C
), tapereg
);
221 //store i8 %tape.%d, i8 *%head.%d
222 builder
->CreateStore(tape_1
, curhead
);
228 //%tape.%d = load i8 *%head.%d
229 LoadInst
*tape_0
= builder
->CreateLoad(curhead
, tapereg
);
231 //%tape.%d = sext i8 %tape.%d to i32
232 Value
*tape_1
= builder
->
233 CreateSExt(tape_0
, IntegerType::getInt32Ty(C
), tapereg
);
235 //call i32 @putchar(i32 %tape.%d)
236 Value
*putchar_params
[] = {
239 CallInst
*putchar_call
= builder
->
240 CreateCall(putchar_func
,
242 putchar_call
->setTailCall(false);
248 //%head.%d = getelementptr i8 *%head.%d, i32 %d
250 CreateGEP(curhead
, ConstantInt::get(C
, APInt(32, curvalue
)),
253 //Error block for array out of bounds
254 if (comflag
& flag_arraybounds
)
256 //%test.%d = icmp uge i8 *%head.%d, %arrmax
257 Value
*test_0
= builder
->
258 CreateICmpUGE(curhead
, ptr_arrmax
, testreg
);
260 //%test.%d = icmp ult i8 *%head.%d, %arr
261 Value
*test_1
= builder
->
262 CreateICmpULT(curhead
, ptr_arr
, testreg
);
264 //%test.%d = or i1 %test.%d, %test.%d
265 Value
*test_2
= builder
->
266 CreateOr(test_0
, test_1
, testreg
);
268 //br i1 %test.%d, label %main.%d, label %main.%d
269 BasicBlock
*nextbb
= BasicBlock::Create(C
, label
, brainf_func
);
270 builder
->CreateCondBr(test_2
, aberrorbb
, nextbb
);
273 builder
->SetInsertPoint(nextbb
);
280 //%tape.%d = load i8 *%head.%d
281 LoadInst
*tape_0
= builder
->CreateLoad(curhead
, tapereg
);
283 //%tape.%d = add i8 %tape.%d, %d
284 Value
*tape_1
= builder
->
285 CreateAdd(tape_0
, ConstantInt::get(C
, APInt(8, curvalue
)), tapereg
);
287 //store i8 %tape.%d, i8 *%head.%d\n"
288 builder
->CreateStore(tape_1
, curhead
);
295 BasicBlock
*testbb
= BasicBlock::Create(C
, label
, brainf_func
);
296 builder
->CreateBr(testbb
);
299 BasicBlock
*bb_0
= builder
->GetInsertBlock();
300 BasicBlock
*bb_1
= BasicBlock::Create(C
, label
, brainf_func
);
301 builder
->SetInsertPoint(bb_1
);
303 // Make part of PHI instruction now, wait until end of loop to finish
305 PHINode::Create(PointerType::getUnqual(IntegerType::getInt8Ty(C
)),
307 phi_0
->addIncoming(curhead
, bb_0
);
310 readloop(phi_0
, bb_1
, testbb
, C
);
315 std::cerr
<< "Error: Unknown symbol.\n";
321 curvalue
= nextvalue
;
324 // Reading stdin loop
325 loop
= (cursym
== SYM_NONE
)
326 || (cursym
== SYM_MOVE
)
327 || (cursym
== SYM_CHANGE
);
331 if (cursym
== SYM_NONE
) {
345 if (cursym
== SYM_CHANGE
) {
346 curvalue
+= direction
;
349 if (cursym
== SYM_NONE
) {
351 curvalue
= direction
;
354 nextsym
= SYM_CHANGE
;
355 nextvalue
= direction
;
366 if (cursym
== SYM_MOVE
) {
367 curvalue
+= direction
;
370 if (cursym
== SYM_NONE
) {
372 curvalue
= direction
;
376 nextvalue
= direction
;
383 if (cursym
== SYM_NONE
) {
392 if (cursym
== SYM_NONE
) {
401 if (cursym
== SYM_NONE
) {
410 if (cursym
== SYM_NONE
) {
411 cursym
= SYM_ENDLOOP
;
413 nextsym
= SYM_ENDLOOP
;
418 // Ignore other characters
426 if (cursym
== SYM_ENDLOOP
) {
428 std::cerr
<< "Error: Extra ']'\n";
435 builder
->CreateBr(testbb
);
439 //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
440 //Finish phi made at beginning of loop
441 phi
->addIncoming(curhead
, builder
->GetInsertBlock());
444 //%tape.%d = load i8 *%head.%d
445 LoadInst
*tape_0
= new LoadInst(head_0
, tapereg
, testbb
);
447 //%test.%d = icmp eq i8 %tape.%d, 0
448 ICmpInst
*test_0
= new ICmpInst(*testbb
, ICmpInst::ICMP_EQ
, tape_0
,
449 ConstantInt::get(C
, APInt(8, 0)), testreg
);
451 //br i1 %test.%d, label %main.%d, label %main.%d
452 BasicBlock
*bb_0
= BasicBlock::Create(C
, label
, brainf_func
);
453 BranchInst::Create(bb_0
, oldbb
, test_0
, testbb
);
456 builder
->SetInsertPoint(bb_0
);
458 //%head.%d = phi i8 *[%head.%d, %main.%d]
459 PHINode
*phi_1
= builder
->
460 CreatePHI(PointerType::getUnqual(IntegerType::getInt8Ty(C
)), 1,
462 phi_1
->addIncoming(head_0
, testbb
);
469 //End of the program, so go to return block
470 builder
->CreateBr(endbb
);
473 std::cerr
<< "Error: Missing ']'\n";