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