private void EmitBinaryExpression(Expression expr, CompilationFlags flags) { BinaryExpression b = (BinaryExpression)expr; Debug.Assert(b.NodeType != ExpressionType.AndAlso && b.NodeType != ExpressionType.OrElse && b.NodeType != ExpressionType.Coalesce); if (b.Method != null) { EmitBinaryMethod(b, flags); return; } // For EQ and NE, if there is a user-specified method, use it. // Otherwise implement the C# semantics that allow equality // comparisons on non-primitive nullable structs that don't // overload "==" if ((b.NodeType == ExpressionType.Equal || b.NodeType == ExpressionType.NotEqual) && (b.Type == typeof(bool) || b.Type == typeof(bool?))) { // If we have x==null, x!=null, null==x or null!=x where x is // nullable but not null, then generate a call to x.HasValue. Debug.Assert(!b.IsLiftedToNull || b.Type == typeof(bool?)); if (ConstantCheck.IsNull(b.Left) && !ConstantCheck.IsNull(b.Right) && TypeUtils.IsNullableType(b.Right.Type)) { EmitNullEquality(b.NodeType, b.Right, b.IsLiftedToNull); return; } if (ConstantCheck.IsNull(b.Right) && !ConstantCheck.IsNull(b.Left) && TypeUtils.IsNullableType(b.Left.Type)) { EmitNullEquality(b.NodeType, b.Left, b.IsLiftedToNull); return; } // For EQ and NE, we can avoid some conversions if we're // ultimately just comparing two managed pointers. EmitExpression(GetEqualityOperand(b.Left)); EmitExpression(GetEqualityOperand(b.Right)); } else { // Otherwise generate it normally EmitExpression(b.Left); EmitExpression(b.Right); } EmitBinaryOperator(b.NodeType, b.Left.Type, b.Right.Type, b.Type, b.IsLiftedToNull); }
private void EmitBranchComparison(bool branch, BinaryExpression node, Label label) { Debug.Assert(node.NodeType == ExpressionType.Equal || node.NodeType == ExpressionType.NotEqual); Debug.Assert(!node.IsLiftedToNull); // To share code paths, we want to treat NotEqual as an inverted Equal bool branchWhenEqual = branch == (node.NodeType == ExpressionType.Equal); if (node.Method != null) { EmitBinaryMethod(node, CompilationFlags.EmitAsNoTail); // EmitBinaryMethod takes into account the Equal/NotEqual // node kind, so use the original branch value EmitBranchOp(branch, label); } else if (ConstantCheck.IsNull(node.Left)) { if (TypeUtils.IsNullableType(node.Right.Type)) { EmitAddress(node.Right, node.Right.Type); _ilg.EmitHasValue(node.Right.Type); } else { Debug.Assert(!node.Right.Type.IsValueType); EmitExpression(GetEqualityOperand(node.Right)); } EmitBranchOp(!branchWhenEqual, label); } else if (ConstantCheck.IsNull(node.Right)) { if (TypeUtils.IsNullableType(node.Left.Type)) { EmitAddress(node.Left, node.Left.Type); _ilg.EmitHasValue(node.Left.Type); } else { Debug.Assert(!node.Left.Type.IsValueType); EmitExpression(GetEqualityOperand(node.Left)); } EmitBranchOp(!branchWhenEqual, label); } else if (TypeUtils.IsNullableType(node.Left.Type) || TypeUtils.IsNullableType(node.Right.Type)) { EmitBinaryExpression(node); // EmitBinaryExpression takes into account the Equal/NotEqual // node kind, so use the original branch value EmitBranchOp(branch, label); } else { EmitExpression(GetEqualityOperand(node.Left)); EmitExpression(GetEqualityOperand(node.Right)); if (branchWhenEqual) { _ilg.Emit(OpCodes.Beq, label); } else { _ilg.Emit(OpCodes.Ceq); _ilg.Emit(OpCodes.Brfalse, label); } } }