summaryrefslogtreecommitdiff
path: root/examples/BrainF/BrainF.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2007-09-12 18:24:00 +0000
committerChris Lattner <sabre@nondot.org>2007-09-12 18:24:00 +0000
commitbef8e0b0a7afe602ddf09165ff4dbb8fa5f696a9 (patch)
tree9a11138b3fd17b1b812d75b34d3e8a4f9972aabc /examples/BrainF/BrainF.cpp
parent36597a5ddb11d9f84638a8e1e8cfa28292eeced0 (diff)
downloadllvm-bef8e0b0a7afe602ddf09165ff4dbb8fa5f696a9.tar.gz
llvm-bef8e0b0a7afe602ddf09165ff4dbb8fa5f696a9.tar.bz2
llvm-bef8e0b0a7afe602ddf09165ff4dbb8fa5f696a9.tar.xz
add a new BF->LLVM translator, contributed by Sterling Stein.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41881 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'examples/BrainF/BrainF.cpp')
-rw-r--r--examples/BrainF/BrainF.cpp458
1 files changed, 458 insertions, 0 deletions
diff --git a/examples/BrainF/BrainF.cpp b/examples/BrainF/BrainF.cpp
new file mode 100644
index 0000000000..e7e11aca0b
--- /dev/null
+++ b/examples/BrainF/BrainF.cpp
@@ -0,0 +1,458 @@
+//===-- BrainF.cpp - BrainF compiler example ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Sterling Stein and is distributed under the
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+//
+// This class compiles the BrainF language into LLVM assembly.
+//
+// The BrainF language has 8 commands:
+// Command Equivalent C Action
+// ------- ------------ ------
+// , *h=getchar(); Read a character from stdin, 255 on EOF
+// . putchar(*h); Write a character to stdout
+// - --*h; Decrement tape
+// + ++*h; Increment tape
+// < --h; Move head left
+// > ++h; Move head right
+// [ while(*h) { Start loop
+// ] } End loop
+//
+//===--------------------------------------------------------------------===//
+
+#include "BrainF.h"
+#include "llvm/Constants.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace llvm;
+
+//Set the constants for naming
+const char *BrainF::tapereg = "tape";
+const char *BrainF::headreg = "head";
+const char *BrainF::label = "brainf";
+const char *BrainF::testreg = "test";
+
+Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf) {
+ in = in1;
+ memtotal = mem;
+ comflag = cf;
+
+ header();
+ readloop(0, 0, 0);
+ delete builder;
+ return module;
+}
+
+void BrainF::header() {
+ module = new Module("BrainF");
+
+ //Function prototypes
+
+ //declare void @llvm.memset.i32(i8 *, i8, i32, i32)
+ Function *memset_func = cast<Function>(module->
+ getOrInsertFunction("llvm.memset.i32", Type::VoidTy,
+ PointerType::get(IntegerType::Int8Ty),
+ IntegerType::Int8Ty, IntegerType::Int32Ty,
+ IntegerType::Int32Ty, NULL));
+
+ //declare i32 @getchar()
+ getchar_func = cast<Function>(module->
+ getOrInsertFunction("getchar", IntegerType::Int32Ty, NULL));
+
+ //declare i32 @putchar(i32)
+ putchar_func = cast<Function>(module->
+ getOrInsertFunction("putchar", IntegerType::Int32Ty,
+ IntegerType::Int32Ty, NULL));
+
+
+ //Function header
+
+ //define void @brainf()
+ brainf_func = cast<Function>(module->
+ getOrInsertFunction("brainf", Type::VoidTy, NULL));
+
+ builder = new LLVMBuilder(new BasicBlock(label, brainf_func));
+
+ //%arr = malloc i8, i32 %d
+ ConstantInt *val_mem = ConstantInt::get(APInt(32, memtotal));
+ ptr_arr = builder->CreateMalloc(IntegerType::Int8Ty, val_mem, "arr");
+
+ //call void @llvm.memset.i32(i8 *%arr, i8 0, i32 %d, i32 1)
+ {
+ Value *memset_params[] = {
+ ptr_arr,
+ ConstantInt::get(APInt(8, 0)),
+ val_mem,
+ ConstantInt::get(APInt(32, 1))
+ };
+
+ CallInst *memset_call = builder->
+ CreateCall(memset_func, memset_params, array_endof(memset_params));
+ memset_call->setTailCall(false);
+ }
+
+ //%arrmax = getelementptr i8 *%arr, i32 %d
+ if (comflag & flag_arraybounds) {
+ ptr_arrmax = builder->
+ CreateGEP(ptr_arr, ConstantInt::get(APInt(32, memtotal)), "arrmax");
+ }
+
+ //%head.%d = getelementptr i8 *%arr, i32 %d
+ curhead = builder->CreateGEP(ptr_arr,
+ ConstantInt::get(APInt(32, memtotal/2)),
+ headreg);
+
+
+
+ //Function footer
+
+ //brainf.end:
+ endbb = new BasicBlock(label, brainf_func);
+
+ //free i8 *%arr
+ new FreeInst(ptr_arr, endbb);
+
+ //ret void
+ new ReturnInst(endbb);
+
+
+
+ //Error block for array out of bounds
+ if (comflag & flag_arraybounds)
+ {
+ //@aberrormsg = internal constant [%d x i8] c"\00"
+ Constant *msg_0 = ConstantArray::
+ get("Error: The head has left the tape.", true);
+
+ GlobalVariable *aberrormsg = new GlobalVariable(
+ msg_0->getType(),
+ true,
+ GlobalValue::InternalLinkage,
+ msg_0,
+ "aberrormsg",
+ module);
+
+ //declare i32 @puts(i8 *)
+ Function *puts_func = cast<Function>(module->
+ getOrInsertFunction("puts", IntegerType::Int32Ty,
+ PointerType::get(IntegerType::Int8Ty), NULL));
+
+ //brainf.aberror:
+ aberrorbb = new BasicBlock(label, brainf_func);
+
+ //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
+ {
+ Constant *zero_32 = Constant::getNullValue(IntegerType::Int32Ty);
+
+ Constant *gep_params[] = {
+ zero_32,
+ zero_32
+ };
+
+ Constant *msgptr = ConstantExpr::
+ getGetElementPtr(aberrormsg, gep_params,
+ array_lengthof(gep_params));
+
+ Value *puts_params[] = {
+ msgptr
+ };
+
+ CallInst *puts_call =
+ new CallInst(puts_func,
+ puts_params, array_endof(puts_params),
+ "", aberrorbb);
+ puts_call->setTailCall(false);
+ }
+
+ //br label %brainf.end
+ new BranchInst(endbb, aberrorbb);
+ }
+}
+
+void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb) {
+ Symbol cursym = SYM_NONE;
+ int curvalue = 0;
+ Symbol nextsym = SYM_NONE;
+ int nextvalue = 0;
+ char c;
+ int loop;
+ int direction;
+
+ while(cursym != SYM_EOF && cursym != SYM_ENDLOOP) {
+ // Write out commands
+ switch(cursym) {
+ case SYM_NONE:
+ // Do nothing
+ break;
+
+ case SYM_READ:
+ {
+ //%tape.%d = call i32 @getchar()
+ CallInst *getchar_call = builder->CreateCall(getchar_func, tapereg);
+ getchar_call->setTailCall(false);
+ Value *tape_0 = getchar_call;
+
+ //%tape.%d = trunc i32 %tape.%d to i8
+ TruncInst *tape_1 = builder->
+ CreateTrunc(tape_0, IntegerType::Int8Ty, tapereg);
+
+ //store i8 %tape.%d, i8 *%head.%d
+ builder->CreateStore(tape_1, curhead);
+ }
+ break;
+
+ case SYM_WRITE:
+ {
+ //%tape.%d = load i8 *%head.%d
+ LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);
+
+ //%tape.%d = sext i8 %tape.%d to i32
+ SExtInst *tape_1 = builder->
+ CreateSExt(tape_0, IntegerType::Int32Ty, tapereg);
+
+ //call i32 @putchar(i32 %tape.%d)
+ Value *putchar_params[] = {
+ tape_1
+ };
+ CallInst *putchar_call = builder->
+ CreateCall(putchar_func,
+ putchar_params, array_endof(putchar_params));
+ putchar_call->setTailCall(false);
+ }
+ break;
+
+ case SYM_MOVE:
+ {
+ //%head.%d = getelementptr i8 *%head.%d, i32 %d
+ curhead = builder->
+ CreateGEP(curhead, ConstantInt::get(APInt(32, curvalue)),
+ headreg);
+
+ //Error block for array out of bounds
+ if (comflag & flag_arraybounds)
+ {
+ //%test.%d = icmp uge i8 *%head.%d, %arrmax
+ ICmpInst *test_0 = builder->
+ CreateICmpUGE(curhead, ptr_arrmax, testreg);
+
+ //%test.%d = icmp ult i8 *%head.%d, %arr
+ ICmpInst *test_1 = builder->
+ CreateICmpULT(curhead, ptr_arr, testreg);
+
+ //%test.%d = or i1 %test.%d, %test.%d
+ BinaryOperator *test_2 = builder->
+ CreateOr(test_0, test_1, testreg);
+
+ //br i1 %test.%d, label %main.%d, label %main.%d
+ BasicBlock *nextbb = new BasicBlock(label, brainf_func);
+ builder->CreateCondBr(test_2, aberrorbb, nextbb);
+
+ //main.%d:
+ builder->SetInsertPoint(nextbb);
+ }
+ }
+ break;
+
+ case SYM_CHANGE:
+ {
+ //%tape.%d = load i8 *%head.%d
+ LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);
+
+ //%tape.%d = add i8 %tape.%d, %d
+ BinaryOperator *tape_1 = builder->
+ CreateAdd(tape_0, ConstantInt::get(APInt(8, curvalue)), tapereg);
+
+ //store i8 %tape.%d, i8 *%head.%d\n"
+ builder->CreateStore(tape_1, curhead);
+ }
+ break;
+
+ case SYM_LOOP:
+ {
+ //br label %main.%d
+ BasicBlock *testbb = new BasicBlock(label, brainf_func);
+ builder->CreateBr(testbb);
+
+ //main.%d:
+ BasicBlock *bb_0 = builder->GetInsertBlock();
+ BasicBlock *bb_1 = new BasicBlock(label, brainf_func);
+ builder->SetInsertPoint(bb_1);
+
+ //Make part of PHI instruction now, wait until end of loop to finish
+ PHINode *phi_0 = new PHINode(PointerType::get(IntegerType::Int8Ty),
+ headreg, testbb);
+ phi_0->reserveOperandSpace(2);
+ phi_0->addIncoming(curhead, bb_0);
+ curhead = phi_0;
+
+ readloop(phi_0, bb_1, testbb);
+ }
+ break;
+
+ default:
+ cerr<<"Error: Unknown symbol.\n";
+ abort();
+ break;
+ }
+
+ cursym = nextsym;
+ curvalue = nextvalue;
+ nextsym = SYM_NONE;
+
+ // Reading stdin loop
+ loop = (cursym == SYM_NONE)
+ || (cursym == SYM_MOVE)
+ || (cursym == SYM_CHANGE);
+ while(loop) {
+ *in>>c;
+ if (in->eof()) {
+ if (cursym == SYM_NONE) {
+ cursym = SYM_EOF;
+ } else {
+ nextsym = SYM_EOF;
+ }
+ loop = 0;
+ } else {
+ direction = 1;
+ switch(c) {
+ case '-':
+ direction = -1;
+ // Fall through
+
+ case '+':
+ if (cursym == SYM_CHANGE) {
+ curvalue += direction;
+ // loop = 1
+ } else {
+ if (cursym == SYM_NONE) {
+ cursym = SYM_CHANGE;
+ curvalue = direction;
+ // loop = 1
+ } else {
+ nextsym = SYM_CHANGE;
+ nextvalue = direction;
+ loop = 0;
+ }
+ }
+ break;
+
+ case '<':
+ direction = -1;
+ // Fall through
+
+ case '>':
+ if (cursym == SYM_MOVE) {
+ curvalue += direction;
+ // loop = 1
+ } else {
+ if (cursym == SYM_NONE) {
+ cursym = SYM_MOVE;
+ curvalue = direction;
+ // loop = 1
+ } else {
+ nextsym = SYM_MOVE;
+ nextvalue = direction;
+ loop = 0;
+ }
+ }
+ break;
+
+ case ',':
+ if (cursym == SYM_NONE) {
+ cursym = SYM_READ;
+ } else {
+ nextsym = SYM_READ;
+ }
+ loop = 0;
+ break;
+
+ case '.':
+ if (cursym == SYM_NONE) {
+ cursym = SYM_WRITE;
+ } else {
+ nextsym = SYM_WRITE;
+ }
+ loop = 0;
+ break;
+
+ case '[':
+ if (cursym == SYM_NONE) {
+ cursym = SYM_LOOP;
+ } else {
+ nextsym = SYM_LOOP;
+ }
+ loop = 0;
+ break;
+
+ case ']':
+ if (cursym == SYM_NONE) {
+ cursym = SYM_ENDLOOP;
+ } else {
+ nextsym = SYM_ENDLOOP;
+ }
+ loop = 0;
+ break;
+
+ // Ignore other characters
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (cursym == SYM_ENDLOOP) {
+ if (!phi) {
+ cerr<<"Error: Extra ']'\n";
+ abort();
+ }
+
+ // Write loop test
+ {
+ //br label %main.%d
+ builder->CreateBr(testbb);
+
+ //main.%d:
+
+ //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
+ //Finish phi made at beginning of loop
+ phi->addIncoming(curhead, builder->GetInsertBlock());
+ Value *head_0 = phi;
+
+ //%tape.%d = load i8 *%head.%d
+ LoadInst *tape_0 = new LoadInst(head_0, tapereg, testbb);
+
+ //%test.%d = icmp eq i8 %tape.%d, 0
+ ICmpInst *test_0 = new ICmpInst(ICmpInst::ICMP_EQ, tape_0,
+ ConstantInt::get(APInt(8, 0)), testreg,
+ testbb);
+
+ //br i1 %test.%d, label %main.%d, label %main.%d
+ BasicBlock *bb_0 = new BasicBlock(label, brainf_func);
+ new BranchInst(bb_0, oldbb, test_0, testbb);
+
+ //main.%d:
+ builder->SetInsertPoint(bb_0);
+
+ //%head.%d = phi i8 *[%head.%d, %main.%d]
+ PHINode *phi_1 = builder->
+ CreatePHI(PointerType::get(IntegerType::Int8Ty), headreg);
+ phi_1->reserveOperandSpace(1);
+ phi_1->addIncoming(head_0, testbb);
+ curhead = phi_1;
+ }
+
+ return;
+ }
+
+ //End of the program, so go to return block
+ builder->CreateBr(endbb);
+
+ if (phi) {
+ cerr<<"Error: Missing ']'\n";
+ abort();
+ }
+}