Skip to content
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
2 changes: 1 addition & 1 deletion include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ class IRGenOptions {
EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false),
LazyInitializeClassMetadata(false),
LazyInitializeProtocolConformances(false), DisableLegacyTypeInfo(false),
PrespecializeGenericMetadata(false), UseIncrementalLLVMCodeGen(true),
PrespecializeGenericMetadata(true), UseIncrementalLLVMCodeGen(true),
UseSwiftCall(false), GenerateProfile(false),
EnableDynamicReplacementChaining(false),
DisableRoundTripDebugTypes(false), DisableDebuggerShadowCopies(false),
Expand Down
6 changes: 3 additions & 3 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -651,9 +651,9 @@ def disable_verify_exclusivity : Flag<["-"], "disable-verify-exclusivity">,
def disable_legacy_type_info : Flag<["-"], "disable-legacy-type-info">,
HelpText<"Completely disable legacy type layout">;

def prespecialize_generic_metadata : Flag<["-"], "prespecialize-generic-metadata">,
HelpText<"Statically specialize metadata for generic types at types that "
"are known to be used in source.">;
def disable_generic_metadata_prespecialization : Flag<["-"], "disable-generic-metadata-prespecialization">,
HelpText<"Do not statically specialize metadata for generic types at types "
"that are known to be used in source.">;

def read_legacy_type_info_path_EQ : Joined<["-"], "read-legacy-type-info-path=">,
HelpText<"Read legacy type layout from the given path instead of default path">;
Expand Down
4 changes: 2 additions & 2 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1327,8 +1327,8 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
Opts.DisableLegacyTypeInfo = true;
}

if (Args.hasArg(OPT_prespecialize_generic_metadata)) {
Opts.PrespecializeGenericMetadata = true;
if (Args.hasArg(OPT_disable_generic_metadata_prespecialization)) {
Opts.PrespecializeGenericMetadata = false;
}

if (const Arg *A = Args.getLastArg(OPT_read_legacy_type_info_path_EQ)) {
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,8 @@ bool IRGenModule::shouldPrespecializeGenericMetadata() {
AvailabilityContext::forDeploymentTarget(context);
return IRGen.Opts.PrespecializeGenericMetadata &&
deploymentAvailability.isContainedIn(
context.getPrespecializedGenericMetadataAvailability());
context.getPrespecializedGenericMetadataAvailability()) &&
(Triple.isOSDarwin() || Triple.isTvOS() || Triple.isOSLinux());
}

void IRGenerator::addGenModule(SourceFile *SF, IRGenModule *IGM) {
Expand Down
85 changes: 47 additions & 38 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -701,36 +701,40 @@ bool irgen::isNominalGenericContextTypeMetadataAccessTrivial(
auto substitutions =
type->getContextSubstitutionMap(IGM.getSwiftModule(), &nominal);

return llvm::all_of(environment->getGenericParams(), [&](auto parameter) {
auto conformances =
environment->getGenericSignature()->getConformsTo(parameter);
auto witnessTablesAreReferenceable =
llvm::all_of(conformances, [&](ProtocolDecl *conformance) {
return conformance->getModuleContext() == IGM.getSwiftModule() &&
!conformance->isResilient(IGM.getSwiftModule(),
ResilienceExpansion::Minimal);
});
auto allWitnessTablesAreReferenceable = llvm::all_of(environment->getGenericParams(), [&](auto parameter) {
auto signature = environment->getGenericSignature();
auto protocols = signature->getConformsTo(parameter);
auto argument = ((Type *)parameter)->subst(substitutions);
auto genericArgument = argument->getAnyGeneric();
// For now, to avoid statically specializing generic protocol witness
// tables, don't statically specialize metadata for types any of whose
// arguments are generic.
//
// TODO: This is more pessimistic than necessary. Specialize even in
// the face of generic arguments so long as those arguments
// aren't required to conform to any protocols.
//
auto canonicalType = argument->getCanonicalType();
auto witnessTablesAreReferenceable = [&]() {
return llvm::all_of(protocols, [&](ProtocolDecl *protocol) {
auto conformance =
signature->lookupConformance(canonicalType, protocol);
if (!conformance.isConcrete()) {
return false;
}
auto rootConformance = conformance.getConcrete()->getRootConformance();
return !IGM.isDependentConformance(rootConformance) &&
!IGM.isResilientConformance(rootConformance);
});
};
// TODO: Once witness tables are statically specialized, check whether the
// ConformanceInfo returns nullptr from tryGetConstantTable.
// early return.
auto isGeneric = genericArgument && genericArgument->isGenericContext();
auto isNominal = argument->getNominalOrBoundGenericNominal();
auto isExistential = argument->isExistentialType();
return isNominal && !isGeneric && !isExistential &&
witnessTablesAreReferenceable &&
irgen::isTypeMetadataAccessTrivial(IGM,
argument->getCanonicalType());
}) && IGM.getTypeInfoForUnlowered(type).isFixedSize(ResilienceExpansion::Maximal);
auto isGenericWithoutPrespecializedConformance = [&]() {
auto genericArgument = argument->getAnyGeneric();
return genericArgument && genericArgument->isGenericContext() &&
(protocols.size() > 0);
};
auto isExistential = [&]() { return argument->isExistentialType(); };
auto metadataAccessIsTrivial = [&]() {
return irgen::isTypeMetadataAccessTrivial(IGM,
argument->getCanonicalType());
};
return !isGenericWithoutPrespecializedConformance() && !isExistential() &&
metadataAccessIsTrivial() && witnessTablesAreReferenceable();
});
return allWitnessTablesAreReferenceable
&& IGM.getTypeInfoForUnlowered(type).isFixedSize(ResilienceExpansion::Maximal);
}

/// Is it basically trivial to access the given metadata? If so, we don't
Expand Down Expand Up @@ -1753,28 +1757,33 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction(
SmallVector<std::pair<llvm::BasicBlock *, llvm::Value *>, 4>
specializationBlocks;
auto switchDestination = llvm::BasicBlock::Create(IGM.getLLVMContext());
unsigned long index = 0;
unsigned long blockIndex = 0;
for (auto specialization : specializations) {
auto conditionBlock = conditionBlocks[index];
auto conditionBlock = conditionBlocks[blockIndex];
IGF.Builder.emitBlock(conditionBlock);
auto successorBlock = index < conditionBlocks.size() - 1
? conditionBlocks[index + 1]
auto successorBlock = blockIndex < conditionBlocks.size() - 1
? conditionBlocks[blockIndex + 1]
: switchDestination;
auto specializationBlock = llvm::BasicBlock::Create(IGM.getLLVMContext());
auto substitutions = specialization->getContextSubstitutionMap(
IGM.getSwiftModule(), nominal);

llvm::Value *condition = llvm::ConstantInt::get(IGM.Int1Ty, 1);
auto generic = specialization->getAnyGeneric();
auto parameters = generic->getGenericEnvironment()->getGenericParams();
for (size_t index = 0; index < parameters.size(); ++index) {
auto parameter = parameters[index];
auto argument = ((Type *)parameter)->subst(substitutions);
auto nominal = specialization->getAnyNominal();
auto requirements = GenericTypeRequirements(IGF.IGM, nominal);
int requirementIndex = 0;
for (auto requirement : requirements.getRequirements()) {
if (requirement.Protocol) {
continue;
}
auto parameter = requirement.TypeParameter;
auto argument = parameter.subst(substitutions);
llvm::Constant *addr =
IGM.getAddrOfTypeMetadata(argument->getCanonicalType());
auto addrInt = IGF.Builder.CreateBitCast(addr, IGM.Int8PtrTy);
condition = IGF.Builder.CreateAnd(
condition, IGF.Builder.CreateICmpEQ(addrInt, valueAtIndex(index)));
condition, IGF.Builder.CreateICmpEQ(addrInt, valueAtIndex(requirementIndex)));
++requirementIndex;
}
IGF.Builder.CreateCondBr(condition, specializationBlock, successorBlock);

Expand All @@ -1793,7 +1802,7 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction(
response = IGF.Builder.CreateInsertValue(
response, state, 1, "insert metadata state into response");
specializationBlocks.push_back({specializationBlock, response});
++index;
++blockIndex;
}

for (auto pair : specializationBlocks) {
Expand Down
8 changes: 4 additions & 4 deletions test/IRGen/conditional_conformances.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass.swift --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift --check-prefix=CHECK --check-prefix=%target-os

// Too many pointer-sized integers in the IR
// REQUIRES: PTRSIZE=64
Expand Down
9 changes: 9 additions & 0 deletions test/IRGen/conditional_conformances_future.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %target-swift-frontend -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances_future.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_with_assoc.swift | %FileCheck %S/../Inputs/conditional_conformance_with_assoc_future.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_subclass.swift | %FileCheck %S/../Inputs/conditional_conformance_subclass_future.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=%target-os
// RUN: %target-swift-frontend -target %module-target-future -emit-ir %S/../Inputs/conditional_conformance_recursive.swift | %FileCheck %S/../Inputs/conditional_conformance_recursive.swift -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=%target-os

// Too many pointer-sized integers in the IR
// REQUIRES: PTRSIZE=64
// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -target x86_64-apple-macosx10.99 -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=TYPEBYNAME
// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -target x86_64-apple-macosx10.99 -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=TYPEBYNAME
// RUN: %target-swift-frontend -target x86_64-apple-macosx10.99 -emit-ir %S/../Inputs/conditional_conformance_basic_conformances.swift | %FileCheck %S/../Inputs/conditional_conformance_basic_conformances.swift --check-prefix=TYPEBYNAME_PRESPECIALIZED

// Too many pointer-sized integers in the IR
// REQUIRES: PTRSIZE=64
Expand Down
3 changes: 2 additions & 1 deletion test/IRGen/dynamic_self_metadata.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %target-swift-frontend %s -emit-ir -parse-as-library | %FileCheck %s
// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization %s -emit-ir -parse-as-library | %FileCheck %s

// UNSUPPORTED: OS=windows-msvc
// REQUIRES: CPU=x86_64

// FIXME: Not a SIL test because we can't parse dynamic Self in SIL.
Expand Down
79 changes: 79 additions & 0 deletions test/IRGen/dynamic_self_metadata_future.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// RUN: %target-swift-frontend %s -target %module-target-future -emit-ir -parse-as-library | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment


// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu
// REQUIRES: CPU=x86_64

// FIXME: Not a SIL test because we can't parse dynamic Self in SIL.
// <rdar://problem/16931299>

// CHECK: [[TYPE:%.+]] = type <{ [8 x i8] }>

@inline(never) func id<T>(_ t: T) -> T {
return t
}
// CHECK-LABEL: define hidden swiftcc void @"$s28dynamic_self_metadata_future2idyxxlF"

protocol P {
associatedtype T
}

extension P {
func f() {}
}

struct G<T> : P {
var t: T
}

class C {
class func fromMetatype() -> Self? { return nil }
// CHECK-LABEL: define hidden swiftcc i64 @"$s28dynamic_self_metadata_future1CC12fromMetatypeACXDSgyFZ"(%swift.type* swiftself)
// CHECK: ret i64 0

func fromInstance() -> Self? { return nil }
// CHECK-LABEL: define hidden swiftcc i64 @"$s28dynamic_self_metadata_future1CC12fromInstanceACXDSgyF"(%T28dynamic_self_metadata_future1CC* swiftself)
// CHECK: ret i64 0

func dynamicSelfArgument() -> Self? {
return id(nil)
}
// CHECK-LABEL: define hidden swiftcc i64 @"$s28dynamic_self_metadata_future1CC0A12SelfArgumentACXDSgyF"(%T28dynamic_self_metadata_future1CC* swiftself)
// CHECK: [[GEP1:%.+]] = getelementptr {{.*}} %0
// CHECK: [[TYPE1:%.+]] = load {{.*}} [[GEP1]]
// CHECK: [[T0:%.+]] = call swiftcc %swift.metadata_response @"$sSqMa"(i64 0, %swift.type* [[TYPE1]])
// CHECK: [[TYPE2:%.+]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK: call swiftcc void @"$s28dynamic_self_metadata_future2idyxxlF"({{.*}}, %swift.type* [[TYPE2]])

func dynamicSelfConformingType() -> Self? {
_ = G(t: self).f()
return nil
}
// CHECK-LABEL: define hidden swiftcc i64 @"$s28dynamic_self_metadata_future1CC0A18SelfConformingTypeACXDSgyF"(%T28dynamic_self_metadata_future1CC* swiftself)
// CHECK: [[SELF_GEP:%.+]] = getelementptr {{.*}} %0
// CHECK: [[SELF_TYPE:%.+]] = load {{.*}} [[SELF_GEP]]
// CHECK: call i8** @swift_getWitnessTable(
// CHECK-SAME: %swift.protocol_conformance_descriptor* bitcast (
// CHECK-SAME: {{.*}} @"$s28dynamic_self_metadata_future1GVyxGAA1PAAMc"
// CHECK-SAME: to %swift.protocol_conformance_descriptor*
// CHECK-SAME: ),
// CHECK-SAME: %swift.type* getelementptr inbounds (
// CHECK-SAME: %swift.full_type,
// CHECK-SAME: %swift.full_type* bitcast (
// CHECK-SAME: <{
// CHECK-SAME: i8**,
// CHECK-SAME: [[INT]],
// CHECK-SAME: %swift.type_descriptor*,
// CHECK-SAME: %swift.type*,
// CHECK-SAME: i32,
// CHECK-SAME: {{(\[4 x i8\])?}},
// CHECK-SAME: i64
// CHECK-SAME: }>* @"$s28dynamic_self_metadata_future1GVyAA1CCXDGMf"
// CHECK-SAME: to %swift.full_type*
// CHECK-SAME: ),
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 1
// CHECK-SAME: ),
// CHECK-SAME: i8*** undef
// CHECK-SAME: )
}
2 changes: 1 addition & 1 deletion test/IRGen/foreign_types.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -I %S/Inputs/abi %s -emit-ir | %FileCheck %s -DINT=i%target-ptrsize
// RUN: %target-swift-frontend -disable-generic-metadata-prespecialization -I %S/Inputs/abi %s -emit-ir | %FileCheck %s -DINT=i%target-ptrsize

sil_stage canonical
import c_layout
Expand Down
44 changes: 44 additions & 0 deletions test/IRGen/foreign_types_future.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: %target-swift-frontend -target %module-target-future -I %S/Inputs/abi %s -emit-ir | %FileCheck %s -DINT=i%target-ptrsize

// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=linux-gnu
// UNSUPPORTED: CPU=i386 && OS=ios
// UNSUPPORTED: CPU=armv7 && OS=ios
// UNSUPPORTED: CPU=armv7s && OS=ios

sil_stage canonical
import c_layout

// CHECK: [[AMAZING_COLOR_NAME:@.*]] = private constant [13 x i8] c"AmazingColor\00"

// CHECK-LABEL: @"$sSo12AmazingColorVMn" = linkonce_odr hidden constant
// CHECK-SAME: [[AMAZING_COLOR_NAME]]
// CHECK-SAME: @"$sSo12AmazingColorVMa"

// CHECK: [[HAS_NESTED_UNION_NAME:@.*]] = private constant [15 x i8] c"HasNestedUnion\00"

// CHECK-LABEL: @"$sSo14HasNestedUnionVMn" = linkonce_odr hidden constant
// CHECK-SAME: [[HAS_NESTED_UNION_NAME]]
// CHECK-SAME: @"$sSo14HasNestedUnionVMa"

// CHECK-LABEL: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMf" = linkonce_odr hidden constant
// CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVWV"
// CHECK-SAME: [[INT]] 512,
// CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMn"
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 4,
// CHECK-SAME: i64 0 }

// CHECK-LABEL: @"\01l_type_metadata_table" = private constant
// CHECK-SAME: @"$sSo12AmazingColorVMn"
// CHECK-SAME: @"$sSo14HasNestedUnionVMn"
// CHECK-SAME: @"$sSo14HasNestedUnionV18__Unnamed_struct_sVMn"

sil @test0 : $() -> () {
bb0:
%0 = metatype $@thick HasNestedUnion.Type
%1 = metatype $@thick AmazingColor.Type

%ret = tuple ()
return %ret : $()
}

Loading