Skip to content

Revert "Make VFE / WME / conditional records work even with ObjC interop and with reflection metadata (#39808)" #39877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 54 additions & 77 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,9 @@ static void collectGlobalList(IRGenModule &IGM,
static llvm::GlobalVariable *
emitGlobalList(IRGenModule &IGM, ArrayRef<llvm::WeakTrackingVH> handles,
StringRef name, StringRef section,
llvm::GlobalValue::LinkageTypes linkage, llvm::Type *eltTy,
bool isConstant, bool asContiguousArray) {
llvm::GlobalValue::LinkageTypes linkage,
llvm::Type *eltTy,
bool isConstant) {
// Do nothing if the list is empty.
if (handles.empty()) return nullptr;

Expand All @@ -557,31 +558,6 @@ emitGlobalList(IRGenModule &IGM, ArrayRef<llvm::WeakTrackingVH> handles,
// so that the linker doesn't accidentally put padding in the list.
Alignment alignment = IGM.getPointerAlignment();

if (!asContiguousArray) {
// Emit as individual globals, which is required for conditional runtime
// records to work.
for (auto &handle : handles) {
llvm::Constant *elt = cast<llvm::Constant>(&*handle);
auto eltName = name + "_" + elt->getName();
if (elt->getType() != eltTy)
elt = llvm::ConstantExpr::getBitCast(elt, eltTy);
auto var = new llvm::GlobalVariable(IGM.Module, eltTy, isConstant,
linkage, elt, eltName);
var->setSection(section);
var->setAlignment(llvm::MaybeAlign(alignment.getValue()));
disableAddressSanitizer(IGM, var);
if (llvm::GlobalValue::isLocalLinkage(linkage))
IGM.addUsedGlobal(var);

if (IGM.IRGen.Opts.ConditionalRuntimeRecords) {
// Allow dead-stripping `var` (the runtime record from the global list)
// when `handle` / `elt` (the underlaying entity) is not referenced.
IGM.appendLLVMUsedConditionalEntry(var, elt->stripPointerCasts());
}
}
return nullptr;
}

// We have an array of value handles, but we need an array of constants.
SmallVector<llvm::Constant*, 8> elts;
elts.reserve(handles.size());
Expand Down Expand Up @@ -1061,41 +1037,36 @@ void IRGenModule::emitGlobalLists() {
if (ObjCInterop) {
// Objective-C class references go in a variable with a meaningless
// name but a magic section.
emitGlobalList(
*this, ObjCClasses, "objc_classes",
GetObjCSectionName("__objc_classlist", "regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, /*isConstant*/ false,
/*asContiguousArray*/ false);
emitGlobalList(*this, ObjCClasses, "objc_classes",
GetObjCSectionName("__objc_classlist",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);

// So do resilient class stubs.
emitGlobalList(
*this, ObjCClassStubs, "objc_class_stubs",
GetObjCSectionName("__objc_stublist", "regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, /*isConstant*/ false,
/*asContiguousArray*/ true);
emitGlobalList(*this, ObjCClassStubs, "objc_class_stubs",
GetObjCSectionName("__objc_stublist",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);

// So do categories.
emitGlobalList(
*this, ObjCCategories, "objc_categories",
GetObjCSectionName("__objc_catlist", "regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, /*isConstant*/ false,
/*asContiguousArray*/ true);
emitGlobalList(*this, ObjCCategories, "objc_categories",
GetObjCSectionName("__objc_catlist",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);

// And categories on class stubs.
emitGlobalList(
*this, ObjCCategoriesOnStubs, "objc_categories_stubs",
GetObjCSectionName("__objc_catlist2", "regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, /*isConstant*/ false,
/*asContiguousArray*/ true);

// Emit nonlazily realized class references in a second magic section to
// make sure they are realized by the Objective-C runtime before any
// instances are allocated.
emitGlobalList(
*this, ObjCNonLazyClasses, "objc_non_lazy_classes",
GetObjCSectionName("__objc_nlclslist", "regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, /*isConstant*/ false,
/*asContiguousArray*/ true);
emitGlobalList(*this, ObjCCategoriesOnStubs, "objc_categories_stubs",
GetObjCSectionName("__objc_catlist2",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);

// Emit nonlazily realized class references in a second magic section to make
// sure they are realized by the Objective-C runtime before any instances
// are allocated.
emitGlobalList(*this, ObjCNonLazyClasses, "objc_non_lazy_classes",
GetObjCSectionName("__objc_nlclslist",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);
}

// @llvm.used
Expand All @@ -1105,15 +1076,15 @@ void IRGenModule::emitGlobalLists() {
emitGlobalList(*this, LLVMUsed, "llvm.used", "llvm.metadata",
llvm::GlobalValue::AppendingLinkage,
Int8PtrTy,
/*isConstant*/false, /*asContiguousArray*/true);
false);

// Collect llvm.compiler.used globals already in the module (coming
// from ClangCodeGen).
collectGlobalList(*this, LLVMCompilerUsed, "llvm.compiler.used");
emitGlobalList(*this, LLVMCompilerUsed, "llvm.compiler.used", "llvm.metadata",
llvm::GlobalValue::AppendingLinkage,
Int8PtrTy,
/*isConstant*/false, /*asContiguousArray*/true);
false);
}

static bool hasCodeCoverageInstrumentation(SILFunction &f, SILModule &m) {
Expand Down Expand Up @@ -3738,34 +3709,39 @@ IRGenModule::emitDirectRelativeReference(llvm::Constant *target,

/// Expresses that `var` is removable (dead-strippable) when `dependsOn` is not
/// referenced.
void IRGenModule::appendLLVMUsedConditionalEntry(llvm::GlobalVariable *var,
llvm::Constant *dependsOn) {
static void appendLLVMUsedConditionalEntry(IRGenModule &IGM,
llvm::GlobalVariable *var,
llvm::Constant *dependsOn) {
llvm::Metadata *metadata[] = {
// (1) which variable is being conditionalized, "target"
llvm::ConstantAsMetadata::get(var),
// (2) type, not relevant for a single-edge condition
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
llvm::Type::getInt32Ty(Module.getContext()), 0)),
llvm::Type::getInt32Ty(IGM.Module.getContext()), 0)),
// (3) the "edge" that holds the target alive, if it's missing the target
// is allowed to be removed
llvm::MDNode::get(Module.getContext(),
llvm::MDNode::get(IGM.Module.getContext(),
{
llvm::ConstantAsMetadata::get(dependsOn),
}),
};
auto *usedConditional =
Module.getOrInsertNamedMetadata("llvm.used.conditional");
usedConditional->addOperand(llvm::MDNode::get(Module.getContext(), metadata));
IGM.Module.getOrInsertNamedMetadata("llvm.used.conditional");
usedConditional->addOperand(
llvm::MDNode::get(IGM.Module.getContext(), metadata));
}

/// Expresses that `var` is removable (dead-strippable) when either the protocol
/// from `record` is not referenced or the type from `record` is not referenced.
void IRGenModule::appendLLVMUsedConditionalEntry(
llvm::GlobalVariable *var, const ProtocolConformance *conformance) {
auto *protocol = getAddrOfProtocolDescriptor(conformance->getProtocol())
->stripPointerCasts();
auto *type = getAddrOfTypeContextDescriptor(
conformance->getType()->getAnyNominal(), DontRequireMetadata)
static void
appendLLVMUsedConditionalEntry(IRGenModule &IGM, llvm::GlobalVariable *var,
const ConformanceDescription &record) {
auto *protocol =
IGM.getAddrOfProtocolDescriptor(record.conformance->getProtocol())
->stripPointerCasts();
auto *type = IGM.getAddrOfTypeContextDescriptor(
record.conformance->getType()->getAnyNominal(),
DontRequireMetadata)
->stripPointerCasts();

llvm::Metadata *metadata[] = {
Expand All @@ -3774,17 +3750,18 @@ void IRGenModule::appendLLVMUsedConditionalEntry(
// (2) type, "1" = if either edge is missing, the target is allowed to be
// removed.
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
llvm::Type::getInt32Ty(Module.getContext()), 1)),
llvm::Type::getInt32Ty(IGM.Module.getContext()), 1)),
// (3) list of edges
llvm::MDNode::get(Module.getContext(),
llvm::MDNode::get(IGM.Module.getContext(),
{
llvm::ConstantAsMetadata::get(protocol),
llvm::ConstantAsMetadata::get(type),
}),
};
auto *usedConditional =
Module.getOrInsertNamedMetadata("llvm.used.conditional");
usedConditional->addOperand(llvm::MDNode::get(Module.getContext(), metadata));
IGM.Module.getOrInsertNamedMetadata("llvm.used.conditional");
usedConditional->addOperand(
llvm::MDNode::get(IGM.Module.getContext(), metadata));
}

/// Emit the protocol descriptors list and return it (if asContiguousArray is
Expand Down Expand Up @@ -3866,7 +3843,7 @@ llvm::Constant *IRGenModule::emitSwiftProtocols(bool asContiguousArray) {
if (IRGen.Opts.ConditionalRuntimeRecords) {
// Allow dead-stripping `var` (the protocol record) when the protocol
// (descriptorRef) is not referenced.
appendLLVMUsedConditionalEntry(var, descriptorRef.getValue());
appendLLVMUsedConditionalEntry(*this, var, descriptorRef.getValue());
}
}

Expand Down Expand Up @@ -3960,7 +3937,7 @@ llvm::Constant *IRGenModule::emitProtocolConformances(bool asContiguousArray) {
if (IRGen.Opts.ConditionalRuntimeRecords) {
// Allow dead-stripping `var` (the conformance record) when the protocol
// or type (from the conformance) is not referenced.
appendLLVMUsedConditionalEntry(var, record.conformance);
appendLLVMUsedConditionalEntry(*this, var, record);
}
}

Expand Down Expand Up @@ -4075,7 +4052,7 @@ llvm::Constant *IRGenModule::emitTypeMetadataRecords(bool asContiguousArray) {
if (IRGen.Opts.ConditionalRuntimeRecords) {
// Allow dead-stripping `var` (the type record) when the type (`ref`) is
// not referenced.
appendLLVMUsedConditionalEntry(var, ref.getValue());
appendLLVMUsedConditionalEntry(*this, var, ref.getValue());
}
}

Expand Down
40 changes: 11 additions & 29 deletions lib/IRGen/GenReflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,20 +676,11 @@ class AssociatedTypeMetadataBuilder : public ReflectionMetadataBuilder {

llvm::GlobalVariable *emit() {
auto section = IGM.getAssociatedTypeMetadataSectionName();
llvm::GlobalVariable *var = ReflectionMetadataBuilder::emit(
[&](IRGenModule &IGM, ConstantInit init) -> llvm::Constant * {
return IGM.getAddrOfReflectionAssociatedTypeDescriptor(Conformance,
init);
},
section);

if (IGM.IRGen.Opts.ConditionalRuntimeRecords) {
// Allow dead-stripping `var` (the reflection record) when the protocol
// or type (from the conformance) is not referenced.
IGM.appendLLVMUsedConditionalEntry(var, Conformance);
}

return var;
return ReflectionMetadataBuilder::emit(
[&](IRGenModule &IGM, ConstantInit init) -> llvm::Constant* {
return IGM.getAddrOfReflectionAssociatedTypeDescriptor(Conformance,init);
},
section);
}
};

Expand Down Expand Up @@ -865,21 +856,12 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {

llvm::GlobalVariable *emit() {
auto section = IGM.getFieldTypeMetadataSectionName();
llvm::GlobalVariable *var = ReflectionMetadataBuilder::emit(
[&](IRGenModule &IGM, ConstantInit definition) -> llvm::Constant * {
return IGM.getAddrOfReflectionFieldDescriptor(
NTD->getDeclaredType()->getCanonicalType(), definition);
},
section);

if (IGM.IRGen.Opts.ConditionalRuntimeRecords) {
// Allow dead-stripping `var` (the reflection record) when the type
// (NTD) is not referenced.
auto ref = IGM.getTypeEntityReference(const_cast<NominalTypeDecl *>(NTD));
IGM.appendLLVMUsedConditionalEntry(var, ref.getValue());
}

return var;
return ReflectionMetadataBuilder::emit(
[&](IRGenModule &IGM, ConstantInit definition) -> llvm::Constant* {
return IGM.getAddrOfReflectionFieldDescriptor(
NTD->getDeclaredType()->getCanonicalType(), definition);
},
section);
}
};

Expand Down
5 changes: 0 additions & 5 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1462,11 +1462,6 @@ private: \

TypeEntityReference getTypeEntityReference(GenericTypeDecl *D);

void appendLLVMUsedConditionalEntry(llvm::GlobalVariable *var,
llvm::Constant *dependsOn);
void appendLLVMUsedConditionalEntry(llvm::GlobalVariable *var,
const ProtocolConformance *conformance);

llvm::Constant *
getAddrOfTypeMetadata(CanType concreteType,
TypeMetadataCanonicality canonicality =
Expand Down
3 changes: 1 addition & 2 deletions test/IRGen/MachO-objc-sections.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ class D {
// CHECK-MACHO: @"$s4main1CCMf" = {{.*}}, section "__DATA,__objc_data, regular"
// CHECK-MACHO: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = {{.*}}, section "__DATA,__objc_protolist,coalesced,no_dead_strip"
// CHECK-MACHO: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P" = {{.*}}, section "__DATA,__objc_protorefs,coalesced,no_dead_strip"
// CHECK-MACHO: @"objc_classes_$s4main1CCN" = {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip"
// CHECK-MACHO: @"objc_classes_$s4main1DCN" = {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip"
// CHECK-MACHO: @objc_classes = {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip"
// CHECK-MACHO: @objc_categories = {{.*}}, section "__DATA,__objc_catlist,regular,no_dead_strip"
// CHECK-MACHO: @objc_non_lazy_classes = {{.*}}, section "__DATA,__objc_nlclslist,regular,no_dead_strip"

14 changes: 4 additions & 10 deletions test/IRGen/conditional-dead-strip-exec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

// RUN: %empty-directory(%t)

// RUN: %target-build-swift -Xfrontend -conditional-runtime-records %s -emit-ir -o %t/main.ll
// RUN: %target-build-swift -Xfrontend -disable-objc-interop \
// RUN: -Xfrontend -disable-reflection-metadata -Xfrontend -disable-reflection-names \
// RUN: -Xfrontend -conditional-runtime-records \
// RUN: %s -emit-ir -o %t/main.ll

// RUN: %target-clang %t/main.ll -isysroot %sdk -L%swift_obj_root/lib/swift/%target-sdk-name -flto -o %t/main
// RUN: %target-run %t/main | %FileCheck %s
Expand Down Expand Up @@ -45,10 +48,6 @@ class UsedClass : UnusedProto, ActuallyUsedProto {
public func bark() { print("UsedClass.bark") }
}

// (9) unused protocol with associated type
protocol ProtoWithAssocType { associatedtype T }
struct Implementor : ProtoWithAssocType { typealias T = Int }

print("Hello!")
func1_used()
let o = UsedClass()
Expand All @@ -72,11 +71,6 @@ p.bark()
// (2)
// NM-NOT: $s4main10func2_deadyyF

// (9)
// NM-NOT: $s4main11ImplementorVAA18ProtoWithAssocTypeAAMA
// NM-NOT: $s4main11ImplementorVMf
// NM-NOT: $s4main11ImplementorVMn

// (4)
// NM-NOT: $s4main11TheProtocolMp

Expand Down
31 changes: 13 additions & 18 deletions test/IRGen/conditional-dead-strip-ir.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
// enum, protocol, and protocol conformance records as conditionally removable
// via !llvm.used.conditional metadata.

// RUN: %target-build-swift -Xfrontend -conditional-runtime-records -Xfrontend -disable-objc-interop %s -emit-ir -o - | %FileCheck %s
// RUN: %target-build-swift -Xfrontend -disable-objc-interop -Xfrontend -conditional-runtime-records \
// RUN: %s -emit-ir -o - | %FileCheck %s

public protocol TheProtocol {
}
Expand All @@ -24,25 +25,19 @@ public enum Enum {
// CHECK-SAME: @"$s4main4EnumOHn"
// CHECK-SAME: ], section "llvm.metadata"

// CHECK: !llvm.used.conditional = !{[[M1:!.*]], [[M2:!.*]], [[M3:!.*]], [[M4:!.*]], [[C1:!.*]], [[C2:!.*]], [[C3:!.*]], [[C4:!.*]], [[C5:!.*]]}
// CHECK: !llvm.used.conditional = !{[[C1:!.*]], [[C2:!.*]], [[C3:!.*]], [[C4:!.*]], [[C5:!.*]]}

// CHECK-DAG: [[M1]] = !{{{.*}} @"$s4main11TheProtocol_pMF", i32 0, [[M1A:!.*]]}
// CHECK-DAG: [[M1A]] = !{{{.*}} @"$s4main11TheProtocolMp"
// CHECK-DAG: [[M2]] = !{{{.*}} @"$s4main5ClassCMF", i32 0, [[M2A:!.*]]}
// CHECK-DAG: [[M2A]] = !{{{.*}} @"$s4main5ClassCMn"
// CHECK-DAG: [[M3]] = !{{{.*}} @"$s4main6StructVMF", i32 0, [[M3A:!.*]]}
// CHECK-DAG: [[M3A]] = !{{{.*}} @"$s4main6StructVMn"
// CHECK-DAG: [[M4]] = !{{{.*}} @"$s4main4EnumOMF", i32 0, [[M4A:!.*]]}
// CHECK-DAG: [[M4A]] = !{{{.*}} @"$s4main4EnumOMn"
// CHECK: [[C1]] = !{{{.*}} @"$s4main11TheProtocolHr", i32 0, [[C1A:!.*]]}
// CHECK: [[C1A]] = !{{{.*}} @"$s4main11TheProtocolMp"}

// CHECK-DAG: [[C1]] = !{{{.*}} @"$s4main11TheProtocolHr", i32 0, [[C1A:!.*]]}
// CHECK-DAG: [[C1A]] = !{{{.*}} @"$s4main11TheProtocolMp"}
// CHECK: [[C2]] = !{{{.*}} @"$s4main5ClassCAA11TheProtocolAAHc", i32 1, [[C2A:!.*]]}
// CHECK: [[C2A]] = !{{{.*}} @"$s4main11TheProtocolMp", {{.*}} @"$s4main5ClassCMn"}

// CHECK-DAG: [[C2]] = !{{{.*}} @"$s4main5ClassCAA11TheProtocolAAHc", i32 1, [[C2A:!.*]]}
// CHECK-DAG: [[C2A]] = !{{{.*}} @"$s4main11TheProtocolMp", {{.*}} @"$s4main5ClassCMn"}
// CHECK: [[C3]] = !{{{.*}} @"$s4main5ClassCHn", i32 0, [[C3A:!.*]]}
// CHECK: [[C3A]] = !{{{.*}} @"$s4main5ClassCMn"}

// CHECK-DAG: [[C3]] = !{{{.*}} @"$s4main5ClassCHn", i32 0, [[M2A:!.*]]}
// CHECK: [[C4]] = !{{{.*}} @"$s4main6StructVHn", i32 0, [[C4A:!.*]]}
// CHECK: [[C4A]] = !{{{.*}} @"$s4main6StructVMn"}

// CHECK-DAG: [[C4]] = !{{{.*}} @"$s4main6StructVHn", i32 0, [[M3A:!.*]]}

// CHECK-DAG: [[C5]] = !{{{.*}} @"$s4main4EnumOHn", i32 0, [[M4A:!.*]]}
// CHECK: [[C5]] = !{{{.*}} @"$s4main4EnumOHn", i32 0, [[C5A:!.*]]}
// CHECK: [[C5A]] = !{{{.*}} @"$s4main4EnumOMn"}
Loading