I\'ve written a DSL and a compiler that generates a .NET expression tree from it. All expressions within the tree are side-effect-free and the expression is guaranteed to b
You are doing unnecessary work, common sub-expression elimination is the job of the jitter optimizer. Let's take your example and look at the generated code. I wrote it like this:
static void Main(string[] args) {
var lambda = new Func(foo =>
(foo.Bar * 5 + foo.Baz * 2 > 7)
|| (foo.Bar * 5 + foo.Baz * 2 < 3)
|| (foo.Bar * 5 + 3 == foo.Xyz));
var obj = new Foo() { Bar = 1, Baz = 2, Xyz = 3 };
var result = lambda(obj);
Console.WriteLine(result);
}
}
class Foo {
public int Bar { get; internal set; }
public int Baz { get; internal set; }
public int Xyz { get; internal set; }
}
The x86 jitter generated this machine code for the lambda expression:
006526B8 push ebp ; prologue
006526B9 mov ebp,esp
006526BB push esi
006526BC mov esi,dword ptr [ecx+4] ; esi = foo.Bar
006526BF lea esi,[esi+esi*4] ; esi = 5 * foo.Bar
006526C2 mov edx,dword ptr [ecx+8] ; edx = foo.Baz
006526C5 add edx,edx ; edx = 2 * foo.Baz
006526C7 lea eax,[esi+edx] ; eax = 5 * foo.Bar + 2 * foo.Baz
006526CA cmp eax,7 ; > 7 test
006526CD jg 006526E7 ; > 7 then return true
006526CF add edx,esi ; HERE!!
006526D1 cmp edx,3 ; < 3 test
006526D4 jl 006526E7 ; < 3 then return true
006526D6 add esi,3 ; HERE!!
006526D9 mov eax,esi
006526DB cmp eax,dword ptr [ecx+0Ch] ; == foo.Xyz test
006526DE sete al ; convert to bool
006526E1 movzx eax,al
006526E4 pop esi ; epilogue
006526E5 pop ebp
006526E6 ret
006526E7 mov eax,1
006526EC pop esi
006526ED pop ebp
006526EE ret
I marked the places in the code where the foo.Bar * 5
sub-expression was eliminated with HERE. Notable is how it did not eliminate the foo.Bar * 5 + foo.Baz * 2
sub-expression, the addition was performed again at address 006526CF. There is a good reason for that, the x86 jitter doesn't have enough registers available to store the intermediary result. If you look at the machine code generated by the x64 jitter then you do see it eliminated, the r9 register stores it.
This ought to give enough reasons to reconsider your intend. You are doing work that doesn't need to be done. And not only that, you are liable to generate worse code than the jitter will generate since you don't have the luxury to estimate the CPU register budget.
Don't do this.