Merge pull request #78427 from compnerd/internals

IRGen: special case VWT emission linkage computation
This commit is contained in:
Saleem Abdulrasool
2025-01-25 08:51:06 -08:00
committed by GitHub
5 changed files with 69 additions and 36 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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),

View File

@@ -1137,6 +1137,8 @@ public:
ClassMetadataStrategy getClassMetadataStrategy(const ClassDecl *theClass);
bool IsWellKnownBuiltinOrStructralType(CanType type) const;
private:
TypeConverter &Types;
friend TypeConverter;

View File

@@ -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