@@ -141,11 +141,12 @@ void jl_link_global(GlobalVariable *GV, void *addr) JL_NOTSAFEPOINT
141141 ++LinkedGlobals;
142142 Constant *P = literal_static_pointer_val (addr, GV->getValueType ());
143143 GV->setInitializer (P);
144+ GV->setDSOLocal (true );
144145 if (jl_options.image_codegen ) {
145146 // If we are forcing imaging mode codegen for debugging,
146147 // emit external non-const symbol to avoid LLVM optimizing the code
147148 // similar to non-imaging mode.
148- GV->setLinkage (GlobalValue::ExternalLinkage );
149+ assert ( GV->hasExternalLinkage () );
149150 }
150151 else {
151152 GV->setConstant (true );
@@ -162,6 +163,23 @@ void jl_jit_globals(std::map<void *, GlobalVariable*> &globals) JL_NOTSAFEPOINT
162163 }
163164}
164165
166+ // used for image_codegen, where we keep all the gvs external
167+ // so we can't jit them directly into each module
168+ static orc::ThreadSafeModule jl_get_globals_module (orc::ThreadSafeContext &ctx, bool imaging_mode, const DataLayout &DL, const Triple &T, std::map<void *, GlobalVariable*> &globals) JL_NOTSAFEPOINT
169+ {
170+ auto lock = ctx.getLock ();
171+ auto GTSM = jl_create_ts_module (" globals" , ctx, imaging_mode, DL, T);
172+ auto GM = GTSM.getModuleUnlocked ();
173+ for (auto &global : globals) {
174+ auto GV = global.second ;
175+ auto GV2 = new GlobalVariable (*GM, GV->getValueType (), GV->isConstant (), GlobalValue::ExternalLinkage, literal_static_pointer_val (global.first , GV->getValueType ()), GV->getName (), nullptr , GV->getThreadLocalMode (), GV->getAddressSpace (), false );
176+ GV2->copyAttributesFrom (GV);
177+ GV2->setDSOLocal (true );
178+ GV2->setAlignment (GV->getAlign ());
179+ }
180+ return GTSM;
181+ }
182+
165183// this generates llvm code for the lambda info
166184// and adds the result to the jitlayers
167185// (and the shadow module),
@@ -211,46 +229,53 @@ static jl_callptr_t _jl_compile_codeinst(
211229
212230 if (params._shared_module )
213231 jl_ExecutionEngine->addModule (orc::ThreadSafeModule (std::move (params._shared_module ), params.tsctx ));
214- if (!params.imaging ) {
215- StringMap<orc::ThreadSafeModule*> NewExports;
232+
233+ // In imaging mode, we can't inline global variable initializers in order to preserve
234+ // the fiction that we don't know what loads from the global will return. Thus, we
235+ // need to emit a separate module for the globals before any functions are compiled,
236+ // to ensure that the globals are defined when they are compiled.
237+ if (params.imaging ) {
238+ jl_ExecutionEngine->addModule (jl_get_globals_module (params.tsctx , params.imaging , params.DL , params.TargetTriple , params.global_targets ));
239+ } else {
216240 StringMap<void *> NewGlobals;
217241 for (auto &global : params.global_targets ) {
218242 NewGlobals[global.second ->getName ()] = global.first ;
219243 }
220244 for (auto &def : emitted) {
221- orc::ThreadSafeModule &TSM = std::get<0 >(def.second );
222- // The underlying context object is still locked because params is not destroyed yet
223- auto M = TSM.getModuleUnlocked ();
224- for (auto &F : M->global_objects ()) {
225- if (!F.isDeclaration () && F.getLinkage () == GlobalValue::ExternalLinkage) {
226- NewExports[F.getName ()] = &TSM;
227- }
228- }
229- // Let's link all globals here also (for now)
245+ auto M = std::get<0 >(def.second ).getModuleUnlocked ();
230246 for (auto &GV : M->globals ()) {
231247 auto InitValue = NewGlobals.find (GV.getName ());
232248 if (InitValue != NewGlobals.end ()) {
233249 jl_link_global (&GV, InitValue->second );
234250 }
235251 }
236252 }
237- DenseMap<orc::ThreadSafeModule*, int > Queued;
238- std::vector<orc::ThreadSafeModule*> Stack;
239- for (auto &def : emitted) {
240- // Add the results to the execution engine now
241- orc::ThreadSafeModule &M = std::get<0 >(def.second );
242- jl_add_to_ee (M, NewExports, Queued, Stack);
243- assert (Queued.empty () && Stack.empty () && !M);
244- }
245- } else {
246- jl_jit_globals (params.global_targets );
247- auto main = std::move (emitted[codeinst].first );
248- for (auto &def : emitted) {
249- if (def.first != codeinst) {
250- jl_merge_module (main, std::move (def.second .first ));
253+ }
254+
255+ // Collect the exported functions from the emitted modules,
256+ // which form dependencies on which functions need to be
257+ // compiled first. Cycles of functions are compiled together.
258+ // (essentially we compile a DAG of SCCs in reverse topological order,
259+ // if we treat declarations of external functions as edges from declaration
260+ // to definition)
261+ StringMap<orc::ThreadSafeModule*> NewExports;
262+ for (auto &def : emitted) {
263+ orc::ThreadSafeModule &TSM = std::get<0 >(def.second );
264+ // The underlying context object is still locked because params is not destroyed yet
265+ auto M = TSM.getModuleUnlocked ();
266+ for (auto &F : M->global_objects ()) {
267+ if (!F.isDeclaration () && F.getLinkage () == GlobalValue::ExternalLinkage) {
268+ NewExports[F.getName ()] = &TSM;
251269 }
252270 }
253- jl_ExecutionEngine->addModule (std::move (main));
271+ }
272+ DenseMap<orc::ThreadSafeModule*, int > Queued;
273+ std::vector<orc::ThreadSafeModule*> Stack;
274+ for (auto &def : emitted) {
275+ // Add the results to the execution engine now
276+ orc::ThreadSafeModule &M = std::get<0 >(def.second );
277+ jl_add_to_ee (M, NewExports, Queued, Stack);
278+ assert (Queued.empty () && Stack.empty () && !M);
254279 }
255280 ++CompiledCodeinsts;
256281 MaxWorkqueueSize.updateMax (emitted.size ());
0 commit comments