public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { WriteILRange(output, options); output.Write(OpCode); output.Write("." + BinaryNumericInstruction.GetOperatorName(Operator)); if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue) { output.Write(".new"); } else { output.Write(".old"); } if (CheckForOverflow) { output.Write(".ovf"); } if (Sign == Sign.Unsigned) { output.Write(".unsigned"); } else if (Sign == Sign.Signed) { output.Write(".signed"); } output.Write('('); Target.WriteTo(output, options); output.Write(", "); Value.WriteTo(output, options); output.Write(')'); }
public NumericCompoundAssign(BinaryNumericInstruction binary, ILInstruction target, ILInstruction value, IType type, CompoundAssignmentType compoundAssignmentType) : base(OpCode.NumericCompoundAssign, compoundAssignmentType, target, value) { Debug.Assert(IsBinaryCompatibleWithType(binary, type)); this.CheckForOverflow = binary.CheckForOverflow; this.Sign = binary.Sign; this.LeftInputType = binary.LeftInputType; this.RightInputType = binary.RightInputType; this.UnderlyingResultType = binary.UnderlyingResultType; this.Operator = binary.Operator; this.IsLifted = binary.IsLifted; this.type = type; this.AddILRange(binary); Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub)); Debug.Assert(IsValidCompoundAssignmentTarget(Target)); }
/// <summary> /// Gets whether the specific binary instruction is compatible with a compound operation on the specified type. /// </summary> internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type) { if (binary.IsLifted) { if (!NullableType.IsNullable(type)) { return(false); } type = NullableType.GetUnderlyingType(type); } if (type.Kind == TypeKind.Unknown) { return(false); // avoid introducing a potentially-incorrect compound assignment } else if (type.Kind == TypeKind.Enum) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitOr: case BinaryNumericOperator.BitXor: break; // OK default: return(false); // operator not supported on enum types } } else if (type.Kind == TypeKind.Pointer) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: // ensure that the byte offset is a multiple of the pointer size return(PointerArithmeticOffset.Detect( binary.Right, ((PointerType)type).ElementType, checkForOverflow: binary.CheckForOverflow ) != null); default: return(false); // operator not supported on pointer types } } if (binary.Sign != Sign.None) { if (type.IsCSharpSmallIntegerType()) { // C# will use numeric promotion to int, binary op must be signed if (binary.Sign != Sign.Signed) { return(false); } } else { // C# will use sign from type if (type.GetSign() != binary.Sign) { return(false); } } } // Can't transform if the RHS value would be need to be truncated for the LHS type. if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, null, binary.IsLifted)) { return(false); } return(true); }