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/Constants.h"
28 #include "llvm/Intrinsics.h"
29 #include "llvm/ADT/STLExtras.h"
33 //Set the constants for naming
34 const char *BrainF::tapereg
= "tape";
35 const char *BrainF::headreg
= "head";
36 const char *BrainF::label
= "brainf";
37 const char *BrainF::testreg
= "test";
39 Module
*BrainF::parse(std::istream
*in1
, int mem
, CompileFlags cf
) {
50 void BrainF::header() {
51 module
= new Module("BrainF");
55 //declare void @llvm.memset.i32(i8 *, i8, i32, i32)
56 const Type
*Tys
[] = { Type::Int32Ty
};
57 Function
*memset_func
= Intrinsic::getDeclaration(module
, Intrinsic::memset
,
60 //declare i32 @getchar()
61 getchar_func
= cast
<Function
>(module
->
62 getOrInsertFunction("getchar", IntegerType::Int32Ty
, NULL
));
64 //declare i32 @putchar(i32)
65 putchar_func
= cast
<Function
>(module
->
66 getOrInsertFunction("putchar", IntegerType::Int32Ty
,
67 IntegerType::Int32Ty
, NULL
));
72 //define void @brainf()
73 brainf_func
= cast
<Function
>(module
->
74 getOrInsertFunction("brainf", Type::VoidTy
, NULL
));
76 builder
= new IRBuilder
<>(BasicBlock::Create(label
, brainf_func
));
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");
82 //call void @llvm.memset.i32(i8 *%arr, i8 0, i32 %d, i32 1)
84 Value
*memset_params
[] = {
86 ConstantInt::get(APInt(8, 0)),
88 ConstantInt::get(APInt(32, 1))
91 CallInst
*memset_call
= builder
->
92 CreateCall(memset_func
, memset_params
, array_endof(memset_params
));
93 memset_call
->setTailCall(false);
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");
102 //%head.%d = getelementptr i8 *%arr, i32 %d
103 curhead
= builder
->CreateGEP(ptr_arr
,
104 ConstantInt::get(APInt(32, memtotal
/2)),
112 endbb
= BasicBlock::Create(label
, brainf_func
);
115 new FreeInst(ptr_arr
, endbb
);
118 ReturnInst::Create(endbb
);
122 //Error block for array out of bounds
123 if (comflag
& flag_arraybounds
)
125 //@aberrormsg = internal constant [%d x i8] c"\00"
126 Constant
*msg_0
= ConstantArray::
127 get("Error: The head has left the tape.", true);
129 GlobalVariable
*aberrormsg
= new GlobalVariable(
132 GlobalValue::InternalLinkage
,
137 //declare i32 @puts(i8 *)
138 Function
*puts_func
= cast
<Function
>(module
->
139 getOrInsertFunction("puts", IntegerType::Int32Ty
,
140 PointerType::getUnqual(IntegerType::Int8Ty
), NULL
));
143 aberrorbb
= BasicBlock::Create(label
, brainf_func
);
145 //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
147 Constant
*zero_32
= Constant::getNullValue(IntegerType::Int32Ty
);
149 Constant
*gep_params
[] = {
154 Constant
*msgptr
= ConstantExpr::
155 getGetElementPtr(aberrormsg
, gep_params
,
156 array_lengthof(gep_params
));
158 Value
*puts_params
[] = {
162 CallInst
*puts_call
=
163 CallInst::Create(puts_func
,
164 puts_params
, array_endof(puts_params
),
166 puts_call
->setTailCall(false);
169 //br label %brainf.end
170 BranchInst::Create(endbb
, aberrorbb
);
174 void BrainF::readloop(PHINode
*phi
, BasicBlock
*oldbb
, BasicBlock
*testbb
) {
175 Symbol cursym
= SYM_NONE
;
177 Symbol nextsym
= SYM_NONE
;
183 while(cursym
!= SYM_EOF
&& cursym
!= SYM_ENDLOOP
) {
184 // Write out commands
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
;
197 //%tape.%d = trunc i32 %tape.%d to i8
198 Value
*tape_1
= builder
->
199 CreateTrunc(tape_0
, IntegerType::Int8Ty
, tapereg
);
201 //store i8 %tape.%d, i8 *%head.%d
202 builder
->CreateStore(tape_1
, curhead
);
208 //%tape.%d = load i8 *%head.%d
209 LoadInst
*tape_0
= builder
->CreateLoad(curhead
, tapereg
);
211 //%tape.%d = sext i8 %tape.%d to i32
212 Value
*tape_1
= builder
->
213 CreateSExt(tape_0
, IntegerType::Int32Ty
, tapereg
);
215 //call i32 @putchar(i32 %tape.%d)
216 Value
*putchar_params
[] = {
219 CallInst
*putchar_call
= builder
->
220 CreateCall(putchar_func
,
221 putchar_params
, array_endof(putchar_params
));
222 putchar_call
->setTailCall(false);
228 //%head.%d = getelementptr i8 *%head.%d, i32 %d
230 CreateGEP(curhead
, ConstantInt::get(APInt(32, curvalue
)),
233 //Error block for array out of bounds
234 if (comflag
& flag_arraybounds
)
236 //%test.%d = icmp uge i8 *%head.%d, %arrmax
237 Value
*test_0
= builder
->
238 CreateICmpUGE(curhead
, ptr_arrmax
, testreg
);
240 //%test.%d = icmp ult i8 *%head.%d, %arr
241 Value
*test_1
= builder
->
242 CreateICmpULT(curhead
, ptr_arr
, testreg
);
244 //%test.%d = or i1 %test.%d, %test.%d
245 Value
*test_2
= builder
->
246 CreateOr(test_0
, test_1
, testreg
);
248 //br i1 %test.%d, label %main.%d, label %main.%d
249 BasicBlock
*nextbb
= BasicBlock::Create(label
, brainf_func
);
250 builder
->CreateCondBr(test_2
, aberrorbb
, nextbb
);
253 builder
->SetInsertPoint(nextbb
);
260 //%tape.%d = load i8 *%head.%d
261 LoadInst
*tape_0
= builder
->CreateLoad(curhead
, tapereg
);
263 //%tape.%d = add i8 %tape.%d, %d
264 Value
*tape_1
= builder
->
265 CreateAdd(tape_0
, ConstantInt::get(APInt(8, curvalue
)), tapereg
);
267 //store i8 %tape.%d, i8 *%head.%d\n"
268 builder
->CreateStore(tape_1
, curhead
);
275 BasicBlock
*testbb
= BasicBlock::Create(label
, brainf_func
);
276 builder
->CreateBr(testbb
);
279 BasicBlock
*bb_0
= builder
->GetInsertBlock();
280 BasicBlock
*bb_1
= BasicBlock::Create(label
, brainf_func
);
281 builder
->SetInsertPoint(bb_1
);
283 // Make part of PHI instruction now, wait until end of loop to finish
285 PHINode::Create(PointerType::getUnqual(IntegerType::Int8Ty
),
287 phi_0
->reserveOperandSpace(2);
288 phi_0
->addIncoming(curhead
, bb_0
);
291 readloop(phi_0
, bb_1
, testbb
);
296 std::cerr
<< "Error: Unknown symbol.\n";
302 curvalue
= nextvalue
;
305 // Reading stdin loop
306 loop
= (cursym
== SYM_NONE
)
307 || (cursym
== SYM_MOVE
)
308 || (cursym
== SYM_CHANGE
);
312 if (cursym
== SYM_NONE
) {
326 if (cursym
== SYM_CHANGE
) {
327 curvalue
+= direction
;
330 if (cursym
== SYM_NONE
) {
332 curvalue
= direction
;
335 nextsym
= SYM_CHANGE
;
336 nextvalue
= direction
;
347 if (cursym
== SYM_MOVE
) {
348 curvalue
+= direction
;
351 if (cursym
== SYM_NONE
) {
353 curvalue
= direction
;
357 nextvalue
= direction
;
364 if (cursym
== SYM_NONE
) {
373 if (cursym
== SYM_NONE
) {
382 if (cursym
== SYM_NONE
) {
391 if (cursym
== SYM_NONE
) {
392 cursym
= SYM_ENDLOOP
;
394 nextsym
= SYM_ENDLOOP
;
399 // Ignore other characters
407 if (cursym
== SYM_ENDLOOP
) {
409 std::cerr
<< "Error: Extra ']'\n";
416 builder
->CreateBr(testbb
);
420 //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
421 //Finish phi made at beginning of loop
422 phi
->addIncoming(curhead
, builder
->GetInsertBlock());
425 //%tape.%d = load i8 *%head.%d
426 LoadInst
*tape_0
= new LoadInst(head_0
, tapereg
, testbb
);
428 //%test.%d = icmp eq i8 %tape.%d, 0
429 ICmpInst
*test_0
= new ICmpInst(ICmpInst::ICMP_EQ
, tape_0
,
430 ConstantInt::get(APInt(8, 0)), testreg
,
433 //br i1 %test.%d, label %main.%d, label %main.%d
434 BasicBlock
*bb_0
= BasicBlock::Create(label
, brainf_func
);
435 BranchInst::Create(bb_0
, oldbb
, test_0
, testbb
);
438 builder
->SetInsertPoint(bb_0
);
440 //%head.%d = phi i8 *[%head.%d, %main.%d]
441 PHINode
*phi_1
= builder
->
442 CreatePHI(PointerType::getUnqual(IntegerType::Int8Ty
), headreg
);
443 phi_1
->reserveOperandSpace(1);
444 phi_1
->addIncoming(head_0
, testbb
);
451 //End of the program, so go to return block
452 builder
->CreateBr(endbb
);
455 std::cerr
<< "Error: Missing ']'\n";