问题
I'm trying to implement a code generation/register allocation algorithm for Trees in favor of my old one, where I put everything on stack. Now I'm trying to implement Sethi-Ullman algorithm but from only contents I've found on Wikipedia and some web pages some parts of the algorithm remain unclear to me.
I'm looking for an explanation to parts I'm missing with some pseudo-code/C/C++ working code.
1) Which approach should I use to chose free register? ie, the stack of registers beging used. I'm using what I consider a very poor one: Alternately return registers: if previously used register was R0, return R1. If R1, return R0 and so on. It doesn't work to small expressions.
2) What should I do when label(left) >= K and label(right) >= K
?
Here's the label
and sethi-ullman
functions
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;
}
}
For a tree from an exp like this:
2+b*3
It does generate:
LOAD R0,[b]
LOAD R1,3
MUL R0,R1
LOAD R1,2
ADD R1,R0
And from one like this:
8+(2+b*3)
It does generate:
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
Above I provided only the main algorithms, but I can provided full code to a test case on your machine, if needed.
回答1:
I don't quite understand why the 8+(2+b*3)
expression doesn't just "work", because to me, the expression shouldn't need more than 2 registers in the calculation. However, if you can't perform the whole calculation in two register, then you need to do "spilling" - storing the register in a temporary (stack) location, and then restoring the value from that temporary location when you need it again.
This is the code you posted:
LOAD R0,[b]
LOAD R1,3
MUL R0,R1 ; R0 = b*3
LOAD R1,2
ADD R1,R0 ; R1 = 2+(b*3)
LOAD R1,8 < R1 is not preserved. I don't know how it should be done.
ADD R0,R1
We can rewrite it, using spilling:
LOAD R0,[b]
LOAD R1,3
MUL R0,R1 ; R0 = b*3
LOAD R1,2
ADD R1,R0 ; R1 = 2+(b*3)
STORE R1, [tmp]
LOAD R1,8 < R1 is not preserved. I don't know how it should be done.
LOAD R0, [tmp]
ADD R0,R1
However, it is possible to do without spilling, which suggests that the actual algorithm you are using is wrong:
LOAD R0,[b]
LOAD R1,3
MUL R0,R1 ; R0 = b*3
LOAD R1,2
ADD R0,R1 ; R0 = 2+(b*3)
LOAD R1,8 ; Use R0 above -> R1 is now free.
ADD R0,R1
Or, equally:
LOAD R0,[b]
LOAD R1,3
MUL R0,R1 ; R0 = b*3
LOAD R1,2
ADD R1,R0 ; R1 = 2+(b*3)
LOAD R0,8 ; Store in R1 above -> R0 is now free.
ADD R0,R1
I'm not sure, but I think it may well be the way around you pick the left/right operand of the first ADD
instruction.
I would add some printouts to follow the code, and see what it does in different circumstances.
来源:https://stackoverflow.com/questions/23401809/algorithm-for-register-allocation