12b8e4170SEugene Zelenko //===-- BrainF.cpp - BrainF compiler example ------------------------------===//
2909ef097SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6909ef097SChris Lattner //
72b8e4170SEugene Zelenko //===----------------------------------------------------------------------===//
8909ef097SChris Lattner //
9909ef097SChris Lattner // This class compiles the BrainF language into LLVM assembly.
10909ef097SChris Lattner //
11909ef097SChris Lattner // The BrainF language has 8 commands:
12909ef097SChris Lattner // Command   Equivalent C    Action
13909ef097SChris Lattner // -------   ------------    ------
14909ef097SChris Lattner // ,         *h=getchar();   Read a character from stdin, 255 on EOF
15909ef097SChris Lattner // .         putchar(*h);    Write a character to stdout
16909ef097SChris Lattner // -         --*h;           Decrement tape
17909ef097SChris Lattner // +         ++*h;           Increment tape
18909ef097SChris Lattner // <         --h;            Move head left
19909ef097SChris Lattner // >         ++h;            Move head right
20909ef097SChris Lattner // [         while(*h) {     Start loop
21909ef097SChris Lattner // ]         }               End loop
22909ef097SChris Lattner //
232b8e4170SEugene Zelenko //===----------------------------------------------------------------------===//
24909ef097SChris Lattner 
25909ef097SChris Lattner #include "BrainF.h"
262b8e4170SEugene Zelenko #include "llvm/ADT/APInt.h"
272b8e4170SEugene Zelenko #include "llvm/IR/BasicBlock.h"
282b8e4170SEugene Zelenko #include "llvm/IR/Constant.h"
29005f27a0SChandler Carruth #include "llvm/IR/Constants.h"
302b8e4170SEugene Zelenko #include "llvm/IR/DerivedTypes.h"
312b8e4170SEugene Zelenko #include "llvm/IR/Function.h"
322b8e4170SEugene Zelenko #include "llvm/IR/GlobalValue.h"
332b8e4170SEugene Zelenko #include "llvm/IR/GlobalVariable.h"
342b8e4170SEugene Zelenko #include "llvm/IR/InstrTypes.h"
352b8e4170SEugene Zelenko #include "llvm/IR/Instruction.h"
36005f27a0SChandler Carruth #include "llvm/IR/Instructions.h"
37005f27a0SChandler Carruth #include "llvm/IR/Intrinsics.h"
382b8e4170SEugene Zelenko #include "llvm/IR/Module.h"
392b8e4170SEugene Zelenko #include "llvm/IR/Type.h"
402b8e4170SEugene Zelenko #include "llvm/Support/Casting.h"
412b8e4170SEugene Zelenko #include <cstdlib>
428e8eae68SChris Lattner #include <iostream>
43cc9deb48SHans Wennborg 
44909ef097SChris Lattner using namespace llvm;
45909ef097SChris Lattner 
46909ef097SChris Lattner //Set the constants for naming
47909ef097SChris Lattner const char *BrainF::tapereg = "tape";
48909ef097SChris Lattner const char *BrainF::headreg = "head";
49909ef097SChris Lattner const char *BrainF::label   = "brainf";
50909ef097SChris Lattner const char *BrainF::testreg = "test";
51909ef097SChris Lattner 
parse(std::istream * in1,int mem,CompileFlags cf,LLVMContext & Context)526773d388SOwen Anderson Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf,
532a15443aSOwen Anderson                       LLVMContext& Context) {
54909ef097SChris Lattner   in       = in1;
55909ef097SChris Lattner   memtotal = mem;
56909ef097SChris Lattner   comflag  = cf;
57909ef097SChris Lattner 
586773d388SOwen Anderson   header(Context);
59cc9deb48SHans Wennborg   readloop(nullptr, nullptr, nullptr, Context);
60909ef097SChris Lattner   delete builder;
61909ef097SChris Lattner   return module;
62909ef097SChris Lattner }
63909ef097SChris Lattner 
header(LLVMContext & C)642a15443aSOwen Anderson void BrainF::header(LLVMContext& C) {
656773d388SOwen Anderson   module = new Module("BrainF", C);
66909ef097SChris Lattner 
67909ef097SChris Lattner   //Function prototypes
68909ef097SChris Lattner 
696d23f298SRicky Zhou   //declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i1)
70ce206000SFrancois Pichet   Type *Tys[] = { Type::getInt8PtrTy(C), Type::getInt32Ty(C) };
71dd708345SChris Lattner   Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset,
72e6e1933fSBenjamin Kramer                                                     Tys);
73909ef097SChris Lattner 
74909ef097SChris Lattner   //declare i32 @getchar()
7513680223SJames Y Knight   getchar_func =
7613680223SJames Y Knight       module->getOrInsertFunction("getchar", IntegerType::getInt32Ty(C));
77909ef097SChris Lattner 
78909ef097SChris Lattner   //declare i32 @putchar(i32)
7913680223SJames Y Knight   putchar_func = module->getOrInsertFunction(
8013680223SJames Y Knight       "putchar", IntegerType::getInt32Ty(C), IntegerType::getInt32Ty(C));
81909ef097SChris Lattner 
82909ef097SChris Lattner   //Function header
83909ef097SChris Lattner 
84909ef097SChris Lattner   //define void @brainf()
85473e3420SJames Y Knight   brainf_func = Function::Create(FunctionType::get(Type::getVoidTy(C), false),
86473e3420SJames Y Knight                                  Function::ExternalLinkage, "brainf", module);
87909ef097SChris Lattner 
8855f1c09eSOwen Anderson   builder = new IRBuilder<>(BasicBlock::Create(C, label, brainf_func));
89909ef097SChris Lattner 
90909ef097SChris Lattner   //%arr = malloc i8, i32 %d
91edb4a703SOwen Anderson   ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal));
92c7d6a832SVictor Hernandez   BasicBlock* BB = builder->GetInsertBlock();
93805d0945SChris Lattner   Type* IntPtrTy = IntegerType::getInt32Ty(C);
94805d0945SChris Lattner   Type* Int8Ty = IntegerType::getInt8Ty(C);
95f3db9152SVictor Hernandez   Constant* allocsize = ConstantExpr::getSizeOf(Int8Ty);
96f3db9152SVictor Hernandez   allocsize = ConstantExpr::getTruncOrBitCast(allocsize, IntPtrTy);
97f3db9152SVictor Hernandez   ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, Int8Ty, allocsize, val_mem,
98cc9deb48SHans Wennborg                                    nullptr, "arr");
99c7d6a832SVictor Hernandez   BB->getInstList().push_back(cast<Instruction>(ptr_arr));
100909ef097SChris Lattner 
1016d23f298SRicky Zhou   //call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i1 0)
102909ef097SChris Lattner   {
103909ef097SChris Lattner     Value *memset_params[] = {
104909ef097SChris Lattner       ptr_arr,
105edb4a703SOwen Anderson       ConstantInt::get(C, APInt(8, 0)),
106909ef097SChris Lattner       val_mem,
1070b6dce4eSChris Lattner       ConstantInt::get(C, APInt(1, 0))
108909ef097SChris Lattner     };
109909ef097SChris Lattner 
110909ef097SChris Lattner     CallInst *memset_call = builder->
111c5d10504SFrancois Pichet       CreateCall(memset_func, memset_params);
112909ef097SChris Lattner     memset_call->setTailCall(false);
113909ef097SChris Lattner   }
114909ef097SChris Lattner 
115909ef097SChris Lattner   //%arrmax = getelementptr i8 *%arr, i32 %d
116909ef097SChris Lattner   if (comflag & flag_arraybounds) {
117*649977c6SDavid Blaikie     ptr_arrmax = builder->CreateGEP(
118*649977c6SDavid Blaikie         Int8Ty, ptr_arr, ConstantInt::get(C, APInt(32, memtotal)), "arrmax");
119909ef097SChris Lattner   }
120909ef097SChris Lattner 
121909ef097SChris Lattner   //%head.%d = getelementptr i8 *%arr, i32 %d
122*649977c6SDavid Blaikie   curhead = builder->CreateGEP(
123*649977c6SDavid Blaikie       Int8Ty, ptr_arr, ConstantInt::get(C, APInt(32, memtotal / 2)), headreg);
124909ef097SChris Lattner 
125909ef097SChris Lattner   //Function footer
126909ef097SChris Lattner 
127909ef097SChris Lattner   //brainf.end:
12855f1c09eSOwen Anderson   endbb = BasicBlock::Create(C, label, brainf_func);
129909ef097SChris Lattner 
130de5ad42aSVictor Hernandez   //call free(i8 *%arr)
131de5ad42aSVictor Hernandez   endbb->getInstList().push_back(CallInst::CreateFree(ptr_arr, endbb));
132909ef097SChris Lattner 
133909ef097SChris Lattner   //ret void
13455f1c09eSOwen Anderson   ReturnInst::Create(C, endbb);
135909ef097SChris Lattner 
136909ef097SChris Lattner   //Error block for array out of bounds
137909ef097SChris Lattner   if (comflag & flag_arraybounds)
138909ef097SChris Lattner   {
139909ef097SChris Lattner     //@aberrormsg = internal constant [%d x i8] c"\00"
140b6b25300SOwen Anderson     Constant *msg_0 =
1414ce6e6efSFrancois Pichet       ConstantDataArray::getString(C, "Error: The head has left the tape.",
1424ce6e6efSFrancois Pichet                                    true);
143909ef097SChris Lattner 
144909ef097SChris Lattner     GlobalVariable *aberrormsg = new GlobalVariable(
145b17f3294SOwen Anderson       *module,
146909ef097SChris Lattner       msg_0->getType(),
147909ef097SChris Lattner       true,
148909ef097SChris Lattner       GlobalValue::InternalLinkage,
149909ef097SChris Lattner       msg_0,
150b17f3294SOwen Anderson       "aberrormsg");
151909ef097SChris Lattner 
152909ef097SChris Lattner     //declare i32 @puts(i8 *)
15313680223SJames Y Knight     FunctionCallee puts_func = module->getOrInsertFunction(
15413680223SJames Y Knight         "puts", IntegerType::getInt32Ty(C),
15513680223SJames Y Knight         PointerType::getUnqual(IntegerType::getInt8Ty(C)));
156909ef097SChris Lattner 
157909ef097SChris Lattner     //brainf.aberror:
15855f1c09eSOwen Anderson     aberrorbb = BasicBlock::Create(C, label, brainf_func);
159909ef097SChris Lattner 
160909ef097SChris Lattner     //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
161909ef097SChris Lattner     {
16255f1c09eSOwen Anderson       Constant *zero_32 = Constant::getNullValue(IntegerType::getInt32Ty(C));
163909ef097SChris Lattner 
164909ef097SChris Lattner       Constant *gep_params[] = {
165909ef097SChris Lattner         zero_32,
166909ef097SChris Lattner         zero_32
167909ef097SChris Lattner       };
168909ef097SChris Lattner 
169909ef097SChris Lattner       Constant *msgptr = ConstantExpr::
170696f2759SNAKAMURA Takumi         getGetElementPtr(aberrormsg->getValueType(), aberrormsg, gep_params);
171909ef097SChris Lattner 
172909ef097SChris Lattner       Value *puts_params[] = {
173909ef097SChris Lattner         msgptr
174909ef097SChris Lattner       };
175909ef097SChris Lattner 
176909ef097SChris Lattner       CallInst *puts_call =
177e9ecc68dSGabor Greif         CallInst::Create(puts_func,
178c5d10504SFrancois Pichet                          puts_params,
179909ef097SChris Lattner                          "", aberrorbb);
180909ef097SChris Lattner       puts_call->setTailCall(false);
181909ef097SChris Lattner     }
182909ef097SChris Lattner 
183909ef097SChris Lattner     //br label %brainf.end
184e9ecc68dSGabor Greif     BranchInst::Create(endbb, aberrorbb);
185909ef097SChris Lattner   }
186909ef097SChris Lattner }
187909ef097SChris Lattner 
readloop(PHINode * phi,BasicBlock * oldbb,BasicBlock * testbb,LLVMContext & C)188b6b25300SOwen Anderson void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb,
189b6b25300SOwen Anderson                       LLVMContext &C) {
190909ef097SChris Lattner   Symbol cursym = SYM_NONE;
191909ef097SChris Lattner   int curvalue = 0;
192909ef097SChris Lattner   Symbol nextsym = SYM_NONE;
193909ef097SChris Lattner   int nextvalue = 0;
194909ef097SChris Lattner   char c;
195909ef097SChris Lattner   int loop;
196909ef097SChris Lattner   int direction;
197*649977c6SDavid Blaikie   Type *Int8Ty = IntegerType::getInt8Ty(C);
198909ef097SChris Lattner 
199909ef097SChris Lattner   while(cursym != SYM_EOF && cursym != SYM_ENDLOOP) {
200909ef097SChris Lattner     // Write out commands
201909ef097SChris Lattner     switch(cursym) {
202909ef097SChris Lattner       case SYM_NONE:
203909ef097SChris Lattner         // Do nothing
204909ef097SChris Lattner         break;
205909ef097SChris Lattner 
206909ef097SChris Lattner       case SYM_READ:
207909ef097SChris Lattner         {
208909ef097SChris Lattner           //%tape.%d = call i32 @getchar()
2095b9bc2f8SNAKAMURA Takumi           CallInst *getchar_call =
2105b9bc2f8SNAKAMURA Takumi               builder->CreateCall(getchar_func, {}, tapereg);
211909ef097SChris Lattner           getchar_call->setTailCall(false);
212909ef097SChris Lattner           Value *tape_0 = getchar_call;
213909ef097SChris Lattner 
214909ef097SChris Lattner           //%tape.%d = trunc i32 %tape.%d to i8
215a07136eeSDuncan Sands           Value *tape_1 = builder->
21655f1c09eSOwen Anderson             CreateTrunc(tape_0, IntegerType::getInt8Ty(C), tapereg);
217909ef097SChris Lattner 
218909ef097SChris Lattner           //store i8 %tape.%d, i8 *%head.%d
219909ef097SChris Lattner           builder->CreateStore(tape_1, curhead);
220909ef097SChris Lattner         }
221909ef097SChris Lattner         break;
222909ef097SChris Lattner 
223909ef097SChris Lattner       case SYM_WRITE:
224909ef097SChris Lattner         {
225909ef097SChris Lattner           //%tape.%d = load i8 *%head.%d
226*649977c6SDavid Blaikie           LoadInst *tape_0 = builder->CreateLoad(Int8Ty, curhead, tapereg);
227909ef097SChris Lattner 
228909ef097SChris Lattner           //%tape.%d = sext i8 %tape.%d to i32
229a07136eeSDuncan Sands           Value *tape_1 = builder->
23055f1c09eSOwen Anderson             CreateSExt(tape_0, IntegerType::getInt32Ty(C), tapereg);
231909ef097SChris Lattner 
232909ef097SChris Lattner           //call i32 @putchar(i32 %tape.%d)
233909ef097SChris Lattner           Value *putchar_params[] = {
234909ef097SChris Lattner             tape_1
235909ef097SChris Lattner           };
236909ef097SChris Lattner           CallInst *putchar_call = builder->
237909ef097SChris Lattner             CreateCall(putchar_func,
238c5d10504SFrancois Pichet                        putchar_params);
239909ef097SChris Lattner           putchar_call->setTailCall(false);
240909ef097SChris Lattner         }
241909ef097SChris Lattner         break;
242909ef097SChris Lattner 
243909ef097SChris Lattner       case SYM_MOVE:
244909ef097SChris Lattner         {
245909ef097SChris Lattner           //%head.%d = getelementptr i8 *%head.%d, i32 %d
246*649977c6SDavid Blaikie           curhead = builder->CreateGEP(Int8Ty, curhead,
247*649977c6SDavid Blaikie                                        ConstantInt::get(C, APInt(32, curvalue)),
248909ef097SChris Lattner                                        headreg);
249909ef097SChris Lattner 
250909ef097SChris Lattner           //Error block for array out of bounds
251909ef097SChris Lattner           if (comflag & flag_arraybounds)
252909ef097SChris Lattner           {
253909ef097SChris Lattner             //%test.%d = icmp uge i8 *%head.%d, %arrmax
254a07136eeSDuncan Sands             Value *test_0 = builder->
255909ef097SChris Lattner               CreateICmpUGE(curhead, ptr_arrmax, testreg);
256909ef097SChris Lattner 
257909ef097SChris Lattner             //%test.%d = icmp ult i8 *%head.%d, %arr
258a07136eeSDuncan Sands             Value *test_1 = builder->
259909ef097SChris Lattner               CreateICmpULT(curhead, ptr_arr, testreg);
260909ef097SChris Lattner 
261909ef097SChris Lattner             //%test.%d = or i1 %test.%d, %test.%d
262a07136eeSDuncan Sands             Value *test_2 = builder->
263909ef097SChris Lattner               CreateOr(test_0, test_1, testreg);
264909ef097SChris Lattner 
265909ef097SChris Lattner             //br i1 %test.%d, label %main.%d, label %main.%d
26655f1c09eSOwen Anderson             BasicBlock *nextbb = BasicBlock::Create(C, label, brainf_func);
267909ef097SChris Lattner             builder->CreateCondBr(test_2, aberrorbb, nextbb);
268909ef097SChris Lattner 
269909ef097SChris Lattner             //main.%d:
270909ef097SChris Lattner             builder->SetInsertPoint(nextbb);
271909ef097SChris Lattner           }
272909ef097SChris Lattner         }
273909ef097SChris Lattner         break;
274909ef097SChris Lattner 
275909ef097SChris Lattner       case SYM_CHANGE:
276909ef097SChris Lattner         {
277909ef097SChris Lattner           //%tape.%d = load i8 *%head.%d
278*649977c6SDavid Blaikie           LoadInst *tape_0 = builder->CreateLoad(Int8Ty, curhead, tapereg);
279909ef097SChris Lattner 
280909ef097SChris Lattner           //%tape.%d = add i8 %tape.%d, %d
281a07136eeSDuncan Sands           Value *tape_1 = builder->
282edb4a703SOwen Anderson             CreateAdd(tape_0, ConstantInt::get(C, APInt(8, curvalue)), tapereg);
283909ef097SChris Lattner 
284909ef097SChris Lattner           //store i8 %tape.%d, i8 *%head.%d\n"
285909ef097SChris Lattner           builder->CreateStore(tape_1, curhead);
286909ef097SChris Lattner         }
287909ef097SChris Lattner         break;
288909ef097SChris Lattner 
289909ef097SChris Lattner       case SYM_LOOP:
290909ef097SChris Lattner         {
291909ef097SChris Lattner           //br label %main.%d
29255f1c09eSOwen Anderson           BasicBlock *testbb = BasicBlock::Create(C, label, brainf_func);
293909ef097SChris Lattner           builder->CreateBr(testbb);
294909ef097SChris Lattner 
295909ef097SChris Lattner           //main.%d:
296909ef097SChris Lattner           BasicBlock *bb_0 = builder->GetInsertBlock();
29755f1c09eSOwen Anderson           BasicBlock *bb_1 = BasicBlock::Create(C, label, brainf_func);
298909ef097SChris Lattner           builder->SetInsertPoint(bb_1);
299909ef097SChris Lattner 
300909ef097SChris Lattner           // Make part of PHI instruction now, wait until end of loop to finish
301*649977c6SDavid Blaikie           PHINode *phi_0 = PHINode::Create(PointerType::getUnqual(Int8Ty), 2,
302*649977c6SDavid Blaikie                                            headreg, testbb);
303909ef097SChris Lattner           phi_0->addIncoming(curhead, bb_0);
304909ef097SChris Lattner           curhead = phi_0;
305909ef097SChris Lattner 
306b6b25300SOwen Anderson           readloop(phi_0, bb_1, testbb, C);
307909ef097SChris Lattner         }
308909ef097SChris Lattner         break;
309909ef097SChris Lattner 
310909ef097SChris Lattner       default:
3118e8eae68SChris Lattner         std::cerr << "Error: Unknown symbol.\n";
312909ef097SChris Lattner         abort();
313909ef097SChris Lattner         break;
314909ef097SChris Lattner     }
315909ef097SChris Lattner 
316909ef097SChris Lattner     cursym = nextsym;
317909ef097SChris Lattner     curvalue = nextvalue;
318909ef097SChris Lattner     nextsym = SYM_NONE;
319909ef097SChris Lattner 
320909ef097SChris Lattner     // Reading stdin loop
321909ef097SChris Lattner     loop = (cursym == SYM_NONE)
322909ef097SChris Lattner         || (cursym == SYM_MOVE)
323909ef097SChris Lattner         || (cursym == SYM_CHANGE);
324909ef097SChris Lattner     while(loop) {
325909ef097SChris Lattner       *in>>c;
326909ef097SChris Lattner       if (in->eof()) {
327909ef097SChris Lattner         if (cursym == SYM_NONE) {
328909ef097SChris Lattner           cursym = SYM_EOF;
329909ef097SChris Lattner         } else {
330909ef097SChris Lattner           nextsym = SYM_EOF;
331909ef097SChris Lattner         }
332909ef097SChris Lattner         loop = 0;
333909ef097SChris Lattner       } else {
334909ef097SChris Lattner         direction = 1;
335909ef097SChris Lattner         switch(c) {
336909ef097SChris Lattner           case '-':
337909ef097SChris Lattner             direction = -1;
338cd1d5aafSJustin Bogner             LLVM_FALLTHROUGH;
339909ef097SChris Lattner 
340909ef097SChris Lattner           case '+':
341909ef097SChris Lattner             if (cursym == SYM_CHANGE) {
342909ef097SChris Lattner               curvalue += direction;
343909ef097SChris Lattner               // loop = 1
344909ef097SChris Lattner             } else {
345909ef097SChris Lattner               if (cursym == SYM_NONE) {
346909ef097SChris Lattner                 cursym = SYM_CHANGE;
347909ef097SChris Lattner                 curvalue = direction;
348909ef097SChris Lattner                 // loop = 1
349909ef097SChris Lattner               } else {
350909ef097SChris Lattner                 nextsym = SYM_CHANGE;
351909ef097SChris Lattner                 nextvalue = direction;
352909ef097SChris Lattner                 loop = 0;
353909ef097SChris Lattner               }
354909ef097SChris Lattner             }
355909ef097SChris Lattner             break;
356909ef097SChris Lattner 
357909ef097SChris Lattner           case '<':
358909ef097SChris Lattner             direction = -1;
359cd1d5aafSJustin Bogner             LLVM_FALLTHROUGH;
360909ef097SChris Lattner 
361909ef097SChris Lattner           case '>':
362909ef097SChris Lattner             if (cursym == SYM_MOVE) {
363909ef097SChris Lattner               curvalue += direction;
364909ef097SChris Lattner               // loop = 1
365909ef097SChris Lattner             } else {
366909ef097SChris Lattner               if (cursym == SYM_NONE) {
367909ef097SChris Lattner                 cursym = SYM_MOVE;
368909ef097SChris Lattner                 curvalue = direction;
369909ef097SChris Lattner                 // loop = 1
370909ef097SChris Lattner               } else {
371909ef097SChris Lattner                 nextsym = SYM_MOVE;
372909ef097SChris Lattner                 nextvalue = direction;
373909ef097SChris Lattner                 loop = 0;
374909ef097SChris Lattner               }
375909ef097SChris Lattner             }
376909ef097SChris Lattner             break;
377909ef097SChris Lattner 
378909ef097SChris Lattner           case ',':
379909ef097SChris Lattner             if (cursym == SYM_NONE) {
380909ef097SChris Lattner               cursym = SYM_READ;
381909ef097SChris Lattner             } else {
382909ef097SChris Lattner               nextsym = SYM_READ;
383909ef097SChris Lattner             }
384909ef097SChris Lattner             loop = 0;
385909ef097SChris Lattner             break;
386909ef097SChris Lattner 
387909ef097SChris Lattner           case '.':
388909ef097SChris Lattner             if (cursym == SYM_NONE) {
389909ef097SChris Lattner               cursym = SYM_WRITE;
390909ef097SChris Lattner             } else {
391909ef097SChris Lattner               nextsym = SYM_WRITE;
392909ef097SChris Lattner             }
393909ef097SChris Lattner             loop = 0;
394909ef097SChris Lattner             break;
395909ef097SChris Lattner 
396909ef097SChris Lattner           case '[':
397909ef097SChris Lattner             if (cursym == SYM_NONE) {
398909ef097SChris Lattner               cursym = SYM_LOOP;
399909ef097SChris Lattner             } else {
400909ef097SChris Lattner               nextsym = SYM_LOOP;
401909ef097SChris Lattner             }
402909ef097SChris Lattner             loop = 0;
403909ef097SChris Lattner             break;
404909ef097SChris Lattner 
405909ef097SChris Lattner           case ']':
406909ef097SChris Lattner             if (cursym == SYM_NONE) {
407909ef097SChris Lattner               cursym = SYM_ENDLOOP;
408909ef097SChris Lattner             } else {
409909ef097SChris Lattner               nextsym = SYM_ENDLOOP;
410909ef097SChris Lattner             }
411909ef097SChris Lattner             loop = 0;
412909ef097SChris Lattner             break;
413909ef097SChris Lattner 
414909ef097SChris Lattner           // Ignore other characters
415909ef097SChris Lattner           default:
416909ef097SChris Lattner             break;
417909ef097SChris Lattner         }
418909ef097SChris Lattner       }
419909ef097SChris Lattner     }
420909ef097SChris Lattner   }
421909ef097SChris Lattner 
422909ef097SChris Lattner   if (cursym == SYM_ENDLOOP) {
423909ef097SChris Lattner     if (!phi) {
4248e8eae68SChris Lattner       std::cerr << "Error: Extra ']'\n";
425909ef097SChris Lattner       abort();
426909ef097SChris Lattner     }
427909ef097SChris Lattner 
428909ef097SChris Lattner     // Write loop test
429909ef097SChris Lattner     {
430909ef097SChris Lattner       //br label %main.%d
431909ef097SChris Lattner       builder->CreateBr(testbb);
432909ef097SChris Lattner 
433909ef097SChris Lattner       //main.%d:
434909ef097SChris Lattner 
435909ef097SChris Lattner       //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
436909ef097SChris Lattner       //Finish phi made at beginning of loop
437909ef097SChris Lattner       phi->addIncoming(curhead, builder->GetInsertBlock());
438909ef097SChris Lattner       Value *head_0 = phi;
439909ef097SChris Lattner 
440909ef097SChris Lattner       //%tape.%d = load i8 *%head.%d
441*649977c6SDavid Blaikie       LoadInst *tape_0 = new LoadInst(Int8Ty, head_0, tapereg, testbb);
442909ef097SChris Lattner 
443909ef097SChris Lattner       //%test.%d = icmp eq i8 %tape.%d, 0
4441e5f00e7SOwen Anderson       ICmpInst *test_0 = new ICmpInst(*testbb, ICmpInst::ICMP_EQ, tape_0,
445edb4a703SOwen Anderson                                     ConstantInt::get(C, APInt(8, 0)), testreg);
446909ef097SChris Lattner 
447909ef097SChris Lattner       //br i1 %test.%d, label %main.%d, label %main.%d
44855f1c09eSOwen Anderson       BasicBlock *bb_0 = BasicBlock::Create(C, label, brainf_func);
449e9ecc68dSGabor Greif       BranchInst::Create(bb_0, oldbb, test_0, testbb);
450909ef097SChris Lattner 
451909ef097SChris Lattner       //main.%d:
452909ef097SChris Lattner       builder->SetInsertPoint(bb_0);
453909ef097SChris Lattner 
454909ef097SChris Lattner       //%head.%d = phi i8 *[%head.%d, %main.%d]
455*649977c6SDavid Blaikie       PHINode *phi_1 =
456*649977c6SDavid Blaikie           builder->CreatePHI(PointerType::getUnqual(Int8Ty), 1, headreg);
457909ef097SChris Lattner       phi_1->addIncoming(head_0, testbb);
458909ef097SChris Lattner       curhead = phi_1;
459909ef097SChris Lattner     }
460909ef097SChris Lattner 
461909ef097SChris Lattner     return;
462909ef097SChris Lattner   }
463909ef097SChris Lattner 
464909ef097SChris Lattner   //End of the program, so go to return block
465909ef097SChris Lattner   builder->CreateBr(endbb);
466909ef097SChris Lattner 
467909ef097SChris Lattner   if (phi) {
4688e8eae68SChris Lattner     std::cerr << "Error: Missing ']'\n";
469909ef097SChris Lattner     abort();
470909ef097SChris Lattner   }
471909ef097SChris Lattner }
472