1 module d.llvm.backend; 2 3 import d.llvm.codegen; 4 import d.llvm.evaluator; 5 import d.llvm.datalayout; 6 7 import d.ir.symbol; 8 9 import llvm.c.core; 10 import llvm.c.target; 11 import llvm.c.targetMachine; 12 13 final class LLVMBackend { 14 private: 15 CodeGen pass; 16 17 uint optLevel; 18 string[] linkerPaths; 19 20 LLVMEvaluator evaluator; 21 LLVMDataLayout dataLayout; 22 23 LLVMTargetMachineRef targetMachine; 24 25 public: 26 import d.semantic.semantic; 27 this(SemanticPass sema, string name, uint optLevel, string[] linkerPaths) { 28 this.optLevel = optLevel; 29 this.linkerPaths = linkerPaths; 30 31 LLVMInitializeX86TargetInfo(); 32 LLVMInitializeX86Target(); 33 LLVMInitializeX86TargetMC(); 34 35 import llvm.c.executionEngine; 36 LLVMLinkInMCJIT(); 37 LLVMInitializeX86AsmPrinter(); 38 39 version(OSX) { 40 auto triple = "x86_64-apple-darwin9".ptr; 41 } else version (FreeBSD) { 42 auto triple = "x86_64-unknown-freebsd".ptr; 43 } else { 44 auto triple = "x86_64-pc-linux-gnu".ptr; 45 } 46 47 version(linux) { 48 enum Reloc = LLVMRelocMode.PIC; 49 } else { 50 enum Reloc = LLVMRelocMode.Default; 51 } 52 53 targetMachine = LLVMCreateTargetMachine( 54 LLVMGetFirstTarget(), 55 triple, 56 "x86-64".ptr, 57 "".ptr, 58 LLVMCodeGenOptLevel.Default, 59 Reloc, 60 LLVMCodeModel.Default, 61 ); 62 63 auto td = LLVMCreateTargetDataLayout(targetMachine); 64 scope(exit) LLVMDisposeTargetData(td); 65 66 pass = new CodeGen(sema, name, this, td); 67 dataLayout = new LLVMDataLayout(pass, pass.targetData); 68 } 69 70 ~this() { 71 LLVMDisposeTargetMachine(targetMachine); 72 } 73 74 auto getPass() { 75 return pass; 76 } 77 78 auto getEvaluator() { 79 if (evaluator is null) { 80 evaluator = new LLVMEvaluator(pass); 81 } 82 83 return evaluator; 84 } 85 86 auto getDataLayout() { 87 return dataLayout; 88 } 89 90 void visit(Module mod) { 91 pass.visit(mod); 92 } 93 94 void visit(Function f) { 95 import d.llvm.global; 96 GlobalGen(pass).define(f); 97 } 98 99 private void runLLVMPasses(Module[] modules) { 100 foreach(m; modules) { 101 pass.visit(m); 102 } 103 104 import llvm.c.transforms.passManagerBuilder; 105 auto pmb = LLVMPassManagerBuilderCreate(); 106 scope(exit) LLVMPassManagerBuilderDispose(pmb); 107 108 uint optLevel = optLevel; 109 if (optLevel == 0) { 110 LLVMPassManagerBuilderUseInlinerWithThreshold(pmb, 0); 111 LLVMPassManagerBuilderSetOptLevel(pmb, 0); 112 } else { 113 LLVMPassManagerBuilderUseInlinerWithThreshold(pmb, 100); 114 LLVMPassManagerBuilderSetOptLevel(pmb, optLevel); 115 } 116 117 auto pm = LLVMCreatePassManager(); 118 scope(exit) LLVMDisposePassManager(pm); 119 120 LLVMPassManagerBuilderPopulateModulePassManager(pmb, pm); 121 LLVMRunPassManager(pm, pass.dmodule); 122 } 123 124 void emitObject(Module[] modules, string objFile) { 125 runLLVMPasses(modules); 126 127 import std.string; 128 char* errorPtr; 129 auto emitError = LLVMTargetMachineEmitToFile( 130 targetMachine, 131 pass.dmodule, 132 objFile.toStringz(), 133 LLVMCodeGenFileType.Object, 134 &errorPtr, 135 ); 136 137 if (emitError) { 138 scope(exit) LLVMDisposeMessage(errorPtr); 139 140 import core.stdc.string, std.stdio; 141 writeln(errorPtr[0 .. strlen(errorPtr)]); 142 143 assert(0, "Fail to emit object file ! Exiting..."); 144 } 145 } 146 147 void emitAsm(Module[] modules, string filename) { 148 runLLVMPasses(modules); 149 150 import std.string; 151 char* errorPtr; 152 auto printError = LLVMTargetMachineEmitToFile( 153 targetMachine, 154 pass.dmodule, 155 filename.toStringz(), 156 LLVMCodeGenFileType.Assembly, 157 &errorPtr, 158 ); 159 160 if (printError) { 161 scope(exit) LLVMDisposeMessage(errorPtr); 162 163 import core.stdc.string, std.stdio; 164 writeln(errorPtr[0 .. strlen(errorPtr)]); 165 166 assert(0, "Failed to output assembly file! Exiting..."); 167 } 168 } 169 170 void emitLLVMAsm(Module[] modules, string filename) { 171 runLLVMPasses(modules); 172 173 import std.string; 174 char* errorPtr; 175 auto printError = LLVMPrintModuleToFile( 176 pass.dmodule, 177 filename.toStringz(), 178 &errorPtr, 179 ); 180 181 if (printError) { 182 scope(exit) LLVMDisposeMessage(errorPtr); 183 184 import core.stdc.string, std.stdio; 185 writeln(errorPtr[0 .. strlen(errorPtr)]); 186 187 assert(0, "Failed to output LLVM assembly file! Exiting..."); 188 } 189 } 190 191 void emitLLVMBitcode(Module[] modules, string filename) { 192 runLLVMPasses(modules); 193 194 import llvm.c.bitWriter; 195 import std.string; 196 auto error = LLVMWriteBitcodeToFile(pass.dmodule, filename.toStringz()); 197 if (error) { 198 assert(0, "Failed to output LLVM bitcode file! Exiting..."); 199 } 200 } 201 202 void link(string objFile, string executable) { 203 import std.algorithm, std.array; 204 auto params = linkerPaths 205 .map!(path => " -L" ~ (cast(string) path)) 206 .join(); 207 208 import std.process; 209 auto linkCommand = "gcc -o " 210 ~ escapeShellFileName(executable) ~ " " 211 ~ escapeShellFileName(objFile) 212 ~ params ~ " -lsdrt -lphobos -lpthread"; 213 214 wait(spawnShell(linkCommand)); 215 } 216 217 auto runUnittests(Module[] modules) { 218 // In a first step, we do all the codegen. 219 // We need to do it in a first step so that we can reuse 220 // one instance of MCJIT. 221 auto e = getEvaluator(); 222 223 struct Test { 224 Function unit; 225 LLVMValueRef stub; 226 227 this(LLVMEvaluator e, Function t) { 228 unit = t; 229 stub = e.createTestStub(t); 230 } 231 } 232 233 Test[] tests; 234 foreach (m; modules) { 235 foreach (t; m.tests) { 236 import source.name; 237 tests ~= Test(e, t); 238 } 239 } 240 241 // Now that we generated the IR, we run the unittests. 242 import d.llvm.evaluator; 243 auto ee = createExecutionEngine(pass.dmodule); 244 scope(exit) destroyExecutionEngine(ee, pass.dmodule); 245 246 struct Result { 247 import std.bitmanip; 248 mixin(taggedClassRef!( 249 Function, "test", 250 bool, "pass", 1, 251 )); 252 253 this(Function test, bool pass) { 254 this.test = test; 255 this.pass = pass; 256 } 257 } 258 259 Result[] results; 260 261 foreach (t; tests) { 262 import llvm.c.executionEngine; 263 auto result = LLVMRunFunction(ee, t.stub, 0, null); 264 scope(exit) LLVMDisposeGenericValue(result); 265 266 // Check the return value and report. 267 // TODO: We need to make a specific report of the failure 268 // if indeed there is failure. 269 bool pass = !LLVMGenericValueToInt(result, false); 270 results ~= Result(t.unit, pass); 271 } 272 273 return results; 274 } 275 }