Skip to content

Commit 59e7c1b

Browse files
committed
IRGen: special case VWT emission linkage computation
The well known builtin and structural types are strongly defined in the runtime which is compacted into the standard library. Given that the VWT is defined in the runtime, it is not visible to the Swift compilation process and as we do not provide a Swift definition, we would previously compute the linkage as being module external (`dllimport` for shared library builds). This formed incorrect references to these variables and would require thunking to adjust the references. One special case that we add here is the "any function" type representation (`@escaping () -> ()`) as we do use the VWT for this type in the standard library but do not consider it part of the well known builtin or structural type enumeration. These errors were previously being swallowed by the build system and thus escaped from being fixed when the other cases of incorrect DLL storage were.
1 parent e252cbb commit 59e7c1b

File tree

5 files changed

+69
-36
lines changed

5 files changed

+69
-36
lines changed

include/swift/IRGen/Linking.h

+2
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,8 @@ class LinkEntity {
16641664
/// Determine whether entity that represents a symbol is in DATA segment.
16651665
bool isData() const { return !isText(); }
16661666

1667+
bool isTypeKind() const { return isTypeKind(getKind()); }
1668+
16671669
bool isAlwaysSharedLinkage() const;
16681670
#undef LINKENTITY_GET_FIELD
16691671
#undef LINKENTITY_SET_FIELD

lib/IRGen/GenDecl.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -3907,6 +3907,34 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
39073907
auto var = createVariable(*this, link, definitionType,
39083908
entity.getAlignment(*this), DbgTy);
39093909

3910+
// @escaping () -> ()
3911+
// NOTE: we explicitly desugar the `Void` type for the return as the test
3912+
// suite makes assumptions that it can emit the value witness table without a
3913+
// standard library for the target. `Context.getVoidType()` will attempt to
3914+
// lookup the `Decl` before returning the canonical type. To workaround this
3915+
// dependency, we simply desugar the `Void` return type to `()`.
3916+
static CanType kAnyFunctionType =
3917+
FunctionType::get({}, Context.TheEmptyTupleType,
3918+
ASTExtInfo{})->getCanonicalType();
3919+
3920+
// Adjust the linkage for the well-known VWTs that are strongly defined
3921+
// in the runtime.
3922+
//
3923+
// We special case the "AnyFunctionType" here as this type is referened
3924+
// inside the standard library with the definition being in the runtime
3925+
// preventing the normal detection from identifying that this is module
3926+
// local.
3927+
if (getSwiftModule()->isStdlibModule())
3928+
if (entity.isTypeKind() &&
3929+
(IsWellKnownBuiltinOrStructralType(entity.getType()) ||
3930+
entity.getType() == kAnyFunctionType))
3931+
if (auto *GV = dyn_cast<llvm::GlobalValue>(var))
3932+
if (GV->hasDLLImportStorageClass())
3933+
ApplyIRLinkage({llvm::GlobalValue::ExternalLinkage,
3934+
llvm::GlobalValue::DefaultVisibility,
3935+
llvm::GlobalValue::DefaultStorageClass})
3936+
.to(GV);
3937+
39103938
// Install the concrete definition if we have one.
39113939
if (definition && definition.hasInit()) {
39123940
definition.getInit().installInGlobal(var);

lib/IRGen/IRGenModule.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,39 @@ llvm::Module *IRGenModule::getModule() const {
13751375
return ClangCodeGen->GetModule();
13761376
}
13771377

1378+
bool IRGenModule::IsWellKnownBuiltinOrStructralType(CanType T) const {
1379+
static const CanType kStructural[] = {
1380+
Context.TheEmptyTupleType, Context.TheNativeObjectType,
1381+
Context.TheBridgeObjectType, Context.TheRawPointerType,
1382+
Context.getAnyObjectType()
1383+
};
1384+
1385+
if (std::any_of(std::begin(kStructural), std::end(kStructural),
1386+
[T](const CanType &ST) { return T == ST; }))
1387+
return true;
1388+
1389+
if (auto IntTy = dyn_cast<BuiltinIntegerType>(T)) {
1390+
auto Width = IntTy->getWidth();
1391+
if (Width.isPointerWidth())
1392+
return true;
1393+
if (!Width.isFixedWidth())
1394+
return false;
1395+
switch (Width.getFixedWidth()) {
1396+
case 8:
1397+
case 16:
1398+
case 32:
1399+
case 64:
1400+
case 128:
1401+
case 256:
1402+
return true;
1403+
default:
1404+
break;
1405+
}
1406+
}
1407+
1408+
return false;
1409+
}
1410+
13781411
GeneratedModule IRGenModule::intoGeneratedModule() && {
13791412
return GeneratedModule{
13801413
std::move(LLVMContext),

lib/IRGen/IRGenModule.h

+2
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,8 @@ class IRGenModule {
11371137

11381138
ClassMetadataStrategy getClassMetadataStrategy(const ClassDecl *theClass);
11391139

1140+
bool IsWellKnownBuiltinOrStructralType(CanType type) const;
1141+
11401142
private:
11411143
TypeConverter &Types;
11421144
friend TypeConverter;

lib/IRGen/MetadataRequest.cpp

+4-36
Original file line numberDiff line numberDiff line change
@@ -3694,41 +3694,6 @@ namespace {
36943694
return nullptr;
36953695
}
36963696

3697-
bool hasVisibleValueWitnessTable(CanType t) const {
3698-
// Some builtin and structural types have value witnesses exported from
3699-
// the runtime.
3700-
auto &C = IGF.IGM.Context;
3701-
if (t == C.TheEmptyTupleType
3702-
|| t == C.TheNativeObjectType
3703-
|| t == C.TheBridgeObjectType
3704-
|| t == C.TheRawPointerType
3705-
|| t == C.getAnyObjectType())
3706-
return true;
3707-
if (auto intTy = dyn_cast<BuiltinIntegerType>(t)) {
3708-
auto width = intTy->getWidth();
3709-
if (width.isPointerWidth())
3710-
return true;
3711-
if (width.isFixedWidth()) {
3712-
switch (width.getFixedWidth()) {
3713-
case 8:
3714-
case 16:
3715-
case 32:
3716-
case 64:
3717-
case 128:
3718-
case 256:
3719-
return true;
3720-
default:
3721-
return false;
3722-
}
3723-
}
3724-
return false;
3725-
}
3726-
3727-
// TODO: If a nominal type is in the same source file as we're currently
3728-
// emitting, we would be able to see its value witness table.
3729-
return false;
3730-
}
3731-
37323697
/// Fallback default implementation.
37333698
llvm::Value *visitType(CanType t, DynamicMetadataRequest request) {
37343699
auto silTy = IGF.IGM.getLoweredType(t);
@@ -3737,7 +3702,10 @@ namespace {
37373702
// If the type is in the same source file, or has a common value
37383703
// witness table exported from the runtime, we can project from the
37393704
// value witness table instead of emitting a new record.
3740-
if (hasVisibleValueWitnessTable(t))
3705+
//
3706+
// TODO: If a nominal type is in the same source file as we're currently
3707+
// emitting, we would be able to see its value witness table.
3708+
if (IGF.IGM.IsWellKnownBuiltinOrStructralType(t))
37413709
return emitFromValueWitnessTable(t);
37423710

37433711
// If the type is a singleton aggregate, the field's layout is equivalent

0 commit comments

Comments
 (0)