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