@@ -172,6 +172,10 @@ class MemoryBehaviorVisitor
172
172
MemBehavior visitCopyAddrInst (CopyAddrInst *CAI);
173
173
MemBehavior visitApplyInst (ApplyInst *AI);
174
174
MemBehavior visitTryApplyInst (TryApplyInst *AI);
175
+ MemBehavior visitBeginApplyInst (BeginApplyInst *AI);
176
+ MemBehavior visitEndApplyInst (EndApplyInst *EAI);
177
+ MemBehavior visitAbortApplyInst (AbortApplyInst *AAI);
178
+ MemBehavior getApplyBehavior (FullApplySite AS);
175
179
MemBehavior visitBuiltinInst (BuiltinInst *BI);
176
180
MemBehavior visitStrongReleaseInst (StrongReleaseInst *BI);
177
181
MemBehavior visitReleaseValueInst (ReleaseValueInst *BI);
@@ -326,70 +330,137 @@ MemBehavior MemoryBehaviorVisitor::visitBuiltinInst(BuiltinInst *BI) {
326
330
}
327
331
328
332
MemBehavior MemoryBehaviorVisitor::visitTryApplyInst (TryApplyInst *AI) {
329
- MemBehavior Behavior = MemBehavior::MayHaveSideEffects;
330
- // Ask escape analysis.
331
- if (!EA->canEscapeTo (V, AI))
332
- Behavior = MemBehavior::None;
333
-
334
- // Otherwise be conservative and return that we may have side effects.
335
- LLVM_DEBUG (llvm::dbgs () << " Found tryapply, returning " << Behavior <<' \n ' );
336
- return Behavior;
333
+ return getApplyBehavior (AI);
337
334
}
338
335
339
336
MemBehavior MemoryBehaviorVisitor::visitApplyInst (ApplyInst *AI) {
337
+ return getApplyBehavior (AI);
338
+ }
340
339
341
- FunctionSideEffects ApplyEffects;
342
- SEA->getCalleeEffects (ApplyEffects, AI);
340
+ MemBehavior MemoryBehaviorVisitor::visitBeginApplyInst (BeginApplyInst *AI) {
341
+ return getApplyBehavior (AI);
342
+ }
343
+
344
+ MemBehavior MemoryBehaviorVisitor::visitEndApplyInst (EndApplyInst *EAI) {
345
+ return getApplyBehavior (EAI->getBeginApply ());
346
+ }
347
+
348
+ MemBehavior MemoryBehaviorVisitor::visitAbortApplyInst (AbortApplyInst *AAI) {
349
+ return getApplyBehavior (AAI->getBeginApply ());
350
+ }
351
+
352
+ // / Returns true if the \p address may have any users which let the address
353
+ // / escape in an unusual way, e.g. with an address_to_pointer instruction.
354
+ static bool hasEscapingUses (SILValue address, int &numChecks) {
355
+ for (Operand *use : address->getUses ()) {
356
+ SILInstruction *user = use->getUser ();
357
+
358
+ // Avoid quadratic complexity in corner cases. A limit of 24 is more than
359
+ // enough in most cases.
360
+ if (++numChecks > 24 )
361
+ return true ;
362
+
363
+ switch (user->getKind ()) {
364
+ case SILInstructionKind::DebugValueAddrInst:
365
+ case SILInstructionKind::FixLifetimeInst:
366
+ case SILInstructionKind::LoadInst:
367
+ case SILInstructionKind::StoreInst:
368
+ case SILInstructionKind::CopyAddrInst:
369
+ case SILInstructionKind::DestroyAddrInst:
370
+ case SILInstructionKind::DeallocStackInst:
371
+ // Those instructions have no result and cannot escape the address.
372
+ break ;
373
+ case SILInstructionKind::ApplyInst:
374
+ case SILInstructionKind::TryApplyInst:
375
+ case SILInstructionKind::BeginApplyInst:
376
+ // Apply instructions can not let an address escape either. It's not
377
+ // possible that an address, passed as an indirect parameter, escapes
378
+ // the function in any way (which is not unsafe and undefined behavior).
379
+ break ;
380
+ case SILInstructionKind::OpenExistentialAddrInst:
381
+ case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
382
+ case SILInstructionKind::StructElementAddrInst:
383
+ case SILInstructionKind::TupleElementAddrInst:
384
+ case SILInstructionKind::UncheckedAddrCastInst:
385
+ // Check the uses of address projections.
386
+ if (hasEscapingUses (cast<SingleValueInstruction>(user), numChecks))
387
+ return true ;
388
+ break ;
389
+ case SILInstructionKind::AddressToPointerInst:
390
+ // This is _the_ instruction which can let an address escape.
391
+ return true ;
392
+ default :
393
+ // To be conservative, also bail for anything we don't handle here.
394
+ return true ;
395
+ }
396
+ }
397
+ return false ;
398
+ }
343
399
344
- MemBehavior Behavior = MemBehavior::None;
400
+ MemBehavior MemoryBehaviorVisitor::getApplyBehavior (FullApplySite AS) {
345
401
346
- // We can ignore mayTrap().
347
- bool any_in_guaranteed_params = false ;
348
- for (auto op : enumerate(AI-> getArgumentOperands () )) {
349
- if (op. value () .get () == V &&
350
- AI-> getSubstCalleeConv (). getSILArgumentConvention (op. index ()) == swift::SILArgumentConvention::Indirect_In_Guaranteed) {
351
- any_in_guaranteed_params = true ;
352
- break ;
402
+ // Do a quick check first: if V is directly passed to an in_guaranteed
403
+ // argument, we know that the function cannot write to it.
404
+ for (Operand &argOp : AS. getArgumentOperands ()) {
405
+ if (argOp .get () == V &&
406
+ AS. getArgumentConvention (argOp) ==
407
+ swift::SILArgumentConvention::Indirect_In_Guaranteed) {
408
+ return MemBehavior::MayRead ;
353
409
}
354
410
}
355
411
356
- if (any_in_guaranteed_params) {
357
- // one the parameters in the function call is @in_guaranteed of V, ie. the
358
- // callee isn't allowed to modify it.
359
- Behavior = MemBehavior::MayRead;
360
- } else {
361
- auto &GlobalEffects = ApplyEffects.getGlobalEffects ();
362
- Behavior = GlobalEffects.getMemBehavior (RetainObserveKind::IgnoreRetains);
363
-
364
- // Check all parameter effects.
365
- for (unsigned Idx = 0 , End = AI->getNumArguments ();
366
- Idx < End && Behavior < MemBehavior::MayHaveSideEffects; ++Idx) {
367
- auto &ArgEffect = ApplyEffects.getParameterEffects ()[Idx];
368
- auto ArgBehavior = ArgEffect.getMemBehavior (RetainObserveKind::IgnoreRetains);
369
- if (ArgEffect.mayRelease ()) {
370
- Behavior = MemBehavior::MayHaveSideEffects;
371
- break ;
372
- }
373
- auto NewBehavior = combineMemoryBehavior (Behavior, ArgBehavior);
374
- if (NewBehavior != Behavior) {
375
- SILValue Arg = AI->getArgument (Idx);
376
- // We only consider the argument effects if the argument aliases V.
377
- if (!Arg->getType ().isAddress () || mayAlias (Arg))
378
- Behavior = NewBehavior;
379
- }
412
+ SILValue object = getUnderlyingObject (V);
413
+ int numUsesChecked = 0 ;
414
+
415
+ // For exclusive/local addresses we can do a quick and good check with alias
416
+ // analysis. For everything else we use escape analysis (see below).
417
+ // TODO: The check for not-escaping can probably done easier with the upcoming
418
+ // API of AccessStorage.
419
+ bool nonEscapingAddress =
420
+ (isa<AllocStackInst>(object) || isExclusiveArgument (object)) &&
421
+ !hasEscapingUses (object, numUsesChecked);
422
+
423
+ FunctionSideEffects applyEffects;
424
+ SEA->getCalleeEffects (applyEffects, AS);
425
+
426
+ MemBehavior behavior = MemBehavior::None;
427
+ MemBehavior globalBehavior = applyEffects.getGlobalEffects ().getMemBehavior (
428
+ RetainObserveKind::IgnoreRetains);
429
+
430
+ // If it's a non-escaping address, we don't care about the "global" effects
431
+ // of the called function.
432
+ if (!nonEscapingAddress)
433
+ behavior = globalBehavior;
434
+
435
+ // Check all parameter effects.
436
+ for (unsigned argIdx = 0 , end = AS.getNumArguments ();
437
+ argIdx < end && behavior < MemBehavior::MayHaveSideEffects;
438
+ ++argIdx) {
439
+ SILValue arg = AS.getArgument (argIdx);
440
+
441
+ // In case the argument is not an address, alias analysis will always report
442
+ // a no-alias. Therefore we have to treat non-address arguments
443
+ // conservatively here. For example V could be a ref_element_addr of a
444
+ // reference argument. In this case V clearly "aliases" the argument, but
445
+ // this is not reported by alias analysis.
446
+ if ((!nonEscapingAddress && !arg->getType ().isAddress ()) ||
447
+ mayAlias (arg)) {
448
+ MemBehavior argBehavior = applyEffects.getArgumentBehavior (AS, argIdx);
449
+ behavior = combineMemoryBehavior (behavior, argBehavior);
380
450
}
381
451
}
382
452
383
- if (Behavior > MemBehavior::None) {
384
- if (Behavior > MemBehavior::MayRead && isLetValue ())
385
- Behavior = MemBehavior::MayRead;
453
+ if (behavior > MemBehavior::None) {
454
+ if (behavior > MemBehavior::MayRead && isLetValue ())
455
+ behavior = MemBehavior::MayRead;
386
456
387
457
// Ask escape analysis.
388
- if (!EA->canEscapeTo (V, AI ))
389
- Behavior = MemBehavior::None;
458
+ if (!nonEscapingAddress && ! EA->canEscapeTo (V, AS ))
459
+ behavior = MemBehavior::None;
390
460
}
391
- LLVM_DEBUG (llvm::dbgs () << " Found apply, returning " << Behavior << ' \n ' );
392
- return Behavior;
461
+ LLVM_DEBUG (llvm::dbgs () << " Found apply, returning " << behavior << ' \n ' );
462
+
463
+ return behavior;
393
464
}
394
465
395
466
MemBehavior
0 commit comments