mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #78427 from compnerd/internals
IRGen: special case VWT emission linkage computation
This commit is contained in:
@@ -1664,6 +1664,8 @@ public:
|
||||
/// Determine whether entity that represents a symbol is in DATA segment.
|
||||
bool isData() const { return !isText(); }
|
||||
|
||||
bool isTypeKind() const { return isTypeKind(getKind()); }
|
||||
|
||||
bool isAlwaysSharedLinkage() const;
|
||||
#undef LINKENTITY_GET_FIELD
|
||||
#undef LINKENTITY_SET_FIELD
|
||||
|
||||
@@ -3909,6 +3909,34 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity,
|
||||
auto var = createVariable(*this, link, definitionType,
|
||||
entity.getAlignment(*this), DbgTy);
|
||||
|
||||
// @escaping () -> ()
|
||||
// NOTE: we explicitly desugar the `Void` type for the return as the test
|
||||
// suite makes assumptions that it can emit the value witness table without a
|
||||
// standard library for the target. `Context.getVoidType()` will attempt to
|
||||
// lookup the `Decl` before returning the canonical type. To workaround this
|
||||
// dependency, we simply desugar the `Void` return type to `()`.
|
||||
static CanType kAnyFunctionType =
|
||||
FunctionType::get({}, Context.TheEmptyTupleType,
|
||||
ASTExtInfo{})->getCanonicalType();
|
||||
|
||||
// Adjust the linkage for the well-known VWTs that are strongly defined
|
||||
// in the runtime.
|
||||
//
|
||||
// We special case the "AnyFunctionType" here as this type is referened
|
||||
// inside the standard library with the definition being in the runtime
|
||||
// preventing the normal detection from identifying that this is module
|
||||
// local.
|
||||
if (getSwiftModule()->isStdlibModule())
|
||||
if (entity.isTypeKind() &&
|
||||
(IsWellKnownBuiltinOrStructralType(entity.getType()) ||
|
||||
entity.getType() == kAnyFunctionType))
|
||||
if (auto *GV = dyn_cast<llvm::GlobalValue>(var))
|
||||
if (GV->hasDLLImportStorageClass())
|
||||
ApplyIRLinkage({llvm::GlobalValue::ExternalLinkage,
|
||||
llvm::GlobalValue::DefaultVisibility,
|
||||
llvm::GlobalValue::DefaultStorageClass})
|
||||
.to(GV);
|
||||
|
||||
// Install the concrete definition if we have one.
|
||||
if (definition && definition.hasInit()) {
|
||||
definition.getInit().installInGlobal(var);
|
||||
|
||||
@@ -1362,6 +1362,39 @@ llvm::Module *IRGenModule::getModule() const {
|
||||
return ClangCodeGen->GetModule();
|
||||
}
|
||||
|
||||
bool IRGenModule::IsWellKnownBuiltinOrStructralType(CanType T) const {
|
||||
static const CanType kStructural[] = {
|
||||
Context.TheEmptyTupleType, Context.TheNativeObjectType,
|
||||
Context.TheBridgeObjectType, Context.TheRawPointerType,
|
||||
Context.getAnyObjectType()
|
||||
};
|
||||
|
||||
if (std::any_of(std::begin(kStructural), std::end(kStructural),
|
||||
[T](const CanType &ST) { return T == ST; }))
|
||||
return true;
|
||||
|
||||
if (auto IntTy = dyn_cast<BuiltinIntegerType>(T)) {
|
||||
auto Width = IntTy->getWidth();
|
||||
if (Width.isPointerWidth())
|
||||
return true;
|
||||
if (!Width.isFixedWidth())
|
||||
return false;
|
||||
switch (Width.getFixedWidth()) {
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
case 256:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GeneratedModule IRGenModule::intoGeneratedModule() && {
|
||||
return GeneratedModule{
|
||||
std::move(LLVMContext),
|
||||
|
||||
@@ -1137,6 +1137,8 @@ public:
|
||||
|
||||
ClassMetadataStrategy getClassMetadataStrategy(const ClassDecl *theClass);
|
||||
|
||||
bool IsWellKnownBuiltinOrStructralType(CanType type) const;
|
||||
|
||||
private:
|
||||
TypeConverter &Types;
|
||||
friend TypeConverter;
|
||||
|
||||
@@ -3688,41 +3688,6 @@ namespace {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool hasVisibleValueWitnessTable(CanType t) const {
|
||||
// Some builtin and structural types have value witnesses exported from
|
||||
// the runtime.
|
||||
auto &C = IGF.IGM.Context;
|
||||
if (t == C.TheEmptyTupleType
|
||||
|| t == C.TheNativeObjectType
|
||||
|| t == C.TheBridgeObjectType
|
||||
|| t == C.TheRawPointerType
|
||||
|| t == C.getAnyObjectType())
|
||||
return true;
|
||||
if (auto intTy = dyn_cast<BuiltinIntegerType>(t)) {
|
||||
auto width = intTy->getWidth();
|
||||
if (width.isPointerWidth())
|
||||
return true;
|
||||
if (width.isFixedWidth()) {
|
||||
switch (width.getFixedWidth()) {
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
case 256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: If a nominal type is in the same source file as we're currently
|
||||
// emitting, we would be able to see its value witness table.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Fallback default implementation.
|
||||
llvm::Value *visitType(CanType t, DynamicMetadataRequest request) {
|
||||
auto silTy = IGF.IGM.getLoweredType(t);
|
||||
@@ -3731,7 +3696,10 @@ namespace {
|
||||
// If the type is in the same source file, or has a common value
|
||||
// witness table exported from the runtime, we can project from the
|
||||
// value witness table instead of emitting a new record.
|
||||
if (hasVisibleValueWitnessTable(t))
|
||||
//
|
||||
// TODO: If a nominal type is in the same source file as we're currently
|
||||
// emitting, we would be able to see its value witness table.
|
||||
if (IGF.IGM.IsWellKnownBuiltinOrStructralType(t))
|
||||
return emitFromValueWitnessTable(t);
|
||||
|
||||
// If the type is a singleton aggregate, the field's layout is equivalent
|
||||
|
||||
Reference in New Issue
Block a user