@@ -191,9 +191,37 @@ removeInstructions(ArrayRef<SILInstruction*> UsersToRemove) {
191
191
// Use Graph Analysis
192
192
// ===----------------------------------------------------------------------===//
193
193
194
+ static bool mutatesOnlyExpectedSelf (ApplyInst *Apply, SILInstruction *ExpectedSelf) {
195
+ if (!Apply->hasSemantics (" interpolation.selfEffectsOnly" ))
196
+ return false ;
197
+ assert (Apply->hasSelfArgument () && " interpolation.selfEffectsOnly on non-method" );
198
+
199
+ SILInstruction *ActualSelf = Apply->getSelfArgument ()->getDefiningInstruction ();
200
+ return ActualSelf == ExpectedSelf;
201
+ }
202
+
203
+ // FIXME: This is blatantly awful and needs to be better.
204
+ static bool isStringObjectReleaseLoad (LoadInst *Load) {
205
+ // Are we dereferencing a pointer stored in _StringGuts._object?
206
+ if (auto *StructLookup = dyn_cast<StructElementAddrInst>(Load->getOperand ()->getDefiningInstruction ())) {
207
+ if (StructLookup->getField ()->getName ().is (" _object" ) && StructLookup->getStructDecl ()->getName ().is (" _StringObject" )) {
208
+
209
+ // Are the only uses strong_release?
210
+ for (auto Use : Load->getUses ()) {
211
+ if (!isa<StrongReleaseInst>(Use->getUser ()))
212
+ return false ;
213
+ }
214
+ return true ;
215
+ }
216
+ }
217
+
218
+ return false ;
219
+ }
220
+
194
221
// / Returns false if Inst is an instruction that would require us to keep the
195
222
// / alloc_ref alive.
196
- static bool canZapInstruction (SILInstruction *Inst, bool acceptRefCountInsts) {
223
+ static bool canZapInstruction (SILInstruction *Inst, bool acceptRefCountInsts,
224
+ SILInstruction *AllocInst) {
197
225
if (isa<SetDeallocatingInst>(Inst) || isa<FixLifetimeInst>(Inst))
198
226
return true ;
199
227
@@ -224,6 +252,16 @@ static bool canZapInstruction(SILInstruction *Inst, bool acceptRefCountInsts) {
224
252
if (isa<DestroyAddrInst>(Inst))
225
253
return true ;
226
254
255
+ // We can remove applies of certain interpolation-related methods.
256
+ if (auto *Apply = dyn_cast<ApplyInst>(Inst))
257
+ if (mutatesOnlyExpectedSelf (Apply, AllocInst))
258
+ return true ;
259
+
260
+ // FIXME: Necessary for string interpolation, but is it correct?
261
+ if (auto *Load = dyn_cast<LoadInst>(Inst))
262
+ if (isStringObjectReleaseLoad (Load))
263
+ return true ;
264
+
227
265
// Otherwise we do not know how to handle this instruction. Be conservative
228
266
// and don't zap it.
229
267
return false ;
@@ -252,7 +290,7 @@ hasUnremovableUsers(SILInstruction *AllocRef, UserList &Users,
252
290
}
253
291
254
292
// If we can't zap this instruction... bail...
255
- if (!canZapInstruction (I, acceptRefCountInsts)) {
293
+ if (!canZapInstruction (I, acceptRefCountInsts, AllocRef )) {
256
294
LLVM_DEBUG (llvm::dbgs () << " Found instruction we can't zap...\n " );
257
295
return true ;
258
296
}
@@ -715,10 +753,24 @@ bool DeadObjectElimination::processAllocRef(AllocRefInst *ARI) {
715
753
return true ;
716
754
}
717
755
756
+ static bool isDefaultStringInterpolation (SILType silTy) {
757
+ auto astTy = silTy.getASTType ();
758
+ if (!astTy) return false ;
759
+
760
+ auto nomTy = astTy.getNominalOrBoundGenericNominal ();
761
+ if (!nomTy) return false ;
762
+
763
+ // FIXME: Do this in a non-horrible way.
764
+ return nomTy->getName ().is (" DefaultStringInterpolation" );
765
+ }
766
+
718
767
bool DeadObjectElimination::processAllocStack (AllocStackInst *ASI) {
719
768
// Trivial types don't have destructors. Let's try to zap this AllocStackInst.
720
- if (!ASI->getElementType ().isTrivial (ASI->getModule ()))
769
+ if (!ASI->getElementType ().isTrivial (ASI->getModule ()) &&
770
+ !isDefaultStringInterpolation (ASI->getElementType ())) {
771
+ LLVM_DEBUG (llvm::dbgs () << " Skipping due to non-trivial type:" << *ASI);
721
772
return false ;
773
+ }
722
774
723
775
UserList UsersToRemove;
724
776
if (hasUnremovableUsers (ASI, UsersToRemove, /* acceptRefCountInsts=*/ true )) {
0 commit comments