2016-05-25 09:18:36 +08:00
|
|
|
//===-- BrainF.cpp - BrainF compiler example ------------------------------===//
|
2007-09-13 02:24:00 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2007-09-13 02:24:00 +08:00
|
|
|
//
|
2016-05-25 09:18:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2007-09-13 02:24:00 +08:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
2016-05-25 09:18:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
#include "BrainF.h"
|
2016-05-25 09:18:36 +08:00
|
|
|
#include "llvm/ADT/APInt.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/Constant.h"
|
2013-01-02 19:56:33 +08:00
|
|
|
#include "llvm/IR/Constants.h"
|
2016-05-25 09:18:36 +08:00
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalValue.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
|
|
#include "llvm/IR/InstrTypes.h"
|
|
|
|
#include "llvm/IR/Instruction.h"
|
2013-01-02 19:56:33 +08:00
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
|
#include "llvm/IR/Intrinsics.h"
|
2016-05-25 09:18:36 +08:00
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/IR/Type.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include <cstdlib>
|
2008-08-24 06:00:15 +08:00
|
|
|
#include <iostream>
|
2015-09-30 02:02:48 +08:00
|
|
|
|
2007-09-13 02:24:00 +08:00
|
|
|
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";
|
|
|
|
|
2009-07-02 00:58:40 +08:00
|
|
|
Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf,
|
2009-07-02 07:13:44 +08:00
|
|
|
LLVMContext& Context) {
|
2007-09-13 02:24:00 +08:00
|
|
|
in = in1;
|
|
|
|
memtotal = mem;
|
|
|
|
comflag = cf;
|
|
|
|
|
2009-07-02 00:58:40 +08:00
|
|
|
header(Context);
|
2015-09-30 02:02:48 +08:00
|
|
|
readloop(nullptr, nullptr, nullptr, Context);
|
2007-09-13 02:24:00 +08:00
|
|
|
delete builder;
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
2009-07-02 07:13:44 +08:00
|
|
|
void BrainF::header(LLVMContext& C) {
|
2009-07-02 00:58:40 +08:00
|
|
|
module = new Module("BrainF", C);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//Function prototypes
|
|
|
|
|
2020-05-11 04:51:01 +08:00
|
|
|
//declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i1)
|
2011-07-13 06:04:11 +08:00
|
|
|
Type *Tys[] = { Type::getInt8PtrTy(C), Type::getInt32Ty(C) };
|
2008-11-22 00:42:48 +08:00
|
|
|
Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset,
|
2011-07-15 01:45:39 +08:00
|
|
|
Tys);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//declare i32 @getchar()
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
getchar_func =
|
|
|
|
module->getOrInsertFunction("getchar", IntegerType::getInt32Ty(C));
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//declare i32 @putchar(i32)
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
putchar_func = module->getOrInsertFunction(
|
|
|
|
"putchar", IntegerType::getInt32Ty(C), IntegerType::getInt32Ty(C));
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//Function header
|
|
|
|
|
|
|
|
//define void @brainf()
|
2019-02-01 11:23:42 +08:00
|
|
|
brainf_func = Function::Create(FunctionType::get(Type::getVoidTy(C), false),
|
|
|
|
Function::ExternalLinkage, "brainf", module);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
2009-08-14 05:58:54 +08:00
|
|
|
builder = new IRBuilder<>(BasicBlock::Create(C, label, brainf_func));
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//%arr = malloc i8, i32 %d
|
2009-07-25 07:12:02 +08:00
|
|
|
ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal));
|
2009-10-17 08:00:19 +08:00
|
|
|
BasicBlock* BB = builder->GetInsertBlock();
|
2011-07-18 12:52:58 +08:00
|
|
|
Type* IntPtrTy = IntegerType::getInt32Ty(C);
|
|
|
|
Type* Int8Ty = IntegerType::getInt8Ty(C);
|
2009-11-07 08:16:28 +08:00
|
|
|
Constant* allocsize = ConstantExpr::getSizeOf(Int8Ty);
|
|
|
|
allocsize = ConstantExpr::getTruncOrBitCast(allocsize, IntPtrTy);
|
|
|
|
ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, Int8Ty, allocsize, val_mem,
|
2015-09-30 02:02:48 +08:00
|
|
|
nullptr, "arr");
|
2009-10-17 08:00:19 +08:00
|
|
|
BB->getInstList().push_back(cast<Instruction>(ptr_arr));
|
2007-09-13 02:24:00 +08:00
|
|
|
|
2020-05-11 04:51:01 +08:00
|
|
|
//call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i1 0)
|
2007-09-13 02:24:00 +08:00
|
|
|
{
|
|
|
|
Value *memset_params[] = {
|
|
|
|
ptr_arr,
|
2009-07-25 07:12:02 +08:00
|
|
|
ConstantInt::get(C, APInt(8, 0)),
|
2007-09-13 02:24:00 +08:00
|
|
|
val_mem,
|
2010-08-11 05:45:38 +08:00
|
|
|
ConstantInt::get(C, APInt(1, 0))
|
2007-09-13 02:24:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
CallInst *memset_call = builder->
|
2011-07-15 18:59:52 +08:00
|
|
|
CreateCall(memset_func, memset_params);
|
2007-09-13 02:24:00 +08:00
|
|
|
memset_call->setTailCall(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
//%arrmax = getelementptr i8 *%arr, i32 %d
|
|
|
|
if (comflag & flag_arraybounds) {
|
|
|
|
ptr_arrmax = builder->
|
2009-07-25 07:12:02 +08:00
|
|
|
CreateGEP(ptr_arr, ConstantInt::get(C, APInt(32, memtotal)), "arrmax");
|
2007-09-13 02:24:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//%head.%d = getelementptr i8 *%arr, i32 %d
|
|
|
|
curhead = builder->CreateGEP(ptr_arr,
|
2009-07-25 07:12:02 +08:00
|
|
|
ConstantInt::get(C, APInt(32, memtotal/2)),
|
2007-09-13 02:24:00 +08:00
|
|
|
headreg);
|
|
|
|
|
|
|
|
//Function footer
|
|
|
|
|
|
|
|
//brainf.end:
|
2009-08-14 05:58:54 +08:00
|
|
|
endbb = BasicBlock::Create(C, label, brainf_func);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
2009-10-27 07:43:48 +08:00
|
|
|
//call free(i8 *%arr)
|
|
|
|
endbb->getInstList().push_back(CallInst::CreateFree(ptr_arr, endbb));
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//ret void
|
2009-08-14 05:58:54 +08:00
|
|
|
ReturnInst::Create(C, endbb);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//Error block for array out of bounds
|
|
|
|
if (comflag & flag_arraybounds)
|
|
|
|
{
|
|
|
|
//@aberrormsg = internal constant [%d x i8] c"\00"
|
2009-07-15 07:09:55 +08:00
|
|
|
Constant *msg_0 =
|
2012-01-31 17:35:01 +08:00
|
|
|
ConstantDataArray::getString(C, "Error: The head has left the tape.",
|
|
|
|
true);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
GlobalVariable *aberrormsg = new GlobalVariable(
|
2009-07-09 03:03:57 +08:00
|
|
|
*module,
|
2007-09-13 02:24:00 +08:00
|
|
|
msg_0->getType(),
|
|
|
|
true,
|
|
|
|
GlobalValue::InternalLinkage,
|
|
|
|
msg_0,
|
2009-07-09 03:03:57 +08:00
|
|
|
"aberrormsg");
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//declare i32 @puts(i8 *)
|
[opaque pointer types] Add a FunctionCallee wrapper type, and use it.
Recommit r352791 after tweaking DerivedTypes.h slightly, so that gcc
doesn't choke on it, hopefully.
Original Message:
The FunctionCallee type is effectively a {FunctionType*,Value*} pair,
and is a useful convenience to enable code to continue passing the
result of getOrInsertFunction() through to EmitCall, even once pointer
types lose their pointee-type.
Then:
- update the CallInst/InvokeInst instruction creation functions to
take a Callee,
- modify getOrInsertFunction to return FunctionCallee, and
- update all callers appropriately.
One area of particular note is the change to the sanitizer
code. Previously, they had been casting the result of
`getOrInsertFunction` to a `Function*` via
`checkSanitizerInterfaceFunction`, and storing that. That would report
an error if someone had already inserted a function declaraction with
a mismatching signature.
However, in general, LLVM allows for such mismatches, as
`getOrInsertFunction` will automatically insert a bitcast if
needed. As part of this cleanup, cause the sanitizer code to do the
same. (It will call its functions using the expected signature,
however they may have been declared.)
Finally, in a small number of locations, callers of
`getOrInsertFunction` actually were expecting/requiring that a brand
new function was being created. In such cases, I've switched them to
Function::Create instead.
Differential Revision: https://reviews.llvm.org/D57315
llvm-svn: 352827
2019-02-01 10:28:03 +08:00
|
|
|
FunctionCallee puts_func = module->getOrInsertFunction(
|
|
|
|
"puts", IntegerType::getInt32Ty(C),
|
|
|
|
PointerType::getUnqual(IntegerType::getInt8Ty(C)));
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//brainf.aberror:
|
2009-08-14 05:58:54 +08:00
|
|
|
aberrorbb = BasicBlock::Create(C, label, brainf_func);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
|
|
|
|
{
|
2009-08-14 05:58:54 +08:00
|
|
|
Constant *zero_32 = Constant::getNullValue(IntegerType::getInt32Ty(C));
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
Constant *gep_params[] = {
|
|
|
|
zero_32,
|
|
|
|
zero_32
|
|
|
|
};
|
|
|
|
|
|
|
|
Constant *msgptr = ConstantExpr::
|
2015-04-03 06:44:00 +08:00
|
|
|
getGetElementPtr(aberrormsg->getValueType(), aberrormsg, gep_params);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
Value *puts_params[] = {
|
|
|
|
msgptr
|
|
|
|
};
|
|
|
|
|
|
|
|
CallInst *puts_call =
|
2008-04-07 04:25:17 +08:00
|
|
|
CallInst::Create(puts_func,
|
2011-07-15 18:59:52 +08:00
|
|
|
puts_params,
|
2008-04-07 04:25:17 +08:00
|
|
|
"", aberrorbb);
|
2007-09-13 02:24:00 +08:00
|
|
|
puts_call->setTailCall(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
//br label %brainf.end
|
2008-04-07 04:25:17 +08:00
|
|
|
BranchInst::Create(endbb, aberrorbb);
|
2007-09-13 02:24:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-15 07:09:55 +08:00
|
|
|
void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb,
|
|
|
|
LLVMContext &C) {
|
2007-09-13 02:24:00 +08:00
|
|
|
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()
|
2015-05-19 14:50:19 +08:00
|
|
|
CallInst *getchar_call =
|
|
|
|
builder->CreateCall(getchar_func, {}, tapereg);
|
2007-09-13 02:24:00 +08:00
|
|
|
getchar_call->setTailCall(false);
|
|
|
|
Value *tape_0 = getchar_call;
|
|
|
|
|
|
|
|
//%tape.%d = trunc i32 %tape.%d to i8
|
2008-04-13 14:22:09 +08:00
|
|
|
Value *tape_1 = builder->
|
2009-08-14 05:58:54 +08:00
|
|
|
CreateTrunc(tape_0, IntegerType::getInt8Ty(C), tapereg);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//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
|
2008-04-13 14:22:09 +08:00
|
|
|
Value *tape_1 = builder->
|
2009-08-14 05:58:54 +08:00
|
|
|
CreateSExt(tape_0, IntegerType::getInt32Ty(C), tapereg);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//call i32 @putchar(i32 %tape.%d)
|
|
|
|
Value *putchar_params[] = {
|
|
|
|
tape_1
|
|
|
|
};
|
|
|
|
CallInst *putchar_call = builder->
|
|
|
|
CreateCall(putchar_func,
|
2011-07-15 18:59:52 +08:00
|
|
|
putchar_params);
|
2007-09-13 02:24:00 +08:00
|
|
|
putchar_call->setTailCall(false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SYM_MOVE:
|
|
|
|
{
|
|
|
|
//%head.%d = getelementptr i8 *%head.%d, i32 %d
|
|
|
|
curhead = builder->
|
2009-07-25 07:12:02 +08:00
|
|
|
CreateGEP(curhead, ConstantInt::get(C, APInt(32, curvalue)),
|
2007-09-13 02:24:00 +08:00
|
|
|
headreg);
|
|
|
|
|
|
|
|
//Error block for array out of bounds
|
|
|
|
if (comflag & flag_arraybounds)
|
|
|
|
{
|
|
|
|
//%test.%d = icmp uge i8 *%head.%d, %arrmax
|
2008-04-13 14:22:09 +08:00
|
|
|
Value *test_0 = builder->
|
2007-09-13 02:24:00 +08:00
|
|
|
CreateICmpUGE(curhead, ptr_arrmax, testreg);
|
|
|
|
|
|
|
|
//%test.%d = icmp ult i8 *%head.%d, %arr
|
2008-04-13 14:22:09 +08:00
|
|
|
Value *test_1 = builder->
|
2007-09-13 02:24:00 +08:00
|
|
|
CreateICmpULT(curhead, ptr_arr, testreg);
|
|
|
|
|
|
|
|
//%test.%d = or i1 %test.%d, %test.%d
|
2008-04-13 14:22:09 +08:00
|
|
|
Value *test_2 = builder->
|
2007-09-13 02:24:00 +08:00
|
|
|
CreateOr(test_0, test_1, testreg);
|
|
|
|
|
|
|
|
//br i1 %test.%d, label %main.%d, label %main.%d
|
2009-08-14 05:58:54 +08:00
|
|
|
BasicBlock *nextbb = BasicBlock::Create(C, label, brainf_func);
|
2007-09-13 02:24:00 +08:00
|
|
|
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
|
2008-04-13 14:22:09 +08:00
|
|
|
Value *tape_1 = builder->
|
2009-07-25 07:12:02 +08:00
|
|
|
CreateAdd(tape_0, ConstantInt::get(C, APInt(8, curvalue)), tapereg);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//store i8 %tape.%d, i8 *%head.%d\n"
|
|
|
|
builder->CreateStore(tape_1, curhead);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SYM_LOOP:
|
|
|
|
{
|
|
|
|
//br label %main.%d
|
2009-08-14 05:58:54 +08:00
|
|
|
BasicBlock *testbb = BasicBlock::Create(C, label, brainf_func);
|
2007-09-13 02:24:00 +08:00
|
|
|
builder->CreateBr(testbb);
|
|
|
|
|
|
|
|
//main.%d:
|
|
|
|
BasicBlock *bb_0 = builder->GetInsertBlock();
|
2009-08-14 05:58:54 +08:00
|
|
|
BasicBlock *bb_1 = BasicBlock::Create(C, label, brainf_func);
|
2007-09-13 02:24:00 +08:00
|
|
|
builder->SetInsertPoint(bb_1);
|
|
|
|
|
2008-05-15 18:04:30 +08:00
|
|
|
// Make part of PHI instruction now, wait until end of loop to finish
|
|
|
|
PHINode *phi_0 =
|
2009-08-14 05:58:54 +08:00
|
|
|
PHINode::Create(PointerType::getUnqual(IntegerType::getInt8Ty(C)),
|
2011-03-30 19:28:46 +08:00
|
|
|
2, headreg, testbb);
|
2007-09-13 02:24:00 +08:00
|
|
|
phi_0->addIncoming(curhead, bb_0);
|
|
|
|
curhead = phi_0;
|
|
|
|
|
2009-07-15 07:09:55 +08:00
|
|
|
readloop(phi_0, bb_1, testbb, C);
|
2007-09-13 02:24:00 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-08-24 06:00:15 +08:00
|
|
|
std::cerr << "Error: Unknown symbol.\n";
|
2007-09-13 02:24:00 +08:00
|
|
|
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;
|
2016-08-18 04:30:52 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
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;
|
2016-08-18 04:30:52 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
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) {
|
2008-08-24 06:00:15 +08:00
|
|
|
std::cerr << "Error: Extra ']'\n";
|
2007-09-13 02:24:00 +08:00
|
|
|
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
|
2020-04-08 07:25:52 +08:00
|
|
|
LoadInst *tape_0 = new LoadInst(IntegerType::getInt8Ty(C), head_0,
|
|
|
|
tapereg, testbb);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//%test.%d = icmp eq i8 %tape.%d, 0
|
2009-07-10 07:48:35 +08:00
|
|
|
ICmpInst *test_0 = new ICmpInst(*testbb, ICmpInst::ICMP_EQ, tape_0,
|
2009-07-25 07:12:02 +08:00
|
|
|
ConstantInt::get(C, APInt(8, 0)), testreg);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//br i1 %test.%d, label %main.%d, label %main.%d
|
2009-08-14 05:58:54 +08:00
|
|
|
BasicBlock *bb_0 = BasicBlock::Create(C, label, brainf_func);
|
2008-04-07 04:25:17 +08:00
|
|
|
BranchInst::Create(bb_0, oldbb, test_0, testbb);
|
2007-09-13 02:24:00 +08:00
|
|
|
|
|
|
|
//main.%d:
|
|
|
|
builder->SetInsertPoint(bb_0);
|
|
|
|
|
|
|
|
//%head.%d = phi i8 *[%head.%d, %main.%d]
|
|
|
|
PHINode *phi_1 = builder->
|
2011-03-30 19:28:46 +08:00
|
|
|
CreatePHI(PointerType::getUnqual(IntegerType::getInt8Ty(C)), 1,
|
|
|
|
headreg);
|
2007-09-13 02:24:00 +08:00
|
|
|
phi_1->addIncoming(head_0, testbb);
|
|
|
|
curhead = phi_1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//End of the program, so go to return block
|
|
|
|
builder->CreateBr(endbb);
|
|
|
|
|
|
|
|
if (phi) {
|
2008-08-24 06:00:15 +08:00
|
|
|
std::cerr << "Error: Missing ']'\n";
|
2007-09-13 02:24:00 +08:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|