Skip to content

Commit c4d13e4

Browse files
committed
[IRGen] Directly reference prespecializations.
When possible, directly reference metadata prespecializations. Doing so is possible when the type is defined in the same module, because in those cases the metadata accessor can be modified to ensure that the prespecialized metadata is canonical. rdar://problem/56994171
1 parent 7068141 commit c4d13e4

File tree

31 files changed

+1225
-6
lines changed

31 files changed

+1225
-6
lines changed

lib/AST/Availability.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,12 @@ AvailabilityContext ASTContext::getSwift52Availability() {
252252
if (target.isMacOSX() ) {
253253
return AvailabilityContext(
254254
VersionRange::allGTE(llvm::VersionTuple(10, 99, 0)));
255-
} else if (target.isiOS() || target.isWatchOS()) {
255+
} else if (target.isiOS()) {
256+
return AvailabilityContext(
257+
VersionRange::allGTE(llvm::VersionTuple(99, 0, 0)));
258+
} else if (target.isWatchOS()) {
256259
return AvailabilityContext(
257-
VersionRange::allGTE(llvm::VersionTuple(9999, 0, 0)));
260+
VersionRange::allGTE(llvm::VersionTuple(9, 99, 0)));
258261
} else {
259262
return AvailabilityContext::alwaysAvailable();
260263
}

lib/IRGen/GenDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3730,6 +3730,14 @@ ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
37303730
IRGen.noteUseOfTypeMetadata(nominal);
37313731
}
37323732

3733+
if (shouldPrespecializeGenericMetadata()) {
3734+
if (auto nominal = concreteType->getAnyNominal()) {
3735+
if (nominal->isGenericContext()) {
3736+
IRGen.noteUseOfSpecializedGenericTypeMetadata(concreteType);
3737+
}
3738+
}
3739+
}
3740+
37333741
Optional<LinkEntity> entity;
37343742
DebugTypeInfo DbgTy;
37353743

lib/IRGen/MetadataRequest.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "swift/SIL/TypeLowering.h"
4141
#include "llvm/ADT/STLExtras.h"
4242
#include "llvm/IR/Constant.h"
43+
#include "llvm/Support/Debug.h"
4344
#include "llvm/Support/FormatVariadic.h"
4445
#include <algorithm>
4546

@@ -643,6 +644,22 @@ llvm::Value *irgen::emitObjCHeapMetadataRef(IRGenFunction &IGF,
643644
classObject);
644645
}
645646

647+
static MetadataResponse emitNominalPrespecializedGenericMetadataRef(
648+
IRGenFunction &IGF, NominalTypeDecl *theDecl, CanType theType,
649+
DynamicMetadataRequest request) {
650+
assert(isNominalGenericContextTypeMetadataAccessTrivial(IGF.IGM, *theDecl,
651+
theType));
652+
// We are applying generic parameters to a generic type.
653+
assert(theType->getAnyNominal() == theDecl);
654+
655+
// Check to see if we've maybe got a local reference already.
656+
if (auto cache = IGF.tryGetLocalTypeMetadata(theType, request))
657+
return cache;
658+
659+
auto metadata = IGF.IGM.getAddrOfTypeMetadata(theType);
660+
return MetadataResponse::forComplete(metadata);
661+
}
662+
646663
/// Returns a metadata reference for a nominal type.
647664
///
648665
/// This is only valid in a couple of special cases:
@@ -683,6 +700,12 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
683700
theDecl->getGenericSignature()->areAllParamsConcrete()) &&
684701
"no generic args?!");
685702

703+
if (isNominalGenericContextTypeMetadataAccessTrivial(IGF.IGM, *theDecl,
704+
theType)) {
705+
return emitNominalPrespecializedGenericMetadataRef(IGF, theDecl, theType,
706+
request);
707+
}
708+
686709
// Call the generic metadata accessor function.
687710
llvm::Function *accessor =
688711
IGF.IGM.getAddrOfGenericTypeMetadataAccessFunction(theDecl,
@@ -699,10 +722,6 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
699722

700723
bool irgen::isNominalGenericContextTypeMetadataAccessTrivial(
701724
IRGenModule &IGM, NominalTypeDecl &nominal, CanType type) {
702-
// TODO: Once prespecialized generic metadata can be lazily emitted, eliminate
703-
// this early return.
704-
return false;
705-
706725
assert(nominal.isGenericContext());
707726

708727
if (!IGM.shouldPrespecializeGenericMetadata()) {

test/IRGen/lit.local.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ config.substitutions.insert(0, ('%build-irgen-test-overlays',
55
'%target-swift-frontend -enable-objc-interop -disable-objc-attr-requires-foundation-module -emit-module -o %t -sdk %S/Inputs %S/Inputs/ObjectiveC.swift && '
66
'%target-swift-frontend -enable-objc-interop -emit-module -o %t -sdk %S/Inputs %S/Inputs/Foundation.swift -I %t'))
77

8+
config.substitutions.insert(0, ('%build-irgen-test-overlays\(mock-sdk-directory: ([^)]+)\)',
9+
SubstituteCaptures(r'%target-swift-frontend -enable-objc-interop -disable-objc-attr-requires-foundation-module -emit-module -o %t -sdk \1 \1/ObjectiveC.swift && '
10+
r'%target-swift-frontend -enable-objc-interop -emit-module -o %t -sdk \1 \1/Foundation.swift -I %t')))
11+
812
def get_target_os():
913
import re
1014
(run_cpu, run_vendor, run_os, run_version) = re.match('([^-]+)-([^-]+)-([^0-9]+)(.*)', config.variant_triple).groups()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %swift -target %module-target-future -parse-stdlib -emit-ir -prespecialize-generic-metadata %s | %FileCheck %s
2+
3+
precedencegroup AssignmentPrecedence {}
4+
5+
class Namespace<T> {}
6+
7+
class Zang {
8+
}
9+
10+
extension Namespace where T == Zang {
11+
class ExtensionNonGeneric {}
12+
}
13+
14+
@inline(never)
15+
func consume<T>(_ t: T) {
16+
Builtin.fixLifetime(t)
17+
}
18+
19+
// CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} {
20+
// CHECK: entry:
21+
// CHECK: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main9NamespaceCA2A4ZangCRszlE19ExtensionNonGenericCyAE_GMa"(i64 0) #{{[0-9]+}}
22+
// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0
23+
// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture %5, %swift.type* [[METADATA]])
24+
// CHECK: }
25+
func doit() {
26+
consume( Namespace<Zang>.ExtensionNonGeneric() )
27+
}
28+
29+
doit()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %swift -target %module-target-future -emit-ir -prespecialize-generic-metadata %s | %FileCheck %s
2+
3+
struct Value {
4+
let first: Int
5+
}
6+
7+
@inline(never)
8+
func consume<T>(_ t: T) {
9+
withExtendedLifetime(t) { t in
10+
}
11+
}
12+
13+
// CHECK: define hidden swiftcc void @"$s4main4doityyF"() #0 {
14+
// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture %{{[0-9]+}}, %swift.type* bitcast (i64* getelementptr inbounds (<{ i8**, i64, <{ i32, i32, i32, i32, i32, i32, i32 }>*, i32, [4 x i8], i64 }>, <{ i8**, i64, <{ i32, i32, i32, i32, i32, i32, i32 }>*, i32, [4 x i8], i64 }>* @"$s4main5ValueVMf", i32 0, i32 1) to %swift.type*))
15+
// CHECK: }
16+
func doit() {
17+
consume( Value(first: 13) )
18+
}
19+
doit()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %swift -target %module-target-future -emit-ir -prespecialize-generic-metadata %s | %FileCheck %s
2+
3+
struct Value<First> {
4+
let first: First
5+
}
6+
7+
@inline(never)
8+
func consume<T>(_ t: T) {
9+
withExtendedLifetime(t) { t in
10+
}
11+
}
12+
13+
// CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} {
14+
// CHECK: }
15+
func doit() {
16+
}
17+
doit()
18+
19+
// CHECK: ; Function Attrs: noinline nounwind readnone
20+
// CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"(i64, %swift.type*) #{{[0-9]+}} {
21+
// CHECK: entry:
22+
// CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8*
23+
// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata(i64 %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}}
24+
// CHECK: ret %swift.metadata_response {{%[0-9]+}}
25+
// CHECK: }
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %swift -target %module-target-future -emit-ir -prespecialize-generic-metadata %s | %FileCheck %s
2+
3+
// CHECK: @"$sytN" = external global %swift.full_type
4+
// CHECK: @"$s4main5ValueVySiGMf" = internal constant <{ i8**, i64, %swift.type_descriptor*, %swift.type*, i8**, i32, [4 x i8], i64 }> <{ i8** getelementptr inbounds (%swift.vwtable, %swift.vwtable* @"$s4main5ValueVWV", i32 0, i32 0), i64 512, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*), %swift.type* @"$sSiN", i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"$sSi4main1PAAWP", i32 0, i32 0), i32 0, [4 x i8] zeroinitializer, i64 3 }>, align 8
5+
protocol P {}
6+
extension Int : P {}
7+
struct Value<First : P> {
8+
let first: First
9+
}
10+
11+
@inline(never)
12+
func consume<T>(_ t: T) {
13+
withExtendedLifetime(t) { t in
14+
}
15+
}
16+
17+
// CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} {
18+
// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture %{{[0-9]+}}, %swift.type* bitcast (i64* getelementptr inbounds (<{ i8**, i64, %swift.type_descriptor*, %swift.type*, i8**, i32, [4 x i8], i64 }>, <{ i8**, i64, %swift.type_descriptor*, %swift.type*, i8**, i32, [4 x i8], i64 }>* @"$s4main5ValueVySiGMf", i32 0, i32 1) to %swift.type*))
19+
// CHECK: }
20+
func doit() {
21+
consume( Value(first: 13) )
22+
}
23+
doit()
24+
25+
// CHECK: ; Function Attrs: noinline nounwind readnone
26+
// CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"(i64, %swift.type*, i8**) #{{[0-9]+}} {
27+
// CHECK: entry:
28+
// CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8*
29+
// CHECK: [[ERASED_TABLE:%[0-9]+]] = bitcast i8** %2 to i8*
30+
// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]]
31+
// CHECK: [[TYPE_COMPARISON_LABEL]]:
32+
// CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]]
33+
// CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]]
34+
// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]]
35+
// CHECK: [[EXIT_PRESPECIALIZED]]:
36+
// CHECK: ret %swift.metadata_response { %swift.type* bitcast (i64* getelementptr inbounds (<{ i8**, i64, %swift.type_descriptor*, %swift.type*, i8**, i32, [4 x i8], i64 }>, <{ i8**, i64, %swift.type_descriptor*, %swift.type*, i8**, i32, [4 x i8], i64 }>* @"$s4main5ValueVySiGMf", i32 0, i32 1) to %swift.type*), i64 0 }
37+
// CHECK: [[EXIT_NORMAL]]:
38+
// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata(i64 %0, i8* [[ERASED_TYPE]], i8* [[ERASED_TABLE]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #12
39+
// CHECK: ret %swift.metadata_response {{%[0-9]+}}
40+
// CHECK: }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %swift -target %module-target-future -emit-ir -prespecialize-generic-metadata %s | %FileCheck %s
2+
3+
// CHECK-NOT: @"$s4main5ValueVyAA7IntegerVGMf"
4+
struct Value<First : Hashable> {
5+
let first: First
6+
}
7+
8+
struct Integer : Hashable {
9+
let value: Int
10+
}
11+
12+
@inline(never)
13+
func consume<T>(_ t: T) {
14+
withExtendedLifetime(t) { t in
15+
}
16+
}
17+
18+
func doit() {
19+
consume( Value(first: Integer(value: 13)) )
20+
}
21+
doit()
22+
23+
// CHECK: ; Function Attrs: noinline nounwind readnone
24+
// CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5ValueVMa"(i64, %swift.type*, i8**) #{{[0-9]+}} {
25+
// CHECK: entry:
26+
// CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8*
27+
// CHECK: [[ERASED_CONFORMANCE:%[0-9]+]] = bitcast i8** %2 to i8*
28+
// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata(i64 %0, i8* [[ERASED_TYPE]], i8* [[ERASED_CONFORMANCE]], i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32 }>* @"$s4main5ValueVMn" to %swift.type_descriptor*)) #{{[0-9]+}}
29+
// CHECK: ret %swift.metadata_response {{%[0-9]+}}
30+
// CHECK: }
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %swift -target %module-target-future -emit-ir -prespecialize-generic-metadata %s | %FileCheck %s
2+
3+
struct Outer<First> {
4+
let first: First
5+
}
6+
7+
struct Inner<First> {
8+
let first: First
9+
}
10+
11+
@inline(never)
12+
func consume<T>(_ t: T) {
13+
withExtendedLifetime(t) { t in
14+
}
15+
}
16+
17+
// CHECK: define hidden swiftcc void @"$s4main4doityyF"() #{{[0-9]+}} {
18+
// TODO: Once prespecialization is done for generic arguments which are
19+
// themselves generic (Outer<Inner<Int>>, here), a direct reference to
20+
// the prespecialized metadata should be emitted here.
21+
// CHECK: [[TYPE:%[0-9]+]] = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s4main5OuterVyAA5InnerVySiGGMD") #11
22+
// CHECK: call swiftcc void @"$s4main7consumeyyxlF"(%swift.opaque* noalias nocapture %{{[0-9]+}}, %swift.type* [[TYPE]])
23+
// CHECK: }
24+
func doit() {
25+
consume( Outer(first: Inner(first: 13)) )
26+
}
27+
doit()
28+
29+
// CHECK: ; Function Attrs: noinline nounwind readnone
30+
// CHECK: define hidden swiftcc %swift.metadata_response @"$s4main5OuterVMa"(i64, %swift.type*) #{{[0-9]+}} {
31+
// CHECK: entry:
32+
// CHECK: [[ERASED_TYPE:%[0-9]+]] = bitcast %swift.type* %1 to i8*
33+
// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata(i64 %0, i8* [[ERASED_TYPE]], i8* undef, i8* undef, %swift.type_descriptor* bitcast (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i8, i8, i8, i8 }>* @"$s4main5OuterVMn" to %swift.type_descriptor*)) #{{[0-9]+}}
34+
// CHECK: ret %swift.metadata_response {{%[0-9]+}}
35+
// CHECK: }

0 commit comments

Comments
 (0)