Exemplo n.º 1
0
        /// <summary>
        /// stloc v(value)
        /// expr(..., deconstruct { ... }, ...)
        /// =>
        /// expr(..., deconstruct { init: stloc v(value) ... }, ...)
        /// </summary>
        bool InlineDeconstructionInitializer(Block block, int pos)
        {
            if (!block.Instructions[pos].MatchStLoc(out var v, out var value))
            {
                return(false);
            }
            if (!(v.IsSingleDefinition && v.LoadCount == 1))
            {
                return(false);
            }
            if (pos + 1 >= block.Instructions.Count)
            {
                return(false);
            }
            var result = ILInlining.FindLoadInNext(block.Instructions[pos + 1], v, value, InliningOptions.FindDeconstruction);

            if (result.Type != ILInlining.FindResultType.Deconstruction)
            {
                return(false);
            }
            var   deconstruction = (DeconstructInstruction)result.LoadInst;
            LdLoc loadInst       = v.LoadInstructions[0];

            if (!loadInst.IsDescendantOf(deconstruction.Assignments))
            {
                return(false);
            }
            if (loadInst.SlotInfo == StObj.TargetSlot)
            {
                if (value.OpCode == OpCode.LdFlda || value.OpCode == OpCode.LdElema)
                {
                    return(false);
                }
            }
            if (deconstruction.Init.Count > 0)
            {
                var a = deconstruction.Init[0].Variable.LoadInstructions.Single();
                var b = v.LoadInstructions.Single();
                if (!b.IsBefore(a))
                {
                    return(false);
                }
            }
            context.Step("InlineDeconstructionInitializer", block.Instructions[pos]);
            deconstruction.Init.Insert(0, (StLoc)block.Instructions[pos]);
            block.Instructions.RemoveAt(pos);
            v.Kind = VariableKind.DeconstructionInitTemporary;
            return(true);
        }
Exemplo n.º 2
0
        internal static FindResult CanExtendNamedArgument(Block block, ILVariable v, ILInstruction expressionBeingMoved, out ILInstruction loadInst)
        {
            Debug.Assert(block.Kind == BlockKind.CallWithNamedArgs);
            var firstArg = ((StLoc)block.Instructions[0]).Value;
            var r        = ILInlining.FindLoadInNext(firstArg, v, expressionBeingMoved, out loadInst);

            if (r == FindResult.Found || r == FindResult.NamedArgument)
            {
                return(r);                // OK, inline into first instruction of block
            }
            var call = (CallInstruction)block.FinalInstruction;

            if (call.IsInstanceCall)
            {
                // For instance calls, block.Instructions[0] is the argument
                // for the 'this' pointer. We can only insert at position 1.
                if (r == FindResult.Stop)
                {
                    // error: can't move expressionBeingMoved after block.Instructions[0]
                    return(FindResult.Stop);
                }
                // Because we always ensure block.Instructions[0] is the 'this' argument,
                // it's possible that the place we actually need to inline into
                // is within block.Instructions[1]:
                if (block.Instructions.Count > 1)
                {
                    r = ILInlining.FindLoadInNext(block.Instructions[1], v, expressionBeingMoved, out loadInst);
                    if (r == FindResult.Found || r == FindResult.NamedArgument)
                    {
                        return(r);                        // OK, inline into block.Instructions[1]
                    }
                }
            }
            foreach (var arg in call.Arguments)
            {
                if (arg.MatchLdLoc(v))
                {
                    loadInst = arg;
                    return(FindResult.NamedArgument);
                }
            }
            return(FindResult.Stop);
        }
Exemplo n.º 3
0
 internal static FindResult CanIntroduceNamedArgument(CallInstruction call, ILInstruction child, ILVariable v, ILInstruction expressionBeingMoved)
 {
     Debug.Assert(child.Parent == call);
     if (call.IsInstanceCall && child.ChildIndex == 0)
     {
         return(FindResult.Stop);                // cannot use named arg to move expressionBeingMoved before this pointer
     }
     if (call.Method.IsOperator || call.Method.IsAccessor)
     {
         return(FindResult.Stop);                // cannot use named arg for operators or accessors
     }
     if (call.Method is VarArgInstanceMethod)
     {
         return(FindResult.Stop);                // CallBuilder doesn't support named args when using varargs
     }
     if (call.Method.IsConstructor)
     {
         IType type = call.Method.DeclaringType;
         if (type.Kind == TypeKind.Delegate || type.IsAnonymousType())
         {
             return(FindResult.Stop);
         }
     }
     if (call.Method.Parameters.Any(p => string.IsNullOrEmpty(p.Name)))
     {
         return(FindResult.Stop);                // cannot use named arguments
     }
     for (int i = child.ChildIndex; i < call.Arguments.Count; i++)
     {
         var r = ILInlining.FindLoadInNext(call.Arguments[i], v, expressionBeingMoved, InliningOptions.None);
         if (r.Type == FindResultType.Found)
         {
             return(FindResult.NamedArgument(r.LoadInst, call.Arguments[i]));
         }
     }
     return(FindResult.Stop);
 }
Exemplo n.º 4
0
        /// <summary>
        /// stloc v(value)
        /// if (logic.not(call get_HasValue(ldloca v))) throw(...)
        /// ... Call(arg1, arg2, call GetValueOrDefault(ldloca v), arg4) ...
        /// =>
        /// ... Call(arg1, arg2, if.notnull(value, throw(...)), arg4) ...
        /// </summary>
        bool TransformThrowExpressionValueTypes(Block block, int pos, StatementTransformContext context)
        {
            if (pos + 2 >= block.Instructions.Count)
            {
                return(false);
            }
            if (!(block.Instructions[pos] is StLoc stloc))
            {
                return(false);
            }
            ILVariable v = stloc.Variable;

            if (!(v.StoreCount == 1 && v.LoadCount == 0 && v.AddressCount == 2))
            {
                return(false);
            }
            if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst))
            {
                return(false);
            }
            if (!(Block.Unwrap(trueInst) is Throw throwInst))
            {
                return(false);
            }
            if (!condition.MatchLogicNot(out var arg))
            {
                return(false);
            }
            if (!(arg is CallInstruction call && NullableLiftingTransform.MatchHasValueCall(call, v)))
            {
                return(false);
            }
            var throwInstParent         = throwInst.Parent;
            var throwInstChildIndex     = throwInst.ChildIndex;
            var nullCoalescingWithThrow = new NullCoalescingInstruction(
                NullCoalescingKind.NullableWithValueFallback,
                stloc.Value,
                throwInst);
            var resultType = NullableType.GetUnderlyingType(call.Method.DeclaringType).GetStackType();

            nullCoalescingWithThrow.UnderlyingResultType = resultType;
            var result = ILInlining.FindLoadInNext(block.Instructions[pos + 2], v, nullCoalescingWithThrow, InliningOptions.None);

            if (result.Type == ILInlining.FindResultType.Found &&
                NullableLiftingTransform.MatchGetValueOrDefault(result.LoadInst.Parent, v))
            {
                context.Step("NullCoalescingTransform (value types + throw expression)", stloc);
                throwInst.resultType = resultType;
                result.LoadInst.Parent.ReplaceWith(nullCoalescingWithThrow);
                block.Instructions.RemoveRange(pos, 2);                 // remove store(s) and if instruction
                return(true);
            }
            else
            {
                // reset the primary position (see remarks on ILInstruction.Parent)
                stloc.Value = stloc.Value;
                var children = throwInstParent.Children;
                children[throwInstChildIndex] = throwInst;
                return(false);
            }
        }