1 2 // Brainf*** JIT frontend for gccjitd 3 // 4 // Copyright (C) 2014 Iain Buclaw. 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 15 // You should have received a copy of the GNU General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 // Written by Iain Buclaw <ibuclaw@gdcproject.org> 19 20 module gccjitd.examples.brainf; 21 22 import gccjit.d; 23 import std.stdio; 24 import std..string; 25 26 void readToBlock(File finput, ref JITBlock block, JITContext ctx, 27 JITLValue stack, JITLValue stackp, int labelnum = 0) 28 { 29 char input; 30 31 while(finput.readf("%s", &input)) 32 { 33 switch(input) 34 { 35 case '>': 36 // stackp += 1; 37 block.addAssignmentOp(stackp, JITBinaryOp.PLUS, 38 ctx.newRValue(JITTypeKind.UNSIGNED_SHORT, 1)); 39 break; 40 41 case '<': 42 // stackp -= 1; 43 block.addAssignmentOp(stackp, JITBinaryOp.MINUS, 44 ctx.newRValue(JITTypeKind.UNSIGNED_SHORT, 1)); 45 break; 46 47 case '+': 48 // stack[stackp] += 1; 49 block.addAssignmentOp(ctx.newArrayAccess(stack, stackp), JITBinaryOp.PLUS, 50 ctx.newRValue(JITTypeKind.SHORT, 1)); 51 break; 52 53 case '-': 54 // stack[stackp] -= 1; 55 block.addAssignmentOp(ctx.newArrayAccess(stack, stackp), JITBinaryOp.MINUS, 56 ctx.newRValue(JITTypeKind.SHORT, 1)); 57 break; 58 59 case '.': 60 // putchar(stack[stackp]); 61 block.addCall(ctx.getBuiltinFunction("putchar"), 62 ctx.newArrayAccess(stack, stackp).castTo(JITTypeKind.INT)); 63 break; 64 65 case ',': 66 // stack[stackp] = getchar(); 67 JITFunction getchar = ctx.newFunction(JITFunctionKind.IMPORTED, 68 JITTypeKind.INT, "getchar", false); 69 block.addAssignment(ctx.newArrayAccess(stack, stackp), 70 ctx.newCall(getchar).castTo(JITTypeKind.SHORT)); 71 break; 72 73 case '[': 74 // while (stack[stackp] != 0) { [loop] } 75 JITFunction func = block.getFunction(); 76 JITBlock condblock = func.newBlock("cond%s".format(labelnum)); 77 JITBlock loopblock = func.newBlock("loop%s".format(labelnum)); 78 JITBlock exitblock = func.newBlock("exit%s".format(labelnum)); 79 labelnum++; 80 81 // Close current block with jump to condition. 82 block.endWithJump(condblock); 83 84 // Evaluate condition, jumping to the loop block if true, else 85 // continue by jumping to the exit block. 86 JITRValue cond = ctx.newComparison(JITComparison.NE, 87 ctx.newArrayAccess(stack, stackp), 88 ctx.newRValue(JITTypeKind.SHORT, 0)); 89 condblock.endWithConditional(cond, loopblock, exitblock); 90 91 // Do code generation for the loop block. 92 readToBlock(finput, loopblock, ctx, stack, stackp, labelnum); 93 94 // Close loop with jump back to condition. 95 loopblock.endWithJump(condblock); 96 97 // We now start generating code from the exit block. 98 block = exitblock; 99 break; 100 101 case ']': 102 return; 103 104 default: 105 // Silently ignore everything else. They can be comment or typos 106 // that will bring you to mental insanity. 107 continue; 108 } 109 } 110 } 111 112 113 void main(string[] args) 114 { 115 File finput = (args.length > 1) ? File(args[1], "r") : stdin; 116 117 JITContext ctx = new JITContext(); 118 ctx.setOption(JITStrOption.PROGNAME, "brainf***"); 119 120 // Turn these on to get various kinds of debugging 121 version(none) 122 { 123 ctx.setOption(JITBoolOption.DUMP_INITIAL_TREE, true); 124 ctx.setOption(JITBoolOption.DUMP_INITIAL_GIMPLE, true); 125 ctx.setOption(JITBoolOption.DUMP_GENERATED_CODE, true); 126 } 127 128 // Adjust this to control optimization level of the generated code 129 version(none) 130 ctx.setOption(JITIntOption.OPTIMIZATION_LEVEL, 1); 131 132 // int bfmain() { 133 JITFunction func = ctx.newFunction(JITFunctionKind.EXPORTED, 134 JITTypeKind.INT, "bfmain", false); 135 JITBlock block = func.newBlock("start"); 136 // static short[65536] stack; 137 JITLValue stack = ctx.newGlobal(JITGlobalKind.INTERNAL, ctx.newArrayType(JITTypeKind.SHORT, 65536), "stack"); 138 // unsigned short stackp; 139 JITLValue stackp = func.newLocal(ctx.getType(JITTypeKind.UNSIGNED_SHORT), "stackp"); 140 // stackp = 0; 141 block.addAssignment(stackp, ctx.newRValue(JITTypeKind.UNSIGNED_SHORT, 0)); 142 143 // [body] 144 readToBlock(finput, block, ctx, stack, stackp); 145 146 // return 0; } 147 block.endWithReturn(ctx.newRValue(JITTypeKind.INT, 0)); 148 149 // 150 JITResult result = ctx.compile(); 151 ctx.release(); 152 153 auto mainfn = cast(int function()) result.getCode("bfmain"); 154 mainfn(); 155 156 result.release(); 157 return; 158 } 159 160