xref: /minix3/external/bsd/llvm/dist/llvm/examples/BrainF/BrainF.cpp (revision f4a2713ac843a11c696ec80c0a5e3e5d80b4d338)
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