BrainF.cpp revision b1dbcd886a4b5597a839f299054b78b33fb2d6df
1//===-- BrainF.cpp - BrainF compiler example ----------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===--------------------------------------------------------------------===// 9// 10// This class compiles the BrainF language into LLVM assembly. 11// 12// The BrainF language has 8 commands: 13// Command Equivalent C Action 14// ------- ------------ ------ 15// , *h=getchar(); Read a character from stdin, 255 on EOF 16// . putchar(*h); Write a character to stdout 17// - --*h; Decrement tape 18// + ++*h; Increment tape 19// < --h; Move head left 20// > ++h; Move head right 21// [ while(*h) { Start loop 22// ] } End loop 23// 24//===--------------------------------------------------------------------===// 25 26#include "BrainF.h" 27#include "llvm/Constants.h" 28#include "llvm/Intrinsics.h" 29#include "llvm/ADT/STLExtras.h" 30 31using namespace llvm; 32 33//Set the constants for naming 34const char *BrainF::tapereg = "tape"; 35const char *BrainF::headreg = "head"; 36const char *BrainF::label = "brainf"; 37const char *BrainF::testreg = "test"; 38 39Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf) { 40 in = in1; 41 memtotal = mem; 42 comflag = cf; 43 44 header(); 45 readloop(0, 0, 0); 46 delete builder; 47 return module; 48} 49 50void BrainF::header() { 51 module = new Module("BrainF"); 52 53 //Function prototypes 54 55 //declare void @llvm.memset.i32(i8 *, i8, i32, i32) 56 Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset_i32); 57 58 //declare i32 @getchar() 59 getchar_func = cast<Function>(module-> 60 getOrInsertFunction("getchar", IntegerType::Int32Ty, NULL)); 61 62 //declare i32 @putchar(i32) 63 putchar_func = cast<Function>(module-> 64 getOrInsertFunction("putchar", IntegerType::Int32Ty, 65 IntegerType::Int32Ty, NULL)); 66 67 68 //Function header 69 70 //define void @brainf() 71 brainf_func = cast<Function>(module-> 72 getOrInsertFunction("brainf", Type::VoidTy, NULL)); 73 74 builder = new IRBuilder(BasicBlock::Create(label, brainf_func)); 75 76 //%arr = malloc i8, i32 %d 77 ConstantInt *val_mem = ConstantInt::get(APInt(32, memtotal)); 78 ptr_arr = builder->CreateMalloc(IntegerType::Int8Ty, val_mem, "arr"); 79 80 //call void @llvm.memset.i32(i8 *%arr, i8 0, i32 %d, i32 1) 81 { 82 Value *memset_params[] = { 83 ptr_arr, 84 ConstantInt::get(APInt(8, 0)), 85 val_mem, 86 ConstantInt::get(APInt(32, 1)) 87 }; 88 89 CallInst *memset_call = builder-> 90 CreateCall(memset_func, memset_params, array_endof(memset_params)); 91 memset_call->setTailCall(false); 92 } 93 94 //%arrmax = getelementptr i8 *%arr, i32 %d 95 if (comflag & flag_arraybounds) { 96 ptr_arrmax = builder-> 97 CreateGEP(ptr_arr, ConstantInt::get(APInt(32, memtotal)), "arrmax"); 98 } 99 100 //%head.%d = getelementptr i8 *%arr, i32 %d 101 curhead = builder->CreateGEP(ptr_arr, 102 ConstantInt::get(APInt(32, memtotal/2)), 103 headreg); 104 105 106 107 //Function footer 108 109 //brainf.end: 110 endbb = BasicBlock::Create(label, brainf_func); 111 112 //free i8 *%arr 113 new FreeInst(ptr_arr, endbb); 114 115 //ret void 116 ReturnInst::Create(endbb); 117 118 119 120 //Error block for array out of bounds 121 if (comflag & flag_arraybounds) 122 { 123 //@aberrormsg = internal constant [%d x i8] c"\00" 124 Constant *msg_0 = ConstantArray:: 125 get("Error: The head has left the tape.", true); 126 127 GlobalVariable *aberrormsg = new GlobalVariable( 128 msg_0->getType(), 129 true, 130 GlobalValue::InternalLinkage, 131 msg_0, 132 "aberrormsg", 133 module); 134 135 //declare i32 @puts(i8 *) 136 Function *puts_func = cast<Function>(module-> 137 getOrInsertFunction("puts", IntegerType::Int32Ty, 138 PointerType::getUnqual(IntegerType::Int8Ty), NULL)); 139 140 //brainf.aberror: 141 aberrorbb = BasicBlock::Create(label, brainf_func); 142 143 //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0)) 144 { 145 Constant *zero_32 = Constant::getNullValue(IntegerType::Int32Ty); 146 147 Constant *gep_params[] = { 148 zero_32, 149 zero_32 150 }; 151 152 Constant *msgptr = ConstantExpr:: 153 getGetElementPtr(aberrormsg, gep_params, 154 array_lengthof(gep_params)); 155 156 Value *puts_params[] = { 157 msgptr 158 }; 159 160 CallInst *puts_call = 161 CallInst::Create(puts_func, 162 puts_params, array_endof(puts_params), 163 "", aberrorbb); 164 puts_call->setTailCall(false); 165 } 166 167 //br label %brainf.end 168 BranchInst::Create(endbb, aberrorbb); 169 } 170} 171 172void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb) { 173 Symbol cursym = SYM_NONE; 174 int curvalue = 0; 175 Symbol nextsym = SYM_NONE; 176 int nextvalue = 0; 177 char c; 178 int loop; 179 int direction; 180 181 while(cursym != SYM_EOF && cursym != SYM_ENDLOOP) { 182 // Write out commands 183 switch(cursym) { 184 case SYM_NONE: 185 // Do nothing 186 break; 187 188 case SYM_READ: 189 { 190 //%tape.%d = call i32 @getchar() 191 CallInst *getchar_call = builder->CreateCall(getchar_func, tapereg); 192 getchar_call->setTailCall(false); 193 Value *tape_0 = getchar_call; 194 195 //%tape.%d = trunc i32 %tape.%d to i8 196 Value *tape_1 = builder-> 197 CreateTrunc(tape_0, IntegerType::Int8Ty, tapereg); 198 199 //store i8 %tape.%d, i8 *%head.%d 200 builder->CreateStore(tape_1, curhead); 201 } 202 break; 203 204 case SYM_WRITE: 205 { 206 //%tape.%d = load i8 *%head.%d 207 LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg); 208 209 //%tape.%d = sext i8 %tape.%d to i32 210 Value *tape_1 = builder-> 211 CreateSExt(tape_0, IntegerType::Int32Ty, tapereg); 212 213 //call i32 @putchar(i32 %tape.%d) 214 Value *putchar_params[] = { 215 tape_1 216 }; 217 CallInst *putchar_call = builder-> 218 CreateCall(putchar_func, 219 putchar_params, array_endof(putchar_params)); 220 putchar_call->setTailCall(false); 221 } 222 break; 223 224 case SYM_MOVE: 225 { 226 //%head.%d = getelementptr i8 *%head.%d, i32 %d 227 curhead = builder-> 228 CreateGEP(curhead, ConstantInt::get(APInt(32, curvalue)), 229 headreg); 230 231 //Error block for array out of bounds 232 if (comflag & flag_arraybounds) 233 { 234 //%test.%d = icmp uge i8 *%head.%d, %arrmax 235 Value *test_0 = builder-> 236 CreateICmpUGE(curhead, ptr_arrmax, testreg); 237 238 //%test.%d = icmp ult i8 *%head.%d, %arr 239 Value *test_1 = builder-> 240 CreateICmpULT(curhead, ptr_arr, testreg); 241 242 //%test.%d = or i1 %test.%d, %test.%d 243 Value *test_2 = builder-> 244 CreateOr(test_0, test_1, testreg); 245 246 //br i1 %test.%d, label %main.%d, label %main.%d 247 BasicBlock *nextbb = BasicBlock::Create(label, brainf_func); 248 builder->CreateCondBr(test_2, aberrorbb, nextbb); 249 250 //main.%d: 251 builder->SetInsertPoint(nextbb); 252 } 253 } 254 break; 255 256 case SYM_CHANGE: 257 { 258 //%tape.%d = load i8 *%head.%d 259 LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg); 260 261 //%tape.%d = add i8 %tape.%d, %d 262 Value *tape_1 = builder-> 263 CreateAdd(tape_0, ConstantInt::get(APInt(8, curvalue)), tapereg); 264 265 //store i8 %tape.%d, i8 *%head.%d\n" 266 builder->CreateStore(tape_1, curhead); 267 } 268 break; 269 270 case SYM_LOOP: 271 { 272 //br label %main.%d 273 BasicBlock *testbb = BasicBlock::Create(label, brainf_func); 274 builder->CreateBr(testbb); 275 276 //main.%d: 277 BasicBlock *bb_0 = builder->GetInsertBlock(); 278 BasicBlock *bb_1 = BasicBlock::Create(label, brainf_func); 279 builder->SetInsertPoint(bb_1); 280 281 // Make part of PHI instruction now, wait until end of loop to finish 282 PHINode *phi_0 = 283 PHINode::Create(PointerType::getUnqual(IntegerType::Int8Ty), 284 headreg, testbb); 285 phi_0->reserveOperandSpace(2); 286 phi_0->addIncoming(curhead, bb_0); 287 curhead = phi_0; 288 289 readloop(phi_0, bb_1, testbb); 290 } 291 break; 292 293 default: 294 cerr<<"Error: Unknown symbol.\n"; 295 abort(); 296 break; 297 } 298 299 cursym = nextsym; 300 curvalue = nextvalue; 301 nextsym = SYM_NONE; 302 303 // Reading stdin loop 304 loop = (cursym == SYM_NONE) 305 || (cursym == SYM_MOVE) 306 || (cursym == SYM_CHANGE); 307 while(loop) { 308 *in>>c; 309 if (in->eof()) { 310 if (cursym == SYM_NONE) { 311 cursym = SYM_EOF; 312 } else { 313 nextsym = SYM_EOF; 314 } 315 loop = 0; 316 } else { 317 direction = 1; 318 switch(c) { 319 case '-': 320 direction = -1; 321 // Fall through 322 323 case '+': 324 if (cursym == SYM_CHANGE) { 325 curvalue += direction; 326 // loop = 1 327 } else { 328 if (cursym == SYM_NONE) { 329 cursym = SYM_CHANGE; 330 curvalue = direction; 331 // loop = 1 332 } else { 333 nextsym = SYM_CHANGE; 334 nextvalue = direction; 335 loop = 0; 336 } 337 } 338 break; 339 340 case '<': 341 direction = -1; 342 // Fall through 343 344 case '>': 345 if (cursym == SYM_MOVE) { 346 curvalue += direction; 347 // loop = 1 348 } else { 349 if (cursym == SYM_NONE) { 350 cursym = SYM_MOVE; 351 curvalue = direction; 352 // loop = 1 353 } else { 354 nextsym = SYM_MOVE; 355 nextvalue = direction; 356 loop = 0; 357 } 358 } 359 break; 360 361 case ',': 362 if (cursym == SYM_NONE) { 363 cursym = SYM_READ; 364 } else { 365 nextsym = SYM_READ; 366 } 367 loop = 0; 368 break; 369 370 case '.': 371 if (cursym == SYM_NONE) { 372 cursym = SYM_WRITE; 373 } else { 374 nextsym = SYM_WRITE; 375 } 376 loop = 0; 377 break; 378 379 case '[': 380 if (cursym == SYM_NONE) { 381 cursym = SYM_LOOP; 382 } else { 383 nextsym = SYM_LOOP; 384 } 385 loop = 0; 386 break; 387 388 case ']': 389 if (cursym == SYM_NONE) { 390 cursym = SYM_ENDLOOP; 391 } else { 392 nextsym = SYM_ENDLOOP; 393 } 394 loop = 0; 395 break; 396 397 // Ignore other characters 398 default: 399 break; 400 } 401 } 402 } 403 } 404 405 if (cursym == SYM_ENDLOOP) { 406 if (!phi) { 407 cerr<<"Error: Extra ']'\n"; 408 abort(); 409 } 410 411 // Write loop test 412 { 413 //br label %main.%d 414 builder->CreateBr(testbb); 415 416 //main.%d: 417 418 //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d] 419 //Finish phi made at beginning of loop 420 phi->addIncoming(curhead, builder->GetInsertBlock()); 421 Value *head_0 = phi; 422 423 //%tape.%d = load i8 *%head.%d 424 LoadInst *tape_0 = new LoadInst(head_0, tapereg, testbb); 425 426 //%test.%d = icmp eq i8 %tape.%d, 0 427 ICmpInst *test_0 = new ICmpInst(ICmpInst::ICMP_EQ, tape_0, 428 ConstantInt::get(APInt(8, 0)), testreg, 429 testbb); 430 431 //br i1 %test.%d, label %main.%d, label %main.%d 432 BasicBlock *bb_0 = BasicBlock::Create(label, brainf_func); 433 BranchInst::Create(bb_0, oldbb, test_0, testbb); 434 435 //main.%d: 436 builder->SetInsertPoint(bb_0); 437 438 //%head.%d = phi i8 *[%head.%d, %main.%d] 439 PHINode *phi_1 = builder-> 440 CreatePHI(PointerType::getUnqual(IntegerType::Int8Ty), headreg); 441 phi_1->reserveOperandSpace(1); 442 phi_1->addIncoming(head_0, testbb); 443 curhead = phi_1; 444 } 445 446 return; 447 } 448 449 //End of the program, so go to return block 450 builder->CreateBr(endbb); 451 452 if (phi) { 453 cerr<<"Error: Missing ']'\n"; 454 abort(); 455 } 456} 457