« 上一篇下一篇 »

动态规划的算法

计算一个结点n的代价包括在给定寄存器数量的情况下对S求值时所需要的全部加载和保 存运算,也包括了计算S的根结点处的运算符所需要的代价。代价向量的第0个元素存放的是把子树S的值计算出来并保存内存的最优代价。只需要考虑S的根结点的各子树的最优程序的 不同组合,就可以生成S的最优程序。这是由连续求值的性质来确保的。这个限制减少了需要考虑的情况。
动态规划算法有三个步骤(假设目标机器具有r个寄存器):

1)对表达式树的每个结点n自底向上地计算得到一个代价数组C,其中C的第i个元素 C[i]是在假设有i(1≤i≤r)个可用寄存器的情况下对以n为根的子树S求值并将结果存放在一个寄存器中的最优代价。

2)遍历T,使用代价向量(数组)来决定T的哪棵子树应该被计算并保存到内存中。

3)使用每个结点的代价向量和相关指令来遍历各棵子树并生成最终的目标代码。在这个过程中,首先为那些需要把结果值保存到内存的子树生成代码。

上述每一个步骤都可以高效地实现,运行所需时间与表达式树的大小成线性关系。

计算一个结点n的代价包括在给定寄存器数量的情况下对S求值时所需要的全部加载和保 存运算,也包括了计算S的根结点处的运算符所需要的代价。代价向量的第0个元素存放的是把子树S的值计算出来并保存到内存的最优代价。只需要考虑S的根结点的各子树的最优程序的 不同组合,就可以生成S的最优程序。这是由连续求值的性质来确保的。这个限制减少了需要考虑的情况。

为了计算结点n的代价C[i],我们那样把指令看作是树重写规则。考虑和结点n处的输人树相匹配的各个模板E。只要检查n的相应后代的代价向量,就可以确定对E的叶子结点所代表的运算分量进行求值时所需要的代价。对于E的寄存器运算分量,考虑对T的相应子树求值并放到寄存器中的各种可能的顺序。在每个顺序中,第一个对应于某个寄存器运算分量的子树可以使用i个寄存器,而第二个则使用i-1个寄存器,以此类推。考虑结点n时,需要加上和模板E相关的指令的代价。C[i]的值就是所有这些可能的顺序所对应的代价值中的最小者。

整棵树的代价向量可以用自底向上的方式计算。计算所需时间和T中结点的个数呈线性正比关系。在每个结点上为各个i值保存用于获得最优代价c[i]所使用的指令可以带来方便。T的根结点的代价向量中的最小值给出了对T求值所需的最小代价。

« 上一篇下一篇 »