【发布时间】:2014-01-13 18:34:33
【问题描述】:
我编写了一个 DSL 和一个编译器,可以从中生成一个 .NET 表达式树。 树中的所有表达式都没有副作用,并且该表达式保证是“非语句”表达式(没有局部变量、循环、块等)。 (编辑:树可能包括文字、属性访问、标准运算符和函数调用——它们可能在内部做一些花哨的事情,比如记忆,但在外部没有副作用)。
现在我想对其进行“通用子表达式消除”优化。
例如,给定一棵对应于 C# lambda 的树:
foo => (foo.Bar * 5 + foo.Baz * 2 > 7)
|| (foo.Bar * 5 + foo.Baz * 2 < 3)
|| (foo.Bar * 5 + 3 == foo.Xyz)
...我想生成树等价物(忽略一些短路语义被忽略的事实):
foo =>
{
var local1 = foo.Bar * 5;
// Notice that this local depends on the first one.
var local2 = local1 + foo.Baz * 2;
// Notice that no unnecessary locals have been generated.
return local2 > 7 || local2 < 3 || (local1 + 3 == foo.Xyz);
}
我熟悉编写表达式访问器,但这种优化的算法对我来说并不是很明显 - 我当然可以在树中找到“重复项”,但显然有一些技巧可以分析其中的依赖关系和子树之间有效和正确地消除子表达式。
我在 Google 上寻找算法,但它们似乎很难快速实现。此外,它们看起来非常“笼统”,不一定考虑到我所考虑的树的简单性。
【问题讨论】:
-
子树之间的依赖关系是什么意思?你不是说这些没有副作用吗?
-
@Mehrdad:是的,没有副作用。我所说的“依赖关系”只是指
foo.Bar * 5 + foo.Baz * 2依赖于foo.Bar等等(即foo.Bar存在于其子树中)。 -
你认为
(a + b) + c等同于a + (b + c)吗? -
@Mehrdad:不,算法没有必要根据关联性(或交换性等)等操作的“特殊”属性进行优化
-
你让我评论这个问题;我不是这个优化方面的专家,所以除了:确保你清楚地了解你正在优化的资源之外,我没有太多要说的。 CSE 通过消除冗余计算减少了时间,但增加了空间使用。增加的空间使用会转化为寄存器争用、更多缓存未命中等,这可能会使事情变得更糟。这是一个棘手的优化,只有当我有强有力的证据表明与空间成本相比,时间优势很大时,我才会这样做。
标签: c# .net algorithm optimization expression-trees