From bce3fa000b04568a0f6109db5f4bf78ca9a33d25 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 10 Nov 2025 23:08:57 -0800 Subject: [PATCH] [IRGen] Correctly assign lazily-emitted global variables in multi-threaded IRGen With multi-threaded IRGen, the global variables associated with "once" initialization tokens were not getting colocated with their actual global variables, which caused the initialization code to get split across different files. This issue manifest as autolinking errors in some projects. Fixes rdar://162400654. --- include/swift/SIL/SILGlobalVariable.h | 24 +++++++++++++++++------- lib/IRGen/GenDecl.cpp | 4 ++-- lib/IRGen/IRGenModule.cpp | 5 ++--- lib/SIL/IR/SILGlobalVariable.cpp | 18 +++++++++++++++++- lib/SILGen/SILGenGlobalVariable.cpp | 1 + test/IRGen/multithread_global_var.swift | 24 ++++++++++++++++++++++++ 6 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 test/IRGen/multithread_global_var.swift diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index acc01dda5a650..84ddda77883e0 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -52,9 +52,11 @@ class SILGlobalVariable /// The SIL module that the global variable belongs to. SILModule &Module; - /// The module that defines this global variable. This member should only be - /// when a global variable is deserialized to be emitted into another module. - ModuleDecl *ParentModule = nullptr; + /// Either the declaration context of the global variable or the parent + /// module in which the global variable resides. + /// + /// The latter is only used for a deserialized global variable. + llvm::PointerUnion DeclCtxOrParentModule; /// The mangled name of the variable, which will be propagated to the /// binary. A pointer into the module's lookup table. @@ -131,13 +133,21 @@ class SILGlobalVariable SILModule &getModule() const { return Module; } - /// Returns the module that defines this function. + /// Returns the module that defines this global variable. ModuleDecl *getParentModule() const; - /// Sets \c ParentModule as fallback if \c DeclCtxt is not available to - /// provide the parent module. + /// Get the declaration context of this global variable, if it has one. + DeclContext *getDeclContext() const; + + /// Sets the parent module for a deserialized global variable. void setParentModule(ModuleDecl *module) { - ParentModule = module; + DeclCtxOrParentModule = module; + } + + /// Sets the declaration context for a global variable that's not anchored to + /// a declaration. + void setDeclContext(DeclContext *declCtx) { + DeclCtxOrParentModule = declCtx; } SILType getLoweredType() const { return LoweredType; } diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index d36385a56f6fd..88c5ab46897ad 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1561,8 +1561,8 @@ void IRGenerator::addLazyGlobalVariable(SILGlobalVariable *v) { assert(!FinishedEmittingLazyDefinitions); LazyGlobalVariables.push_back(v); - if (auto decl = v->getDecl()) { - if (decl->getDeclContext()->getParentSourceFile()) + if (auto dc = v->getDeclContext()) { + if (dc->getParentSourceFile()) return; } diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 9d7512025d90c..15c8d8d72cdfb 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -2333,9 +2333,8 @@ IRGenModule *IRGenerator::getGenModule(SILGlobalVariable *v) { if (found != DefaultIGMForGlobalVariable.end()) return found->second; - if (auto decl = v->getDecl()) { - return getGenModule(decl->getDeclContext()); - } + if (auto *dc = v->getDeclContext()) + return getGenModule(dc); return getPrimaryIGM(); } diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index 8b8b5b1260b0c..2349b7702efd6 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -44,7 +44,23 @@ SILGlobalVariable *SILGlobalVariable::create(SILModule &M, SILLinkage linkage, } ModuleDecl *SILGlobalVariable::getParentModule() const { - return ParentModule ? ParentModule : getModule().getSwiftModule(); + if (auto parentModule = DeclCtxOrParentModule.dyn_cast()) + return parentModule; + + if (auto declContext = DeclCtxOrParentModule.dyn_cast()) + return declContext->getParentModule(); + + return getModule().getSwiftModule(); +} + +DeclContext *SILGlobalVariable::getDeclContext() const { + if (auto var = getDecl()) + return var->getDeclContext(); + + if (auto declContext = DeclCtxOrParentModule.dyn_cast()) + return declContext; + + return nullptr; } static bool isGlobalLet(SILModule &mod, VarDecl *decl, SILType type) { diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 337a503bf3c7a..d1af47fcd48e7 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -243,6 +243,7 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, IsNotSerialized, onceTokenBuffer, onceSILTy); onceToken->setDeclaration(false); + onceToken->setDeclContext(pd->getDeclContext()); // Emit the initialization code into a function. Mangle::ASTMangler FuncMangler(pd->getASTContext()); diff --git a/test/IRGen/multithread_global_var.swift b/test/IRGen/multithread_global_var.swift new file mode 100644 index 0000000000000..45853cccfdf28 --- /dev/null +++ b/test/IRGen/multithread_global_var.swift @@ -0,0 +1,24 @@ +// RUN: %empty-directory(%t/src) +// RUN: split-file %s %t/src + +// RUN: %target-swift-frontend %t/src/A.swift %t/src/B.swift -emit-ir -o %t/A.ll -o %t/B.ll -num-threads 2 -O -g -module-name test +// RUN: %FileCheck --check-prefix=CHECK-A %s <%t/A.ll +// RUN: %FileCheck --check-prefix=CHECK-B %s <%t/B.ll + +//--- A.swift + +public func f() -> String { "hello" } + +public func g() -> Bool { + f() == X.introduction +} + +// CHECK-A: @"$s4test1XV12introduction_Wz" = external hidden global + +//--- B.swift + +public struct X { + public static var introduction: String = f().uppercased() +} + +// CHECK-B: @"$s4test1XV12introduction_Wz" = weak_odr hidden global