mirror of https://github.com/icsharpcode/ILSpy.git
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							223 lines
						
					
					
						
							7.1 KiB
						
					
					
				
			
		
		
	
	
							223 lines
						
					
					
						
							7.1 KiB
						
					
					
				// Copyright (c) 2014 Daniel Grunwald | 
						|
//  | 
						|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this | 
						|
// software and associated documentation files (the "Software"), to deal in the Software | 
						|
// without restriction, including without limitation the rights to use, copy, modify, merge, | 
						|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | 
						|
// to whom the Software is furnished to do so, subject to the following conditions: | 
						|
//  | 
						|
// The above copyright notice and this permission notice shall be included in all copies or | 
						|
// substantial portions of the Software. | 
						|
//  | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | 
						|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | 
						|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | 
						|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | 
						|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
						|
// DEALINGS IN THE SOFTWARE. | 
						|
 | 
						|
using System; | 
						|
using System.Diagnostics; | 
						|
using ICSharpCode.Decompiler.CSharp.Syntax; | 
						|
using ICSharpCode.Decompiler.TypeSystem; | 
						|
using ICSharpCode.Decompiler.Util; | 
						|
 | 
						|
namespace ICSharpCode.Decompiler.IL | 
						|
{ | 
						|
	public enum ComparisonKind : byte | 
						|
	{ | 
						|
		Equality, | 
						|
		Inequality, | 
						|
		LessThan, | 
						|
		LessThanOrEqual, | 
						|
		GreaterThan, | 
						|
		GreaterThanOrEqual | 
						|
	} | 
						|
	 | 
						|
	static class ComparisonKindExtensions | 
						|
	{ | 
						|
		public static bool IsEqualityOrInequality(this ComparisonKind kind) | 
						|
		{ | 
						|
			return kind == ComparisonKind.Equality || kind == ComparisonKind.Inequality; | 
						|
		} | 
						|
		 | 
						|
		public static ComparisonKind Negate(this ComparisonKind kind) | 
						|
		{ | 
						|
			switch (kind) { | 
						|
				case ComparisonKind.Equality: | 
						|
					return ComparisonKind.Inequality; | 
						|
				case ComparisonKind.Inequality: | 
						|
					return ComparisonKind.Equality; | 
						|
				case ComparisonKind.LessThan: | 
						|
					return ComparisonKind.GreaterThanOrEqual; | 
						|
				case ComparisonKind.LessThanOrEqual: | 
						|
					return ComparisonKind.GreaterThan; | 
						|
				case ComparisonKind.GreaterThan: | 
						|
					return ComparisonKind.LessThanOrEqual; | 
						|
				case ComparisonKind.GreaterThanOrEqual: | 
						|
					return ComparisonKind.LessThan; | 
						|
				default: | 
						|
					throw new NotSupportedException(); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		public static BinaryOperatorType ToBinaryOperatorType(this ComparisonKind kind) | 
						|
		{ | 
						|
			switch (kind) { | 
						|
				case ComparisonKind.Equality: | 
						|
					return BinaryOperatorType.Equality; | 
						|
				case ComparisonKind.Inequality: | 
						|
					return BinaryOperatorType.InEquality; | 
						|
				case ComparisonKind.LessThan: | 
						|
					return BinaryOperatorType.LessThan; | 
						|
				case ComparisonKind.LessThanOrEqual: | 
						|
					return BinaryOperatorType.LessThanOrEqual; | 
						|
				case ComparisonKind.GreaterThan: | 
						|
					return BinaryOperatorType.GreaterThan; | 
						|
				case ComparisonKind.GreaterThanOrEqual: | 
						|
					return BinaryOperatorType.GreaterThanOrEqual; | 
						|
				default: | 
						|
					throw new NotSupportedException(); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		public static string GetToken(this ComparisonKind kind) | 
						|
		{ | 
						|
			return BinaryOperatorExpression.GetOperatorRole(kind.ToBinaryOperatorType()).Token; | 
						|
		} | 
						|
	} | 
						|
	 | 
						|
	public enum ComparisonLiftingKind | 
						|
	{ | 
						|
		/// <summary> | 
						|
		/// Not a lifted comparison. | 
						|
		/// </summary> | 
						|
		None, | 
						|
		/// <summary> | 
						|
		/// C#-style lifted comparison: | 
						|
		/// * operands that have a ResultType != this.InputType are expected to return a value of | 
						|
		///   type Nullable{T}, where T.GetStackType() == this.InputType. | 
						|
		/// * if both operands are <c>null</c>, equality comparisons evaluate to 1, all other comparisons to 0. | 
						|
		/// * if one operand is <c>null</c>, inequality comparisons evaluate to 1, all other comparisons to 0. | 
						|
		/// * if neither operand is <c>null</c>, the underlying comparison is performed. | 
						|
		///  | 
						|
		/// Note that even though C#-style lifted comparisons set IsLifted=true, | 
						|
		/// the ResultType remains I4 as with normal comparisons. | 
						|
		/// </summary> | 
						|
		CSharp, | 
						|
		/// <summary> | 
						|
		/// SQL-style lifted comparison: works like a lifted binary numeric instruction, | 
						|
		/// that is, if any input operand is <c>null</c>, the comparison evaluates to <c>null</c>. | 
						|
		/// </summary> | 
						|
		/// <remarks> | 
						|
		/// This lifting kind is currently only used for operator! on bool?. | 
						|
		/// </remarks> | 
						|
		ThreeValuedLogic | 
						|
	} | 
						|
 | 
						|
	partial class Comp : ILiftableInstruction | 
						|
	{ | 
						|
		ComparisonKind kind; | 
						|
 | 
						|
		public ComparisonKind Kind { | 
						|
			get { return kind; } | 
						|
			set { | 
						|
				kind = value; | 
						|
				MakeDirty(); | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		public readonly ComparisonLiftingKind LiftingKind; | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets the stack type of the comparison inputs. | 
						|
		/// For lifted comparisons, this is the underlying input type. | 
						|
		/// </summary> | 
						|
		public StackType InputType; | 
						|
 | 
						|
		/// <summary> | 
						|
		/// If this is an integer comparison, specifies the sign used to interpret the integers. | 
						|
		/// </summary> | 
						|
		public readonly Sign Sign; | 
						|
 | 
						|
		public Comp(ComparisonKind kind, Sign sign, ILInstruction left, ILInstruction right) : base(OpCode.Comp, left, right) | 
						|
		{ | 
						|
			this.kind = kind; | 
						|
			this.LiftingKind = ComparisonLiftingKind.None; | 
						|
			this.InputType = left.ResultType; | 
						|
			this.Sign = sign; | 
						|
			Debug.Assert(left.ResultType == right.ResultType); | 
						|
		} | 
						|
 | 
						|
		public Comp(ComparisonKind kind, ComparisonLiftingKind lifting, StackType inputType, Sign sign, ILInstruction left, ILInstruction right) : base(OpCode.Comp, left, right) | 
						|
		{ | 
						|
			this.kind = kind; | 
						|
			this.LiftingKind = lifting; | 
						|
			this.InputType = inputType; | 
						|
			this.Sign = sign; | 
						|
		} | 
						|
 | 
						|
		public override StackType ResultType => LiftingKind == ComparisonLiftingKind.ThreeValuedLogic ? StackType.O : StackType.I4; | 
						|
		public bool IsLifted => LiftingKind != ComparisonLiftingKind.None; | 
						|
		public StackType UnderlyingResultType => StackType.I4; | 
						|
 | 
						|
		internal override void CheckInvariant(ILPhase phase) | 
						|
		{ | 
						|
			base.CheckInvariant(phase); | 
						|
			if (LiftingKind == ComparisonLiftingKind.None) { | 
						|
				Debug.Assert(Left.ResultType == InputType); | 
						|
				Debug.Assert(Right.ResultType == InputType); | 
						|
			} else { | 
						|
				Debug.Assert(Left.ResultType == InputType || Left.ResultType == StackType.O); | 
						|
				Debug.Assert(Right.ResultType == InputType || Right.ResultType == StackType.O); | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		public override void WriteTo(ITextOutput output, ILAstWritingOptions options) | 
						|
		{ | 
						|
			ILRange.WriteTo(output, options); | 
						|
			if (options.UseLogicOperationSugar && MatchLogicNot(out var arg)) { | 
						|
				output.Write("logic.not("); | 
						|
				arg.WriteTo(output, options); | 
						|
				output.Write(')'); | 
						|
				return; | 
						|
			} | 
						|
			output.Write(OpCode); | 
						|
			switch (Sign) { | 
						|
				case Sign.Signed: | 
						|
					output.Write(".signed"); | 
						|
					break; | 
						|
				case Sign.Unsigned: | 
						|
					output.Write(".unsigned"); | 
						|
					break; | 
						|
			} | 
						|
			switch (LiftingKind) { | 
						|
				case ComparisonLiftingKind.CSharp: | 
						|
					output.Write(".lifted[C#]"); | 
						|
					break; | 
						|
				case ComparisonLiftingKind.ThreeValuedLogic: | 
						|
					output.Write(".lifted[3VL]"); | 
						|
					break; | 
						|
			} | 
						|
			output.Write('('); | 
						|
			Left.WriteTo(output, options); | 
						|
			output.Write(' '); | 
						|
			output.Write(Kind.GetToken()); | 
						|
			output.Write(' '); | 
						|
			Right.WriteTo(output, options); | 
						|
			output.Write(')'); | 
						|
		} | 
						|
 | 
						|
		public static Comp LogicNot(ILInstruction arg) | 
						|
		{ | 
						|
			return new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0)); | 
						|
		} | 
						|
 | 
						|
		public static Comp LogicNot(ILInstruction arg, Interval ilrange) | 
						|
		{ | 
						|
			return new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0)) { ILRange = ilrange }; | 
						|
		} | 
						|
	} | 
						|
} | 
						|
 | 
						|
 | 
						|
 |