1 module d.llvm.codegen; 2 3 import d.ir.expression; 4 import d.ir.symbol; 5 import d.ir.type; 6 7 import util.visitor; 8 9 import llvm.c.analysis; 10 import llvm.c.core; 11 import llvm.c.target; 12 13 // Conflict with Interface in object.di 14 alias Interface = d.ir.symbol.Interface; 15 16 final class CodeGen { 17 import source.context; 18 Context context; 19 20 import d.semantic.scheduler; 21 Scheduler scheduler; 22 23 import d.object; 24 ObjectReference object; 25 26 LLVMContextRef llvmCtx; 27 LLVMModuleRef dmodule; 28 29 LLVMValueRef[ValueSymbol] globals; 30 31 import d.llvm.local; 32 LocalData localData; 33 34 LLVMTargetDataRef targetData; 35 36 import d.llvm.type; 37 TypeGenData typeGenData; 38 39 private LLVMValueRef[string] stringLiterals; 40 41 import d.llvm.statement; 42 StatementGenData statementGenData; 43 44 import d.llvm.intrinsic; 45 IntrinsicGenData intrinsicGenData; 46 47 LLVMValueRef unlikelyBranch; 48 uint profKindID; 49 50 // FIXME: We hold a refernece to the backend here so it is not GCed. 51 // Now that JIT use its own codegen, no reference to the JIT backend 52 // is held if that one goes. The whole thing needs to be refactored 53 // in a way that is more sensible. 54 import d.llvm.backend; 55 LLVMBackend backend; 56 57 import d.semantic.semantic; 58 this(SemanticPass sema, string name, LLVMBackend backend, LLVMTargetDataRef targetData) { 59 this.context = sema.context; 60 this.scheduler = sema.scheduler; 61 this.object = sema.object; 62 this.backend = backend; 63 64 // Make sure globals are initialized. 65 globals[null] = null; 66 globals.remove(null); 67 68 llvmCtx = LLVMContextCreate(); 69 70 import std.string; 71 dmodule = LLVMModuleCreateWithNameInContext(name.toStringz(), llvmCtx); 72 73 LLVMSetModuleDataLayout(dmodule, targetData); 74 this.targetData = LLVMGetModuleDataLayout(dmodule); 75 76 LLVMValueRef[3] branch_metadata; 77 78 auto id = "branch_weights"; 79 branch_metadata[0] = LLVMMDStringInContext(llvmCtx, id.ptr, cast(uint) id.length); 80 branch_metadata[1] = LLVMConstInt(LLVMInt32TypeInContext(llvmCtx), 65536, false); 81 branch_metadata[2] = LLVMConstInt(LLVMInt32TypeInContext(llvmCtx), 0, false); 82 83 unlikelyBranch = LLVMMDNodeInContext(llvmCtx, branch_metadata.ptr, cast(uint) branch_metadata.length); 84 85 id = "prof"; 86 profKindID = LLVMGetMDKindIDInContext(llvmCtx, id.ptr, cast(uint) id.length); 87 } 88 89 ~this() { 90 LLVMDisposeModule(dmodule); 91 LLVMContextDispose(llvmCtx); 92 } 93 94 Module visit(Module m) { 95 // Dump module content on failure (for debug purpose). 96 scope(failure) LLVMDumpModule(dmodule); 97 98 foreach(s; m.members) { 99 import d.llvm.global; 100 GlobalGen(this).define(s); 101 } 102 103 checkModule(); 104 return m; 105 } 106 107 auto buildDString(string str) in { 108 assert(str.length <= uint.max, "string length must be <= uint.max"); 109 } do { 110 return stringLiterals.get(str, stringLiterals[str] = { 111 auto cstr = str ~ '\0'; 112 auto charArray = LLVMConstStringInContext(llvmCtx, cstr.ptr, cast(uint) cstr.length, true); 113 114 auto globalVar = LLVMAddGlobal(dmodule, LLVMTypeOf(charArray), ".str"); 115 LLVMSetInitializer(globalVar, charArray); 116 LLVMSetLinkage(globalVar, LLVMLinkage.Private); 117 LLVMSetGlobalConstant(globalVar, true); 118 LLVMSetUnnamedAddr(globalVar, true); 119 120 auto zero = LLVMConstInt(LLVMInt64TypeInContext(llvmCtx), 0, true); 121 LLVMValueRef[2] indices = [zero, zero]; 122 123 LLVMValueRef[2] slice; 124 slice[0] = LLVMConstInt(LLVMInt64TypeInContext(llvmCtx), str.length, false); 125 slice[1] = LLVMConstInBoundsGEP(globalVar, indices.ptr, indices.length); 126 127 return LLVMConstStructInContext(llvmCtx, slice.ptr, indices.length, false); 128 }()); 129 } 130 131 auto checkModule() { 132 char* msg; 133 if (LLVMVerifyModule(dmodule, LLVMVerifierFailureAction.ReturnStatus, &msg)) { 134 scope(exit) LLVMDisposeMessage(msg); 135 136 import core.stdc.string; 137 auto error = msg[0 .. strlen(msg)].idup; 138 139 throw new Exception(error); 140 } 141 } 142 143 auto getAttribute(string name, ulong val = 0) { 144 auto id = LLVMGetEnumAttributeKindForName(name.ptr, name.length); 145 return LLVMCreateEnumAttribute(llvmCtx, id, val); 146 } 147 }