我正在尝试为树实现代码生成/寄存器分配算法,以取代我以前把所有东西都放在堆栈上的旧算法。现在我正在尝试实现Sethi-Ullman算法,但是从维基百科和一些网页中找到的内容,该算法的某些部分对我来说仍然不清楚。
我正在寻找一些缺失部分的解释,并附有伪代码/C/C++工作代码。
1)我应该使用哪种方法选择空闲寄存器?即,正在使用的寄存器堆栈。我使用了我认为非常糟糕的方法:交替返回寄存器:如果先前使用的寄存器是R0,则返回R1。如果是R1,则返回R0,依此类推。它对于小表达式无效。
2)当
这里是
它确实生成了:
它会生成:
我正在寻找一些缺失部分的解释,并附有伪代码/C/C++工作代码。
1)我应该使用哪种方法选择空闲寄存器?即,正在使用的寄存器堆栈。我使用了我认为非常糟糕的方法:交替返回寄存器:如果先前使用的寄存器是R0,则返回R1。如果是R1,则返回R0,依此类推。它对于小表达式无效。
2)当
label(left) >= K and label(right) >= K
时,我应该怎么做?这里是
label
和sethi-ullman
函数。REG reg()
{
static REG r = REG_NONE;
switch(r) {
case REG_NONE:
r = REG_r0;
break;
case REG_r0:
r = REG_r1;
break;
case REG_r1:
r = REG_r0;
break;
default:
assert(0);
break;
}
return r;
}
void SethiUllman(AST *node)
{
static const int K = 2;
if(node->left != NULL && node->right != NULL) {
int l = node->left->n;
int r = node->right->n;
if(l >= K && r >= K) {
SethiUllman(node->right);
node->n = node->n - 1;
//emit(node->right, REG_r0);
SethiUllman(node->left);
//emit(node->left, REG_r1);
}
else if(l >= r) {
SethiUllman(node->left);
SethiUllman(node->right);
node->n = node->n - 1;
}
else if(l < r) {
SethiUllman(node->right);
SethiUllman(node->left);
node->n = node->n - 1;
}
node->reg = reg();
printf("%s %s,%s\n",
op_string(node->type),
reg_string(node->left->reg),
reg_string(node->right->reg));
}
else if(node->type == TYPE::id) {
node->n = node->n + 1;
node->reg = reg();
emit(node);
}
else {
node->reg = reg();
emit(node);
}
}
void label(AST *node)
{
if(node == NULL)
return;
label(node->left);
label(node->right);
if(node->left != NULL && node->right != NULL) {
int l = node->left->n;
int r = node->right->n;
if(l == r)
node->n = 1 + l;
else
node->n = max(1, l, r);
}
else if(node->type == TYPE::id) {
node->n = 1;
} else if(node->type == TYPE::number) {
node->n = 0;
}
}
对于这样一个表达式中的树结构:
2+b*3
它确实生成了:
LOAD R0,[b]
LOAD R1,3
MUL R0,R1
LOAD R1,2
ADD R1,R0
并从这样的一个:
8+(2+b*3)
它会生成:
LOAD R0,[b]
LOAD R1,3
MUL R0,R1
LOAD R1,2
ADD R1,R0
LOAD R1,8 < R1 is not preserved. I don't know how it should be done.
ADD R0,R1
以上我仅提供了主要算法,如果需要,我可以提供完整的代码来在您的计算机上测试。