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 }