1 module d.llvm.global; 2 3 import d.llvm.codegen; 4 5 import d.ir.symbol; 6 import d.ir.type; 7 8 import util.visitor; 9 10 import llvm.c.analysis; 11 import llvm.c.core; 12 13 // Conflict with Interface in object.di 14 alias Interface = d.ir.symbol.Interface; 15 16 struct GlobalGen { 17 private CodeGen pass; 18 alias pass this; 19 20 import d.llvm.local : Mode; 21 Mode mode; 22 23 this(CodeGen pass, Mode mode = Mode.Lazy) { 24 this.pass = pass; 25 this.mode = mode; 26 } 27 28 void define(Symbol s) in { 29 assert(s.step == Step.Processed); 30 } do { 31 if (auto f = cast(Function) s) { 32 define(f); 33 } else if (auto t = cast(Template) s) { 34 define(t); 35 } else if (auto a = cast(Aggregate) s) { 36 define(a); 37 } else if (auto v = cast(Variable) s) { 38 define(v); 39 } 40 } 41 42 LLVMValueRef declare(Function f) in { 43 assert(!f.hasContext, "function must not have context"); 44 } do { 45 import d.llvm.local; 46 return LocalGen(pass).declare(f); 47 } 48 49 LLVMValueRef define(Function f) in { 50 assert(!f.hasContext, "function must not have context"); 51 } do { 52 import d.llvm.local; 53 return LocalGen(pass).define(f); 54 } 55 56 LLVMValueRef declare(Variable v) in { 57 assert(v.storage.isGlobal, "locals not supported"); 58 assert(!v.isFinal); 59 assert(!v.isRef); 60 } do { 61 auto var = globals.get(v, { 62 if (v.storage == Storage.Enum) { 63 import d.llvm.constant; 64 return ConstantGen(pass).visit(v.value); 65 } 66 67 return createVariableStorage(v); 68 }()); 69 70 // Register the variable. 71 globals[v] = var; 72 if (!v.value || v.storage == Storage.Enum) { 73 return var; 74 } 75 76 if (v.inTemplate || mode == Mode.Eager) { 77 if (maybeDefine(v, var)) { 78 LLVMSetLinkage(var, LLVMLinkage.LinkOnceODR); 79 } 80 } 81 82 return var; 83 } 84 85 LLVMValueRef define(Variable v) in { 86 assert(v.storage.isGlobal, "locals not supported"); 87 assert(!v.isFinal); 88 assert(!v.isRef); 89 } do { 90 auto var = declare(v); 91 if (!v.value || v.storage == Storage.Enum) { 92 return var; 93 } 94 95 if (!maybeDefine(v, var)) { 96 auto linkage = LLVMGetLinkage(var); 97 assert(linkage == LLVMLinkage.LinkOnceODR, "variable " ~ v.mangle.toString(context) ~ " already defined"); 98 LLVMSetLinkage(var, LLVMLinkage.External); 99 } 100 101 return var; 102 } 103 104 bool maybeDefine(Variable v, LLVMValueRef var) in { 105 assert(v.storage.isGlobal, "locals not supported"); 106 assert(v.storage != Storage.Enum, "enum do not have a storage"); 107 assert(!v.isFinal); 108 assert(!v.isRef); 109 } do { 110 if (LLVMGetInitializer(var)) { 111 return false; 112 } 113 114 import d.llvm.constant; 115 auto value = ConstantGen(pass).visit(v.value); 116 117 // Store the initial value into the global variable. 118 LLVMSetInitializer(var, value); 119 return true; 120 } 121 122 private LLVMValueRef createVariableStorage(Variable v) in { 123 assert(v.storage.isGlobal, "locals not supported"); 124 assert(v.storage != Storage.Enum, "enum do not have a storage"); 125 } do { 126 auto qualifier = v.type.qualifier; 127 128 import d.llvm.type; 129 auto type = TypeGen(pass).visit(v.type); 130 131 // If it is not enum, it must be static. 132 assert(v.storage == Storage.Static); 133 auto var = LLVMAddGlobal(dmodule, type, v.mangle.toStringz(context)); 134 135 // Depending on the type qualifier, 136 // make it thread local/ constant or nothing. 137 final switch(qualifier) with(TypeQualifier) { 138 case Mutable, Inout, Const: 139 LLVMSetThreadLocal(var, true); 140 break; 141 142 case Shared, ConstShared: 143 break; 144 145 case Immutable: 146 LLVMSetGlobalConstant(var, true); 147 break; 148 } 149 150 return var; 151 } 152 153 LLVMTypeRef define(Aggregate a) in { 154 assert(a.step == Step.Processed); 155 } do { 156 return this.dispatch(a); 157 } 158 159 LLVMTypeRef visit(Struct s) in { 160 assert(s.step == Step.Processed); 161 } do { 162 import d.llvm.type; 163 auto ret = TypeGen(pass).visit(s); 164 165 foreach(m; s.members) { 166 if (typeid(m) !is typeid(Field)) { 167 define(m); 168 } 169 } 170 171 return ret; 172 } 173 174 LLVMTypeRef visit(Class c) in { 175 assert(c.step == Step.Processed); 176 } do { 177 import d.llvm.type; 178 auto ret = TypeGen(pass).visit(c); 179 180 foreach(m; c.members) { 181 if (auto f = cast(Method) m) { 182 // We don't want to define inherited methods in childs. 183 if (!f.hasThis || f.type.parameters[0].getType().dclass is c) { 184 define(f); 185 } 186 187 continue; 188 } 189 190 if (typeid(m) !is typeid(Field)) { 191 define(m); 192 } 193 } 194 195 return ret; 196 } 197 198 LLVMTypeRef visit(Union u) in { 199 assert(u.step == Step.Processed); 200 } do { 201 import d.llvm.type; 202 auto ret = TypeGen(pass).visit(u); 203 204 foreach(m; u.members) { 205 if (typeid(m) !is typeid(Field)) { 206 define(m); 207 } 208 } 209 210 return ret; 211 } 212 213 LLVMTypeRef visit(Interface i) in { 214 assert(i.step == Step.Processed); 215 } do { 216 import d.llvm.type; 217 return TypeGen(pass).visit(i); 218 } 219 220 void define(Template t) { 221 foreach(i; t.instances) { 222 if (i.hasThis || i.hasContext) { 223 continue; 224 } 225 226 foreach(m; i.members) { 227 import d.llvm.local; 228 LocalGen(pass).define(m); 229 } 230 } 231 } 232 }