/// <summary> /// Finds the position to inline to. /// </summary> /// <returns>true = found; false = cannot continue search; null = not found</returns> internal static FindResult FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, InliningOptions options) { if (expr == null) { return(FindResult.Stop); } if (expr.MatchLdLoc(v) || expr.MatchLdLoca(v)) { // Match found, we can inline if (expr.SlotInfo == StObj.TargetSlot && !((StObj)expr.Parent).CanInlineIntoTargetSlot(expressionBeingMoved)) { // special case: the StObj.TargetSlot does not accept some kinds of expressions return(FindResult.Stop); } return(FindResult.Found(expr)); } else if (expr is Block block) { // Inlining into inline-blocks? switch (block.Kind) { case BlockKind.ArrayInitializer: case BlockKind.CollectionInitializer: case BlockKind.ObjectInitializer: case BlockKind.CallInlineAssign: // Allow inlining into the first instruction of the block if (block.Instructions.Count == 0) { return(FindResult.Stop); } return(NoContinue(FindLoadInNext(block.Instructions[0], v, expressionBeingMoved, options))); // If FindLoadInNext() returns null, we still can't continue searching // because we can't inline over the remainder of the block. case BlockKind.CallWithNamedArgs: return(NamedArgumentTransform.CanExtendNamedArgument(block, v, expressionBeingMoved)); default: return(FindResult.Stop); } } else if (expr is BlockContainer container && container.EntryPoint.IncomingEdgeCount == 1) { // Possibly a switch-container, allow inlining into the switch instruction: return(NoContinue(FindLoadInNext(container.EntryPoint.Instructions[0], v, expressionBeingMoved, options))); // If FindLoadInNext() returns null, we still can't continue searching // because we can't inline over the remainder of the blockcontainer. }
/// <summary> /// Finds the position to inline to. /// </summary> /// <returns>true = found; false = cannot continue search; null = not found</returns> internal static FindResult FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, InliningOptions options) { if (expr == null) { return(FindResult.Stop); } if (expr.MatchLdLoc(v) || expr.MatchLdLoca(v)) { // Match found, we can inline if (expr.SlotInfo == StObj.TargetSlot && !((StObj)expr.Parent).CanInlineIntoTargetSlot(expressionBeingMoved)) { if ((options & InliningOptions.AllowChangingOrderOfEvaluationForExceptions) != 0) { // Intentionally change code semantics so that we can avoid a ref local if (expressionBeingMoved is LdFlda ldflda) { ldflda.DelayExceptions = true; } else if (expressionBeingMoved is LdElema ldelema) { ldelema.DelayExceptions = true; } } else { // special case: the StObj.TargetSlot does not accept some kinds of expressions return(FindResult.Stop); } } return(FindResult.Found(expr)); } else if (expr is Block block) { // Inlining into inline-blocks? switch (block.Kind) { case BlockKind.ControlFlow when block.Parent is BlockContainer: case BlockKind.ArrayInitializer: case BlockKind.CollectionInitializer: case BlockKind.ObjectInitializer: case BlockKind.CallInlineAssign: // Allow inlining into the first instruction of the block if (block.Instructions.Count == 0) { return(FindResult.Stop); } return(NoContinue(FindLoadInNext(block.Instructions[0], v, expressionBeingMoved, options))); // If FindLoadInNext() returns null, we still can't continue searching // because we can't inline over the remainder of the block. case BlockKind.CallWithNamedArgs: return(NamedArgumentTransform.CanExtendNamedArgument(block, v, expressionBeingMoved)); default: return(FindResult.Stop); } } else if (options.HasFlag(InliningOptions.FindDeconstruction) && expr is DeconstructInstruction di) { return(FindResult.Deconstruction(di)); } foreach (var child in expr.Children) { if (!expr.CanInlineIntoSlot(child.ChildIndex, expressionBeingMoved)) { return(FindResult.Stop); } // Recursively try to find the load instruction FindResult r = FindLoadInNext(child, v, expressionBeingMoved, options); if (r.Type != FindResultType.Continue) { if (r.Type == FindResultType.Stop && (options & InliningOptions.IntroduceNamedArguments) != 0 && expr is CallInstruction call) { return(NamedArgumentTransform.CanIntroduceNamedArgument(call, child, v, expressionBeingMoved)); } return(r); } } if (IsSafeForInlineOver(expr, expressionBeingMoved)) { return(FindResult.Continue); // continue searching } else { return(FindResult.Stop); // abort, inlining not possible } }