1 // Toy interpreter backend using gccjitd. 2 // 3 // Copyright (C) 2014-2015 Iain Buclaw. 4 // This program is free software; you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation; either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 14 // You should have received a copy of the GNU General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 // Written by Iain Buclaw <ibuclaw@gdcproject.org> 18 19 module toy.backend; 20 21 import toy.ast; 22 23 private import gccjit.d; 24 25 /// Internal backend value exposed via alias. 26 alias BEValue = JITRValue; 27 28 /// Backend visitor class. 29 class Backend 30 { 31 JITContext context; 32 JITFunction func; 33 JITBlock block; 34 35 this() 36 { 37 this.context = new JITContext(); 38 this.func = this.context.newFunction(JITFunctionKind.EXPORTED, 39 JITTypeKind.VOID, "toymain", false); 40 this.block = this.func.newBlock(); 41 this.context.setOption(JITStrOption.PROGNAME, "toy"); 42 debug this.context.setOption(JITBoolOption.DUMP_INITIAL_GIMPLE, true); 43 } 44 45 void run() 46 { 47 this.block.endWithReturn(); 48 49 JITResult result = this.context.compile(); 50 this.context.release(); 51 52 auto toymain = cast(void function()) result.getCode("toymain"); 53 toymain(); 54 55 result.release(); 56 } 57 58 void compile(AssignStatement as) 59 { 60 JITLValue name = cast(JITLValue) as.name.compile(this); 61 JITRValue value = as.value.compile(this); 62 this.block.addAssignment(name, value); 63 } 64 65 void compile(CompoundStatement cs) 66 { 67 if (cs.s1 !is null) 68 cs.s1.compile(this); 69 if (cs.s2 !is null) 70 cs.s2.compile(this); 71 } 72 73 void compile(IfStatement ifs) 74 { 75 JITBlock condblock = this.func.newBlock(); 76 JITBlock exitblock = this.func.newBlock(); 77 JITBlock trueblock = this.func.newBlock(); 78 JITBlock falseblock = ifs.elsebody ? this.func.newBlock() : null; 79 80 this.block.endWithJump(condblock); 81 this.block = condblock; 82 JITRValue condition = ifs.condition.compile(this); 83 this.block.endWithConditional(condition, trueblock, falseblock ? falseblock : exitblock); 84 85 this.block = trueblock; 86 ifs.ifbody.compile(this); 87 this.block.endWithJump(exitblock); 88 89 if (falseblock !is null) 90 { 91 this.block = falseblock; 92 ifs.elsebody.compile(this); 93 this.block.endWithJump(exitblock); 94 } 95 96 this.block = exitblock; 97 } 98 99 void compile(WhileStatement ws) 100 { 101 JITBlock condblock = this.func.newBlock(); 102 JITBlock exitblock = this.func.newBlock(); 103 JITBlock loopblock = this.func.newBlock(); 104 105 this.block.endWithJump(condblock); 106 this.block = condblock; 107 JITRValue condition = ws.condition.compile(this); 108 this.block.endWithConditional(condition, loopblock, exitblock); 109 110 this.block = loopblock; 111 ws.whilebody.compile(this); 112 this.block.endWithJump(condblock); 113 114 this.block = exitblock; 115 } 116 117 void compile(PrintStatement ps) 118 { 119 JITRValue value = ps.value.compile(this); 120 this.block.addCall(this.context.getBuiltinFunction("printf"), 121 this.context.newRValue("%d\n"), value); 122 } 123 124 BEValue compile(IntegerExp ie) 125 { 126 if (ie.bevalue is null) 127 ie.bevalue = this.context.newRValue(JITTypeKind.INT, ie.e1); 128 return ie.bevalue; 129 } 130 131 BEValue compile(VarExp ve) 132 { 133 if (ve.bevalue is null) 134 ve.bevalue = this.func.newLocal(this.context.getType(JITTypeKind.INT), ve.e1); 135 return ve.bevalue; 136 } 137 138 BEValue compile(BinExp be) 139 { 140 JITRValue e1 = be.e1.compile(this); 141 JITRValue e2 = be.e2.compile(this); 142 JITBinaryOp op; 143 144 final switch (be.op) 145 { 146 case "/": op = JITBinaryOp.DIVIDE; break; 147 case "*": op = JITBinaryOp.MULT; break; 148 case "+": op = JITBinaryOp.PLUS; break; 149 case "-": op = JITBinaryOp.MINUS; break; 150 } 151 return this.context.newBinaryOp(op, e2.getType(), e1, e2); 152 } 153 154 BEValue compile(CmpExp ce) 155 { 156 JITRValue e1 = ce.e1.compile(this); 157 JITRValue e2 = ce.e2.compile(this); 158 JITComparison op; 159 160 final switch (ce.op) 161 { 162 case "=": op = JITComparison.EQ; break; 163 case "!=": op = JITComparison.NE; break; 164 case "<": op = JITComparison.LT; break; 165 case "<=": op = JITComparison.LE; break; 166 case ">": op = JITComparison.GT; break; 167 case ">=": op = JITComparison.GE; break; 168 } 169 return this.context.newComparison(op, e1, e2); 170 } 171 172 BEValue compile(AndExp ae) 173 { 174 JITRValue e1 = ae.e1.compile(this); 175 JITRValue e2 = ae.e2.compile(this); 176 return this.context.newBinaryOp(JITBinaryOp.LOGICAL_AND, e2.getType(), e1, e2); 177 } 178 179 BEValue compile(OrExp oe) 180 { 181 JITRValue e1 = oe.e1.compile(this); 182 JITRValue e2 = oe.e2.compile(this); 183 return this.context.newBinaryOp(JITBinaryOp.LOGICAL_OR, e2.getType(), e1, e2); 184 } 185 186 BEValue compile(NotExp ne) 187 { 188 JITRValue e1 = ne.e1.compile(this); 189 return this.context.newUnaryOp(JITUnaryOp.LOGICAL_NEGATE, e1.getType(), e1); 190 } 191 }