Skip to content

Commit e6dc10a

Browse files
committed
IRGen: More accurate getAddrOfLLVMVariableOrGOTEquivalent()
The logic here used to consist of a couple of ad-hoc checks, followed by a general assumption that if something had already been emitted, it could be referenced directly, whereas everything else had to go through a GOT entry. This is way too conservative. Instead, let's try to correctly calculate what translation unit an entity is going to end up in.
1 parent 8bdabe8 commit e6dc10a

File tree

5 files changed

+62
-49
lines changed

5 files changed

+62
-49
lines changed

include/swift/IRGen/Linking.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,9 @@ class LinkEntity {
11301130
bool isSILFunction() const {
11311131
return getKind() == Kind::SILFunction;
11321132
}
1133+
bool isDynamicallyReplaceableFunctionKey() const {
1134+
return getKind() == Kind::DynamicallyReplaceableFunctionKey;
1135+
}
11331136
bool isNominalTypeDescriptor() const {
11341137
return getKind() == Kind::NominalTypeDescriptor;
11351138
}

lib/IRGen/GenDecl.cpp

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2861,14 +2861,18 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
28612861
/// relative references to the GOT entry for the variable in the object file.
28622862
ConstantReference
28632863
IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity) {
2864+
auto canDirectlyReferenceSILFunction = [&](SILFunction *silFn) {
2865+
return (silFn->isDefinition() &&
2866+
!isAvailableExternally(silFn->getLinkage()) &&
2867+
this == IRGen.getGenModule(silFn));
2868+
};
2869+
28642870
// Handle SILFunctions specially, because unlike other entities they aren't
28652871
// variables and aren't kept in the GlobalVars table.
28662872
if (entity.isSILFunction()) {
28672873
auto *silFn = entity.getSILFunction();
28682874
auto fn = getAddrOfSILFunction(silFn, NotForDefinition);
2869-
if (silFn->isDefinition() &&
2870-
!isAvailableExternally(silFn->getLinkage()) &&
2871-
this == IRGen.getGenModule(silFn)) {
2875+
if (canDirectlyReferenceSILFunction(silFn)) {
28722876
return {fn, ConstantReference::Direct};
28732877
}
28742878

@@ -2888,22 +2892,6 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity) {
28882892
// Ensure the variable is at least forward-declared.
28892893
getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo());
28902894

2891-
// Guess whether a global entry is a definition from this TU. This isn't
2892-
// bulletproof, but at the point we emit conformance tables, we're far enough
2893-
// along that we should have emitted any metadata objects we were going to.
2894-
auto isDefinition = [&](llvm::Constant *global) -> bool {
2895-
// We only emit aliases for definitions. (An extern alias would be an
2896-
// extern global.)
2897-
if (isa<llvm::GlobalAlias>(global))
2898-
return true;
2899-
// Global vars are definitions if they have an initializer.
2900-
if (auto var = dyn_cast<llvm::GlobalVariable>(global))
2901-
return var->hasInitializer();
2902-
// Assume anything else isn't a definition.
2903-
return false;
2904-
};
2905-
2906-
//
29072895
auto entry = GlobalVars[entity];
29082896

29092897
/// Returns a direct reference.
@@ -2928,36 +2916,59 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity) {
29282916
if (IRGen.Opts.IntegratedREPL)
29292917
return indirect();
29302918

2931-
// Nominal type descriptors are only emitted once and can only be
2932-
// referenced directly from the same TU.
2933-
if (entity.isNominalTypeDescriptor()) {
2934-
auto *dc = entity.getDecl()->getDeclContext();
2935-
if (isa<ClangModuleUnit>(dc->getModuleScopeContext()) &&
2936-
this != IRGen.getGenModule(dc))
2937-
return indirect();
2938-
}
2919+
// Dynamically replaceable function keys are stored in the GlobalVars
2920+
// table, but they don't have an associated Decl, so they require
2921+
// special treatment here.
2922+
if (entity.isDynamicallyReplaceableFunctionKey()) {
2923+
auto *silFn = entity.getSILFunction();
2924+
if (canDirectlyReferenceSILFunction(silFn))
2925+
return direct();
29392926

2940-
// If the variable has already been defined in this TU,
2941-
// then it definitely doesn't need a GOT entry, and we can
2942-
// relative-reference it directly.
2943-
if (!entity.isAvailableExternally(*this) || isDefinition(entry)) {
2944-
return direct();
2927+
return indirect();
29452928
}
29462929

2947-
// If the entity will be emitted as part of the current source file
2948-
// (if we know what that is), then we can reference it directly.
2949-
if (CurSourceFile
2950-
&& !isa<ClangModuleUnit>(CurSourceFile)) {
2951-
if (auto *dc = entity.getDeclContextForEmission())
2952-
if (CurSourceFile == dc->getParentSourceFile())
2930+
if (auto *entityDC = entity.getDeclContextForEmission()) {
2931+
auto *entitySF = entityDC->getModuleScopeContext();
2932+
bool clangImportedEntity = isa<ClangModuleUnit>(entitySF);
2933+
2934+
auto &mod = getSILModule();
2935+
2936+
if (!mod.isWholeModule()) {
2937+
// In non-WMO builds, the associated context of the SILModule must
2938+
// be a source file. Every source file is its own translation unit.
2939+
auto *modDC = mod.getAssociatedContext();
2940+
auto *modSF = modDC->getModuleScopeContext();
2941+
assert(modSF != nullptr);
2942+
2943+
// Imported entities are in a different Swift module, but are emitted
2944+
// on demand and can be referenced directly. Entities in the same
2945+
// source file can also be referenced directly.
2946+
if (clangImportedEntity ||
2947+
modSF == entitySF)
2948+
return direct();
2949+
2950+
// Everything else must be referenced indirectly.
2951+
return indirect();
2952+
}
2953+
2954+
// We're performing a WMO build.
2955+
//
2956+
// The associated context of the SILModule is the entire AST ModuleDecl,
2957+
// but we might be doing a multi-threaded IRGen build, in which case
2958+
// there is one translation unit per source file.
2959+
2960+
// Imported entities are in a different Swift module and are emitted
2961+
// on demand. In multi-threaded builds, they will be emitted into one
2962+
// translation unit only.
2963+
if (clangImportedEntity ||
2964+
entitySF->getParentModule() == mod.getSwiftModule()) {
2965+
// If we're doing a single-threaded WMO build, or if the entity is
2966+
// scheduled to be emitted in the same translation unit, reference
2967+
// it directly.
2968+
if (this == IRGen.getGenModule(entitySF))
29532969
return direct();
2970+
}
29542971
}
2955-
2956-
// TODO: If we know the target entry is going to be linked into the same
2957-
// binary, then we ought to be able to directly relative-reference the
2958-
// symbol. However, some platforms don't have the necessary relocations to
2959-
// represent a relative reference to an undefined symbol, so conservatively
2960-
// produce an indirect reference in this case.
29612972

29622973
// Fall back to an indirect reference if we can't establish that a direct
29632974
// reference is OK.

test/IRGen/keypaths.sil

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,9 @@ sil_vtable C2 {}
181181
// CHECK-SAME: @"symbolic
182182
// -- instantiable in-line, size 16
183183
// CHECK-SAME: <i32 0x8000_0010>,
184-
// -- computed, settable, nonmutating, identified by indirect pointer, no args
185-
// CHECK-SAME: <i32 0x0240_0002>,
186-
// CHECK-SAME: @"{{got.|__imp_}}$s8keypaths1CC1wSivgTq"
184+
// -- computed, settable, nonmutating, identified by direct pointer, no args
185+
// CHECK-SAME: <i32 0x0240_0000>,
186+
// CHECK-SAME: @"$s8keypaths1CCMn"
187187
// CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_get
188188
// CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_set
189189

test/IRGen/keypaths_objc.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ sil @x_get : $@convention(thin) (@in_guaranteed C) -> @out NSString
2525
// CHECK: [[KEYPATH_B:@keypath(\..*)?]] = private global
2626
// -- class mutable stored property with indirect offset
2727
// CHECK-SAME: <i32 0x03fffffd>,
28-
// CHECK-SAME: @"got.$s13keypaths_objc1CC6storedSivpWvd"
28+
// CHECK-SAME: @"$s13keypaths_objc1CC6storedSivpWvd"
2929

3030
// CHECK-LABEL: define swiftcc void @objc_only_property()
3131
sil @objc_only_property : $@convention(thin) () -> () {

test/IRGen/symbolic_references.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ protocol P {
88
// CHECK-DAG: @"symbolic _____ 19symbolic_references3Foo016_{{.*}}V5InnerV" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 1
99
// CHECK-DAG: @"symbolic _____ 19symbolic_references3Foo016_{{.*}}V" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 1
1010

11-
// PRIVATE-DAG: @"symbolic _____ 19symbolic_references3Foo016_{{.*}}V5InnerV9InnermostV" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 2
1211
// PRIVATE-DAG: @"symbolic _____ 19symbolic_references3Foo016_{{.*}}V5InnerV" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 1
1312
// PRIVATE-DAG: @"symbolic _____ 19symbolic_references3Foo016_{{.*}}V" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 1
1413

0 commit comments

Comments
 (0)