1 module cfg; 2 3 import brainfuck; 4 5 import std.algorithm.iteration; 6 import std.array; 7 import std.format; 8 9 abstract class CFG { 10 CFG[] incoming; 11 12 abstract CFG run(VM); 13 abstract string compile(); 14 } 15 16 class BasicBlockCFG : CFG { 17 CFG outgoing; 18 BrainfuckInstruction[] insts; 19 20 this(BrainfuckInstruction[] insts) { 21 this.insts = insts; 22 } 23 24 override CFG run(VM vm) { 25 foreach(inst; insts) { 26 inst.run(vm); 27 } 28 29 return outgoing; 30 } 31 32 override string compile() { 33 char[] s; 34 s ~= " _%s:\n".format(cast(void*) this); 35 36 foreach(inst; insts) { 37 s ~= " %s\n".format(inst.compile); 38 } 39 40 s ~= " goto _%s;\n".format(cast(void*) outgoing); 41 return cast(string) s; 42 } 43 } 44 45 enum IfType { Loop, If, Move } 46 47 class IfCFG : CFG { 48 IfType type; 49 CFG outgoing_true; 50 CFG outgoing_false; 51 52 this(IfType type) { 53 this.type = type; 54 } 55 56 override CFG run(VM vm) { 57 if(vm.tape[vm.pointer] != 0) { 58 return outgoing_true; 59 } else { 60 return outgoing_false; 61 } 62 } 63 64 override string compile() { 65 char[] s; 66 s ~= " _%s:\n".format(cast(void*) this); 67 s ~= " if(*p) goto _%s;\n".format(cast(void*) outgoing_true); 68 s ~= " goto _%s;\n".format(cast(void*) outgoing_false); 69 return cast(string) s; 70 } 71 } 72 73 class MoveCFG : CFG { 74 CFG outgoing; 75 MoveLoop inst; 76 77 this(MoveLoop inst) { 78 this.inst = inst; 79 } 80 81 override CFG run(VM vm) { 82 inst.run(vm); 83 return outgoing; 84 } 85 86 override string compile() { 87 char[] s; 88 s ~= " _%s:\n".format(cast(void*) this); 89 90 foreach(pointer, modify; inst.modifications) { 91 s ~= " *(p + %s) += %s * (*p);\n".format(pointer, modify); 92 } 93 94 s ~= " *p = 0;\n"; 95 s ~= " goto _%s;\n".format(cast(void*) outgoing); 96 return cast(string) s; 97 } 98 } 99 100 class IRParser { 101 BrainfuckInstruction[][] insts; 102 uint[] index; 103 size_t depth; 104 105 this(BrainfuckInstruction[] insts) { 106 index ~= 0; 107 this.insts ~= insts; 108 } 109 110 void seek(int d) { 111 index[depth] += d; 112 } 113 114 void next() { 115 seek(1); 116 } 117 118 void prev() { 119 seek(-1); 120 } 121 122 void dive(BrainfuckInstruction[] i) { 123 depth++; 124 insts ~= i; 125 index ~= 0; 126 } 127 128 void rise() { 129 depth--; 130 index.popBack; 131 insts.popBack; 132 } 133 134 BrainfuckInstruction instruction() { 135 auto i = index[depth]; 136 137 if(i >= 0 && i < insts[depth].length) { 138 return insts[depth][index[depth]]; 139 } 140 141 return null; 142 } 143 144 bool is_basic(BrainfuckInstruction inst) { 145 return cast(Select) inst 146 || cast(Modify) inst 147 || cast(Clear) inst 148 || cast(Input) inst 149 || cast(Output) inst 150 || cast(UnrolledLoop) inst; 151 } 152 153 CFG parse() { 154 auto inst = instruction; 155 156 if(inst !is null) { 157 if(is_basic(inst)) { 158 return parse_basic_block; 159 } else { 160 return parse_if; 161 } 162 } 163 164 return null; 165 } 166 167 BasicBlockCFG parse_basic_block() { 168 auto inst = instruction; 169 BrainfuckInstruction[] insts; 170 171 while(is_basic(inst)) { 172 if(auto unroll = cast(UnrolledLoop) inst) { 173 for(uint i = 0; i < unroll.count; i++) { 174 foreach(inner_inst; unroll.insts) { 175 insts ~= inner_inst; 176 } 177 } 178 } else { 179 insts ~= inst; 180 } 181 182 next; 183 inst = instruction; 184 } 185 186 auto block = new BasicBlockCFG(insts); 187 block.outgoing = parse; 188 if(block.outgoing !is null) block.outgoing.incoming ~= block; 189 return block; 190 } 191 192 IfCFG parse_if() { 193 auto inst = instruction; 194 195 if(auto loop = cast(Loop) inst) { 196 auto if_cfg = new IfCFG(IfType.Loop); 197 next; 198 if_cfg.outgoing_false = parse; 199 if(if_cfg.outgoing_false !is null) if_cfg.outgoing_false.incoming ~= if_cfg; 200 dive(loop.insts); 201 if_cfg.outgoing_true = parse; 202 if(if_cfg.outgoing_true !is null) if_cfg.outgoing_true.incoming ~= if_cfg; 203 204 CFG current = if_cfg.outgoing_true; 205 while(true) { 206 if(auto basic_cfg = cast(BasicBlockCFG) current) { 207 current = basic_cfg.outgoing; 208 if(current is null) { 209 basic_cfg.outgoing = if_cfg; 210 if_cfg.incoming ~= basic_cfg; 211 break; 212 } 213 } else if(auto inner_if_cfg = cast(IfCFG) current) { 214 current = inner_if_cfg.outgoing_false; 215 if(current is null) { 216 inner_if_cfg.outgoing_false = if_cfg; 217 if_cfg.incoming ~= inner_if_cfg; 218 break; 219 } 220 } else if(auto move_cfg = cast(MoveCFG) current) { 221 current = move_cfg.outgoing; 222 } 223 } 224 225 rise; 226 return if_cfg; 227 } else if(auto move = cast(MoveLoop) inst) { 228 auto move_cfg = new MoveCFG(move); 229 auto if_cfg = new IfCFG(IfType.Move); 230 if_cfg.outgoing_true = move_cfg; 231 move_cfg.incoming ~= if_cfg; 232 next; 233 234 auto next_instruction = parse; 235 if_cfg.outgoing_false = next_instruction; 236 if(next_instruction !is null) next_instruction.incoming ~= if_cfg; 237 move_cfg.outgoing = if_cfg; 238 if_cfg.incoming ~= move_cfg; 239 return if_cfg; 240 } else if(auto if_bf = cast(If) inst) { 241 auto if_cfg = new IfCFG(IfType.If); 242 dive(if_bf.insts); 243 if_cfg.outgoing_true = parse; 244 if(if_cfg !is null) if_cfg.outgoing_true.incoming ~= if_cfg; 245 rise; 246 247 next; 248 auto next_instruction = parse; 249 if_cfg.outgoing_false = next_instruction; 250 if(next_instruction !is null) next_instruction.incoming ~= if_cfg.outgoing_false; 251 252 CFG current = if_cfg.outgoing_true; 253 while(true) { 254 if(auto basic_cfg = cast(BasicBlockCFG) current) { 255 current = basic_cfg.outgoing; 256 if(current is null) { 257 basic_cfg.outgoing = if_cfg; 258 if_cfg.incoming ~= basic_cfg; 259 break; 260 } 261 } else if(auto inner_if_cfg = cast(IfCFG) current) { 262 current = inner_if_cfg.outgoing_false; 263 if(current is null) { 264 inner_if_cfg.outgoing_false = if_cfg; 265 if_cfg.incoming ~= inner_if_cfg; 266 break; 267 } 268 } else if(auto move_cfg = cast(MoveCFG) current) { 269 current = move_cfg.outgoing; 270 } 271 } 272 273 return if_cfg; 274 } 275 276 return null; 277 } 278 }