xref: /netbsd-src/external/apache2/llvm/dist/llvm/examples/BrainF/BrainF.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
17330f729Sjoerg //===-- BrainF.cpp - BrainF compiler example ------------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This class compiles the BrainF language into LLVM assembly.
107330f729Sjoerg //
117330f729Sjoerg // The BrainF language has 8 commands:
127330f729Sjoerg // Command   Equivalent C    Action
137330f729Sjoerg // -------   ------------    ------
147330f729Sjoerg // ,         *h=getchar();   Read a character from stdin, 255 on EOF
157330f729Sjoerg // .         putchar(*h);    Write a character to stdout
167330f729Sjoerg // -         --*h;           Decrement tape
177330f729Sjoerg // +         ++*h;           Increment tape
187330f729Sjoerg // <         --h;            Move head left
197330f729Sjoerg // >         ++h;            Move head right
207330f729Sjoerg // [         while(*h) {     Start loop
217330f729Sjoerg // ]         }               End loop
227330f729Sjoerg //
237330f729Sjoerg //===----------------------------------------------------------------------===//
247330f729Sjoerg 
257330f729Sjoerg #include "BrainF.h"
267330f729Sjoerg #include "llvm/ADT/APInt.h"
277330f729Sjoerg #include "llvm/IR/BasicBlock.h"
287330f729Sjoerg #include "llvm/IR/Constant.h"
297330f729Sjoerg #include "llvm/IR/Constants.h"
307330f729Sjoerg #include "llvm/IR/DerivedTypes.h"
317330f729Sjoerg #include "llvm/IR/Function.h"
327330f729Sjoerg #include "llvm/IR/GlobalValue.h"
337330f729Sjoerg #include "llvm/IR/GlobalVariable.h"
347330f729Sjoerg #include "llvm/IR/InstrTypes.h"
357330f729Sjoerg #include "llvm/IR/Instruction.h"
367330f729Sjoerg #include "llvm/IR/Instructions.h"
377330f729Sjoerg #include "llvm/IR/Intrinsics.h"
387330f729Sjoerg #include "llvm/IR/Module.h"
397330f729Sjoerg #include "llvm/IR/Type.h"
407330f729Sjoerg #include "llvm/Support/Casting.h"
417330f729Sjoerg #include <cstdlib>
427330f729Sjoerg #include <iostream>
437330f729Sjoerg 
447330f729Sjoerg using namespace llvm;
457330f729Sjoerg 
467330f729Sjoerg //Set the constants for naming
477330f729Sjoerg const char *BrainF::tapereg = "tape";
487330f729Sjoerg const char *BrainF::headreg = "head";
497330f729Sjoerg const char *BrainF::label   = "brainf";
507330f729Sjoerg const char *BrainF::testreg = "test";
517330f729Sjoerg 
parse(std::istream * in1,int mem,CompileFlags cf,LLVMContext & Context)527330f729Sjoerg Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf,
537330f729Sjoerg                       LLVMContext& Context) {
547330f729Sjoerg   in       = in1;
557330f729Sjoerg   memtotal = mem;
567330f729Sjoerg   comflag  = cf;
577330f729Sjoerg 
587330f729Sjoerg   header(Context);
597330f729Sjoerg   readloop(nullptr, nullptr, nullptr, Context);
607330f729Sjoerg   delete builder;
617330f729Sjoerg   return module;
627330f729Sjoerg }
637330f729Sjoerg 
header(LLVMContext & C)647330f729Sjoerg void BrainF::header(LLVMContext& C) {
657330f729Sjoerg   module = new Module("BrainF", C);
667330f729Sjoerg 
677330f729Sjoerg   //Function prototypes
687330f729Sjoerg 
69*82d56013Sjoerg   //declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i1)
707330f729Sjoerg   Type *Tys[] = { Type::getInt8PtrTy(C), Type::getInt32Ty(C) };
717330f729Sjoerg   Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset,
727330f729Sjoerg                                                     Tys);
737330f729Sjoerg 
747330f729Sjoerg   //declare i32 @getchar()
757330f729Sjoerg   getchar_func =
767330f729Sjoerg       module->getOrInsertFunction("getchar", IntegerType::getInt32Ty(C));
777330f729Sjoerg 
787330f729Sjoerg   //declare i32 @putchar(i32)
797330f729Sjoerg   putchar_func = module->getOrInsertFunction(
807330f729Sjoerg       "putchar", IntegerType::getInt32Ty(C), IntegerType::getInt32Ty(C));
817330f729Sjoerg 
827330f729Sjoerg   //Function header
837330f729Sjoerg 
847330f729Sjoerg   //define void @brainf()
857330f729Sjoerg   brainf_func = Function::Create(FunctionType::get(Type::getVoidTy(C), false),
867330f729Sjoerg                                  Function::ExternalLinkage, "brainf", module);
877330f729Sjoerg 
887330f729Sjoerg   builder = new IRBuilder<>(BasicBlock::Create(C, label, brainf_func));
897330f729Sjoerg 
907330f729Sjoerg   //%arr = malloc i8, i32 %d
917330f729Sjoerg   ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal));
927330f729Sjoerg   BasicBlock* BB = builder->GetInsertBlock();
937330f729Sjoerg   Type* IntPtrTy = IntegerType::getInt32Ty(C);
947330f729Sjoerg   Type* Int8Ty = IntegerType::getInt8Ty(C);
957330f729Sjoerg   Constant* allocsize = ConstantExpr::getSizeOf(Int8Ty);
967330f729Sjoerg   allocsize = ConstantExpr::getTruncOrBitCast(allocsize, IntPtrTy);
977330f729Sjoerg   ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, Int8Ty, allocsize, val_mem,
987330f729Sjoerg                                    nullptr, "arr");
997330f729Sjoerg   BB->getInstList().push_back(cast<Instruction>(ptr_arr));
1007330f729Sjoerg 
101*82d56013Sjoerg   //call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i1 0)
1027330f729Sjoerg   {
1037330f729Sjoerg     Value *memset_params[] = {
1047330f729Sjoerg       ptr_arr,
1057330f729Sjoerg       ConstantInt::get(C, APInt(8, 0)),
1067330f729Sjoerg       val_mem,
1077330f729Sjoerg       ConstantInt::get(C, APInt(1, 0))
1087330f729Sjoerg     };
1097330f729Sjoerg 
1107330f729Sjoerg     CallInst *memset_call = builder->
1117330f729Sjoerg       CreateCall(memset_func, memset_params);
1127330f729Sjoerg     memset_call->setTailCall(false);
1137330f729Sjoerg   }
1147330f729Sjoerg 
1157330f729Sjoerg   //%arrmax = getelementptr i8 *%arr, i32 %d
1167330f729Sjoerg   if (comflag & flag_arraybounds) {
1177330f729Sjoerg     ptr_arrmax = builder->
1187330f729Sjoerg       CreateGEP(ptr_arr, ConstantInt::get(C, APInt(32, memtotal)), "arrmax");
1197330f729Sjoerg   }
1207330f729Sjoerg 
1217330f729Sjoerg   //%head.%d = getelementptr i8 *%arr, i32 %d
1227330f729Sjoerg   curhead = builder->CreateGEP(ptr_arr,
1237330f729Sjoerg                                ConstantInt::get(C, APInt(32, memtotal/2)),
1247330f729Sjoerg                                headreg);
1257330f729Sjoerg 
1267330f729Sjoerg   //Function footer
1277330f729Sjoerg 
1287330f729Sjoerg   //brainf.end:
1297330f729Sjoerg   endbb = BasicBlock::Create(C, label, brainf_func);
1307330f729Sjoerg 
1317330f729Sjoerg   //call free(i8 *%arr)
1327330f729Sjoerg   endbb->getInstList().push_back(CallInst::CreateFree(ptr_arr, endbb));
1337330f729Sjoerg 
1347330f729Sjoerg   //ret void
1357330f729Sjoerg   ReturnInst::Create(C, endbb);
1367330f729Sjoerg 
1377330f729Sjoerg   //Error block for array out of bounds
1387330f729Sjoerg   if (comflag & flag_arraybounds)
1397330f729Sjoerg   {
1407330f729Sjoerg     //@aberrormsg = internal constant [%d x i8] c"\00"
1417330f729Sjoerg     Constant *msg_0 =
1427330f729Sjoerg       ConstantDataArray::getString(C, "Error: The head has left the tape.",
1437330f729Sjoerg                                    true);
1447330f729Sjoerg 
1457330f729Sjoerg     GlobalVariable *aberrormsg = new GlobalVariable(
1467330f729Sjoerg       *module,
1477330f729Sjoerg       msg_0->getType(),
1487330f729Sjoerg       true,
1497330f729Sjoerg       GlobalValue::InternalLinkage,
1507330f729Sjoerg       msg_0,
1517330f729Sjoerg       "aberrormsg");
1527330f729Sjoerg 
1537330f729Sjoerg     //declare i32 @puts(i8 *)
1547330f729Sjoerg     FunctionCallee puts_func = module->getOrInsertFunction(
1557330f729Sjoerg         "puts", IntegerType::getInt32Ty(C),
1567330f729Sjoerg         PointerType::getUnqual(IntegerType::getInt8Ty(C)));
1577330f729Sjoerg 
1587330f729Sjoerg     //brainf.aberror:
1597330f729Sjoerg     aberrorbb = BasicBlock::Create(C, label, brainf_func);
1607330f729Sjoerg 
1617330f729Sjoerg     //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
1627330f729Sjoerg     {
1637330f729Sjoerg       Constant *zero_32 = Constant::getNullValue(IntegerType::getInt32Ty(C));
1647330f729Sjoerg 
1657330f729Sjoerg       Constant *gep_params[] = {
1667330f729Sjoerg         zero_32,
1677330f729Sjoerg         zero_32
1687330f729Sjoerg       };
1697330f729Sjoerg 
1707330f729Sjoerg       Constant *msgptr = ConstantExpr::
1717330f729Sjoerg         getGetElementPtr(aberrormsg->getValueType(), aberrormsg, gep_params);
1727330f729Sjoerg 
1737330f729Sjoerg       Value *puts_params[] = {
1747330f729Sjoerg         msgptr
1757330f729Sjoerg       };
1767330f729Sjoerg 
1777330f729Sjoerg       CallInst *puts_call =
1787330f729Sjoerg         CallInst::Create(puts_func,
1797330f729Sjoerg                          puts_params,
1807330f729Sjoerg                          "", aberrorbb);
1817330f729Sjoerg       puts_call->setTailCall(false);
1827330f729Sjoerg     }
1837330f729Sjoerg 
1847330f729Sjoerg     //br label %brainf.end
1857330f729Sjoerg     BranchInst::Create(endbb, aberrorbb);
1867330f729Sjoerg   }
1877330f729Sjoerg }
1887330f729Sjoerg 
readloop(PHINode * phi,BasicBlock * oldbb,BasicBlock * testbb,LLVMContext & C)1897330f729Sjoerg void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb,
1907330f729Sjoerg                       LLVMContext &C) {
1917330f729Sjoerg   Symbol cursym = SYM_NONE;
1927330f729Sjoerg   int curvalue = 0;
1937330f729Sjoerg   Symbol nextsym = SYM_NONE;
1947330f729Sjoerg   int nextvalue = 0;
1957330f729Sjoerg   char c;
1967330f729Sjoerg   int loop;
1977330f729Sjoerg   int direction;
1987330f729Sjoerg 
1997330f729Sjoerg   while(cursym != SYM_EOF && cursym != SYM_ENDLOOP) {
2007330f729Sjoerg     // Write out commands
2017330f729Sjoerg     switch(cursym) {
2027330f729Sjoerg       case SYM_NONE:
2037330f729Sjoerg         // Do nothing
2047330f729Sjoerg         break;
2057330f729Sjoerg 
2067330f729Sjoerg       case SYM_READ:
2077330f729Sjoerg         {
2087330f729Sjoerg           //%tape.%d = call i32 @getchar()
2097330f729Sjoerg           CallInst *getchar_call =
2107330f729Sjoerg               builder->CreateCall(getchar_func, {}, tapereg);
2117330f729Sjoerg           getchar_call->setTailCall(false);
2127330f729Sjoerg           Value *tape_0 = getchar_call;
2137330f729Sjoerg 
2147330f729Sjoerg           //%tape.%d = trunc i32 %tape.%d to i8
2157330f729Sjoerg           Value *tape_1 = builder->
2167330f729Sjoerg             CreateTrunc(tape_0, IntegerType::getInt8Ty(C), tapereg);
2177330f729Sjoerg 
2187330f729Sjoerg           //store i8 %tape.%d, i8 *%head.%d
2197330f729Sjoerg           builder->CreateStore(tape_1, curhead);
2207330f729Sjoerg         }
2217330f729Sjoerg         break;
2227330f729Sjoerg 
2237330f729Sjoerg       case SYM_WRITE:
2247330f729Sjoerg         {
2257330f729Sjoerg           //%tape.%d = load i8 *%head.%d
226*82d56013Sjoerg           LoadInst *tape_0 =
227*82d56013Sjoerg               builder->CreateLoad(IntegerType::getInt8Ty(C), curhead, tapereg);
2287330f729Sjoerg 
2297330f729Sjoerg           //%tape.%d = sext i8 %tape.%d to i32
2307330f729Sjoerg           Value *tape_1 = builder->
2317330f729Sjoerg             CreateSExt(tape_0, IntegerType::getInt32Ty(C), tapereg);
2327330f729Sjoerg 
2337330f729Sjoerg           //call i32 @putchar(i32 %tape.%d)
2347330f729Sjoerg           Value *putchar_params[] = {
2357330f729Sjoerg             tape_1
2367330f729Sjoerg           };
2377330f729Sjoerg           CallInst *putchar_call = builder->
2387330f729Sjoerg             CreateCall(putchar_func,
2397330f729Sjoerg                        putchar_params);
2407330f729Sjoerg           putchar_call->setTailCall(false);
2417330f729Sjoerg         }
2427330f729Sjoerg         break;
2437330f729Sjoerg 
2447330f729Sjoerg       case SYM_MOVE:
2457330f729Sjoerg         {
2467330f729Sjoerg           //%head.%d = getelementptr i8 *%head.%d, i32 %d
2477330f729Sjoerg           curhead = builder->
2487330f729Sjoerg             CreateGEP(curhead, ConstantInt::get(C, APInt(32, curvalue)),
2497330f729Sjoerg                       headreg);
2507330f729Sjoerg 
2517330f729Sjoerg           //Error block for array out of bounds
2527330f729Sjoerg           if (comflag & flag_arraybounds)
2537330f729Sjoerg           {
2547330f729Sjoerg             //%test.%d = icmp uge i8 *%head.%d, %arrmax
2557330f729Sjoerg             Value *test_0 = builder->
2567330f729Sjoerg               CreateICmpUGE(curhead, ptr_arrmax, testreg);
2577330f729Sjoerg 
2587330f729Sjoerg             //%test.%d = icmp ult i8 *%head.%d, %arr
2597330f729Sjoerg             Value *test_1 = builder->
2607330f729Sjoerg               CreateICmpULT(curhead, ptr_arr, testreg);
2617330f729Sjoerg 
2627330f729Sjoerg             //%test.%d = or i1 %test.%d, %test.%d
2637330f729Sjoerg             Value *test_2 = builder->
2647330f729Sjoerg               CreateOr(test_0, test_1, testreg);
2657330f729Sjoerg 
2667330f729Sjoerg             //br i1 %test.%d, label %main.%d, label %main.%d
2677330f729Sjoerg             BasicBlock *nextbb = BasicBlock::Create(C, label, brainf_func);
2687330f729Sjoerg             builder->CreateCondBr(test_2, aberrorbb, nextbb);
2697330f729Sjoerg 
2707330f729Sjoerg             //main.%d:
2717330f729Sjoerg             builder->SetInsertPoint(nextbb);
2727330f729Sjoerg           }
2737330f729Sjoerg         }
2747330f729Sjoerg         break;
2757330f729Sjoerg 
2767330f729Sjoerg       case SYM_CHANGE:
2777330f729Sjoerg         {
2787330f729Sjoerg           //%tape.%d = load i8 *%head.%d
279*82d56013Sjoerg           LoadInst *tape_0 =
280*82d56013Sjoerg               builder->CreateLoad(IntegerType::getInt8Ty(C), curhead, tapereg);
2817330f729Sjoerg 
2827330f729Sjoerg           //%tape.%d = add i8 %tape.%d, %d
2837330f729Sjoerg           Value *tape_1 = builder->
2847330f729Sjoerg             CreateAdd(tape_0, ConstantInt::get(C, APInt(8, curvalue)), tapereg);
2857330f729Sjoerg 
2867330f729Sjoerg           //store i8 %tape.%d, i8 *%head.%d\n"
2877330f729Sjoerg           builder->CreateStore(tape_1, curhead);
2887330f729Sjoerg         }
2897330f729Sjoerg         break;
2907330f729Sjoerg 
2917330f729Sjoerg       case SYM_LOOP:
2927330f729Sjoerg         {
2937330f729Sjoerg           //br label %main.%d
2947330f729Sjoerg           BasicBlock *testbb = BasicBlock::Create(C, label, brainf_func);
2957330f729Sjoerg           builder->CreateBr(testbb);
2967330f729Sjoerg 
2977330f729Sjoerg           //main.%d:
2987330f729Sjoerg           BasicBlock *bb_0 = builder->GetInsertBlock();
2997330f729Sjoerg           BasicBlock *bb_1 = BasicBlock::Create(C, label, brainf_func);
3007330f729Sjoerg           builder->SetInsertPoint(bb_1);
3017330f729Sjoerg 
3027330f729Sjoerg           // Make part of PHI instruction now, wait until end of loop to finish
3037330f729Sjoerg           PHINode *phi_0 =
3047330f729Sjoerg             PHINode::Create(PointerType::getUnqual(IntegerType::getInt8Ty(C)),
3057330f729Sjoerg                             2, headreg, testbb);
3067330f729Sjoerg           phi_0->addIncoming(curhead, bb_0);
3077330f729Sjoerg           curhead = phi_0;
3087330f729Sjoerg 
3097330f729Sjoerg           readloop(phi_0, bb_1, testbb, C);
3107330f729Sjoerg         }
3117330f729Sjoerg         break;
3127330f729Sjoerg 
3137330f729Sjoerg       default:
3147330f729Sjoerg         std::cerr << "Error: Unknown symbol.\n";
3157330f729Sjoerg         abort();
3167330f729Sjoerg         break;
3177330f729Sjoerg     }
3187330f729Sjoerg 
3197330f729Sjoerg     cursym = nextsym;
3207330f729Sjoerg     curvalue = nextvalue;
3217330f729Sjoerg     nextsym = SYM_NONE;
3227330f729Sjoerg 
3237330f729Sjoerg     // Reading stdin loop
3247330f729Sjoerg     loop = (cursym == SYM_NONE)
3257330f729Sjoerg         || (cursym == SYM_MOVE)
3267330f729Sjoerg         || (cursym == SYM_CHANGE);
3277330f729Sjoerg     while(loop) {
3287330f729Sjoerg       *in>>c;
3297330f729Sjoerg       if (in->eof()) {
3307330f729Sjoerg         if (cursym == SYM_NONE) {
3317330f729Sjoerg           cursym = SYM_EOF;
3327330f729Sjoerg         } else {
3337330f729Sjoerg           nextsym = SYM_EOF;
3347330f729Sjoerg         }
3357330f729Sjoerg         loop = 0;
3367330f729Sjoerg       } else {
3377330f729Sjoerg         direction = 1;
3387330f729Sjoerg         switch(c) {
3397330f729Sjoerg           case '-':
3407330f729Sjoerg             direction = -1;
3417330f729Sjoerg             LLVM_FALLTHROUGH;
3427330f729Sjoerg 
3437330f729Sjoerg           case '+':
3447330f729Sjoerg             if (cursym == SYM_CHANGE) {
3457330f729Sjoerg               curvalue += direction;
3467330f729Sjoerg               // loop = 1
3477330f729Sjoerg             } else {
3487330f729Sjoerg               if (cursym == SYM_NONE) {
3497330f729Sjoerg                 cursym = SYM_CHANGE;
3507330f729Sjoerg                 curvalue = direction;
3517330f729Sjoerg                 // loop = 1
3527330f729Sjoerg               } else {
3537330f729Sjoerg                 nextsym = SYM_CHANGE;
3547330f729Sjoerg                 nextvalue = direction;
3557330f729Sjoerg                 loop = 0;
3567330f729Sjoerg               }
3577330f729Sjoerg             }
3587330f729Sjoerg             break;
3597330f729Sjoerg 
3607330f729Sjoerg           case '<':
3617330f729Sjoerg             direction = -1;
3627330f729Sjoerg             LLVM_FALLTHROUGH;
3637330f729Sjoerg 
3647330f729Sjoerg           case '>':
3657330f729Sjoerg             if (cursym == SYM_MOVE) {
3667330f729Sjoerg               curvalue += direction;
3677330f729Sjoerg               // loop = 1
3687330f729Sjoerg             } else {
3697330f729Sjoerg               if (cursym == SYM_NONE) {
3707330f729Sjoerg                 cursym = SYM_MOVE;
3717330f729Sjoerg                 curvalue = direction;
3727330f729Sjoerg                 // loop = 1
3737330f729Sjoerg               } else {
3747330f729Sjoerg                 nextsym = SYM_MOVE;
3757330f729Sjoerg                 nextvalue = direction;
3767330f729Sjoerg                 loop = 0;
3777330f729Sjoerg               }
3787330f729Sjoerg             }
3797330f729Sjoerg             break;
3807330f729Sjoerg 
3817330f729Sjoerg           case ',':
3827330f729Sjoerg             if (cursym == SYM_NONE) {
3837330f729Sjoerg               cursym = SYM_READ;
3847330f729Sjoerg             } else {
3857330f729Sjoerg               nextsym = SYM_READ;
3867330f729Sjoerg             }
3877330f729Sjoerg             loop = 0;
3887330f729Sjoerg             break;
3897330f729Sjoerg 
3907330f729Sjoerg           case '.':
3917330f729Sjoerg             if (cursym == SYM_NONE) {
3927330f729Sjoerg               cursym = SYM_WRITE;
3937330f729Sjoerg             } else {
3947330f729Sjoerg               nextsym = SYM_WRITE;
3957330f729Sjoerg             }
3967330f729Sjoerg             loop = 0;
3977330f729Sjoerg             break;
3987330f729Sjoerg 
3997330f729Sjoerg           case '[':
4007330f729Sjoerg             if (cursym == SYM_NONE) {
4017330f729Sjoerg               cursym = SYM_LOOP;
4027330f729Sjoerg             } else {
4037330f729Sjoerg               nextsym = SYM_LOOP;
4047330f729Sjoerg             }
4057330f729Sjoerg             loop = 0;
4067330f729Sjoerg             break;
4077330f729Sjoerg 
4087330f729Sjoerg           case ']':
4097330f729Sjoerg             if (cursym == SYM_NONE) {
4107330f729Sjoerg               cursym = SYM_ENDLOOP;
4117330f729Sjoerg             } else {
4127330f729Sjoerg               nextsym = SYM_ENDLOOP;
4137330f729Sjoerg             }
4147330f729Sjoerg             loop = 0;
4157330f729Sjoerg             break;
4167330f729Sjoerg 
4177330f729Sjoerg           // Ignore other characters
4187330f729Sjoerg           default:
4197330f729Sjoerg             break;
4207330f729Sjoerg         }
4217330f729Sjoerg       }
4227330f729Sjoerg     }
4237330f729Sjoerg   }
4247330f729Sjoerg 
4257330f729Sjoerg   if (cursym == SYM_ENDLOOP) {
4267330f729Sjoerg     if (!phi) {
4277330f729Sjoerg       std::cerr << "Error: Extra ']'\n";
4287330f729Sjoerg       abort();
4297330f729Sjoerg     }
4307330f729Sjoerg 
4317330f729Sjoerg     // Write loop test
4327330f729Sjoerg     {
4337330f729Sjoerg       //br label %main.%d
4347330f729Sjoerg       builder->CreateBr(testbb);
4357330f729Sjoerg 
4367330f729Sjoerg       //main.%d:
4377330f729Sjoerg 
4387330f729Sjoerg       //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
4397330f729Sjoerg       //Finish phi made at beginning of loop
4407330f729Sjoerg       phi->addIncoming(curhead, builder->GetInsertBlock());
4417330f729Sjoerg       Value *head_0 = phi;
4427330f729Sjoerg 
4437330f729Sjoerg       //%tape.%d = load i8 *%head.%d
444*82d56013Sjoerg       LoadInst *tape_0 = new LoadInst(IntegerType::getInt8Ty(C), head_0,
445*82d56013Sjoerg                                       tapereg, testbb);
4467330f729Sjoerg 
4477330f729Sjoerg       //%test.%d = icmp eq i8 %tape.%d, 0
4487330f729Sjoerg       ICmpInst *test_0 = new ICmpInst(*testbb, ICmpInst::ICMP_EQ, tape_0,
4497330f729Sjoerg                                     ConstantInt::get(C, APInt(8, 0)), testreg);
4507330f729Sjoerg 
4517330f729Sjoerg       //br i1 %test.%d, label %main.%d, label %main.%d
4527330f729Sjoerg       BasicBlock *bb_0 = BasicBlock::Create(C, label, brainf_func);
4537330f729Sjoerg       BranchInst::Create(bb_0, oldbb, test_0, testbb);
4547330f729Sjoerg 
4557330f729Sjoerg       //main.%d:
4567330f729Sjoerg       builder->SetInsertPoint(bb_0);
4577330f729Sjoerg 
4587330f729Sjoerg       //%head.%d = phi i8 *[%head.%d, %main.%d]
4597330f729Sjoerg       PHINode *phi_1 = builder->
4607330f729Sjoerg         CreatePHI(PointerType::getUnqual(IntegerType::getInt8Ty(C)), 1,
4617330f729Sjoerg                   headreg);
4627330f729Sjoerg       phi_1->addIncoming(head_0, testbb);
4637330f729Sjoerg       curhead = phi_1;
4647330f729Sjoerg     }
4657330f729Sjoerg 
4667330f729Sjoerg     return;
4677330f729Sjoerg   }
4687330f729Sjoerg 
4697330f729Sjoerg   //End of the program, so go to return block
4707330f729Sjoerg   builder->CreateBr(endbb);
4717330f729Sjoerg 
4727330f729Sjoerg   if (phi) {
4737330f729Sjoerg     std::cerr << "Error: Missing ']'\n";
4747330f729Sjoerg     abort();
4757330f729Sjoerg   }
4767330f729Sjoerg }
477