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