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.