1*f4a2713aSLionel Sambuc //===-- BrainF.cpp - BrainF compiler example ----------------------------===//
2*f4a2713aSLionel Sambuc //
3*f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4*f4a2713aSLionel Sambuc //
5*f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6*f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7*f4a2713aSLionel Sambuc //
8*f4a2713aSLionel Sambuc //===--------------------------------------------------------------------===//
9*f4a2713aSLionel Sambuc //
10*f4a2713aSLionel Sambuc // This class compiles the BrainF language into LLVM assembly.
11*f4a2713aSLionel Sambuc //
12*f4a2713aSLionel Sambuc // The BrainF language has 8 commands:
13*f4a2713aSLionel Sambuc // Command Equivalent C Action
14*f4a2713aSLionel Sambuc // ------- ------------ ------
15*f4a2713aSLionel Sambuc // , *h=getchar(); Read a character from stdin, 255 on EOF
16*f4a2713aSLionel Sambuc // . putchar(*h); Write a character to stdout
17*f4a2713aSLionel Sambuc // - --*h; Decrement tape
18*f4a2713aSLionel Sambuc // + ++*h; Increment tape
19*f4a2713aSLionel Sambuc // < --h; Move head left
20*f4a2713aSLionel Sambuc // > ++h; Move head right
21*f4a2713aSLionel Sambuc // [ while(*h) { Start loop
22*f4a2713aSLionel Sambuc // ] } End loop
23*f4a2713aSLionel Sambuc //
24*f4a2713aSLionel Sambuc //===--------------------------------------------------------------------===//
25*f4a2713aSLionel Sambuc
26*f4a2713aSLionel Sambuc #include "BrainF.h"
27*f4a2713aSLionel Sambuc #include "llvm/ADT/STLExtras.h"
28*f4a2713aSLionel Sambuc #include "llvm/IR/Constants.h"
29*f4a2713aSLionel Sambuc #include "llvm/IR/Instructions.h"
30*f4a2713aSLionel Sambuc #include "llvm/IR/Intrinsics.h"
31*f4a2713aSLionel Sambuc #include <iostream>
32*f4a2713aSLionel Sambuc using namespace llvm;
33*f4a2713aSLionel Sambuc
34*f4a2713aSLionel Sambuc //Set the constants for naming
35*f4a2713aSLionel Sambuc const char *BrainF::tapereg = "tape";
36*f4a2713aSLionel Sambuc const char *BrainF::headreg = "head";
37*f4a2713aSLionel Sambuc const char *BrainF::label = "brainf";
38*f4a2713aSLionel Sambuc const char *BrainF::testreg = "test";
39*f4a2713aSLionel Sambuc
parse(std::istream * in1,int mem,CompileFlags cf,LLVMContext & Context)40*f4a2713aSLionel Sambuc Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf,
41*f4a2713aSLionel Sambuc LLVMContext& Context) {
42*f4a2713aSLionel Sambuc in = in1;
43*f4a2713aSLionel Sambuc memtotal = mem;
44*f4a2713aSLionel Sambuc comflag = cf;
45*f4a2713aSLionel Sambuc
46*f4a2713aSLionel Sambuc header(Context);
47*f4a2713aSLionel Sambuc readloop(0, 0, 0, Context);
48*f4a2713aSLionel Sambuc delete builder;
49*f4a2713aSLionel Sambuc return module;
50*f4a2713aSLionel Sambuc }
51*f4a2713aSLionel Sambuc
header(LLVMContext & C)52*f4a2713aSLionel Sambuc void BrainF::header(LLVMContext& C) {
53*f4a2713aSLionel Sambuc module = new Module("BrainF", C);
54*f4a2713aSLionel Sambuc
55*f4a2713aSLionel Sambuc //Function prototypes
56*f4a2713aSLionel Sambuc
57*f4a2713aSLionel Sambuc //declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i32, i1)
58*f4a2713aSLionel Sambuc Type *Tys[] = { Type::getInt8PtrTy(C), Type::getInt32Ty(C) };
59*f4a2713aSLionel Sambuc Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset,
60*f4a2713aSLionel Sambuc Tys);
61*f4a2713aSLionel Sambuc
62*f4a2713aSLionel Sambuc //declare i32 @getchar()
63*f4a2713aSLionel Sambuc getchar_func = cast<Function>(module->
64*f4a2713aSLionel Sambuc getOrInsertFunction("getchar", IntegerType::getInt32Ty(C), NULL));
65*f4a2713aSLionel Sambuc
66*f4a2713aSLionel Sambuc //declare i32 @putchar(i32)
67*f4a2713aSLionel Sambuc putchar_func = cast<Function>(module->
68*f4a2713aSLionel Sambuc getOrInsertFunction("putchar", IntegerType::getInt32Ty(C),
69*f4a2713aSLionel Sambuc IntegerType::getInt32Ty(C), NULL));
70*f4a2713aSLionel Sambuc
71*f4a2713aSLionel Sambuc
72*f4a2713aSLionel Sambuc //Function header
73*f4a2713aSLionel Sambuc
74*f4a2713aSLionel Sambuc //define void @brainf()
75*f4a2713aSLionel Sambuc brainf_func = cast<Function>(module->
76*f4a2713aSLionel Sambuc getOrInsertFunction("brainf", Type::getVoidTy(C), NULL));
77*f4a2713aSLionel Sambuc
78*f4a2713aSLionel Sambuc builder = new IRBuilder<>(BasicBlock::Create(C, label, brainf_func));
79*f4a2713aSLionel Sambuc
80*f4a2713aSLionel Sambuc //%arr = malloc i8, i32 %d
81*f4a2713aSLionel Sambuc ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal));
82*f4a2713aSLionel Sambuc BasicBlock* BB = builder->GetInsertBlock();
83*f4a2713aSLionel Sambuc Type* IntPtrTy = IntegerType::getInt32Ty(C);
84*f4a2713aSLionel Sambuc Type* Int8Ty = IntegerType::getInt8Ty(C);
85*f4a2713aSLionel Sambuc Constant* allocsize = ConstantExpr::getSizeOf(Int8Ty);
86*f4a2713aSLionel Sambuc allocsize = ConstantExpr::getTruncOrBitCast(allocsize, IntPtrTy);
87*f4a2713aSLionel Sambuc ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, Int8Ty, allocsize, val_mem,
88*f4a2713aSLionel Sambuc NULL, "arr");
89*f4a2713aSLionel Sambuc BB->getInstList().push_back(cast<Instruction>(ptr_arr));
90*f4a2713aSLionel Sambuc
91*f4a2713aSLionel Sambuc //call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i32 1, i1 0)
92*f4a2713aSLionel Sambuc {
93*f4a2713aSLionel Sambuc Value *memset_params[] = {
94*f4a2713aSLionel Sambuc ptr_arr,
95*f4a2713aSLionel Sambuc ConstantInt::get(C, APInt(8, 0)),
96*f4a2713aSLionel Sambuc val_mem,
97*f4a2713aSLionel Sambuc ConstantInt::get(C, APInt(32, 1)),
98*f4a2713aSLionel Sambuc ConstantInt::get(C, APInt(1, 0))
99*f4a2713aSLionel Sambuc };
100*f4a2713aSLionel Sambuc
101*f4a2713aSLionel Sambuc CallInst *memset_call = builder->
102*f4a2713aSLionel Sambuc CreateCall(memset_func, memset_params);
103*f4a2713aSLionel Sambuc memset_call->setTailCall(false);
104*f4a2713aSLionel Sambuc }
105*f4a2713aSLionel Sambuc
106*f4a2713aSLionel Sambuc //%arrmax = getelementptr i8 *%arr, i32 %d
107*f4a2713aSLionel Sambuc if (comflag & flag_arraybounds) {
108*f4a2713aSLionel Sambuc ptr_arrmax = builder->
109*f4a2713aSLionel Sambuc CreateGEP(ptr_arr, ConstantInt::get(C, APInt(32, memtotal)), "arrmax");
110*f4a2713aSLionel Sambuc }
111*f4a2713aSLionel Sambuc
112*f4a2713aSLionel Sambuc //%head.%d = getelementptr i8 *%arr, i32 %d
113*f4a2713aSLionel Sambuc curhead = builder->CreateGEP(ptr_arr,
114*f4a2713aSLionel Sambuc ConstantInt::get(C, APInt(32, memtotal/2)),
115*f4a2713aSLionel Sambuc headreg);
116*f4a2713aSLionel Sambuc
117*f4a2713aSLionel Sambuc
118*f4a2713aSLionel Sambuc
119*f4a2713aSLionel Sambuc //Function footer
120*f4a2713aSLionel Sambuc
121*f4a2713aSLionel Sambuc //brainf.end:
122*f4a2713aSLionel Sambuc endbb = BasicBlock::Create(C, label, brainf_func);
123*f4a2713aSLionel Sambuc
124*f4a2713aSLionel Sambuc //call free(i8 *%arr)
125*f4a2713aSLionel Sambuc endbb->getInstList().push_back(CallInst::CreateFree(ptr_arr, endbb));
126*f4a2713aSLionel Sambuc
127*f4a2713aSLionel Sambuc //ret void
128*f4a2713aSLionel Sambuc ReturnInst::Create(C, endbb);
129*f4a2713aSLionel Sambuc
130*f4a2713aSLionel Sambuc
131*f4a2713aSLionel Sambuc
132*f4a2713aSLionel Sambuc //Error block for array out of bounds
133*f4a2713aSLionel Sambuc if (comflag & flag_arraybounds)
134*f4a2713aSLionel Sambuc {
135*f4a2713aSLionel Sambuc //@aberrormsg = internal constant [%d x i8] c"\00"
136*f4a2713aSLionel Sambuc Constant *msg_0 =
137*f4a2713aSLionel Sambuc ConstantDataArray::getString(C, "Error: The head has left the tape.",
138*f4a2713aSLionel Sambuc true);
139*f4a2713aSLionel Sambuc
140*f4a2713aSLionel Sambuc GlobalVariable *aberrormsg = new GlobalVariable(
141*f4a2713aSLionel Sambuc *module,
142*f4a2713aSLionel Sambuc msg_0->getType(),
143*f4a2713aSLionel Sambuc true,
144*f4a2713aSLionel Sambuc GlobalValue::InternalLinkage,
145*f4a2713aSLionel Sambuc msg_0,
146*f4a2713aSLionel Sambuc "aberrormsg");
147*f4a2713aSLionel Sambuc
148*f4a2713aSLionel Sambuc //declare i32 @puts(i8 *)
149*f4a2713aSLionel Sambuc Function *puts_func = cast<Function>(module->
150*f4a2713aSLionel Sambuc getOrInsertFunction("puts", IntegerType::getInt32Ty(C),
151*f4a2713aSLionel Sambuc PointerType::getUnqual(IntegerType::getInt8Ty(C)), NULL));
152*f4a2713aSLionel Sambuc
153*f4a2713aSLionel Sambuc //brainf.aberror:
154*f4a2713aSLionel Sambuc aberrorbb = BasicBlock::Create(C, label, brainf_func);
155*f4a2713aSLionel Sambuc
156*f4a2713aSLionel Sambuc //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
157*f4a2713aSLionel Sambuc {
158*f4a2713aSLionel Sambuc Constant *zero_32 = Constant::getNullValue(IntegerType::getInt32Ty(C));
159*f4a2713aSLionel Sambuc
160*f4a2713aSLionel Sambuc Constant *gep_params[] = {
161*f4a2713aSLionel Sambuc zero_32,
162*f4a2713aSLionel Sambuc zero_32
163*f4a2713aSLionel Sambuc };
164*f4a2713aSLionel Sambuc
165*f4a2713aSLionel Sambuc Constant *msgptr = ConstantExpr::
166*f4a2713aSLionel Sambuc getGetElementPtr(aberrormsg, gep_params);
167*f4a2713aSLionel Sambuc
168*f4a2713aSLionel Sambuc Value *puts_params[] = {
169*f4a2713aSLionel Sambuc msgptr
170*f4a2713aSLionel Sambuc };
171*f4a2713aSLionel Sambuc
172*f4a2713aSLionel Sambuc CallInst *puts_call =
173*f4a2713aSLionel Sambuc CallInst::Create(puts_func,
174*f4a2713aSLionel Sambuc puts_params,
175*f4a2713aSLionel Sambuc "", aberrorbb);
176*f4a2713aSLionel Sambuc puts_call->setTailCall(false);
177*f4a2713aSLionel Sambuc }
178*f4a2713aSLionel Sambuc
179*f4a2713aSLionel Sambuc //br label %brainf.end
180*f4a2713aSLionel Sambuc BranchInst::Create(endbb, aberrorbb);
181*f4a2713aSLionel Sambuc }
182*f4a2713aSLionel Sambuc }
183*f4a2713aSLionel Sambuc
readloop(PHINode * phi,BasicBlock * oldbb,BasicBlock * testbb,LLVMContext & C)184*f4a2713aSLionel Sambuc void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb,
185*f4a2713aSLionel Sambuc LLVMContext &C) {
186*f4a2713aSLionel Sambuc Symbol cursym = SYM_NONE;
187*f4a2713aSLionel Sambuc int curvalue = 0;
188*f4a2713aSLionel Sambuc Symbol nextsym = SYM_NONE;
189*f4a2713aSLionel Sambuc int nextvalue = 0;
190*f4a2713aSLionel Sambuc char c;
191*f4a2713aSLionel Sambuc int loop;
192*f4a2713aSLionel Sambuc int direction;
193*f4a2713aSLionel Sambuc
194*f4a2713aSLionel Sambuc while(cursym != SYM_EOF && cursym != SYM_ENDLOOP) {
195*f4a2713aSLionel Sambuc // Write out commands
196*f4a2713aSLionel Sambuc switch(cursym) {
197*f4a2713aSLionel Sambuc case SYM_NONE:
198*f4a2713aSLionel Sambuc // Do nothing
199*f4a2713aSLionel Sambuc break;
200*f4a2713aSLionel Sambuc
201*f4a2713aSLionel Sambuc case SYM_READ:
202*f4a2713aSLionel Sambuc {
203*f4a2713aSLionel Sambuc //%tape.%d = call i32 @getchar()
204*f4a2713aSLionel Sambuc CallInst *getchar_call = builder->CreateCall(getchar_func, tapereg);
205*f4a2713aSLionel Sambuc getchar_call->setTailCall(false);
206*f4a2713aSLionel Sambuc Value *tape_0 = getchar_call;
207*f4a2713aSLionel Sambuc
208*f4a2713aSLionel Sambuc //%tape.%d = trunc i32 %tape.%d to i8
209*f4a2713aSLionel Sambuc Value *tape_1 = builder->
210*f4a2713aSLionel Sambuc CreateTrunc(tape_0, IntegerType::getInt8Ty(C), tapereg);
211*f4a2713aSLionel Sambuc
212*f4a2713aSLionel Sambuc //store i8 %tape.%d, i8 *%head.%d
213*f4a2713aSLionel Sambuc builder->CreateStore(tape_1, curhead);
214*f4a2713aSLionel Sambuc }
215*f4a2713aSLionel Sambuc break;
216*f4a2713aSLionel Sambuc
217*f4a2713aSLionel Sambuc case SYM_WRITE:
218*f4a2713aSLionel Sambuc {
219*f4a2713aSLionel Sambuc //%tape.%d = load i8 *%head.%d
220*f4a2713aSLionel Sambuc LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);
221*f4a2713aSLionel Sambuc
222*f4a2713aSLionel Sambuc //%tape.%d = sext i8 %tape.%d to i32
223*f4a2713aSLionel Sambuc Value *tape_1 = builder->
224*f4a2713aSLionel Sambuc CreateSExt(tape_0, IntegerType::getInt32Ty(C), tapereg);
225*f4a2713aSLionel Sambuc
226*f4a2713aSLionel Sambuc //call i32 @putchar(i32 %tape.%d)
227*f4a2713aSLionel Sambuc Value *putchar_params[] = {
228*f4a2713aSLionel Sambuc tape_1
229*f4a2713aSLionel Sambuc };
230*f4a2713aSLionel Sambuc CallInst *putchar_call = builder->
231*f4a2713aSLionel Sambuc CreateCall(putchar_func,
232*f4a2713aSLionel Sambuc putchar_params);
233*f4a2713aSLionel Sambuc putchar_call->setTailCall(false);
234*f4a2713aSLionel Sambuc }
235*f4a2713aSLionel Sambuc break;
236*f4a2713aSLionel Sambuc
237*f4a2713aSLionel Sambuc case SYM_MOVE:
238*f4a2713aSLionel Sambuc {
239*f4a2713aSLionel Sambuc //%head.%d = getelementptr i8 *%head.%d, i32 %d
240*f4a2713aSLionel Sambuc curhead = builder->
241*f4a2713aSLionel Sambuc CreateGEP(curhead, ConstantInt::get(C, APInt(32, curvalue)),
242*f4a2713aSLionel Sambuc headreg);
243*f4a2713aSLionel Sambuc
244*f4a2713aSLionel Sambuc //Error block for array out of bounds
245*f4a2713aSLionel Sambuc if (comflag & flag_arraybounds)
246*f4a2713aSLionel Sambuc {
247*f4a2713aSLionel Sambuc //%test.%d = icmp uge i8 *%head.%d, %arrmax
248*f4a2713aSLionel Sambuc Value *test_0 = builder->
249*f4a2713aSLionel Sambuc CreateICmpUGE(curhead, ptr_arrmax, testreg);
250*f4a2713aSLionel Sambuc
251*f4a2713aSLionel Sambuc //%test.%d = icmp ult i8 *%head.%d, %arr
252*f4a2713aSLionel Sambuc Value *test_1 = builder->
253*f4a2713aSLionel Sambuc CreateICmpULT(curhead, ptr_arr, testreg);
254*f4a2713aSLionel Sambuc
255*f4a2713aSLionel Sambuc //%test.%d = or i1 %test.%d, %test.%d
256*f4a2713aSLionel Sambuc Value *test_2 = builder->
257*f4a2713aSLionel Sambuc CreateOr(test_0, test_1, testreg);
258*f4a2713aSLionel Sambuc
259*f4a2713aSLionel Sambuc //br i1 %test.%d, label %main.%d, label %main.%d
260*f4a2713aSLionel Sambuc BasicBlock *nextbb = BasicBlock::Create(C, label, brainf_func);
261*f4a2713aSLionel Sambuc builder->CreateCondBr(test_2, aberrorbb, nextbb);
262*f4a2713aSLionel Sambuc
263*f4a2713aSLionel Sambuc //main.%d:
264*f4a2713aSLionel Sambuc builder->SetInsertPoint(nextbb);
265*f4a2713aSLionel Sambuc }
266*f4a2713aSLionel Sambuc }
267*f4a2713aSLionel Sambuc break;
268*f4a2713aSLionel Sambuc
269*f4a2713aSLionel Sambuc case SYM_CHANGE:
270*f4a2713aSLionel Sambuc {
271*f4a2713aSLionel Sambuc //%tape.%d = load i8 *%head.%d
272*f4a2713aSLionel Sambuc LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);
273*f4a2713aSLionel Sambuc
274*f4a2713aSLionel Sambuc //%tape.%d = add i8 %tape.%d, %d
275*f4a2713aSLionel Sambuc Value *tape_1 = builder->
276*f4a2713aSLionel Sambuc CreateAdd(tape_0, ConstantInt::get(C, APInt(8, curvalue)), tapereg);
277*f4a2713aSLionel Sambuc
278*f4a2713aSLionel Sambuc //store i8 %tape.%d, i8 *%head.%d\n"
279*f4a2713aSLionel Sambuc builder->CreateStore(tape_1, curhead);
280*f4a2713aSLionel Sambuc }
281*f4a2713aSLionel Sambuc break;
282*f4a2713aSLionel Sambuc
283*f4a2713aSLionel Sambuc case SYM_LOOP:
284*f4a2713aSLionel Sambuc {
285*f4a2713aSLionel Sambuc //br label %main.%d
286*f4a2713aSLionel Sambuc BasicBlock *testbb = BasicBlock::Create(C, label, brainf_func);
287*f4a2713aSLionel Sambuc builder->CreateBr(testbb);
288*f4a2713aSLionel Sambuc
289*f4a2713aSLionel Sambuc //main.%d:
290*f4a2713aSLionel Sambuc BasicBlock *bb_0 = builder->GetInsertBlock();
291*f4a2713aSLionel Sambuc BasicBlock *bb_1 = BasicBlock::Create(C, label, brainf_func);
292*f4a2713aSLionel Sambuc builder->SetInsertPoint(bb_1);
293*f4a2713aSLionel Sambuc
294*f4a2713aSLionel Sambuc // Make part of PHI instruction now, wait until end of loop to finish
295*f4a2713aSLionel Sambuc PHINode *phi_0 =
296*f4a2713aSLionel Sambuc PHINode::Create(PointerType::getUnqual(IntegerType::getInt8Ty(C)),
297*f4a2713aSLionel Sambuc 2, headreg, testbb);
298*f4a2713aSLionel Sambuc phi_0->addIncoming(curhead, bb_0);
299*f4a2713aSLionel Sambuc curhead = phi_0;
300*f4a2713aSLionel Sambuc
301*f4a2713aSLionel Sambuc readloop(phi_0, bb_1, testbb, C);
302*f4a2713aSLionel Sambuc }
303*f4a2713aSLionel Sambuc break;
304*f4a2713aSLionel Sambuc
305*f4a2713aSLionel Sambuc default:
306*f4a2713aSLionel Sambuc std::cerr << "Error: Unknown symbol.\n";
307*f4a2713aSLionel Sambuc abort();
308*f4a2713aSLionel Sambuc break;
309*f4a2713aSLionel Sambuc }
310*f4a2713aSLionel Sambuc
311*f4a2713aSLionel Sambuc cursym = nextsym;
312*f4a2713aSLionel Sambuc curvalue = nextvalue;
313*f4a2713aSLionel Sambuc nextsym = SYM_NONE;
314*f4a2713aSLionel Sambuc
315*f4a2713aSLionel Sambuc // Reading stdin loop
316*f4a2713aSLionel Sambuc loop = (cursym == SYM_NONE)
317*f4a2713aSLionel Sambuc || (cursym == SYM_MOVE)
318*f4a2713aSLionel Sambuc || (cursym == SYM_CHANGE);
319*f4a2713aSLionel Sambuc while(loop) {
320*f4a2713aSLionel Sambuc *in>>c;
321*f4a2713aSLionel Sambuc if (in->eof()) {
322*f4a2713aSLionel Sambuc if (cursym == SYM_NONE) {
323*f4a2713aSLionel Sambuc cursym = SYM_EOF;
324*f4a2713aSLionel Sambuc } else {
325*f4a2713aSLionel Sambuc nextsym = SYM_EOF;
326*f4a2713aSLionel Sambuc }
327*f4a2713aSLionel Sambuc loop = 0;
328*f4a2713aSLionel Sambuc } else {
329*f4a2713aSLionel Sambuc direction = 1;
330*f4a2713aSLionel Sambuc switch(c) {
331*f4a2713aSLionel Sambuc case '-':
332*f4a2713aSLionel Sambuc direction = -1;
333*f4a2713aSLionel Sambuc // Fall through
334*f4a2713aSLionel Sambuc
335*f4a2713aSLionel Sambuc case '+':
336*f4a2713aSLionel Sambuc if (cursym == SYM_CHANGE) {
337*f4a2713aSLionel Sambuc curvalue += direction;
338*f4a2713aSLionel Sambuc // loop = 1
339*f4a2713aSLionel Sambuc } else {
340*f4a2713aSLionel Sambuc if (cursym == SYM_NONE) {
341*f4a2713aSLionel Sambuc cursym = SYM_CHANGE;
342*f4a2713aSLionel Sambuc curvalue = direction;
343*f4a2713aSLionel Sambuc // loop = 1
344*f4a2713aSLionel Sambuc } else {
345*f4a2713aSLionel Sambuc nextsym = SYM_CHANGE;
346*f4a2713aSLionel Sambuc nextvalue = direction;
347*f4a2713aSLionel Sambuc loop = 0;
348*f4a2713aSLionel Sambuc }
349*f4a2713aSLionel Sambuc }
350*f4a2713aSLionel Sambuc break;
351*f4a2713aSLionel Sambuc
352*f4a2713aSLionel Sambuc case '<':
353*f4a2713aSLionel Sambuc direction = -1;
354*f4a2713aSLionel Sambuc // Fall through
355*f4a2713aSLionel Sambuc
356*f4a2713aSLionel Sambuc case '>':
357*f4a2713aSLionel Sambuc if (cursym == SYM_MOVE) {
358*f4a2713aSLionel Sambuc curvalue += direction;
359*f4a2713aSLionel Sambuc // loop = 1
360*f4a2713aSLionel Sambuc } else {
361*f4a2713aSLionel Sambuc if (cursym == SYM_NONE) {
362*f4a2713aSLionel Sambuc cursym = SYM_MOVE;
363*f4a2713aSLionel Sambuc curvalue = direction;
364*f4a2713aSLionel Sambuc // loop = 1
365*f4a2713aSLionel Sambuc } else {
366*f4a2713aSLionel Sambuc nextsym = SYM_MOVE;
367*f4a2713aSLionel Sambuc nextvalue = direction;
368*f4a2713aSLionel Sambuc loop = 0;
369*f4a2713aSLionel Sambuc }
370*f4a2713aSLionel Sambuc }
371*f4a2713aSLionel Sambuc break;
372*f4a2713aSLionel Sambuc
373*f4a2713aSLionel Sambuc case ',':
374*f4a2713aSLionel Sambuc if (cursym == SYM_NONE) {
375*f4a2713aSLionel Sambuc cursym = SYM_READ;
376*f4a2713aSLionel Sambuc } else {
377*f4a2713aSLionel Sambuc nextsym = SYM_READ;
378*f4a2713aSLionel Sambuc }
379*f4a2713aSLionel Sambuc loop = 0;
380*f4a2713aSLionel Sambuc break;
381*f4a2713aSLionel Sambuc
382*f4a2713aSLionel Sambuc case '.':
383*f4a2713aSLionel Sambuc if (cursym == SYM_NONE) {
384*f4a2713aSLionel Sambuc cursym = SYM_WRITE;
385*f4a2713aSLionel Sambuc } else {
386*f4a2713aSLionel Sambuc nextsym = SYM_WRITE;
387*f4a2713aSLionel Sambuc }
388*f4a2713aSLionel Sambuc loop = 0;
389*f4a2713aSLionel Sambuc break;
390*f4a2713aSLionel Sambuc
391*f4a2713aSLionel Sambuc case '[':
392*f4a2713aSLionel Sambuc if (cursym == SYM_NONE) {
393*f4a2713aSLionel Sambuc cursym = SYM_LOOP;
394*f4a2713aSLionel Sambuc } else {
395*f4a2713aSLionel Sambuc nextsym = SYM_LOOP;
396*f4a2713aSLionel Sambuc }
397*f4a2713aSLionel Sambuc loop = 0;
398*f4a2713aSLionel Sambuc break;
399*f4a2713aSLionel Sambuc
400*f4a2713aSLionel Sambuc case ']':
401*f4a2713aSLionel Sambuc if (cursym == SYM_NONE) {
402*f4a2713aSLionel Sambuc cursym = SYM_ENDLOOP;
403*f4a2713aSLionel Sambuc } else {
404*f4a2713aSLionel Sambuc nextsym = SYM_ENDLOOP;
405*f4a2713aSLionel Sambuc }
406*f4a2713aSLionel Sambuc loop = 0;
407*f4a2713aSLionel Sambuc break;
408*f4a2713aSLionel Sambuc
409*f4a2713aSLionel Sambuc // Ignore other characters
410*f4a2713aSLionel Sambuc default:
411*f4a2713aSLionel Sambuc break;
412*f4a2713aSLionel Sambuc }
413*f4a2713aSLionel Sambuc }
414*f4a2713aSLionel Sambuc }
415*f4a2713aSLionel Sambuc }
416*f4a2713aSLionel Sambuc
417*f4a2713aSLionel Sambuc if (cursym == SYM_ENDLOOP) {
418*f4a2713aSLionel Sambuc if (!phi) {
419*f4a2713aSLionel Sambuc std::cerr << "Error: Extra ']'\n";
420*f4a2713aSLionel Sambuc abort();
421*f4a2713aSLionel Sambuc }
422*f4a2713aSLionel Sambuc
423*f4a2713aSLionel Sambuc // Write loop test
424*f4a2713aSLionel Sambuc {
425*f4a2713aSLionel Sambuc //br label %main.%d
426*f4a2713aSLionel Sambuc builder->CreateBr(testbb);
427*f4a2713aSLionel Sambuc
428*f4a2713aSLionel Sambuc //main.%d:
429*f4a2713aSLionel Sambuc
430*f4a2713aSLionel Sambuc //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
431*f4a2713aSLionel Sambuc //Finish phi made at beginning of loop
432*f4a2713aSLionel Sambuc phi->addIncoming(curhead, builder->GetInsertBlock());
433*f4a2713aSLionel Sambuc Value *head_0 = phi;
434*f4a2713aSLionel Sambuc
435*f4a2713aSLionel Sambuc //%tape.%d = load i8 *%head.%d
436*f4a2713aSLionel Sambuc LoadInst *tape_0 = new LoadInst(head_0, tapereg, testbb);
437*f4a2713aSLionel Sambuc
438*f4a2713aSLionel Sambuc //%test.%d = icmp eq i8 %tape.%d, 0
439*f4a2713aSLionel Sambuc ICmpInst *test_0 = new ICmpInst(*testbb, ICmpInst::ICMP_EQ, tape_0,
440*f4a2713aSLionel Sambuc ConstantInt::get(C, APInt(8, 0)), testreg);
441*f4a2713aSLionel Sambuc
442*f4a2713aSLionel Sambuc //br i1 %test.%d, label %main.%d, label %main.%d
443*f4a2713aSLionel Sambuc BasicBlock *bb_0 = BasicBlock::Create(C, label, brainf_func);
444*f4a2713aSLionel Sambuc BranchInst::Create(bb_0, oldbb, test_0, testbb);
445*f4a2713aSLionel Sambuc
446*f4a2713aSLionel Sambuc //main.%d:
447*f4a2713aSLionel Sambuc builder->SetInsertPoint(bb_0);
448*f4a2713aSLionel Sambuc
449*f4a2713aSLionel Sambuc //%head.%d = phi i8 *[%head.%d, %main.%d]
450*f4a2713aSLionel Sambuc PHINode *phi_1 = builder->
451*f4a2713aSLionel Sambuc CreatePHI(PointerType::getUnqual(IntegerType::getInt8Ty(C)), 1,
452*f4a2713aSLionel Sambuc headreg);
453*f4a2713aSLionel Sambuc phi_1->addIncoming(head_0, testbb);
454*f4a2713aSLionel Sambuc curhead = phi_1;
455*f4a2713aSLionel Sambuc }
456*f4a2713aSLionel Sambuc
457*f4a2713aSLionel Sambuc return;
458*f4a2713aSLionel Sambuc }
459*f4a2713aSLionel Sambuc
460*f4a2713aSLionel Sambuc //End of the program, so go to return block
461*f4a2713aSLionel Sambuc builder->CreateBr(endbb);
462*f4a2713aSLionel Sambuc
463*f4a2713aSLionel Sambuc if (phi) {
464*f4a2713aSLionel Sambuc std::cerr << "Error: Missing ']'\n";
465*f4a2713aSLionel Sambuc abort();
466*f4a2713aSLionel Sambuc }
467*f4a2713aSLionel Sambuc }
468