1 /// Copyright: Copyright (c) 2017-2020 Andrey Penechko. 2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 3 /// Authors: Andrey Penechko. 4 module vox.passes; 5 6 import vox.all; 7 8 void pass_write_binary(ref CompilationContext context, CompilePassPerModule[] subPasses) 9 { 10 import std.file : write; 11 write(context.outputFilename, context.binaryBuffer.data); 12 13 version(Posix) { 14 import std.file : setAttributes, getAttributes; 15 import std.conv : octal; 16 setAttributes(context.outputFilename, getAttributes(context.outputFilename) | octal!111); 17 } 18 } 19 20 void write_bundle(ref CompilationContext context) 21 { 22 import std.file : write; 23 write(context.outputFilename, context.bundleBuffer.data); 24 } 25 26 immutable CompilePassGlobal[] frontendPasses = [ 27 global_pass("Read source", &pass_read_source), 28 global_pass("Lex", &pass_lexer), 29 global_pass("Parse", &pass_parser), 30 global_pass("Register names", &pass_names_register), 31 global_pass("Lookup names", &pass_names_resolve), 32 global_pass("Check types", &pass_type_check), 33 ]; 34 35 immutable CompilePassGlobal[] backendPasses = [ 36 global_pass("IR gen", &pass_ir_gen), 37 38 global_pass("Optimize", &pass_optimize_ir), 39 40 global_pass(null, &run_ir_to_lir_liveness_and_reg_alloc, [ 41 CompilePassPerFunction("IR lower", null), 42 CompilePassPerFunction("IR to LIR AMD64", null), 43 // IR liveness 44 CompilePassPerFunction("Live intervals", null), 45 // IR regalloc 46 CompilePassPerFunction("Linear scan", null), 47 // Stack layout 48 CompilePassPerFunction("Stack layout", null), 49 ]), 50 51 // LIR -> machine code 52 global_pass("Code gen", &pass_emit_mc_amd64), 53 ]; 54 55 immutable CompilePassGlobal[] commonPasses = frontendPasses ~ backendPasses; 56 57 58 59 immutable CompilePassGlobal[] extraJitPasses = [ 60 CompilePassGlobal("Link JIT", &pass_link_jit), 61 ]; 62 63 immutable CompilePassGlobal[] extraExePasses = [ 64 CompilePassGlobal("Link executable", &pass_create_executable), 65 CompilePassGlobal("Write binary", &pass_write_binary), 66 ]; 67 68 CompilePassGlobal[] frontendOnlyPasses = frontendPasses; 69 CompilePassGlobal[] jitPasses = commonPasses ~ extraJitPasses; 70 CompilePassGlobal[] exePasses = commonPasses ~ extraExePasses; 71 CompilePassGlobal[] bundlePasses = commonPasses ~ extraExePasses[0..$-1]; 72 73 void run_global_pass(ref CompilationContext context, CompilePassPerModule[] subPasses) 74 { 75 //context.printMemSize; 76 foreach (ref SourceFileInfo file; context.files.data) 77 { 78 foreach(ref CompilePassPerModule subPass; subPasses) 79 { 80 auto time1 = currTime; 81 82 // throws immediately on unrecoverable error or ICE 83 subPass.run(context, *file.mod, subPass.subPasses); 84 85 auto time2 = currTime; 86 subPass.duration += time2-time1; 87 88 // throws if there were recoverable error in the pass 89 context.throwOnErrors; 90 } 91 } 92 } 93 94 void run_module_pass(ref CompilationContext context, ref ModuleDeclNode mod, CompilePassPerFunction[] subPasses) 95 { 96 foreach (AstIndex funcIndex; mod.functions) 97 { 98 FunctionDeclNode* func = context.getAst!FunctionDeclNode(funcIndex); 99 100 foreach(ref CompilePassPerFunction subPass; subPasses) 101 { 102 auto time1 = currTime; 103 104 // throws immediately on unrecoverable error or ICE 105 subPass.run(context, mod, *func); 106 107 auto time2 = currTime; 108 subPass.duration += time2-time1; 109 110 // throws if there were recoverable error in the pass 111 context.throwOnErrors; 112 } 113 } 114 } 115 116 void run_ir_to_lir_liveness_and_reg_alloc(ref CompilationContext context, CompilePassPerModule[] subPasses) 117 { 118 CompilePassPerFunction* ir_lower_pass = &subPasses[0].subPasses[0]; 119 CompilePassPerFunction* ir_to_lir_pass = &subPasses[0].subPasses[1]; 120 CompilePassPerFunction* liveness_pass = &subPasses[0].subPasses[2]; 121 CompilePassPerFunction* ra_pass = &subPasses[0].subPasses[3]; 122 CompilePassPerFunction* stack_layout_pass = &subPasses[0].subPasses[4]; 123 124 // gets reused for all functions 125 LivenessInfo liveness; 126 LinearScan linearScan; 127 linearScan.context = &context; 128 linearScan.livePtr = &liveness; 129 scope(exit) linearScan.freeMem; 130 131 scope(exit) context.tempBuffer.clear; 132 scope(exit) context.currentFunction = null; 133 134 foreach (ref SourceFileInfo file; context.files.data) 135 { 136 foreach (AstIndex funcIndex; file.mod.functions) 137 { 138 FunctionDeclNode* func = context.getAst!FunctionDeclNode(funcIndex); 139 140 if (func.isExternal) continue; 141 142 context.currentFunction = func; 143 context.tempBuffer.clear; 144 145 146 { 147 auto time1 = currTime; 148 pass_ir_lower(&context, file.mod, func); // throws immediately on unrecoverable error or ICE 149 auto time2 = currTime; 150 ir_lower_pass.duration += time2-time1; 151 context.throwOnErrors; // throws if there were recoverable error in the pass 152 } 153 154 IrBuilder lirBuilder; 155 { 156 auto time1 = currTime; 157 pass_ir_to_lir_amd64(&context, &lirBuilder, file.mod, func); // throws immediately on unrecoverable error or ICE 158 auto time2 = currTime; 159 ir_to_lir_pass.duration += time2-time1; 160 context.throwOnErrors; // throws if there were recoverable error in the pass 161 } 162 163 { 164 auto time1 = currTime; 165 pass_live_intervals(&context, file.mod, func, &liveness); // throws immediately on unrecoverable error or ICE 166 auto time2 = currTime; 167 liveness_pass.duration += time2-time1; 168 context.throwOnErrors; // throws if there were recoverable error in the pass 169 } 170 171 { 172 auto time1 = currTime; 173 174 linearScan.builder = &lirBuilder; 175 linearScan.fun = func; 176 pass_linear_scan(&linearScan); // throws immediately on unrecoverable error or ICE 177 178 auto time2 = currTime; 179 ra_pass.duration += time2-time1; 180 context.throwOnErrors; // throws if there were recoverable error in the pass 181 } 182 183 { 184 auto time1 = currTime; 185 pass_stack_layout(&context, func); // throws immediately on unrecoverable error or ICE 186 auto time2 = currTime; 187 stack_layout_pass.duration += time2-time1; 188 context.throwOnErrors; // throws if there were recoverable error in the pass 189 } 190 } 191 } 192 } 193 194 CompilePassGlobal global_pass(string name, GlobalPassFun run, CompilePassPerModule[] subPasses = null) 195 { 196 return CompilePassGlobal(name, run, subPasses); 197 } 198 199 CompilePassGlobal global_pass(string name, ModulePassFun run, CompilePassPerFunction[] subPasses = null) 200 { 201 return CompilePassGlobal(null, &run_global_pass, [CompilePassPerModule(null, run, subPasses)]); 202 } 203 204 CompilePassGlobal global_pass(string name, GlobalPassFun run, CompilePassPerFunction[] subPasses) 205 { 206 return CompilePassGlobal(name, run, [CompilePassPerModule(null, &run_module_pass, subPasses)]); 207 } 208 209 CompilePassGlobal global_pass(string name, FunctionPassFun run) 210 { 211 return CompilePassGlobal(null, &run_global_pass, [ 212 CompilePassPerModule(null, &run_module_pass, [ 213 CompilePassPerFunction(name, run)])]); 214 } 215 216 alias GlobalPassFun = void function(ref CompilationContext context, CompilePassPerModule[] subPasses); 217 alias ModulePassFun = void function(ref CompilationContext context, ref ModuleDeclNode mod, CompilePassPerFunction[] subPasses); 218 alias FunctionPassFun = void function(ref CompilationContext context, ref ModuleDeclNode mod, ref FunctionDeclNode func); 219 220 /// Must have either `run` or subPasses 221 struct CompilePassGlobal 222 { 223 string name; 224 GlobalPassFun run; 225 CompilePassPerModule[] subPasses; 226 Duration duration; 227 void clear() { 228 duration = Duration.init; 229 foreach(ref subPass; subPasses) subPass.clear; 230 } 231 } 232 233 struct CompilePassPerModule 234 { 235 string name; 236 void function(ref CompilationContext context, ref ModuleDeclNode mod, CompilePassPerFunction[] subPasses) run; 237 CompilePassPerFunction[] subPasses; 238 Duration duration; 239 void clear() { 240 duration = Duration.init; 241 foreach(ref subPass; subPasses) subPass.clear; 242 } 243 } 244 245 struct CompilePassPerFunction 246 { 247 string name; 248 void function(ref CompilationContext context, ref ModuleDeclNode mod, ref FunctionDeclNode func) run; 249 Duration duration; 250 void clear() { 251 duration = Duration.init; 252 } 253 } 254 255 struct PassMetaIterator 256 { 257 CompilePassGlobal[] passes; 258 int opApply(scope int delegate(size_t, string name, Duration duration) dg) 259 { 260 size_t i = 0; 261 foreach(ref pass; passes) 262 { 263 if (auto res = dg(i, pass.name, pass.duration)) return res; 264 ++i; 265 foreach(ref subPass; pass.subPasses) 266 { 267 if (auto res = dg(i, subPass.name, subPass.duration)) return res; 268 ++i; 269 foreach(ref subPass2; subPass.subPasses) 270 { 271 if (auto res = dg(i, subPass2.name, subPass2.duration)) return res; 272 ++i; 273 } 274 } 275 } 276 return 0; 277 } 278 }