Skip to content

Commit 163f58e

Browse files
authored
Merge pull request #7277 from swiftix/wip-partial-pre-specializations-wip-specialize-attribute-2
Teach EagerSpecializer how to use the new form of the @_specialize attribute
2 parents 3652190 + c3bbe64 commit 163f58e

File tree

11 files changed

+1426
-223
lines changed

11 files changed

+1426
-223
lines changed

include/swift/SIL/Mangle.h

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class AbstractClosureExpr;
3030
enum class SpecializationKind : uint8_t {
3131
Generic,
3232
NotReAbstractedGeneric,
33+
Partial,
34+
NotReAbstractedPartial,
3335
FunctionSignature,
3436
};
3537

@@ -73,6 +75,12 @@ class SpecializationManglerBase {
7375
case SpecializationKind::NotReAbstractedGeneric:
7476
M.append("r");
7577
break;
78+
case SpecializationKind::Partial:
79+
M.append("p");
80+
break;
81+
case SpecializationKind::NotReAbstractedPartial:
82+
M.append("P");
83+
break;
7684
case SpecializationKind::FunctionSignature:
7785
M.append("f");
7886
break;
@@ -145,14 +153,44 @@ class GenericSpecializationMangler :
145153
};
146154

147155
GenericSpecializationMangler(Mangle::Mangler &M, SILFunction *F,
148-
SubstitutionList Subs,
156+
SubstitutionList Subs, IsFragile_t Fragile,
157+
ReAbstractionMode isReAbstracted = ReAbstracted)
158+
: SpecializationMangler(isReAbstracted == ReAbstracted
159+
? SpecializationKind::Generic
160+
: SpecializationKind::NotReAbstractedGeneric,
161+
SpecializationPass::GenericSpecializer, M,
162+
Fragile, F),
163+
Subs(Subs) {
164+
}
165+
166+
private:
167+
void mangleSpecialization();
168+
};
169+
170+
class PartialSpecializationMangler :
171+
public SpecializationMangler<PartialSpecializationMangler> {
172+
173+
friend class SpecializationMangler<PartialSpecializationMangler>;
174+
175+
CanSILFunctionType SpecializedFnTy;
176+
public:
177+
178+
enum ReAbstractionMode {
179+
ReAbstracted,
180+
NotReabstracted
181+
};
182+
183+
PartialSpecializationMangler(Mangle::Mangler &M,
184+
SILFunction *F,
185+
CanSILFunctionType SpecializedFnTy,
149186
IsFragile_t Fragile,
150187
ReAbstractionMode isReAbstracted = ReAbstracted)
151188
: SpecializationMangler(isReAbstracted == ReAbstracted ?
152-
SpecializationKind::Generic :
153-
SpecializationKind::NotReAbstractedGeneric,
189+
SpecializationKind::Partial :
190+
SpecializationKind::NotReAbstractedPartial,
154191
SpecializationPass::GenericSpecializer,
155-
M, Fragile, F), Subs(Subs) {}
192+
M, Fragile, F), SpecializedFnTy(SpecializedFnTy) {
193+
}
156194

157195
private:
158196
void mangleSpecialization();

include/swift/SILOptimizer/Utils/Generics.h

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,69 @@ class ReabstractionInfo {
5353
/// out-parameters.
5454
unsigned NumFormalIndirectResults;
5555

56-
/// The function type after applying the substitutions of the original
57-
/// apply site.
56+
/// The function type after applying the substitutions used to call the
57+
/// specialized function.
5858
CanSILFunctionType SubstitutedType;
5959

6060
/// The function type after applying the re-abstractions on the
6161
/// SubstitutedType.
6262
CanSILFunctionType SpecializedType;
6363

64+
/// The generic environment to be used by the specialization.
65+
GenericEnvironment *SpecializedGenericEnv;
66+
67+
/// The generic signature of the specialization.
68+
/// It is nullptr if the specialization is not polymorphic.
69+
GenericSignature *SpecializedGenericSig;
70+
71+
// Set of the substitutions used by the caller's apply instruction before
72+
// any transformations performed by the generic specializer.
73+
// It uses archetypes.
74+
SubstitutionList OriginalParamSubs;
75+
76+
// Set of substitutions to be used by the caller's apply when it calls a
77+
// specialized function.
78+
// It uses archetypes.
79+
SubstitutionList CallerParamSubs;
80+
81+
// Set of substitutions to be used by the cloner during cloning.
82+
// It maps to concrete types for any types which were replaced by
83+
// concrete types in the caller's apply substitution list. All other
84+
// types are replaced by their respective archetypes.
85+
SubstitutionList ClonerParamSubs;
86+
87+
// Reference to the original generic non-specialized function.
88+
SILFunction *OriginalF;
89+
90+
// The apply site which invokes the generic function.
91+
ApplySite Apply;
92+
93+
// Set if a specialized function has unbound generic parameters.
94+
bool HasUnboundGenericParams;
95+
96+
// Substitutions to be used for creating a new function type
97+
// for the specialized function.
98+
// It uses interface types.
99+
SubstitutionMap CallerInterfaceSubs;
100+
101+
// Create a new substituted type with the updated signature.
102+
CanSILFunctionType createSubstitutedType(SILFunction *OrigF,
103+
const SubstitutionMap &SubstMap,
104+
bool HasUnboundGenericParams);
105+
106+
void createSubstitutedAndSpecializedTypes();
64107
public:
65108
/// Constructs the ReabstractionInfo for generic function \p Orig with
66109
/// substitutions \p ParamSubs.
67110
/// If specialization is not possible getSpecializedType() will return an
68111
/// invalid type.
69-
ReabstractionInfo(SILFunction *Orig, SubstitutionList ParamSubs);
112+
ReabstractionInfo(ApplySite Apply, SILFunction *Callee,
113+
SubstitutionList ParamSubs);
114+
115+
/// Constructs the ReabstractionInfo for generic function \p Orig with
116+
/// additional requirements. Requirements may contain new layout,
117+
/// conformances or same concrete type requirements.
118+
ReabstractionInfo(SILFunction *Orig, ArrayRef<Requirement> Requirements);
70119

71120
/// Returns true if the \p ParamIdx'th (non-result) formal parameter is
72121
/// converted from indirect to direct.
@@ -81,6 +130,16 @@ class ReabstractionInfo {
81130
return Conversions.test(ResultIdx);
82131
}
83132

133+
/// Gets the total number of original function arguments.
134+
unsigned getNumArguments() const { return Conversions.size(); }
135+
136+
/// Returns true if the \p ArgIdx'th argument is converted from an
137+
/// indirect
138+
/// result or parameter to a direct result or parameter.
139+
bool isArgConverted(unsigned ArgIdx) const {
140+
return Conversions.test(ArgIdx);
141+
}
142+
84143
/// Returns true if there are any conversions from indirect to direct values.
85144
bool hasConversions() const { return Conversions.any(); }
86145

@@ -92,6 +151,15 @@ class ReabstractionInfo {
92151
Conversions.resize(Conversions.size() - numPartialApplyArgs);
93152
}
94153

154+
/// Returns the index of the first argument of an apply site, which may be
155+
/// > 0 in case of a partial_apply.
156+
unsigned getIndexOfFirstArg(ApplySite Apply) const {
157+
unsigned numArgs = Apply.getNumArguments();
158+
assert(numArgs == Conversions.size() ||
159+
(numArgs < Conversions.size() && isa<PartialApplyInst>(Apply)));
160+
return Conversions.size() - numArgs;
161+
}
162+
95163
/// Get the function type after applying the substitutions to the original
96164
/// generic function.
97165
CanSILFunctionType getSubstitutedType() const { return SubstitutedType; }
@@ -101,10 +169,45 @@ class ReabstractionInfo {
101169
/// possible.
102170
CanSILFunctionType getSpecializedType() const { return SpecializedType; }
103171

172+
GenericEnvironment *getSpecializedGenericEnvironment() const {
173+
return SpecializedGenericEnv;
174+
}
175+
176+
SubstitutionList getCallerParamSubstitutions() const {
177+
return CallerParamSubs;
178+
}
179+
180+
SubstitutionList getClonerParamSubstitutions() const {
181+
return ClonerParamSubs;
182+
}
183+
184+
SubstitutionList getOriginalParamSubstitutions() const {
185+
return OriginalParamSubs;
186+
}
187+
104188
/// Create a specialized function type for a specific substituted type \p
105189
/// SubstFTy by applying the re-abstractions.
106190
CanSILFunctionType createSpecializedType(CanSILFunctionType SubstFTy,
107191
SILModule &M) const;
192+
193+
SILFunction *getNonSpecializedFunction() const { return OriginalF; }
194+
195+
/// Map type into a context of the specialized function.
196+
Type mapTypeIntoContext(Type type) const;
197+
198+
/// Map SIL type into a context of the specialized function.
199+
SILType mapTypeIntoContext(SILType type) const;
200+
201+
SILModule &getModule() const { return OriginalF->getModule(); }
202+
203+
/// Returns true if generic specialization is possible.
204+
bool canBeSpecialized() const;
205+
206+
/// Returns true if it is a full generic specialization.
207+
bool isFullSpecialization() const;
208+
209+
/// Returns true if it is a partial generic specialization.
210+
bool isPartialSpecialization() const;
108211
};
109212

110213
/// Helper class for specializing a generic function given a list of
@@ -118,6 +221,7 @@ class GenericFuncSpecializer {
118221

119222
SubstitutionMap ContextSubs;
120223
std::string ClonedName;
224+
121225
public:
122226
GenericFuncSpecializer(SILFunction *GenericFunc,
123227
SubstitutionList ParamSubs,
@@ -129,7 +233,7 @@ class GenericFuncSpecializer {
129233

130234
/// Return a newly created specialized function.
131235
SILFunction *tryCreateSpecialization();
132-
236+
133237
/// Try to specialize GenericFunc given a list of ParamSubs.
134238
/// Returns either a new or existing specialized function, or nullptr.
135239
SILFunction *trySpecialization() {
@@ -142,6 +246,10 @@ class GenericFuncSpecializer {
142246

143247
return SpecializedF;
144248
}
249+
250+
StringRef getClonedName() {
251+
return ClonedName;
252+
}
145253
};
146254

147255
// =============================================================================

lib/IRGen/GenArchetype.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,14 +280,39 @@ class ClassArchetypeTypeInfo
280280
}
281281
};
282282

283+
class FixedSizeArchetypeTypeInfo
284+
: public PODSingleScalarTypeInfo<FixedSizeArchetypeTypeInfo, LoadableTypeInfo>,
285+
public ArchetypeTypeInfoBase
286+
{
287+
FixedSizeArchetypeTypeInfo(llvm::Type *type, Size size, Alignment align,
288+
const SpareBitVector &spareBits,
289+
ArrayRef<ProtocolEntry> protocols)
290+
: PODSingleScalarTypeInfo(type, size, spareBits, align),
291+
ArchetypeTypeInfoBase(this + 1, protocols) {}
292+
293+
public:
294+
static const FixedSizeArchetypeTypeInfo *
295+
create(llvm::Type *type, Size size, Alignment align,
296+
const SpareBitVector &spareBits, ArrayRef<ProtocolEntry> protocols) {
297+
void *buffer = operator new(sizeof(FixedSizeArchetypeTypeInfo) +
298+
protocols.size() * sizeof(ProtocolEntry));
299+
return ::new (buffer)
300+
FixedSizeArchetypeTypeInfo(type, size, align, spareBits, protocols);
301+
}
302+
};
303+
283304
} // end anonymous namespace
284305

285306
/// Return the ArchetypeTypeInfoBase information from the TypeInfo for any
286307
/// archetype.
287308
static const ArchetypeTypeInfoBase &
288309
getArchetypeInfo(IRGenFunction &IGF, CanArchetypeType t, const TypeInfo &ti) {
289-
if (t->requiresClass())
310+
LayoutConstraint LayoutInfo = t->getLayoutConstraint();
311+
if (t->requiresClass() || (LayoutInfo && LayoutInfo->isRefCountedObject()))
290312
return ti.as<ClassArchetypeTypeInfo>();
313+
if (LayoutInfo && LayoutInfo->isFixedSizeTrivial())
314+
return ti.as<FixedSizeArchetypeTypeInfo>();
315+
// TODO: Handle LayoutConstraintInfo::Trivial
291316
return ti.as<OpaqueArchetypeTypeInfo>();
292317
}
293318

@@ -374,9 +399,12 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
374399
protocols.push_back(ProtocolEntry(protocol, impl));
375400
}
376401

402+
LayoutConstraint LayoutInfo = archetype->getLayoutConstraint();
403+
377404
// If the archetype is class-constrained, use a class pointer
378405
// representation.
379-
if (archetype->requiresClass()) {
406+
if (archetype->requiresClass() ||
407+
(LayoutInfo && LayoutInfo->isRefCountedObject())) {
380408
ReferenceCounting refcount;
381409
llvm::PointerType *reprTy;
382410

@@ -412,6 +440,28 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
412440
protocols, refcount);
413441
}
414442

443+
// If the archetype is trivial fixed-size layout-constrained, use a fixed size
444+
// representation.
445+
if (LayoutInfo && LayoutInfo->isFixedSizeTrivial()) {
446+
Size size(LayoutInfo->getTrivialSizeInBytes());
447+
Alignment align(LayoutInfo->getTrivialSizeInBytes());
448+
auto spareBits =
449+
SpareBitVector::getConstant(size.getValueInBits(), false);
450+
// Get an integer type of the required size.
451+
auto ProperlySizedIntTy = SILType::getBuiltinIntegerType(
452+
size.getValueInBits(), IGM.getSwiftModule()->getASTContext());
453+
auto storageType = IGM.getStorageType(ProperlySizedIntTy);
454+
return FixedSizeArchetypeTypeInfo::create(storageType, size, align,
455+
spareBits, protocols);
456+
}
457+
458+
// If the archetype is a trivial layout-constrained, use a POD
459+
// representation. This type is not loadable, but it is known
460+
// to be a POD.
461+
if (LayoutInfo && LayoutInfo->isAddressOnlyTrivial()) {
462+
// TODO: Create NonFixedSizeArchetypeTypeInfo and return it.
463+
}
464+
415465
// Otherwise, for now, always use an opaque indirect type.
416466
llvm::Type *storageType = IGM.OpaquePtrTy->getElementType();
417467
return OpaqueArchetypeTypeInfo::create(storageType, protocols);

lib/IRGen/GenOpaque.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,9 @@ void irgen::emitAssignWithTakeCall(IRGenFunction &IGF,
669669
void irgen::emitDestroyCall(IRGenFunction &IGF,
670670
SILType T,
671671
Address object) {
672+
// If T is a trivial/POD type, nothing needs to be done.
673+
if (T.getObjectType().isTrivial(IGF.getSILModule()))
674+
return;
672675
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
673676
llvm::Value *fn = IGF.emitValueWitnessForLayout(T,
674677
ValueWitness::Destroy);
@@ -683,6 +686,9 @@ void irgen::emitDestroyArrayCall(IRGenFunction &IGF,
683686
SILType T,
684687
Address object,
685688
llvm::Value *count) {
689+
// If T is a trivial/POD type, nothing needs to be done.
690+
if (T.getObjectType().isTrivial(IGF.getSILModule()))
691+
return;
686692
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
687693
llvm::Value *fn = IGF.emitValueWitnessForLayout(T,
688694
ValueWitness::DestroyArray);

lib/SIL/Mangle.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static void mangleSubstitution(Mangler &M, Substitution Sub) {
5555

5656
void GenericSpecializationMangler::mangleSpecialization() {
5757
Mangler &M = getMangler();
58-
58+
// This is a full specialization.
5959
SILFunctionType *FTy = Function->getLoweredFunctionType();
6060
CanGenericSignature Sig = FTy->getGenericSignature();
6161

@@ -73,6 +73,25 @@ void GenericSpecializationMangler::mangleSpecialization() {
7373
assert(idx == Subs.size() && "subs not parallel to dependent types");
7474
}
7575

76+
void PartialSpecializationMangler::mangleSpecialization() {
77+
Mangler &M = getMangler();
78+
// If the only change to the generic signature during specialization is
79+
// addition of new same-type requirements, which happens in case of a
80+
// full specialization, it would be enough to mangle only the substitutions.
81+
//
82+
// If the types of function arguments have not changed, but some new
83+
// conformances were added to the generic parameters, e.g. in case of
84+
// a pre-specialization, then it would be enough to mangle only the new
85+
// generic signature.
86+
//
87+
// If the types of function arguments have changed as a result of a partial
88+
// specialization, we need to mangle the entire new function type.
89+
90+
// This is a partial specialization.
91+
M.mangleType(SpecializedFnTy, 0);
92+
M.append("_");
93+
}
94+
7695
//===----------------------------------------------------------------------===//
7796
// Function Signature Optimizations
7897
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)