Skip to content

Commit 082fb06

Browse files
committed
@wip eval
1 parent 62fb147 commit 082fb06

2 files changed

Lines changed: 148 additions & 16 deletions

File tree

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 147 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5421,23 +5421,154 @@ private static MethodInfo FindBinaryOperandMethod(
54215421
return null;
54225422
}
54235423

5424+
/// <summary>Operation accepting IComparable inputs and producing bool output</summary>
5425+
private static bool IsComparison(ExpressionType nodeType) =>
5426+
nodeType == ExpressionType.Equal |
5427+
nodeType == ExpressionType.NotEqual |
5428+
nodeType == ExpressionType.GreaterThan |
5429+
nodeType == ExpressionType.GreaterThanOrEqual |
5430+
nodeType == ExpressionType.LessThan |
5431+
nodeType == ExpressionType.LessThanOrEqual;
5432+
5433+
/// <summary>Operation accepting bool inputs and producing bool output</summary>
5434+
private static bool IsLogical(ExpressionType nodeType) =>
5435+
nodeType == ExpressionType.AndAlso |
5436+
nodeType == ExpressionType.OrElse |
5437+
nodeType == ExpressionType.Not;
5438+
5439+
/// <summary>Operation accepting the same primitive type inputs (or of the coalescing types) and producing the "same" primitive type output</summary>
5440+
private static bool IsArithmetic(ExpressionType nodeType) =>
5441+
nodeType == ExpressionType.Add |
5442+
nodeType == ExpressionType.Subtract |
5443+
nodeType == ExpressionType.Multiply |
5444+
nodeType == ExpressionType.Divide |
5445+
nodeType == ExpressionType.Modulo |
5446+
nodeType == ExpressionType.Negate;
5447+
5448+
/// <summary>Eval negate</summary>
5449+
public static object EvalNegateOrNull(object operand)
5450+
{
5451+
return Type.GetTypeCode(operand.GetType()) switch
5452+
{
5453+
TypeCode.SByte => -(sbyte)operand,
5454+
TypeCode.Byte => -(byte)operand,
5455+
TypeCode.Int16 => -(short)operand,
5456+
TypeCode.UInt16 => -(ushort)operand,
5457+
TypeCode.Int32 => -(int)operand,
5458+
TypeCode.UInt32 => -(uint)operand,
5459+
TypeCode.Int64 => -(long)operand,
5460+
TypeCode.Single => -(float)operand,
5461+
TypeCode.Double => -(double)operand,
5462+
TypeCode.Decimal => -(decimal)operand,
5463+
TypeCode.UInt64 => null,
5464+
_ => null,
5465+
};
5466+
}
5467+
5468+
/// <summary>Eval arithmetic</summary>
5469+
public static object EvalArithmeticOrNull(object left, object right, ExpressionType nodeType)
5470+
{
5471+
return nodeType switch
5472+
{
5473+
ExpressionType.Add => Type.GetTypeCode(left.GetType()) switch
5474+
{
5475+
TypeCode.SByte => (sbyte)left + (sbyte)right,
5476+
TypeCode.Byte => (byte)left + (byte)right,
5477+
TypeCode.Int16 => (short)left + (short)right,
5478+
TypeCode.UInt16 => (ushort)left + (ushort)right,
5479+
TypeCode.Int32 => (int)left + (int)right,
5480+
TypeCode.UInt32 => (uint)left + (uint)right,
5481+
TypeCode.Int64 => (long)left + (long)right,
5482+
TypeCode.UInt64 => (ulong)left + (ulong)right,
5483+
TypeCode.Single => (float)left + (float)right,
5484+
TypeCode.Double => (double)left + (double)right,
5485+
TypeCode.Decimal => (decimal)left + (decimal)right,
5486+
_ => null,
5487+
},
5488+
ExpressionType.Subtract => Type.GetTypeCode(left.GetType()) switch
5489+
{
5490+
TypeCode.SByte => (sbyte)left - (sbyte)right,
5491+
TypeCode.Byte => (byte)left - (byte)right,
5492+
TypeCode.Int16 => (short)left - (short)right,
5493+
TypeCode.UInt16 => (ushort)left - (ushort)right,
5494+
TypeCode.Int32 => (int)left - (int)right,
5495+
TypeCode.UInt32 => (uint)left - (uint)right,
5496+
TypeCode.Int64 => (long)left - (long)right,
5497+
TypeCode.UInt64 => (ulong)left - (ulong)right,
5498+
TypeCode.Single => (float)left - (float)right,
5499+
TypeCode.Double => (double)left - (double)right,
5500+
TypeCode.Decimal => (decimal)left - (decimal)right,
5501+
_ => null,
5502+
},
5503+
ExpressionType.Multiply => Type.GetTypeCode(left.GetType()) switch
5504+
{
5505+
TypeCode.SByte => (sbyte)left * (sbyte)right,
5506+
TypeCode.Byte => (byte)left * (byte)right,
5507+
TypeCode.Int16 => (short)left * (short)right,
5508+
TypeCode.UInt16 => (ushort)left * (ushort)right,
5509+
TypeCode.Int32 => (int)left * (int)right,
5510+
TypeCode.UInt32 => (uint)left * (uint)right,
5511+
TypeCode.Int64 => (long)left * (long)right,
5512+
TypeCode.UInt64 => (ulong)left * (ulong)right,
5513+
TypeCode.Single => (float)left * (float)right,
5514+
TypeCode.Double => (double)left * (double)right,
5515+
TypeCode.Decimal => (decimal)left * (decimal)right,
5516+
_ => null,
5517+
},
5518+
ExpressionType.Divide => Type.GetTypeCode(left.GetType()) switch
5519+
{
5520+
TypeCode.SByte => (sbyte)left / (sbyte)right,
5521+
TypeCode.Byte => (byte)left / (byte)right,
5522+
TypeCode.Int16 => (short)left / (short)right,
5523+
TypeCode.UInt16 => (ushort)left / (ushort)right,
5524+
TypeCode.Int32 => (int)left / (int)right,
5525+
TypeCode.UInt32 => (uint)left / (uint)right,
5526+
TypeCode.Int64 => (long)left / (long)right,
5527+
TypeCode.UInt64 => (ulong)left / (ulong)right,
5528+
TypeCode.Single => (float)left / (float)right,
5529+
TypeCode.Double => (double)left / (double)right,
5530+
TypeCode.Decimal => (decimal)left / (decimal)right,
5531+
_ => null,
5532+
},
5533+
ExpressionType.Modulo => Type.GetTypeCode(left.GetType()) switch
5534+
{
5535+
TypeCode.SByte => (sbyte)left % (sbyte)right,
5536+
TypeCode.Byte => (byte)left % (byte)right,
5537+
TypeCode.Int16 => (short)left % (short)right,
5538+
TypeCode.UInt16 => (ushort)left % (ushort)right,
5539+
TypeCode.Int32 => (int)left % (int)right,
5540+
TypeCode.UInt32 => (uint)left % (uint)right,
5541+
TypeCode.Int64 => (long)left % (long)right,
5542+
TypeCode.UInt64 => (ulong)left % (ulong)right,
5543+
TypeCode.Single => (float)left % (float)right,
5544+
TypeCode.Double => (double)left % (double)right,
5545+
TypeCode.Decimal => (decimal)left % (decimal)right,
5546+
_ => null,
5547+
},
5548+
_ => null,
5549+
};
5550+
}
54245551

54255552
// todo: @wip #468
5426-
internal static bool TryReduceComparisonByEvalConstantsAndArithmetics(out bool result, Expression left, Expression right, bool isEquality)
5553+
internal static bool TryReduceLogicalExpression(out bool result,
5554+
ExpressionType nodeType, Expression left, Expression right)
54275555
{
5428-
if (left is ConstantExpression lc && lc.Type.IsPrimitive &&
5429-
right is ConstantExpression rc && rc.Type.IsPrimitive
5556+
result = false;
5557+
if (left is BinaryExpression lb && IsLogical(lb.NodeType))
5558+
{
5559+
var ll = lb.Left;
5560+
var lr = lb.Right;
5561+
if (right is ConstantExpression rc
54305562
#if LIGHT_EXPRESSION
5431-
// exclude the ref
5432-
&& lc is not ConstantRefExpression && rc is not ConstantRefExpression
5563+
&& right is not ConstantRefExpression
54335564
#endif
5434-
)
5435-
{
5565+
)
5566+
{
54365567

5437-
result = lc.Value.Equals(rc.Value) && !isEquality;
5438-
return true;
5568+
}
54395569
}
54405570

5571+
54415572
result = false;
54425573
return false;
54435574
}
@@ -5474,9 +5605,8 @@ private static bool TryEmitComparison(
54745605
var isEqualityOp = nodeType == ExpressionType.Equal | nodeType == ExpressionType.NotEqual;
54755606
if (isEqualityOp)
54765607
{
5477-
54785608
// if (leftType.IsPrimitive &&
5479-
// TryReduceComparisonByEvalConstantsAndArithmetics(out bool result, left, right, nodeType == ExpressionType.Equal))
5609+
// TryReduceArithmeticsOrComparisonOrLogical(out bool result, nodeType, left, right))
54805610
// {
54815611
// il.Demit((bool)result ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
54825612
// return il.EmitPopIfIgnoreResult(parent);
@@ -6074,28 +6204,30 @@ private static Expression TryReduceCondition(Expression testExpr)
60746204
{
60756205
// simplify the not `==` -> `!=`, `!=` -> `==`
60766206
var op = TryReduceCondition(((UnaryExpression)testExpr).Operand);
6077-
if (op.NodeType == ExpressionType.Equal) // ensures that it is a BinaryExpression
6207+
var nodeType = op.NodeType;
6208+
if (nodeType == ExpressionType.Equal) // ensures that it is a BinaryExpression
60786209
{
60796210
var binOp = (BinaryExpression)op;
60806211
return NotEqual(binOp.Left, binOp.Right);
60816212
}
6082-
else if (op.NodeType == ExpressionType.NotEqual) // ensures that it is a BinaryExpression
6213+
else if (nodeType == ExpressionType.NotEqual) // ensures that it is a BinaryExpression
60836214
{
60846215
var binOp = (BinaryExpression)op;
60856216
return Equal(binOp.Left, binOp.Right);
60866217
}
60876218
}
60886219
else if (testExpr is BinaryExpression b)
60896220
{
6090-
if (b.NodeType == ExpressionType.OrElse || b.NodeType == ExpressionType.Or)
6221+
var nodeType = b.NodeType;
6222+
if (nodeType == ExpressionType.OrElse | nodeType == ExpressionType.Or)
60916223
{
60926224
if (b.Left is ConstantExpression lc && lc.Value is bool lcb)
60936225
return lcb ? lc : TryReduceCondition(b.Right);
60946226

60956227
if (b.Right is ConstantExpression rc && rc.Value is bool rcb && !rcb)
60966228
return TryReduceCondition(b.Left);
60976229
}
6098-
else if (b.NodeType == ExpressionType.AndAlso || b.NodeType == ExpressionType.And)
6230+
else if (nodeType == ExpressionType.AndAlso | nodeType == ExpressionType.And)
60996231
{
61006232
if (b.Left is ConstantExpression lc && lc.Value is bool lcb)
61016233
return !lcb ? lc : TryReduceCondition(b.Right);

test/FastExpressionCompiler.Benchmarks/Issue468_Compile_vs_FastCompile.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,4 @@ public object CompiledFast()
107107
{
108108
return _expr.CompileFast();
109109
}
110-
}
110+
}

0 commit comments

Comments
 (0)