protected internal override void VisitStObj(StObj inst)
            {
                base.VisitStObj(inst);
                ILInstruction target;
                IField        field;

                if (!inst.Target.MatchLdFlda(out target, out field) || !MatchesTargetOrCopyLoad(target))
                {
                    return;
                }
                field = (IField)field.MemberDefinition;
                DisplayClassVariable info;
                ILInstruction        value;

                if (initValues.TryGetValue(field, out info))
                {
                    inst.ReplaceWith(new StLoc(info.variable, inst.Value));
                }
                else
                {
                    if (inst.Value.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter)
                    {
                        // special case for parameters: remove copies of parameter values.
                        orphanedVariableInits.Add(inst);
                        value = inst.Value;
                    }
Esempio n. 2
0
 protected internal override void VisitStObj(StObj inst)
 {
     base.VisitStObj(inst);
     // This instruction has been marked deletable, do not transform it further
     if (instructionsToRemove.Contains(inst))
     {
         return;
     }
     // The target of the store instruction must be a field reference
     if (!inst.Target.MatchLdFlda(out ILInstruction target, out IField field))
     {
         return;
     }
     // Get display class info
     if (!(target is LdLoc displayClassLoad && displayClasses.TryGetValue(displayClassLoad.Variable, out var displayClass)))
     {
         return;
     }
     field = (IField)field.MemberDefinition;
     if (displayClass.Variables.TryGetValue(field, out DisplayClassVariable info))
     {
         // If the display class field was previously initialized, we use a simple assignment.
         inst.ReplaceWith(new StLoc(info.Variable, inst.Value).WithILRange(inst));
     }
     else
     {
         // This is an uninitialized variable:
         ILInstruction value;
         if (inst.Value.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter && currentFunction == v.Function)
         {
             // Special case for parameters: remove copies of parameter values.
             instructionsToRemove.Add(inst);
             value = inst.Value;
         }
Esempio n. 3
0
 private bool IsParameterAssignment(StObj inst, out DisplayClass displayClass, out IField field, out ILVariable parameter)
 {
     parameter = null;
     if (!IsDisplayClassFieldAccess(inst.Target, out var displayClassVar, out displayClass, out field))
     {
         return(false);
     }
     if (fieldAssignmentsWithVariableValue[field].Count != 1)
     {
         return(false);
     }
     if (!(inst.Value.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter && v.Function == currentFunction && v.Type.Equals(field.Type)))
     {
         return(false);
     }
     if (displayClass.Variables.ContainsKey((IField)field.MemberDefinition))
     {
         return(false);
     }
     if (displayClassVar.Function != currentFunction)
     {
         return(false);
     }
     parameter = v;
     return(true);
 }
        /// <code>
        /// stloc s(value)
        /// stloc l(ldloc s)
        /// stobj(..., ldloc s)
        /// -->
        /// stloc l(stobj (..., value))
        /// </code>
        /// -or-
        /// <code>
        /// stloc s(value)
        /// stobj (..., ldloc s)
        /// -->
        /// stloc s(stobj (..., value))
        /// </code>
        bool TransformInlineAssignmentStObj(Block block, int i)
        {
            var inst = block.Instructions[i] as StLoc;

            // in some cases it can be a compiler-generated local
            if (inst == null || (inst.Variable.Kind != VariableKind.StackSlot && inst.Variable.Kind != VariableKind.Local))
            {
                return(false);
            }
            var           nextInst = block.Instructions.ElementAtOrDefault(i + 1);
            ILInstruction replacement;
            StObj         fieldStore;
            ILVariable    local;

            if (nextInst is StLoc)               // instance fields
            {
                var localStore = (StLoc)nextInst;
                if (localStore.Variable.Kind == VariableKind.StackSlot || !localStore.Value.MatchLdLoc(inst.Variable))
                {
                    return(false);
                }
                var memberStore = block.Instructions.ElementAtOrDefault(i + 2);
                if (memberStore is StObj)
                {
                    fieldStore = memberStore as StObj;
                    if (!fieldStore.Value.MatchLdLoc(inst.Variable))
                    {
                        return(false);
                    }
                    replacement = new StObj(fieldStore.Target, inst.Value, fieldStore.Type);
                }
                else                     // otherwise it must be local
                {
                    TransformInlineAssignmentLocal(block, i);
                    return(false);
                }
                context.Step("Inline assignment to instance field", fieldStore);
                local = localStore.Variable;
                block.Instructions.RemoveAt(i + 1);
            }
            else if (nextInst is StObj)                 // static fields
            {
                fieldStore = (StObj)nextInst;
                if (!fieldStore.Value.MatchLdLoc(inst.Variable))
                {
                    return(false);
                }
                context.Step("Inline assignment to static field", fieldStore);
                local       = inst.Variable;
                replacement = new StObj(fieldStore.Target, inst.Value, fieldStore.Type);
            }
            else
            {
                return(false);
            }
            block.Instructions.RemoveAt(i + 1);
            inst.ReplaceWith(new StLoc(local, replacement));
            return(true);
        }
 VariableToDeclare AddVariable(DisplayClass result, StObj statement, IField field)
 {
     VariableToDeclare variable = new VariableToDeclare(result, field);
     if (statement != null) {
         variable.Propagate(ResolveVariableToPropagate(statement.Value, field.Type));
         variable.Initializers.Add(statement);
     }
     return variable;
 }
Esempio n. 6
0
 protected internal override void VisitStObj(StObj inst)
 {
     inst.Value.AcceptVisitor(this);
     if (IsParameterAssignment(inst, out var displayClass, out var field, out var parameter))
     {
         context.Step($"Detected parameter assignment {parameter.Name}", inst);
         displayClass.Variables.Add(field, parameter);
         instructionsToRemove.Add(inst);
     }
Esempio n. 7
0
 protected internal override void VisitStObj(StObj inst)
 {
     base.VisitStObj(inst);
     if (EarlyExpressionTransforms.StObjToStLoc(inst, context))
     {
         context.RequestRerun();
         return;
     }
     TransformAssignment.HandleCompoundAssign(inst, context);
 }
Esempio n. 8
0
 // This transform is required because ILInlining only works with stloc/ldloc
 internal static bool StObjToStLoc(StObj inst, ILTransformContext context)
 {
     if (inst.Target.MatchLdLoca(out ILVariable v) &&
         TypeUtils.IsCompatibleTypeForMemoryAccess(v.Type, inst.Type) &&
         inst.UnalignedPrefix == 0 &&
         !inst.IsVolatile)
     {
         context.Step($"stobj(ldloca {v.Name}, ...) => stloc {v.Name}(...)", inst);
         inst.ReplaceWith(new StLoc(v, inst.Value).WithILRange(inst));
         return(true);
     }
     return(false);
 }
 protected internal override void VisitStObj(StObj inst)
 {
     if (IsDisplayClassFieldAccess(inst.Target, out var v, out var displayClass, out var field)) {
         VariableToDeclare vd = displayClass.VariablesToDeclare[(IField)field.MemberDefinition];
         if (vd.CanPropagate && vd.Initializers.Contains(inst)) {
             if (inst.Parent is Block containingBlock) {
                 context.Step($"Remove initializer of {v.Name}.{vd.Name} due to propagation", inst);
                 containingBlock.Instructions.Remove(inst);
                 return;
             }
         }
     }
     base.VisitStObj(inst);
     EarlyExpressionTransforms.StObjToStLoc(inst, context);
 }
Esempio n. 10
0
 internal static ILInstruction HandleCall(Call inst, ILTransformContext context)
 {
     if (inst.Method.IsConstructor && !inst.Method.IsStatic && inst.Method.DeclaringType.Kind == TypeKind.Struct)
     {
         Debug.Assert(inst.Arguments.Count == inst.Method.Parameters.Count + 1);
         context.Step("Transform call to struct constructor", inst);
         // call(ref, ...)
         // => stobj(ref, newobj(...))
         var newObj = new NewObj(inst.Method);
         newObj.ILRange = inst.ILRange;
         newObj.Arguments.AddRange(inst.Arguments.Skip(1));
         var expr = new StObj(inst.Arguments[0], newObj, inst.Method.DeclaringType);
         inst.ReplaceWith(expr);
         return(expr);
     }
     return(null);
 }
Esempio n. 11
0
        // This transform is required because ILInlining only works with stloc/ldloc
        protected internal override void VisitStObj(StObj inst)
        {
            base.VisitStObj(inst);
            if (StObjToStLoc(inst, context))
            {
                return;
            }

            if (inst.Value is BinaryNumericInstruction binary &&
                binary.Left.MatchLdObj(out ILInstruction target, out IType t) &&
                inst.Target.Match(target).Success)
            {
                context.Step("compound assignment", inst);
                // stobj(target, binary.op(ldobj(target), ...))
                // => compound.op(target, ...)
                inst.ReplaceWith(new CompoundAssignmentInstruction(binary.Operator, binary.Left, binary.Right, t, binary.CheckForOverflow, binary.Sign, CompoundAssignmentType.EvaluatesToNewValue));
            }
        }
Esempio n. 12
0
 private bool IsDisplayClassAssignment(StObj inst, out DisplayClass displayClass, out IField field, out ILVariable variable)
 {
     variable = null;
     if (!IsDisplayClassFieldAccess(inst.Target, out var displayClassVar, out displayClass, out field))
     {
         return(false);
     }
     if (!(inst.Value.MatchLdLoc(out var v) && displayClasses.ContainsKey(v)))
     {
         return(false);
     }
     if (displayClassVar.Function != currentFunction)
     {
         return(false);
     }
     variable = v;
     return(true);
 }
Esempio n. 13
0
        /// <summary>
        /// stobj(target, binary.op(ldobj(target), ...))
        ///   where target is pure
        /// => compound.op(target, ...)
        /// </summary>
        /// <remarks>
        /// Called by ExpressionTransforms.
        /// </remarks>
        internal static bool HandleStObjCompoundAssign(StObj inst, ILTransformContext context)
        {
            if (!(UnwrapSmallIntegerConv(inst.Value, out var conv) is BinaryNumericInstruction binary))
            {
                return(false);
            }
            if (!(binary.Left is LdObj ldobj))
            {
                return(false);
            }
            if (!inst.Target.Match(ldobj.Target).Success)
            {
                return(false);
            }
            if (!SemanticHelper.IsPure(ldobj.Target.Flags))
            {
                return(false);
            }
            // ldobj.Type may just be 'int' (due to ldind.i4) when we're actually operating on a 'ref MyEnum'.
            // Try to determine the real type of the object we're modifying:
            IType targetType = ldobj.Target.InferType();

            if (targetType.Kind == TypeKind.Pointer || targetType.Kind == TypeKind.ByReference)
            {
                targetType = ((TypeWithElementType)targetType).ElementType;
                if (targetType.Kind == TypeKind.Unknown || targetType.GetSize() != ldobj.Type.GetSize())
                {
                    targetType = ldobj.Type;
                }
            }
            else
            {
                targetType = ldobj.Type;
            }
            if (!ValidateCompoundAssign(binary, conv, targetType))
            {
                return(false);
            }
            context.Step("compound assignment", inst);
            inst.ReplaceWith(new CompoundAssignmentInstruction(
                                 binary, binary.Left, binary.Right,
                                 targetType, CompoundAssignmentType.EvaluatesToNewValue));
            return(true);
        }
Esempio n. 14
0
 // This transform is required because ILInlining only works with stloc/ldloc
 internal static bool StObjToStLoc(StObj inst, ILTransformContext context)
 {
     if (inst.Target.MatchLdLoca(out ILVariable v) &&
         TypeUtils.IsCompatibleTypeForMemoryAccess(v.Type, inst.Type) &&
         inst.UnalignedPrefix == 0 &&
         !inst.IsVolatile)
     {
         context.Step($"stobj(ldloca {v.Name}, ...) => stloc {v.Name}(...)", inst);
         ILInstruction replacement = new StLoc(v, inst.Value).WithILRange(inst);
         if (v.StackType == StackType.Unknown && inst.Type.Kind != TypeKind.Unknown &&
             inst.SlotInfo != Block.InstructionSlot)
         {
             replacement = new Conv(replacement, inst.Type.ToPrimitiveType(),
                                    checkForOverflow: false, Sign.None);
         }
         inst.ReplaceWith(replacement);
         return(true);
     }
     return(false);
 }
Esempio n. 15
0
 protected internal override void VisitCall(Call inst)
 {
     if (inst.Method.IsConstructor && !inst.Method.IsStatic && inst.Method.DeclaringType.Kind == TypeKind.Struct)
     {
         Debug.Assert(inst.Arguments.Count == inst.Method.Parameters.Count + 1);
         context.Step("Transform call to struct constructor", inst);
         // call(ref, ...)
         // => stobj(ref, newobj(...))
         var newObj = new NewObj(inst.Method);
         newObj.ILRange = inst.ILRange;
         newObj.Arguments.AddRange(inst.Arguments.Skip(1));
         var expr = new StObj(inst.Arguments[0], newObj, inst.Method.DeclaringType);
         inst.ReplaceWith(expr);
         // Both the StObj and the NewObj may trigger further rules, so continue visiting the replacement:
         VisitStObj(expr);
     }
     else
     {
         base.VisitCall(inst);
     }
 }
Esempio n. 16
0
        protected internal override void VisitStObj(StObj inst)
        {
            base.VisitStObj(inst);
            if (EarlyExpressionTransforms.StObjToStLoc(inst, context))
            {
                context.RequestRerun();
                return;
            }

            if (inst.Value is BinaryNumericInstruction binary &&
                binary.Left.MatchLdObj(out ILInstruction target, out IType t) &&
                inst.Target.Match(target).Success &&
                SemanticHelper.IsPure(target.Flags) &&
                CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, t))
            {
                context.Step("compound assignment", inst);
                // stobj(target, binary.op(ldobj(target), ...))
                // => compound.op(target, ...)
                inst.ReplaceWith(new CompoundAssignmentInstruction(
                                     binary, binary.Left, binary.Right,
                                     t, CompoundAssignmentType.EvaluatesToNewValue));
            }
        }
Esempio n. 17
0
 protected internal override void VisitStObj(StObj inst)
 {
     inst.Value.AcceptVisitor(this);
     if (inst.Parent is Block)
     {
         if (IsParameterAssignment(inst, out var displayClass, out var field, out var parameter))
         {
             context.Step($"Detected parameter assignment {parameter.Name}", inst);
             displayClass.Variables.Add((IField)field.MemberDefinition, parameter);
             instructionsToRemove.Add(inst);
             return;
         }
         if (IsDisplayClassAssignment(inst, out displayClass, out field, out var variable))
         {
             context.Step($"Detected display-class assignment {variable.Name}", inst);
             displayClass.Variables.Add((IField)field.MemberDefinition, variable);
             instructionsToRemove.Add(inst);
             return;
         }
     }
     inst.Target.AcceptVisitor(this);
     EarlyExpressionTransforms.StObjToStLoc(inst, context);
 }
 protected internal override void VisitStObj(StObj inst)
 {
     base.VisitStObj(inst);
     StObjToStLoc(inst, context);
 }