Skip to content

Commit 1f30a54

Browse files
committed
Sketch out a SILType::isSingleSwiftRefcounted function.
1 parent 56c7547 commit 1f30a54

File tree

3 files changed

+91
-7
lines changed

3 files changed

+91
-7
lines changed

include/swift/SIL/SILType.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,11 @@ class SILType {
430430
bool isPointerSizeAndAligned(SILModule &M,
431431
ResilienceExpansion expansion) const;
432432

433+
/// True if the layout of the given type consists of a single native Swift-
434+
/// refcounted object reference, possibly nullable.
435+
bool isSingleSwiftRefcounted(SILModule &M,
436+
ResilienceExpansion expansion) const;
437+
433438
/// True if `operTy` can be cast by single-reference value into `resultTy`.
434439
static bool canRefCast(SILType operTy, SILType resultTy, SILModule &M);
435440

lib/SIL/IR/SILType.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,79 @@ bool SILType::isPointerSizeAndAligned(SILModule &M,
191191
return false;
192192
}
193193

194+
static bool isSingleSwiftRefcounted(SILModule &M,
195+
SILType SILTy,
196+
ResilienceExpansion expansion,
197+
bool didUnwrapOptional) {
198+
auto &C = M.getASTContext();
199+
200+
// Unwrap one layer of optionality.
201+
// TODO: Or more generally, any fragile enum with a single payload and single
202+
// no-payload case.
203+
if (!didUnwrapOptional) {
204+
if (auto objectTy = SILTy.getOptionalObjectType()) {
205+
return ::isSingleSwiftRefcounted(M, objectTy, expansion, true);
206+
}
207+
}
208+
209+
// Unwrap singleton aggregates.
210+
if (auto underlyingField = SILTy.getSingletonAggregateFieldType(M, expansion)) {
211+
return ::isSingleSwiftRefcounted(M, underlyingField, expansion,
212+
didUnwrapOptional);
213+
}
214+
215+
auto Ty = SILTy.getASTType();
216+
217+
// Easy cases: Builtin.NativeObject and boxes are always Swift-refcounted.
218+
if (Ty == C.TheNativeObjectType)
219+
return true;
220+
if (isa<SILBoxType>(Ty))
221+
return true;
222+
223+
// Is the type a Swift-refcounted class?
224+
// For a generic type, consider its superclass constraint, if any.
225+
auto ClassTy = Ty;
226+
if (auto archety = dyn_cast<ArchetypeType>(Ty)) {
227+
if (auto superclass = Ty->getSuperclass()) {
228+
ClassTy = superclass->getCanonicalType();
229+
}
230+
}
231+
// For an existential type, consider its superclass constraint, if it carries
232+
// no witness tables.
233+
if (Ty->isAnyExistentialType()) {
234+
auto layout = Ty->getExistentialLayout();
235+
// Must be no protocol constraints that aren't @objc or @_marker.
236+
if (layout.containsNonObjCProtocol) {
237+
for (auto proto : layout.getProtocols()) {
238+
if (!proto->isObjC() && !proto->isMarkerProtocol()) {
239+
return false;
240+
}
241+
}
242+
}
243+
244+
// The Error existential has its own special layout.
245+
if (layout.isErrorExistential()) {
246+
return false;
247+
}
248+
249+
// We can look at the superclass constraint, if any, to see if it's
250+
// Swift-refcounted.
251+
if (!layout.getSuperclass()) {
252+
return false;
253+
}
254+
ClassTy = layout.getSuperclass()->getCanonicalType();
255+
}
256+
257+
// TODO: Does the base class we found have fully native Swift ancestry,
258+
// so we can use Swift native refcounting on it?
259+
return false;
260+
}
261+
262+
bool SILType::isSingleSwiftRefcounted(SILModule &M,
263+
ResilienceExpansion expansion) const {
264+
return ::isSingleSwiftRefcounted(M, *this, expansion, false);
265+
}
266+
194267
// Reference cast from representations with single pointer low bits.
195268
// Only reference cast to simple single pointer representations.
196269
//

lib/SILOptimizer/Transforms/PartialApplySimplification.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class PartialApplySimplificationPass : public SILModuleTransform {
139139
static bool isSimplePartialApply(SILModule &M,
140140
CanSILFunctionType calleeTy,
141141
TypeExpansionContext context,
142+
ParameterConvention calleeConvention,
142143
unsigned numPartiallyAppliedArgs,
143144
bool isOnStack) {
144145
if (calleeTy->isPolymorphic()) {
@@ -157,6 +158,7 @@ static bool isSimplePartialApply(SILModule &M,
157158

158159
auto contextParam = calleeTy->getSelfParameter();
159160

161+
auto argTy = contextParam.getArgumentType(M, calleeTy, context);
160162
if (isOnStack) {
161163
switch (contextParam.getConvention()) {
162164
case ParameterConvention::Indirect_Inout:
@@ -167,13 +169,11 @@ static bool isSimplePartialApply(SILModule &M,
167169
return true;
168170

169171
case ParameterConvention::Direct_Guaranteed:
170-
case ParameterConvention::Direct_Unowned: {
171-
auto argTy = contextParam.getArgumentType(M, calleeTy, context);
172+
case ParameterConvention::Direct_Unowned:
172173
return SILType::getPrimitiveObjectType(argTy)
173174
.isPointerSizeAndAligned(M, context.getResilienceExpansion());
174175
// TODO: If we're running as an IRGen pass, use IRGen's version of
175176
// `isPointerSizeAndAligned` as a more accurate check.
176-
}
177177

178178
// +1 arguments need a thunk to stage a copy for the callee to consume.
179179
case ParameterConvention::Direct_Owned:
@@ -185,12 +185,16 @@ static bool isSimplePartialApply(SILModule &M,
185185
return false;
186186
}
187187

188-
// TODO: Handle native-refcounted classes, single-refcounted aggregates,
189-
// and bit-packable trivial types using knowledge from IRGen if this becomes
190-
// an IRGenPrepare pass
191-
if (!isa<SILBoxType>(contextParam.getInterfaceType())) {
188+
// The context parameter's convention must match the callee convention of
189+
// the resulting closure.
190+
if (contextParam.getConvention() != calleeConvention) {
192191
return false;
193192
}
193+
194+
// The context type must consist of only a swift-refcounted object
195+
// reference.
196+
return SILType::getPrimitiveObjectType(argTy)
197+
.isSingleSwiftRefcounted(M, context.getResilienceExpansion());
194198
}
195199

196200
return true;
@@ -200,6 +204,7 @@ static bool isSimplePartialApply(PartialApplyInst *i) {
200204
return isSimplePartialApply(i->getModule(),
201205
i->getCallee()->getType().castTo<SILFunctionType>(),
202206
i->getFunction()->getTypeExpansionContext(),
207+
i->getFunctionType()->getCalleeConvention(),
203208
i->getNumArguments(),
204209
i->isOnStack());
205210
}
@@ -323,6 +328,7 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
323328
if (isSimplePartialApply(callee->getModule(),
324329
calleeTyAsMethod,
325330
examplePA->getFunction()->getTypeExpansionContext(),
331+
examplePA->getFunctionType()->getCalleeConvention(),
326332
examplePA->getNumArguments(),
327333
examplePA->isOnStack())) {
328334
return rewriteKnownCalleeConventionOnly(callee, pa, examplePA,

0 commit comments

Comments
 (0)