/// <summary> /// Finds the position to inline to. /// </summary> /// <returns>true = found; false = cannot continue search; null = not found</returns> static bool?FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, out ILInstruction loadInst) { loadInst = null; if (expr == null) { return(false); } if (expr.MatchLdLoc(v) || expr.MatchLdLoca(v)) { // Match found, we can inline loadInst = expr; return(true); } else if (expr is Block block && block.Instructions.Count > 0) { // Inlining into inline-blocks? only for some block types, and only into the first instruction. switch (block.Kind) { case BlockKind.ArrayInitializer: case BlockKind.CollectionInitializer: case BlockKind.ObjectInitializer: return(FindLoadInNext(block.Instructions[0], v, expressionBeingMoved, out loadInst) ?? false); // If FindLoadInNext() returns null, we still can't continue searching // because we can't inline over the remainder of the block. default: return(false); } }
bool IsDisplayClassLoad(ILInstruction target, out ILVariable variable) { if (target.MatchLdLoc(out variable) || target.MatchLdLoca(out variable)) { return(true); } return(false); }
private bool IsDisplayClassLoad(ILInstruction target, out ILVariable variable) { // We cannot use MatchLdLocRef here because local functions use ref parameters if (target.MatchLdLoc(out variable) || target.MatchLdLoca(out variable)) { return(true); } return(false); }
/// <summary> /// Finds the position to inline to. /// </summary> /// <returns>true = found; false = cannot continue search; null = not found</returns> static bool?FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, out ILInstruction loadInst) { loadInst = null; if (expr == null) { return(false); } if (expr.MatchLdLoc(v) || expr.MatchLdLoca(v)) { // Match found, we can inline loadInst = expr; return(true); } else if (expr is Block block && block.Instructions.Count > 0) { // Inlining into inline-blocks? only for some block types, and only into the first instruction. switch (block.Type) { case BlockType.ArrayInitializer: case BlockType.CollectionInitializer: case BlockType.ObjectInitializer: return(FindLoadInNext(block.Instructions[0], v, expressionBeingMoved, out loadInst) ?? false); // If FindLoadInNext() returns null, we still can't continue searching // because we can't inline over the remainder of the block. default: return(false); } } foreach (var child in expr.Children) { if (!child.SlotInfo.CanInlineInto) { return(false); } // Recursively try to find the load instruction bool?r = FindLoadInNext(child, v, expressionBeingMoved, out loadInst); if (r != null) { return(r); } } if (IsSafeForInlineOver(expr, expressionBeingMoved)) { return(null); // continue searching } else { return(false); // abort, inlining not possible } }
/// <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, out ILInstruction loadInst) { loadInst = null; if (expr == null) { return(FindResult.Stop); } if (expr.MatchLdLoc(v) || expr.MatchLdLoca(v)) { // Match found, we can inline loadInst = expr; return(FindResult.Found); } 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, out loadInst))); // 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, out loadInst)); 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, out loadInst))); // 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> static bool?FindLoadInNext(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved, out ILInstruction loadInst) { loadInst = null; if (expr == null) { return(false); } if (expr.MatchLdLoc(v) || expr.MatchLdLoca(v)) { // Match found, we can inline loadInst = expr; return(true); } foreach (var child in expr.Children) { if (!child.SlotInfo.CanInlineInto) { return(false); } // Recursively try to find the load instruction bool?r = FindLoadInNext(child, v, expressionBeingMoved, out loadInst); if (r != null) { return(r); } } if (IsSafeForInlineOver(expr, expressionBeingMoved)) { return(null); // continue searching } else { return(false); // abort, inlining not possible } }
/// <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 } }