void EmitBranch(bool branchOnTrue, BinaryExpression expression, Label label)
{
switch (expression.Operator)
{
case BinaryOperatorType.TypeTest:
EmitTypeTest(expression);
_il.Emit(branchOnTrue ? OpCodes.Brtrue : OpCodes.Brfalse, label);
break;
case BinaryOperatorType.Or:
if (branchOnTrue)
{
EmitBranch(true, expression.Left, label);
EmitBranch(true, expression.Right, label);
}
else
{
Label skipRhs = _il.DefineLabel();
EmitBranch(true, expression.Left, skipRhs);
EmitBranch(false, expression.Right, label);
_il.MarkLabel(skipRhs);
}
break;
case BinaryOperatorType.And:
if (branchOnTrue)
{
Label skipRhs = _il.DefineLabel();
EmitBranch(false, expression.Left, skipRhs);
EmitBranch(true, expression.Right, label);
_il.MarkLabel(skipRhs);
}
else
{
EmitBranch(false, expression.Left, label);
EmitBranch(false, expression.Right, label);
}
break;
case BinaryOperatorType.Equality:
if (IsZeroEquivalent(expression.Left))
EmitBranch(!branchOnTrue, expression.Right, label);
else if (IsZeroEquivalent(expression.Right))
EmitBranch(!branchOnTrue, expression.Left, label);
else
{
LoadCmpOperands(expression);
_il.Emit(branchOnTrue ? OpCodes.Beq : OpCodes.Bne_Un, label);
}
break;
case BinaryOperatorType.Inequality:
if (IsZeroEquivalent(expression.Left))
{
EmitBranch(branchOnTrue, expression.Right, label);
}
else if (IsZeroEquivalent(expression.Right))
{
EmitBranch(branchOnTrue, expression.Left, label);
}
else
{
LoadCmpOperands(expression);
_il.Emit(branchOnTrue ? OpCodes.Bne_Un : OpCodes.Beq, label);
}
break;
case BinaryOperatorType.ReferenceEquality:
if (IsNull(expression.Left))
{
EmitRawBranch(!branchOnTrue, expression.Right, label);
break;
}
if (IsNull(expression.Right))
{
EmitRawBranch(!branchOnTrue, expression.Left, label);
break;
}
Visit(expression.Left); PopType();
Visit(expression.Right); PopType();
_il.Emit(branchOnTrue ? OpCodes.Beq : OpCodes.Bne_Un, label);
break;
case BinaryOperatorType.ReferenceInequality:
if (IsNull(expression.Left))
{
EmitRawBranch(branchOnTrue, expression.Right, label);
break;
}
if (IsNull(expression.Right))
{
EmitRawBranch(branchOnTrue, expression.Left, label);
break;
}
Visit(expression.Left); PopType();
Visit(expression.Right); PopType();
_il.Emit(branchOnTrue ? OpCodes.Bne_Un : OpCodes.Beq, label);
break;
case BinaryOperatorType.GreaterThan:
LoadCmpOperands(expression);
_il.Emit(branchOnTrue ? OpCodes.Bgt : OpCodes.Ble, label);
break;
case BinaryOperatorType.GreaterThanOrEqual:
LoadCmpOperands(expression);
_il.Emit(branchOnTrue ? OpCodes.Bge : OpCodes.Blt, label);
break;
case BinaryOperatorType.LessThan:
LoadCmpOperands(expression);
_il.Emit(branchOnTrue ? OpCodes.Blt : OpCodes.Bge, label);
break;
case BinaryOperatorType.LessThanOrEqual:
LoadCmpOperands(expression);
_il.Emit(branchOnTrue ? OpCodes.Ble : OpCodes.Bgt, label);
break;
default:
EmitDefaultBranch(branchOnTrue, expression, label);
break;
}
}