- Moved 2 of the test cases into tests for failure

- Reworked the transformation into ssa form and now I catch all unitialized
  variable uses.
- Several more test cases
- Bumped the version to 0.34
- Verified that -O2 the scc_transform now works.


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@934 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Eric Biederman 2003-07-04 15:14:04 +00:00
parent 830c9886ea
commit 66fe2227df
6 changed files with 345 additions and 74 deletions

View File

@ -1,5 +1,5 @@
VERSION:=0.33 VERSION:=0.34
RELEASE_DATE:=1 July 2003 RELEASE_DATE:=4 July 2003
PACKAGE:=romcc PACKAGE:=romcc
@ -61,9 +61,7 @@ TESTS=\
simple_test39.c \ simple_test39.c \
simple_test40.c \ simple_test40.c \
simple_test41.c \ simple_test41.c \
simple_test42.c \
simple_test43.c \ simple_test43.c \
simple_test44.c \
simple_test45.c \ simple_test45.c \
simple_test46.c \ simple_test46.c \
simple_test47.c \ simple_test47.c \
@ -74,6 +72,8 @@ TESTS=\
simple_test52.c \ simple_test52.c \
simple_test53.c \ simple_test53.c \
simple_test54.c \ simple_test54.c \
simple_test55.c \
simple_test56.c \
raminit_test.c \ raminit_test.c \
raminit_test2.c \ raminit_test2.c \
raminit_test3.c \ raminit_test3.c \
@ -81,7 +81,9 @@ TESTS=\
raminit_test5.c raminit_test5.c
FAIL_TESTS = \ FAIL_TESTS = \
fail_test1.c fail_test1.c \
fail_test2.c \
fail_test3.c
TEST_SRCS:=$(patsubst %, tests/%, $(TESTS)) TEST_SRCS:=$(patsubst %, tests/%, $(TESTS))
TEST_ASM:=$(patsubst %.c, tests/%.S, $(TESTS)) TEST_ASM:=$(patsubst %.c, tests/%.S, $(TESTS))
@ -93,10 +95,10 @@ FAIL_OUT:=$(patsubst %.c, tests/%.out, $(FAIL_TESTS))
$(TEST_ASM): %.S: %.c romcc $(TEST_ASM): %.S: %.c romcc
export ALLOC_CHECK_=2; ./romcc -O -mcpu=k8 -o $@ $< > $*.debug export ALLOC_CHECK_=2; ./romcc -O2 -mcpu=k8 -o $@ $< > $*.debug
$(FAIL_OUT): %.out: %.c romcc $(FAIL_OUT): %.out: %.c romcc
export ALLOC_CHECK_=2; if ./romcc -O -o $*.S $< > $*.debug 2> $@ ; then exit 1 ; else exit 0 ; fi export ALLOC_CHECK_=2; if ./romcc -O2 -o $*.S $< > $*.debug 2> $@ ; then exit 1 ; else exit 0 ; fi
$(TEST_OBJ): %.o: %.S $(TEST_OBJ): %.o: %.S
as $< -o $@ as $< -o $@

View File

@ -23,7 +23,6 @@
#warning "FIXME boundary cases with small types in larger registers" #warning "FIXME boundary cases with small types in larger registers"
#warning "FIXME give clear error messages about unused variables" #warning "FIXME give clear error messages about unused variables"
#warning "FIXME properly handle multi dimensional arrays" #warning "FIXME properly handle multi dimensional arrays"
#warning "FIXME fix scc_transform"
/* Control flow graph of a loop without goto. /* Control flow graph of a loop without goto.
* *
@ -1015,6 +1014,9 @@ static void __internal_warning(struct compile_state *state, struct triple *ptr,
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
loc(stderr, state, ptr); loc(stderr, state, ptr);
if (ptr) {
fprintf(stderr, "%p %s ", ptr, tops(ptr->op));
}
fprintf(stderr, "Internal compiler warning: "); fprintf(stderr, "Internal compiler warning: ");
vfprintf(stderr, fmt, args); vfprintf(stderr, fmt, args);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
@ -1184,40 +1186,6 @@ static void unuse_triple(struct triple *used, struct triple *unuser)
} }
} }
static void push_triple(struct triple *used, struct triple *user)
{
struct triple_set *new;
if (!used)
return;
if (!user)
return;
/* Append new to the head of the list,
* it's the only sensible behavoir for a stack.
*/
new = xcmalloc(sizeof(*new), "triple_set");
new->member = user;
new->next = used->use;
used->use = new;
}
static void pop_triple(struct triple *used, struct triple *unuser)
{
struct triple_set *use, **ptr;
ptr = &used->use;
while(*ptr) {
use = *ptr;
if (use->member == unuser) {
*ptr = use->next;
xfree(use);
/* Only free one occurance from the stack */
return;
}
else {
ptr = &use->next;
}
}
}
static void put_occurance(struct occurance *occurance) static void put_occurance(struct occurance *occurance)
{ {
occurance->count -= 1; occurance->count -= 1;
@ -1827,6 +1795,15 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
{ {
struct triple_set *set, *next; struct triple_set *set, *next;
struct triple **expr; struct triple **expr;
struct block *block;
/* Make certain the we are not the first or last element of a block */
block = block_of_triple(state, ptr);
if (block && (block->last == ptr)) {
block->last = ptr->prev;
}
if (block && (block->first == ptr)) {
block->first = ptr->next;
}
/* Remove ptr from use chains where it is the user */ /* Remove ptr from use chains where it is the user */
expr = triple_rhs(state, ptr, 0); expr = triple_rhs(state, ptr, 0);
for(; expr; expr = triple_rhs(state, ptr, expr)) { for(; expr; expr = triple_rhs(state, ptr, expr)) {
@ -4571,7 +4548,7 @@ static struct triple *array_to_pointer(struct compile_state *state, struct tripl
type = new_type( type = new_type(
TYPE_POINTER | (def->type->type & QUAL_MASK), TYPE_POINTER | (def->type->type & QUAL_MASK),
def->type->left, 0); def->type->left, 0);
if ((def->op == OP_SDECL) || is_const(def)) { if ((def->op == OP_SDECL) || IS_CONST_OP(def->op)) {
struct triple *addrconst; struct triple *addrconst;
if ((def->op != OP_SDECL) && (def->op != OP_BLOBCONST)) { if ((def->op != OP_SDECL) && (def->op != OP_BLOBCONST)) {
internal_error(state, def, "bad array constant"); internal_error(state, def, "bad array constant");
@ -9586,7 +9563,7 @@ static struct block *basic_block(struct compile_state *state,
struct triple *first) struct triple *first)
{ {
struct block *block; struct block *block;
struct triple *ptr; struct triple *ptr, *final;
int op; int op;
if (first->op != OP_LABEL) { if (first->op != OP_LABEL) {
internal_error(state, 0, "block does not start with a label"); internal_error(state, 0, "block does not start with a label");
@ -9595,6 +9572,11 @@ static struct block *basic_block(struct compile_state *state,
if (first->u.block != 0) { if (first->u.block != 0) {
return first->u.block; return first->u.block;
} }
/* Lookup the final instruction.
* It is important that the final instruction has it's own
* basic block.
*/
final = RHS(state->main_function, 0)->prev;
/* Allocate another basic block structure */ /* Allocate another basic block structure */
state->last_vertex += 1; state->last_vertex += 1;
block = xcmalloc(sizeof(*block), "block"); block = xcmalloc(sizeof(*block), "block");
@ -9602,7 +9584,8 @@ static struct block *basic_block(struct compile_state *state,
block->vertex = state->last_vertex; block->vertex = state->last_vertex;
ptr = first; ptr = first;
do { do {
if ((ptr != first) && (ptr->op == OP_LABEL) && ptr->use) { if ((ptr != first) && (ptr->op == OP_LABEL) &&
((ptr->use) || ptr == final)) {
break; break;
} }
block->last = ptr; block->last = ptr;
@ -10486,10 +10469,10 @@ static void insert_phi_operations(struct compile_state *state)
/* Count how many edges flow into this block */ /* Count how many edges flow into this block */
in_edges = front->users; in_edges = front->users;
/* Insert a phi function for this variable */ /* Insert a phi function for this variable */
get_occurance(front->first->occurance); get_occurance(var->occurance);
phi = alloc_triple( phi = alloc_triple(
state, OP_PHI, var->type, -1, in_edges, state, OP_PHI, var->type, -1, in_edges,
front->first->occurance); var->occurance);
phi->u.block = front; phi->u.block = front;
MISC(phi, 0) = var; MISC(phi, 0) = var;
use_triple(var, phi); use_triple(var, phi);
@ -10515,12 +10498,71 @@ static void insert_phi_operations(struct compile_state *state)
xfree(work); xfree(work);
} }
static int count_and_number_adecls(struct compile_state *state)
{
struct triple *first, *ins;
int adecls = 0;
first = RHS(state->main_function, 0);
ins = first;
do {
if (ins->op == OP_ADECL) {
adecls += 1;
ins->id = adecls;
}
ins = ins->next;
} while(ins != first);
return adecls;
}
static struct triple *peek_triple(struct triple_set **stacks, struct triple *var)
{
struct triple_set *head;
struct triple *top_val;
top_val = 0;
head = stacks[var->id];
if (head) {
top_val = head->member;
}
return top_val;
}
static void push_triple(struct triple_set **stacks, struct triple *var, struct triple *val)
{
struct triple_set *new;
/* Append new to the head of the list,
* it's the only sensible behavoir for a stack.
*/
new = xcmalloc(sizeof(*new), "triple_set");
new->member = val;
new->next = stacks[var->id];
stacks[var->id] = new;
}
static void pop_triple(struct triple_set **stacks, struct triple *var, struct triple *oldval)
{
struct triple_set *set, **ptr;
ptr = &stacks[var->id];
while(*ptr) {
set = *ptr;
if (set->member == oldval) {
*ptr = set->next;
xfree(set);
/* Only free one occurance from the stack */
return;
}
else {
ptr = &set->next;
}
}
}
/* /*
* C(V) * C(V)
* S(V) * S(V)
*/ */
static void fixup_block_phi_variables( static void fixup_block_phi_variables(
struct compile_state *state, struct block *parent, struct block *block) struct compile_state *state, struct triple_set **stacks, struct block *parent, struct block *block)
{ {
struct block_set *set; struct block_set *set;
struct triple *ptr; struct triple *ptr;
@ -10545,8 +10587,8 @@ static void fixup_block_phi_variables(
internal_error(state, ptr, "no var???"); internal_error(state, ptr, "no var???");
} }
/* Find the current value of the variable */ /* Find the current value of the variable */
val = var->use->member; val = peek_triple(stacks, var);
if ((val->op == OP_WRITE) || (val->op == OP_READ)) { if (val && ((val->op == OP_WRITE) || (val->op == OP_READ))) {
internal_error(state, val, "bad value in phi"); internal_error(state, val, "bad value in phi");
} }
if (edge >= TRIPLE_RHS(ptr->sizes)) { if (edge >= TRIPLE_RHS(ptr->sizes)) {
@ -10567,7 +10609,7 @@ static void fixup_block_phi_variables(
static void rename_block_variables( static void rename_block_variables(
struct compile_state *state, struct block *block) struct compile_state *state, struct triple_set **stacks, struct block *block)
{ {
struct block_set *user; struct block_set *user;
struct triple *ptr, *next, *last; struct triple *ptr, *next, *last;
@ -10586,11 +10628,11 @@ static void rename_block_variables(
struct triple *var, *val; struct triple *var, *val;
var = RHS(ptr, 0); var = RHS(ptr, 0);
unuse_triple(var, ptr); unuse_triple(var, ptr);
if (!var->use) { /* Find the current value of the variable */
val = peek_triple(stacks, var);
if (!val) {
error(state, ptr, "variable used without being set"); error(state, ptr, "variable used without being set");
} }
/* Find the current value of the variable */
val = var->use->member;
if ((val->op == OP_WRITE) || (val->op == OP_READ)) { if ((val->op == OP_WRITE) || (val->op == OP_READ)) {
internal_error(state, val, "bad value in read"); internal_error(state, val, "bad value in read");
} }
@ -10623,24 +10665,24 @@ static void rename_block_variables(
propogate_use(state, ptr, tval); propogate_use(state, ptr, tval);
unuse_triple(var, ptr); unuse_triple(var, ptr);
/* Push OP_WRITE ptr->right onto a stack of variable uses */ /* Push OP_WRITE ptr->right onto a stack of variable uses */
push_triple(var, tval); push_triple(stacks, var, tval);
} }
if (ptr->op == OP_PHI) { if (ptr->op == OP_PHI) {
struct triple *var; struct triple *var;
var = MISC(ptr, 0); var = MISC(ptr, 0);
/* Push OP_PHI onto a stack of variable uses */ /* Push OP_PHI onto a stack of variable uses */
push_triple(var, ptr); push_triple(stacks, var, ptr);
} }
last = ptr; last = ptr;
} }
block->last = last; block->last = last;
/* Fixup PHI functions in the cf successors */ /* Fixup PHI functions in the cf successors */
fixup_block_phi_variables(state, block, block->left); fixup_block_phi_variables(state, stacks, block, block->left);
fixup_block_phi_variables(state, block, block->right); fixup_block_phi_variables(state, stacks, block, block->right);
/* rename variables in the dominated nodes */ /* rename variables in the dominated nodes */
for(user = block->idominates; user; user = user->next) { for(user = block->idominates; user; user = user->next) {
rename_block_variables(state, user->member); rename_block_variables(state, stacks, user->member);
} }
/* pop the renamed variable stack */ /* pop the renamed variable stack */
last = block->first; last = block->first;
@ -10654,7 +10696,7 @@ static void rename_block_variables(
struct triple *var; struct triple *var;
var = RHS(ptr, 0); var = RHS(ptr, 0);
/* Pop OP_WRITE ptr->right from the stack of variable uses */ /* Pop OP_WRITE ptr->right from the stack of variable uses */
pop_triple(var, RHS(ptr, 1)); pop_triple(stacks, var, RHS(ptr, 1));
release_triple(state, ptr); release_triple(state, ptr);
continue; continue;
} }
@ -10662,7 +10704,7 @@ static void rename_block_variables(
struct triple *var; struct triple *var;
var = MISC(ptr, 0); var = MISC(ptr, 0);
/* Pop OP_WRITE ptr->right from the stack of variable uses */ /* Pop OP_WRITE ptr->right from the stack of variable uses */
pop_triple(var, ptr); pop_triple(stacks, var, ptr);
} }
last = ptr; last = ptr;
} }
@ -10708,15 +10750,117 @@ static void prune_block_variables(struct compile_state *state,
} }
} }
struct phi_triple {
struct triple *phi;
unsigned orig_id;
int alive;
};
static void keep_phi(struct compile_state *state, struct phi_triple *live, struct triple *phi)
{
struct triple **slot;
int zrhs, i;
if (live[phi->id].alive) {
return;
}
live[phi->id].alive = 1;
zrhs = TRIPLE_RHS(phi->sizes);
slot = &RHS(phi, 0);
for(i = 0; i < zrhs; i++) {
struct triple *used;
used = slot[i];
if (used && (used->op == OP_PHI)) {
keep_phi(state, live, used);
}
}
}
static void prune_unused_phis(struct compile_state *state)
{
struct triple *first, *phi;
struct phi_triple *live;
int phis, i;
/* Find the first instruction */
first = RHS(state->main_function, 0);
/* Count how many phi functions I need to process */
phis = 0;
for(phi = first->next; phi != first; phi = phi->next) {
if (phi->op == OP_PHI) {
phis += 1;
}
}
/* Mark them all dead */
live = xcmalloc(sizeof(*live) * (phis + 1), "phi_triple");
phis = 0;
for(phi = first->next; phi != first; phi = phi->next) {
if (phi->op != OP_PHI) {
continue;
}
live[phis].alive = 0;
live[phis].orig_id = phi->id;
live[phis].phi = phi;
phi->id = phis;
phis += 1;
}
/* Mark phis alive that are used by non phis */
for(i = 0; i < phis; i++) {
struct triple_set *set;
for(set = live[i].phi->use; !live[i].alive && set; set = set->next) {
if (set->member->op != OP_PHI) {
keep_phi(state, live, live[i].phi);
break;
}
}
}
/* Delete the extraneous phis */
for(i = 0; i < phis; i++) {
struct triple **slot;
int zrhs, j;
if (!live[i].alive) {
release_triple(state, live[i].phi);
continue;
}
phi = live[i].phi;
slot = &RHS(phi, 0);
zrhs = TRIPLE_RHS(phi->sizes);
for(j = 0; j < zrhs; j++) {
if(!slot[j]) {
error(state, phi, "variable not set on all paths to use");
}
}
}
xfree(live);
}
static void transform_to_ssa_form(struct compile_state *state) static void transform_to_ssa_form(struct compile_state *state)
{ {
struct triple_set **stacks;
int adecls;
insert_phi_operations(state); insert_phi_operations(state);
#if 0 #if 0
printf("@%s:%d\n", __FILE__, __LINE__); printf("@%s:%d\n", __FILE__, __LINE__);
print_blocks(state, stdout); print_blocks(state, stdout);
#endif #endif
rename_block_variables(state, state->first_block);
/* Allocate stacks for the Variables */
adecls = count_and_number_adecls(state);
stacks = xcmalloc(sizeof(stacks[0])*(adecls + 1), "adecl stacks");
rename_block_variables(state, stacks, state->first_block);
xfree(stacks);
prune_block_variables(state, state->first_block); prune_block_variables(state, state->first_block);
#if 1
prune_unused_phis(state);
#endif
} }
@ -11198,6 +11342,15 @@ static void insert_copies_to_phi(struct compile_state *state)
unuse_triple(val, phi); unuse_triple(val, phi);
use_triple(move, phi); use_triple(move, phi);
/* Walk up the dominator tree until I have found the appropriate block */
while(eblock && !tdominates(state, val, eblock->last)) {
eblock = eblock->idom;
}
if (!eblock) {
internal_error(state, phi, "Cannot find block dominated by %p",
val);
}
/* Walk through the block backwards to find /* Walk through the block backwards to find
* an appropriate location for the OP_COPY. * an appropriate location for the OP_COPY.
*/ */
@ -11589,6 +11742,8 @@ static int count_triples(struct compile_state *state)
} while (ins != first); } while (ins != first);
return triples; return triples;
} }
struct dead_triple { struct dead_triple {
struct triple *triple; struct triple *triple;
struct dead_triple *work_next; struct dead_triple *work_next;
@ -14761,21 +14916,40 @@ static void verify_domination(struct compile_state *state)
ins = first; ins = first;
do { do {
for(set = ins->use; set; set = set->next) { for(set = ins->use; set; set = set->next) {
struct triple **expr; struct triple **slot;
if (set->member->op == OP_PHI) { struct triple *use_point;
continue; int i, zrhs;
} use_point = 0;
/* See if the use is on the righ hand side */ zrhs = TRIPLE_RHS(ins->sizes);
expr = triple_rhs(state, set->member, 0); slot = &RHS(set->member, 0);
for(; expr ; expr = triple_rhs(state, set->member, expr)) { /* See if the use is on the right hand side */
if (*expr == ins) { for(i = 0; i < zrhs; i++) {
if (slot[i] == ins) {
break; break;
} }
} }
if (expr && if (i < zrhs) {
!tdominates(state, ins, set->member)) { use_point = set->member;
if (set->member->op == OP_PHI) {
struct block_set *bset;
int edge;
bset = set->member->u.block->use;
for(edge = 0; bset && (edge < i); edge++) {
bset = bset->next;
}
if (!bset) {
internal_error(state, set->member, internal_error(state, set->member,
"non dominated rhs use?"); "no edge for phi rhs %d\n", i);
}
use_point = bset->member->last;
}
}
if (use_point &&
!tdominates(state, ins, use_point)) {
internal_warning(state, ins,
"ins does not dominate rhs use");
internal_error(state, use_point,
"non dominated rhs use point?");
} }
} }
ins = ins->next; ins = ins->next;

View File

@ -0,0 +1,18 @@
static void main(void)
{
unsigned min;
int value, latency;
latency = -2;
if (latency > (((min) >> 8) & 0xff)) {
value = 0xa;
}
if (value < 0) return;
((min) = (((min) & ~0xff)));
}

View File

@ -0,0 +1,10 @@
static void main(void)
{
volatile unsigned long *val = (volatile unsigned long *)0x1234;
int i;
if (val[0] > 25) {
i = 7;
}
val[1] = i;
}

View File

@ -0,0 +1,24 @@
static void main(void)
{
static const int sdivisor = 20;
const int *pdivisor;
unsigned rdpreamble;
unsigned divisor;
pdivisor = &sdivisor;
divisor = *pdivisor;
rdpreamble = 0;
if (divisor == 20) {
rdpreamble = 18;
}
else {
if (divisor == 15) {
rdpreamble = 16;
}
else {
if (divisor == 12) {
rdpreamble = 15;
}
}
}
}

View File

@ -0,0 +1,43 @@
static void spd_enable_refresh(void)
{
/*
* Effects: Uses serial presence detect to set the
* refresh rate in the DRAMC register.
* see spd_set_dramc for the other values.
* FIXME: Check for illegal/unsupported ram configurations and abort
*/
static const unsigned char refresh_rates[] = {
0x01, /* Normal 15.625 us -> 15.6 us */
0x05, /* Reduced(.25X) 3.9 us -> 7.8 us */
0x05, /* Reduced(.5X) 7.8 us -> 7.8 us */
0x02, /* Extended(2x) 31.3 us -> 31.2 us */
0x03, /* Extended(4x) 62.5 us -> 62.4 us */
0x04, /* Extended(8x) 125 us -> 124.8 us */
};
/* Find the first dimm and assume the rest are the same */
int byte;
unsigned device;
unsigned refresh_rate;
byte = -1;
device = 0x50;
while ((byte < 0) && (device <= 0x57)) {
byte = __builtin_inl(device);
device += 1;
}
if (byte < 0) {
/* We couldn't find anything we must have no memory */
while(1);
}
byte &= 0x7f;
/* Default refresh rate be conservative */
refresh_rate = 5;
/* see if the ram refresh is a supported one */
if (byte < 6) {
refresh_rate = refresh_rates[byte];
}
byte = __builtin_inb(0x57);
byte &= 0xf8;
byte |= refresh_rate;
__builtin_outb(byte, 0x57);
}