@@ -172,6 +172,10 @@ class MemoryBehaviorVisitor
172172 MemBehavior visitCopyAddrInst (CopyAddrInst *CAI);
173173 MemBehavior visitApplyInst (ApplyInst *AI);
174174 MemBehavior visitTryApplyInst (TryApplyInst *AI);
175+ MemBehavior visitBeginApplyInst (BeginApplyInst *AI);
176+ MemBehavior visitEndApplyInst (EndApplyInst *EAI);
177+ MemBehavior visitAbortApplyInst (AbortApplyInst *AAI);
178+ MemBehavior getApplyBehavior (FullApplySite AS);
175179 MemBehavior visitBuiltinInst (BuiltinInst *BI);
176180 MemBehavior visitStrongReleaseInst (StrongReleaseInst *BI);
177181 MemBehavior visitReleaseValueInst (ReleaseValueInst *BI);
@@ -326,70 +330,137 @@ MemBehavior MemoryBehaviorVisitor::visitBuiltinInst(BuiltinInst *BI) {
326330}
327331
328332MemBehavior 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);
337334}
338335
339336MemBehavior MemoryBehaviorVisitor::visitApplyInst (ApplyInst *AI) {
337+ return getApplyBehavior (AI);
338+ }
340339
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+ }
343399
344- MemBehavior Behavior = MemBehavior::None;
400+ MemBehavior MemoryBehaviorVisitor::getApplyBehavior (FullApplySite AS) {
345401
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 ;
353409 }
354410 }
355411
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);
380450 }
381451 }
382452
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;
386456
387457 // Ask escape analysis.
388- if (!EA->canEscapeTo (V, AI ))
389- Behavior = MemBehavior::None;
458+ if (!nonEscapingAddress && ! EA->canEscapeTo (V, AS ))
459+ behavior = MemBehavior::None;
390460 }
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;
393464}
394465
395466MemBehavior
0 commit comments