Line 26... |
Line 26... |
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "cuc.h"
|
#include "cuc.h"
|
#include "insn.h"
|
#include "insn.h"
|
#include "profiler.h"
|
#include "profiler.h"
|
#include "opcode/or32.h"
|
#include "opcode/or32.h"
|
|
#include "parse.h"
|
|
|
FILE *flog;
|
FILE *flog;
|
int cuc_debug = 0;
|
int cuc_debug = 0;
|
|
|
/* Last used registers by software convention */
|
/* Last used registers by software convention */
|
Line 38... |
Line 39... |
1, 1, 0, 1, 0, 1, 0, 1,
|
1, 1, 0, 1, 0, 1, 0, 1,
|
0, 1, 0, 1, 0, 1, 0, 1,
|
0, 1, 0, 1, 0, 1, 0, 1,
|
0, 1, 0, 1, 0, 1, 0, 1,
|
0, 1, 0, 1, 0, 1, 0, 1,
|
1, 1};
|
1, 1};
|
|
|
/* Prints out instructions */
|
|
void print_insns (cuc_insn *insn, int ninsn, int verbose)
|
|
{
|
|
int i, j;
|
|
for (i = 0; i < ninsn; i++) {
|
|
dep_list *l = insn[i].dep;
|
|
printf ("%4x%c %-4s ", i, insn[i].index >= 0 ? ':' : '?', cuc_insn_name (&insn[i]));
|
|
if (verbose) {
|
|
printf ("%-20s insn = %08x, index = %i, type = %04x ",
|
|
insn[i].disasm, insn[i].insn, insn[i].index, insn[i].type);
|
|
} else printf ("type = %04x ", insn[i].type);
|
|
for (j = 0; j < MAX_OPERANDS; j++) {
|
|
if (insn[i].opt[j] & OPT_DEST) printf ("*");
|
|
switch (insn[i].opt[j] & ~OPT_DEST) {
|
|
case OPT_NONE: break;
|
|
case OPT_CONST: printf ("0x%08x, ", insn[i].op[j]); break;
|
|
case OPT_JUMP: printf ("J%x ", insn[i].op[j]); break;
|
|
case OPT_REGISTER: printf ("r%i, ", insn[i].op[j]); break;
|
|
case OPT_REF: printf ("[%x.%x], ", REF_BB(insn[i].op[j]), REF_I(insn[i].op[j])); break;
|
|
case OPT_BB: printf ("BB%x, ", insn[i].op[j]); break;
|
|
case OPT_LRBB: printf ("LRBB, "); break;
|
|
default:
|
|
fprintf (stderr, "Invalid operand type %s(%x.%x) = %x\n",
|
|
cuc_insn_name (&insn[i]), i, j, insn[i].opt[j]);
|
|
assert (0);
|
|
}
|
|
}
|
|
if (l) {
|
|
printf ("\n\tdep:");
|
|
while (l) {
|
|
printf (" [%x.%x],", REF_BB (l->ref), REF_I (l->ref));
|
|
l = l->next;
|
|
}
|
|
}
|
|
printf ("\n");
|
|
}
|
|
}
|
|
|
|
void add_dep (dep_list **list, int dep)
|
|
{
|
|
dep_list *ndep;
|
|
dep_list **tmp = list;
|
|
|
|
while (*tmp) {
|
|
if ((*tmp)->ref == dep) return; /* already there */
|
|
tmp = &((*tmp)->next);
|
|
}
|
|
ndep = (dep_list *)malloc (sizeof (dep_list));
|
|
ndep->ref = dep;
|
|
ndep->next = NULL;
|
|
*tmp = ndep;
|
|
}
|
|
|
|
void dispose_list (dep_list **list)
|
|
{
|
|
while (*list) {
|
|
dep_list *tmp = *list;
|
|
*list = tmp->next;
|
|
free (tmp);
|
|
}
|
|
}
|
|
|
|
void add_data_dep (cuc_func *f)
|
|
{
|
|
int b, i, j;
|
|
dep_list *tmp;
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
cuc_insn *insn = f->bb[b].insn;
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
for (j = 0; j < MAX_OPERANDS; j++) {
|
|
fflush (stdout);
|
|
if (insn[i].opt[j] & OPT_REF) {
|
|
/* Copy list from predecessor */
|
|
dep_list *l = f->INSN(insn[i].op[j]).dep;
|
|
while (l) {
|
|
add_dep (&insn[i].dep, l->ref);
|
|
l = l->next;
|
|
}
|
|
/* add predecessor */
|
|
add_dep (&insn[i].dep, insn[i].op[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* returns nonzero, if instruction was simplified */
|
|
int apply_edge_condition (cuc_insn *ii)
|
|
{
|
|
unsigned int c = ii->op[2];
|
|
|
|
if (ii->index == II_AND) {
|
|
if (ii->opt[2] & OPT_CONST && c == 0) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = 0; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
}
|
|
} else if (ii->index == II_OR) {
|
|
if (ii->opt[2] & OPT_CONST && c == 0xffffffff) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = c; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
}
|
|
} else if (ii->index == II_SUB) {
|
|
if (ii->opt[1] == ii->opt[2] && ii->op[1] == ii->op[2]) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = 0; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
}
|
|
} else if (ii->index == II_MUL) {
|
|
if (ii->opt[2] & OPT_CONST && c == 0) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = 0; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
} else
|
|
if (ii->opt[2] & OPT_CONST && c == 1) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = c; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
} else
|
|
if (ii->opt[2] & OPT_CONST && c == 0xffffffff) {
|
|
change_insn_type (ii, II_SUB);
|
|
ii->op[2] = ii->op[1]; ii->opt[2] = ii->opt[1];
|
|
ii->op[1] = 0; ii->opt[1] = OPT_CONST;
|
|
return 1;
|
|
}
|
|
} else if (ii->index == II_SRL) {
|
|
if (ii->opt[2] & OPT_CONST && c == 0) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = c; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
} else if (ii->opt[2] & OPT_CONST && c >= 32) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = 0; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
}
|
|
} else if (ii->index == II_SLL) {
|
|
if (ii->opt[2] & OPT_CONST && c == 0) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = c; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
} else if (ii->opt[2] & OPT_CONST && c >= 32) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = 0; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
}
|
|
} else if (ii->index == II_SRA) {
|
|
if (ii->opt[2] & OPT_CONST && c == 0) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[1] = c; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
return 1;
|
|
}
|
|
} else if (ii->index == II_CMOV) {
|
|
if (ii->opt[1] == ii->opt[2] && ii->op[1] == ii->op[2]) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
ii->opt[3] = OPT_NONE;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Optimizes dataflow tree */
|
|
void optimize_tree (cuc_func *f)
|
|
{
|
|
int b, i, j;
|
|
int modified;
|
|
|
|
do {
|
|
modified = 0;
|
|
for (b = 0; b < f->num_bb; b++) if (!(f->bb[b].type & BB_DEAD)) {
|
|
for (i = 0; i < f->bb[b].ninsn; i++) {
|
|
cuc_insn *ii = &f->bb[b].insn[i];
|
|
/* We tend to have the third parameter const if instruction is cumutative */
|
|
if ((ii->opt[1] & OPT_CONST) && !(ii->opt[2] & OPT_CONST)
|
|
&& known[ii->index].comutative) {
|
|
unsigned long t = ii->opt[1];
|
|
ii->opt[1] = ii->opt[2];
|
|
ii->opt[2] = t;
|
|
t = ii->op[1];
|
|
ii->op[1] = ii->op[2];
|
|
ii->op[2] = t;
|
|
modified = 1; cucdebug (2, "%08x:<>\n", REF(b, i));
|
|
}
|
|
|
|
/* Try to do the promotion */
|
|
/* We have two consecutive expressions, containing constants,
|
|
* if previous is a simple expression we can handle it simply: */
|
|
for (j = 0; j < MAX_OPERANDS; j++)
|
|
if (ii->opt[j] & OPT_REF) {
|
|
cuc_insn *t = &f->INSN(ii->op[j]);
|
|
if (f->INSN(ii->op[j]).index == II_ADD
|
|
&& f->INSN(ii->op[j]).opt[2] & OPT_CONST
|
|
&& f->INSN(ii->op[j]).op[2] == 0
|
|
&& !(ii->type & IT_MEMORY && t->type & IT_MEMADD)
|
|
&& !(ii->type & IT_BRANCH) && !(t->type & IT_COND)) {
|
|
/* do not promote through add-mem, and branches */
|
|
modified = 1; cucdebug (2, "%8x:promote%i %8x %8x\n", REF (b, i), j, ii->op[j], t->op[1]);
|
|
ii->op[j] = t->op[1]; ii->opt[j] = t->opt[1];
|
|
}
|
|
}
|
|
|
|
/* In case of x = cmov x, y; or x = cmov y, x; we have
|
|
asynchroneous loop -> remove it */
|
|
if (ii->index == II_CMOV) {
|
|
int f = 0;
|
|
if ((ii->opt[1] & OPT_REF) && ii->op[1] == REF (b, i)) f = 1;
|
|
if ((ii->opt[2] & OPT_REF) && ii->op[2] == REF (b, i)) f = 2;
|
|
if (ii->opt[1] == ii->opt[2] && ii->op[1] == ii->op[2]) f = 2;
|
|
if (f) {
|
|
change_insn_type (ii, II_ADD);
|
|
cucdebug (2, "%8x:cmov %i\n", REF(b, i), f);
|
|
ii->opt[f] = OPT_CONST;
|
|
ii->op[f] = 0;
|
|
ii->opt[3] = OPT_NONE;
|
|
modified = 1;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Do nothing to volatile instructions */
|
|
if (ii->type & IT_VOLATILE) continue;
|
|
|
|
/* Check whether we can simplify the instruction */
|
|
if (apply_edge_condition (ii)) {
|
|
modified = 1;
|
|
continue;
|
|
}
|
|
/* We cannot do anything more if at least one is not constant */
|
|
if (!(ii->opt[2] & OPT_CONST)) continue;
|
|
|
|
if (ii->opt[1] & OPT_CONST) { /* We have constant expression */
|
|
unsigned long value;
|
|
int ok = 1;
|
|
/* Was constant expression already? */
|
|
if (ii->index == II_ADD && !ii->op[2]) continue;
|
|
|
|
if (ii->index == II_ADD) value = ii->op[1] + ii->op[2];
|
|
else if (ii->index == II_SUB) value = ii->op[1] - ii->op[2];
|
|
else if (ii->index == II_SLL) value = ii->op[1] << ii->op[2];
|
|
else if (ii->index == II_SRL) value = ii->op[1] >> ii->op[2];
|
|
else if (ii->index == II_MUL) value = ii->op[1] * ii->op[2];
|
|
else if (ii->index == II_OR) value = ii->op[1] | ii->op[2];
|
|
else if (ii->index == II_XOR) value = ii->op[1] ^ ii->op[2];
|
|
else if (ii->index == II_AND) value = ii->op[1] & ii->op[2];
|
|
else ok = 0;
|
|
if (ok) {
|
|
change_insn_type (ii, II_ADD);
|
|
ii->op[0] = -1; ii->opt[0] = OPT_REGISTER | OPT_DEST;
|
|
ii->op[1] = value; ii->opt[1] = OPT_CONST;
|
|
ii->op[2] = 0; ii->opt[2] = OPT_CONST;
|
|
modified = 1; cucdebug (2, "%8x:const\n", REF (b, i));
|
|
}
|
|
} else if (ii->opt[1] & OPT_REF) {
|
|
cuc_insn *prev = &f->INSN(ii->op[1]);
|
|
/* Is this just a link? */
|
|
if (ii->index == II_ADD
|
|
&& !(ii->type & IT_MEMADD) && ii->op[2] == 0) {
|
|
int b1, i1, j1;
|
|
cucdebug (2, "%8x:link %8x: ", REF(b, i), ii->op[1]);
|
|
for (b1 = 0; b1 < f->num_bb; b1++) if (!(f->bb[b1].type & BB_DEAD))
|
|
for (i1 = 0; i1 < f->bb[b1].ninsn; i1++)
|
|
for (j1 = 0; j1 < MAX_OPERANDS; j1++)
|
|
if ((f->bb[b1].insn[i1].opt[j1] & OPT_REF)
|
|
&& f->bb[b1].insn[i1].op[j1] == REF(b, i)) {
|
|
cucdebug (2, "%x ", REF (b1, i1));
|
|
f->bb[b1].insn[i1].op[j1] = ii->op[1];
|
|
}
|
|
cucdebug (2, "\n");
|
|
change_insn_type (ii, II_NOP);
|
|
} else if (prev->opt[2] & OPT_CONST) {
|
|
/* Handle some common cases */
|
|
/* add - add joining */
|
|
if (ii->index == II_ADD && prev->index == II_ADD) {
|
|
ii->op[1] = prev->op[1]; ii->opt[1] = prev->opt[1];
|
|
ii->op[2] += prev->op[2];
|
|
modified = 1; cucdebug (2, "%8x: add-add\n", REF(b, i));
|
|
} else /* add - sub joining */
|
|
if (ii->index == II_ADD && prev->index == II_SUB) {
|
|
change_insn_type (&insn[i], II_SUB);
|
|
ii->op[1] = prev->op[1]; ii->opt[1] = prev->opt[1];
|
|
ii->op[2] += prev->op[2];
|
|
modified = 1; cucdebug (2, "%8x: add-sub\n", REF(b, i));
|
|
} else /* sub - add joining */
|
|
if (ii->index == II_SUB && prev->index == II_ADD) {
|
|
ii->op[1] = prev->op[1]; ii->opt[1] = prev->opt[1];
|
|
ii->op[2] += prev->op[2];
|
|
modified = 1; cucdebug (2, "%8x: sub-add\n", REF(b, i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (modified);
|
|
}
|
|
|
|
/* Remove nop instructions */
|
|
void remove_nops (cuc_func *f)
|
|
{
|
|
int b;
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
int c, d = 0, i, j;
|
|
cuc_insn *insn = f->bb[b].insn;
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
if (insn[i].index != II_NOP) {
|
|
reloc [i] = d;
|
|
insn[d++] = insn[i];
|
|
} else {
|
|
reloc[i] = d; /* For jumps only */
|
|
}
|
|
f->bb[b].ninsn = d;
|
|
|
|
/* Relocate references from all basic blocks */
|
|
for (c = 0; c < f->num_bb; c++)
|
|
for (i = 0; i < f->bb[c].ninsn; i++) {
|
|
dep_list *d = f->bb[c].insn[i].dep;
|
|
for (j = 0; j < MAX_OPERANDS; j++)
|
|
if ((f->bb[c].insn[i].opt[j] & OPT_REF)
|
|
&& REF_BB(f->bb[c].insn[i].op[j]) == b)
|
|
f->bb[c].insn[i].op[j] = REF (b, reloc[REF_I (f->bb[c].insn[i].op[j])]);
|
|
|
|
while (d) {
|
|
if (REF_BB(d->ref) == b) d->ref = REF (b, reloc[REF_I (d->ref)]);
|
|
d = d->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Remove unused assignments */
|
|
void remove_dead (cuc_func *f)
|
|
{
|
|
int b, i, j;
|
|
for (b = 0; b < f->num_bb; b++)
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
if (!(f->bb[b].insn[i].type & (IT_VOLATILE | IT_OUTPUT)))
|
|
f->bb[b].insn[i].type |= IT_UNUSED;
|
|
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
for (j = 0; j < MAX_OPERANDS; j++)
|
|
if (f->bb[b].insn[i].opt[j] & OPT_REF) {
|
|
f->INSN(f->bb[b].insn[i].op[j]).type &= ~IT_UNUSED;
|
|
}
|
|
}
|
|
|
|
for (b = 0; b < f->num_bb; b++)
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
if (f->bb[b].insn[i].type & IT_UNUSED) {
|
|
change_insn_type (&f->bb[b].insn[i], II_NOP);
|
|
}
|
|
|
|
remove_nops (f);
|
|
}
|
|
|
|
/* Removes trivial register assignments */
|
|
void remove_trivial_regs (cuc_func *f)
|
|
{
|
|
int b, i;
|
|
for (i = 0; i < MAX_REGS; i++) f->saved_regs[i] = call_saved[i];
|
|
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
cuc_insn *insn = f->bb[b].insn;
|
|
for (i = 0; i < f->bb[b].ninsn; i++) {
|
|
if (insn[i].index == II_ADD
|
|
&& insn[i].opt[0] & OPT_REGISTER
|
|
&& insn[i].opt[1] & OPT_REGISTER && insn[i].op[0] == insn[i].op[1]
|
|
&& insn[i].opt[2] & OPT_CONST && insn[i].op[2] == 0) {
|
|
if (insn[i].type & IT_OUTPUT) f->saved_regs[insn[i].op[0]] = 1;
|
|
change_insn_type (&insn[i], II_NOP);
|
|
}
|
|
}
|
|
}
|
|
if (cuc_debug >= 2) {
|
|
printf ("saved regs ");
|
|
for (i = 0; i < MAX_REGS; i++) printf ("%i:%i ", i, f->saved_regs[i]);
|
|
printf ("\n");
|
|
}
|
|
remove_nops (f);
|
|
}
|
|
|
|
/* Determine inputs and outputs */
|
|
void set_io (cuc_func *f)
|
|
{
|
|
int b, i, j;
|
|
/* Determine register usage */
|
|
for (i = 0; i < MAX_REGS; i++) {
|
|
f->lur[i] = -1;
|
|
f->used_regs[i] = 0;
|
|
}
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
for (j = 0; j < MAX_OPERANDS; j++)
|
|
if (f->bb[b].insn[i].opt[j] & OPT_REGISTER && f->bb[b].insn[i].op[j] >= 0)
|
|
if (f->bb[b].insn[i].opt[j] & OPT_DEST) f->lur[f->bb[b].insn[i].op[j]] = REF (b, i);
|
|
else f->used_regs[f->bb[b].insn[i].op[j]] = 1;
|
|
}
|
|
}
|
|
|
|
/* relocate all accesses inside of BB b to back/fwd */
|
|
static void relocate_bb (cuc_bb *bb, int b, int back, int fwd)
|
|
{
|
|
int i, j;
|
|
for (i = 0; i < bb->ninsn; i++)
|
|
for (j = 0; j < MAX_OPERANDS; j++)
|
|
if (bb->insn[i].opt[j] & OPT_REF
|
|
&& REF_BB (bb->insn[i].op[j]) == b) {
|
|
int t = REF_I (bb->insn[i].op[j]);
|
|
if (t < i) bb->insn[i].op[j] = REF (back, t);
|
|
else bb->insn[i].op[j] = REF (fwd, t);
|
|
}
|
|
}
|
|
|
|
/* split the BB, based on the group numbers in .tmp */
|
|
void expand_bb (cuc_func *f, int b)
|
|
{
|
|
int n = f->num_bb;
|
|
int mg = 0;
|
|
int b1, i, j;
|
|
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
if (f->bb[b].insn[i].tmp > mg) mg = f->bb[b].insn[i].tmp;
|
|
|
|
/* Create copies */
|
|
for (b1 = 1; b1 <= mg; b1++) {
|
|
assert (f->num_bb < MAX_BB);
|
|
cpy_bb (&f->bb[f->num_bb], &f->bb[b]);
|
|
f->num_bb++;
|
|
}
|
|
|
|
/* Relocate */
|
|
for (b1 = 0; b1 < f->num_bb; b1++)
|
|
for (i = 0; i < f->bb[b1].ninsn; i++) {
|
|
dep_list *d = f->bb[b1].insn[i].dep;
|
|
for (j = 0; j < MAX_OPERANDS; j++)
|
|
if (f->bb[b1].insn[i].opt[j] & OPT_REF) {
|
|
int t = f->bb[b1].insn[i].op[j];
|
|
if (REF_BB(t) == b && f->INSN(t).tmp != 0)
|
|
f->bb[b1].insn[i].op[j] = REF (n + f->INSN(t).tmp - 1, REF_I(t));
|
|
}
|
|
while (d) {
|
|
if (REF_BB (d->ref) == b && f->INSN(d->ref).tmp != 0)
|
|
d->ref = REF (n + f->INSN(d->ref).tmp - 1, REF_I(d->ref));
|
|
d = d->next;
|
|
}
|
|
}
|
|
|
|
/* Delete unused instructions */
|
|
for (j = 0; j <= mg; j++) {
|
|
if (j == 0) b1 = b;
|
|
else b1 = n + j - 1;
|
|
for (i = 0; i < f->bb[b1].ninsn; i++) {
|
|
if (f->bb[b1].insn[i].tmp != j)
|
|
change_insn_type (&f->bb[b1].insn[i], II_NOP);
|
|
f->bb[b1].insn[i].tmp = 0;
|
|
}
|
|
if (j < mg) {
|
|
f->bb[b1].next[0] = n + j;
|
|
f->bb[b1].next[1] = -1;
|
|
f->bb[n + j].prev[0] = b1;
|
|
f->bb[n + j].prev[1] = -1;
|
|
} else {
|
|
i = f->bb[b1].next[0];
|
|
f->bb[n + j].prev[0] = j == 1 ? b : b1 - 1;
|
|
f->bb[n + j].prev[1] = -1;
|
|
if (i >= 0) {
|
|
if (f->bb[i].prev[0] == b) f->bb[i].prev[0] = b1;
|
|
if (f->bb[i].prev[1] == b) f->bb[i].prev[1] = b1;
|
|
}
|
|
i = f->bb[b1].next[1];
|
|
if (i >= 0) {
|
|
if (f->bb[i].prev[0] == b) f->bb[i].prev[0] = b1;
|
|
if (f->bb[i].prev[1] == b) f->bb[i].prev[1] = b1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Latch outputs in loops */
|
|
void add_latches (cuc_func *f)
|
|
{
|
|
int b, i, j;
|
|
|
|
//print_cuc_bb (f, "ADD_LATCHES a");
|
|
/* Cuts the tree and marks registers */
|
|
mark_cut (f);
|
|
|
|
/* Split BBs with more than one group */
|
|
for (b = 0; b < f->num_bb; b++) expand_bb (f, b);
|
|
remove_nops (f);
|
|
//print_cuc_bb (f, "ADD_LATCHES 0");
|
|
|
|
/* Convert accesses in BB_INLOOP type block to latched */
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
int j;
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
for (j = 0; j < MAX_OPERANDS; j++) if (f->bb[b].insn[i].opt[j] == OPT_REF) {
|
|
int t = f->bb[b].insn[i].op[j];
|
|
/* If we are pointing to a INLOOP block from outside, or forward
|
|
(= previous loop iteration) we must register that data */
|
|
if ((f->bb[REF_BB(t)].type & BB_INLOOP || no_multicycle)
|
|
&& !(f->INSN(t).type & (IT_BRANCH | IT_COND))
|
|
&& (REF_BB(t) != b || REF_I(t) >= i)) {
|
|
f->INSN(t).type |= IT_LATCHED;
|
|
}
|
|
}
|
|
}
|
|
//print_cuc_bb (f, "ADD_LATCHES 1");
|
|
|
|
/* Add latches at the end of blocks as needed */
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
int nreg = 0;
|
|
cuc_insn *insn;
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
if (f->bb[b].insn[i].type & IT_LATCHED) nreg++;
|
|
if (nreg) {
|
|
insn = (cuc_insn *) malloc (sizeof (cuc_insn) * (f->bb[b].ninsn + nreg));
|
|
j = 0;
|
|
for (i = 0; i < f->bb[b].ninsn; i++) {
|
|
insn[i] = f->bb[b].insn[i];
|
|
if (insn[i].type & IT_LATCHED) {
|
|
cuc_insn *ii = &insn[f->bb[b].ninsn + j++];
|
|
change_insn_type (ii, II_REG);
|
|
ii->op[0] = -1; ii->opt[0] = OPT_DEST | OPT_REGISTER;
|
|
ii->op[1] = REF (b, i); ii->opt[1] = OPT_REF;
|
|
ii->opt[2] = ii->opt[3] = OPT_NONE;
|
|
ii->dep = NULL;
|
|
ii->type = IT_VOLATILE;
|
|
sprintf (ii->disasm, "reg %i_%i", b, i);
|
|
}
|
|
}
|
|
f->bb[b].ninsn += nreg;
|
|
free (f->bb[b].insn);
|
|
f->bb[b].insn = insn;
|
|
}
|
|
}
|
|
//print_cuc_bb (f, "ADD_LATCHES 2");
|
|
|
|
/* Repair references */
|
|
for (b = 0; b < f->num_bb; b++)
|
|
for (i = 0; i < f->bb[b].ninsn; i++)
|
|
for (j = 0; j < MAX_OPERANDS; j++)
|
|
/* If destination instruction is latched, use register instead */
|
|
if (f->bb[b].insn[i].opt[j] == OPT_REF
|
|
&& f->INSN(f->bb[b].insn[i].op[j]).type & IT_LATCHED) {
|
|
int b1, i1;
|
|
b1 = REF_BB (f->bb[b].insn[i].op[j]);
|
|
//cucdebug (2, "%i.%i.%i %x\n", b, i, j, f->bb[b].insn[i].op[j]);
|
|
if (b1 != b || REF_I(f->bb[b].insn[i].op[j]) >= i) {
|
|
for (i1 = f->bb[b1].ninsn - 1; i1 >= 0; i1--) {
|
|
assert (f->bb[b1].insn[i1].index == II_REG);
|
|
if (f->bb[b1].insn[i1].op[1] == f->bb[b].insn[i].op[j]) {
|
|
f->bb[b].insn[i].op[j] = REF (b1, i1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cuc_timings *preunroll_bb (char *bb_filename, cuc_func *f, cuc_timings *timings, int b, int i, int j)
|
cuc_timings *preunroll_bb (char *bb_filename, cuc_func *f, cuc_timings *timings, int b, int i, int j)
|
{
|
{
|
cuc_func *func;
|
cuc_func *func;
|
cucdebug (2, "BB%i unroll %i times preroll %i times\n", b, j, i);
|
cucdebug (2, "BB%i unroll %i times preroll %i times\n", b, j, i);
|
func = preunroll_loop (f, b, i, j, bb_filename);
|
func = preunroll_loop (f, b, i, j, bb_filename);
|
Line 638... |
Line 69... |
remove_trivial_regs (func);
|
remove_trivial_regs (func);
|
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_TRIVIAL");
|
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_TRIVIAL");
|
add_latches (func);
|
add_latches (func);
|
if (cuc_debug >= 1) print_cuc_bb (func, "AFTER_LATCHES");
|
if (cuc_debug >= 1) print_cuc_bb (func, "AFTER_LATCHES");
|
set_io (func);
|
set_io (func);
|
add_memory_dep (func, memory_order);
|
add_memory_dep (func, func->memory_order);
|
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_MEMORY_DEP");
|
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_MEMORY_DEP");
|
add_data_dep (func);
|
add_data_dep (func);
|
if (cuc_debug >= 8) print_cuc_bb (func, "AFTER_DATA_DEP");
|
if (cuc_debug >= 8) print_cuc_bb (func, "AFTER_DATA_DEP");
|
schedule_memory (func, memory_order);
|
schedule_memory (func, func->memory_order);
|
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_SCHEDULE_MEM");
|
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_SCHEDULE_MEM");
|
|
|
analyse_timings (func, timings);
|
analyse_timings (func, timings);
|
cucdebug (2, "new_time = %i, old_time = %i, size = %f\n",
|
cucdebug (2, "new_time = %i, old_time = %i, size = %f\n",
|
timings->new_time, func->orig_time, timings->size);
|
timings->new_time, func->orig_time, timings->size);
|
Line 667... |
Line 98... |
else if (a->new_time > b->new_time) return 1;
|
else if (a->new_time > b->new_time) return 1;
|
else return 0;
|
else return 0;
|
}
|
}
|
|
|
cuc_func *analyse_function (char *module_name, long orig_time,
|
cuc_func *analyse_function (char *module_name, long orig_time,
|
unsigned long start_addr, unsigned long end_addr)
|
unsigned long start_addr, unsigned long end_addr,
|
|
int memory_order)
|
{
|
{
|
cuc_timings timings;
|
cuc_timings timings;
|
cuc_func *func = (cuc_func *) malloc (sizeof (cuc_func));
|
cuc_func *func = (cuc_func *) malloc (sizeof (cuc_func));
|
cuc_func *saved;
|
cuc_func *saved;
|
int b, i, j;
|
int b, i, j;
|
Line 679... |
Line 111... |
char tmp2[256];
|
char tmp2[256];
|
|
|
func->orig_time = orig_time;
|
func->orig_time = orig_time;
|
func->start_addr = start_addr;
|
func->start_addr = start_addr;
|
func->end_addr = end_addr;
|
func->end_addr = end_addr;
|
|
func->memory_order = memory_order;
|
|
|
sprintf (tmp1, "%s.bin", module_name);
|
sprintf (tmp1, "%s.bin", module_name);
|
cucdebug (2, "Loading %s.bin\n", module_name);
|
cucdebug (2, "Loading %s.bin\n", module_name);
|
cuc_load (tmp1);
|
if (cuc_load (tmp1)) {
|
|
free (func);
|
|
return NULL;
|
|
}
|
|
|
log ("Detecting basic blocks\n");
|
log ("Detecting basic blocks\n");
|
detect_bb (func);
|
detect_bb (func);
|
if (cuc_debug >= 2) print_cuc_insns ("WITH_BB_LIMITS", 0);
|
if (cuc_debug >= 2) print_cuc_insns ("WITH_BB_LIMITS", 0);
|
|
|
//sprintf (tmp1, "%s.bin.mp", module_name);
|
//sprintf (tmp1, "%s.bin.mp", module_name);
|
sprintf (tmp2, "%s.bin.bb", module_name);
|
sprintf (tmp2, "%s.bin.bb", module_name);
|
generate_bb_seq (func, config.sim.mprof_fn, tmp2);
|
generate_bb_seq (func, config.sim.mprof_fn, tmp2);
|
|
log ("Assuming %i clk cycle load (%i cyc burst)\n", runtime.cuc.mdelay[0], runtime.cuc.mdelay[2]);
|
|
log ("Assuming %i clk cycle store (%i cyc burst)\n", runtime.cuc.mdelay[1], runtime.cuc.mdelay[3]);
|
|
|
build_bb (func);
|
build_bb (func);
|
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_BUILD_BB");
|
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_BUILD_BB");
|
reg_dep (func);
|
reg_dep (func);
|
|
|
Line 719... |
Line 157... |
remove_dead (func);
|
remove_dead (func);
|
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD");
|
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD");
|
remove_trivial_regs (func);
|
remove_trivial_regs (func);
|
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_TRIVIAL");
|
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_TRIVIAL");
|
|
|
|
#if 0
|
csm (func);
|
csm (func);
|
|
#endif
|
assert (saved = dup_func (func));
|
assert (saved = dup_func (func));
|
|
|
timings.preroll = timings.unroll = 1;
|
timings.preroll = timings.unroll = 1;
|
timings.nshared = 0;
|
timings.nshared = 0;
|
add_latches (func);
|
add_latches (func);
|
set_io (func);
|
set_io (func);
|
|
|
if (cuc_debug >= 1) print_cuc_bb (func, "AFTER_LATCHES");
|
if (cuc_debug >= 1) print_cuc_bb (func, "AFTER_LATCHES");
|
analyse_timings (func, &timings);
|
analyse_timings (func, &timings);
|
add_memory_dep (func, memory_order);
|
add_memory_dep (func, func->memory_order);
|
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_MEMORY_DEP");
|
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_MEMORY_DEP");
|
add_data_dep (func);
|
add_data_dep (func);
|
if (cuc_debug >= 8) print_cuc_bb (func, "AFTER_DATA_DEP");
|
if (cuc_debug >= 8) print_cuc_bb (func, "AFTER_DATA_DEP");
|
schedule_memory (func, memory_order);
|
schedule_memory (func, memory_order);
|
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_SCHEDULE_MEM");
|
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_SCHEDULE_MEM");
|
Line 750... |
Line 190... |
cuc_timings t[MAX_UNROLL * MAX_PREROLL];
|
cuc_timings t[MAX_UNROLL * MAX_PREROLL];
|
cuc_timings *ut;
|
cuc_timings *ut;
|
cuc_timings *cut = &t[0];
|
cuc_timings *cut = &t[0];
|
int nt = 1;
|
int nt = 1;
|
double csize;
|
double csize;
|
|
saved->bb[b].selected_tim = -1;
|
|
|
/* Is it a loop? */
|
/* Is it a loop? */
|
if (saved->bb[b].next[0] != b && saved->bb[b].next[1] != b) continue;
|
if (saved->bb[b].next[0] != b && saved->bb[b].next[1] != b) continue;
|
t[0] = timings;
|
t[0] = timings;
|
t[0].b = b;
|
t[0].b = b;
|
Line 847... |
Line 288... |
}
|
}
|
#endif
|
#endif
|
return saved;
|
return saved;
|
}
|
}
|
|
|
void options_cmd (cuc_func *f, char *name)
|
/* Utility option formatting functions */
|
|
static const char *option_char = "?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
/*static */char *gen_option (char *s, int bb_no, int f_opt)
|
|
{
|
|
if (bb_no >= 0) sprintf (s, "%i", bb_no);
|
|
assert (f_opt <= strlen (option_char));
|
|
sprintf (s, "%s%c", s, option_char[f_opt]);
|
|
return s;
|
|
}
|
|
|
|
/*static */void print_option (int bb_no, int f_opt)
|
|
{
|
|
char tmp1[10];
|
|
char tmp2[10];
|
|
sprintf (tmp2, "%s", gen_option (tmp1, bb_no, f_opt));
|
|
printf ("%3s", tmp2);
|
|
}
|
|
|
|
static char *format_func_options (char *s, cuc_func *f)
|
|
{
|
|
int b, first = 1;
|
|
*s = '\0';
|
|
for (b = 0; b < f->num_bb; b++)
|
|
if (f->bb[b].selected_tim >= 0) {
|
|
char tmp[10];
|
|
sprintf (s, "%s%s%s", s, first ? "" : ",", gen_option (tmp, b, f->bb[b].selected_tim));
|
|
first = 0;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
static void options_cmd (int func_no, cuc_func *f)
|
{
|
{
|
int b, i;
|
int b, i;
|
printf ("%-12s :pre%i,un%i,sha%i: time = %i cyc; size = %.f gates (old time = %i)\n", name,
|
char tmp[20];
|
f->timings.preroll, f->timings.unroll, f->timings.nshared,
|
char *name = prof_func[func_no].name;
|
f->timings.new_time, f->timings.size, f->orig_time);
|
printf ("--------------------------------------------------------\n");
|
|
printf ("|%-16s|pre/unrolled|shared| time | gates | old_time = %i \n",
|
|
strstrip (tmp, name, 16), f->orig_time);
|
|
printf ("| BASE |%4i / %4i | %4i |%8i|%8.f|\n", 1, 1, 0,
|
|
f->timings.new_time, f->timings.size);
|
for (b = 0; b < f->num_bb; b++) {
|
for (b = 0; b < f->num_bb; b++) {
|
/* Print out results */
|
/* Print out results */
|
for (i = 0; i < f->bb[b].ntim; i++) {
|
for (i = 1; i < f->bb[b].ntim; i++) { /* First one is base option */
|
printf ("%-12sBB%-2i:pre%i,un%i,sha%i: time = %i cyc; size = %.f gates\n", name,
|
int time = f->bb[b].tim[i].new_time - f->timings.new_time;
|
f->bb[b].tim[i].b, f->bb[b].tim[i].preroll, f->bb[b].tim[i].unroll,
|
double size = f->bb[b].tim[i].size - f->timings.size;
|
f->bb[b].tim[i].nshared, f->bb[b].tim[i].new_time, f->bb[b].tim[i].size);
|
printf ("| ");
|
|
print_option (b, i);
|
|
printf (" |%4i / %4i | %4i |%+8i|%+8.f|\n",
|
|
f->bb[b].tim[i].preroll, f->bb[b].tim[i].unroll, f->bb[b].tim[i].nshared,
|
|
time, size);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Generates a function, based on specified parameters */
|
|
cuc_func *generate_function (cuc_func *rf, char *name)
|
|
{
|
|
int b, i, j;
|
|
char tmp[256];
|
|
cuc_timings tt;
|
|
cuc_func *f;
|
|
assert (f = dup_func (rf));
|
|
|
|
log ("Generating function %s.\n", name);
|
|
printf ("Generating function %s.\n", name);
|
|
|
|
print_cuc_bb (f, "BEFORE_GENERATE");
|
|
add_latches (f);
|
|
set_io (f);
|
|
if (cuc_debug >= 1) print_cuc_bb (f, "AFTER_LATCHES");
|
|
|
|
format_func_options (tmp, rf);
|
|
if (strlen (tmp)) printf ("Applying options: %s\n", tmp);
|
|
else printf ("Basic options.\n");
|
|
|
|
/* Generate function as specified by options */
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
cuc_timings *st;
|
|
if (rf->bb[b].selected_tim < 0) continue;
|
|
st = &rf->bb[b].tim[rf->bb[b].selected_tim];
|
|
sprintf (tmp, "%s.bin.bb", name);
|
|
preunroll_bb (&tmp[0], f, &tt, b, st->preroll, st->unroll);
|
|
if (cuc_debug >= 1) print_cuc_bb (f, "AFTER_PREUNROLL");
|
|
}
|
|
for (b = 0; b < f->num_bb; b++) {
|
|
cuc_timings *st;
|
|
if (rf->bb[b].selected_tim < 0) continue;
|
|
st = &rf->bb[b].tim[rf->bb[b].selected_tim];
|
|
if (!st->nshared) continue;
|
|
assert (0);
|
|
//csm_gen (f, rf, st->nshared, st->shared);
|
|
}
|
|
analyse_timings (f, &tt);
|
|
add_memory_dep (f, f->memory_order);
|
|
if (cuc_debug >= 7) print_cuc_bb (f, "AFTER_MEMORY_DEP");
|
|
add_data_dep (f);
|
|
if (cuc_debug >= 8) print_cuc_bb (f, "AFTER_DATA_DEP");
|
|
schedule_memory (f, f->memory_order);
|
|
if (cuc_debug >= 7) print_cuc_bb (f, "AFTER_SCHEDULE_MEM");
|
|
output_verilog (f, name);
|
|
return f;
|
|
}
|
|
|
|
/* Calculates required time, based on selected options */
|
|
int calc_cycles (cuc_func *f)
|
|
{
|
|
int b, i, ntime = f->timings.new_time;
|
|
for (b = 0; b < f->num_bb; b++)
|
|
if (f->bb[b].selected_tim >= 0) {
|
|
assert (f->bb[b].selected_tim < f->bb[b].ntim);
|
|
ntime += f->bb[b].tim[f->bb[b].selected_tim].new_time - f->timings.new_time;
|
|
}
|
|
return ntime;
|
}
|
}
|
|
|
|
/* Calculates required size, based on selected options */
|
|
double calc_size (cuc_func *f)
|
|
{
|
|
int b, i;
|
|
double size = f->timings.size;
|
|
for (b = 0; b < f->num_bb; b++)
|
|
if (f->bb[b].selected_tim >= 0) {
|
|
assert (f->bb[b].selected_tim < f->bb[b].ntim);
|
|
size += f->bb[b].tim[f->bb[b].selected_tim].size - f->timings.size;
|
}
|
}
|
|
return size;
|
}
|
}
|
|
|
/* Dumps specified function to file (hex) */
|
/* Dumps specified function to file (hex) */
|
unsigned long extract_function (char *out_fn, unsigned long start_addr)
|
unsigned long extract_function (char *out_fn, unsigned long start_addr)
|
{
|
{
|
Line 886... |
Line 441... |
fclose (fo);
|
fclose (fo);
|
return a - 4;
|
return a - 4;
|
}
|
}
|
|
|
static cuc_func *func[MAX_FUNCS];
|
static cuc_func *func[MAX_FUNCS];
|
|
static int func_v[MAX_FUNCS];
|
|
|
void main_cuc (char *filename)
|
void main_cuc (char *filename)
|
{
|
{
|
int i, j;
|
int i, j;
|
char tmp1[256];
|
char tmp1[256];
|
Line 899... |
Line 455... |
sprintf (tmp1, "%s.log", filename);
|
sprintf (tmp1, "%s.log", filename);
|
printf ("Analyzing. (log file \"%s\").\n", tmp1);
|
printf ("Analyzing. (log file \"%s\").\n", tmp1);
|
assert (flog = fopen (tmp1, "wt+"));
|
assert (flog = fopen (tmp1, "wt+"));
|
|
|
/* Loads in the specified timings table */
|
/* Loads in the specified timings table */
|
load_timing_table ("virtex.tim");
|
printf ("Using timings from \"%s\" at %s\n",config.cuc.timings_fn,
|
|
generate_time_pretty (tmp1, config.sim.clkcycle_ps));
|
|
load_timing_table (config.cuc.timings_fn);
|
|
runtime.cuc.cycle_duration = 1000. * config.sim.clkcycle_ps;
|
|
printf ("Multicycle logic %s, bursts %s, %s memory order.\n",
|
|
config.cuc.no_multicycle ? "OFF" : "ON", config.cuc.enable_bursts ? "ON" : "OFF",
|
|
config.cuc.memory_order == MO_NONE ? "no" : config.cuc.memory_order == MO_WEAK ? "weak" :
|
|
config.cuc.memory_order == MO_STRONG ? "strong" : "exact");
|
|
|
prof_set (1, 0);
|
prof_set (1, 0);
|
assert (prof_acquire (config.sim.prof_fn) == 0);
|
assert (prof_acquire (config.sim.prof_fn) == 0);
|
|
|
cycle_duration = 40.;
|
if (config.cuc.calling_convention)
|
|
printf ("Assuming OpenRISC standard calling convention.\n");
|
|
|
/* Try all functions except "total" */
|
/* Try all functions except "total" */
|
for (i = 0; i < prof_nfuncs - 1; i++) {
|
for (i = 0; i < prof_nfuncs - 1; i++) {
|
long orig_time;
|
long orig_time;
|
unsigned long start_addr, end_addr;
|
unsigned long start_addr, end_addr;
|
Line 918... |
Line 482... |
/* Extract the function from the binary */
|
/* Extract the function from the binary */
|
sprintf (tmp1, "%s.bin", prof_func[i].name);
|
sprintf (tmp1, "%s.bin", prof_func[i].name);
|
end_addr = extract_function (tmp1, start_addr);
|
end_addr = extract_function (tmp1, start_addr);
|
|
|
log ("Testing function %s (%08x - %08x)\n", prof_func[i].name, start_addr, end_addr);
|
log ("Testing function %s (%08x - %08x)\n", prof_func[i].name, start_addr, end_addr);
|
func[i] = analyse_function (prof_func[i].name, orig_time, start_addr, end_addr);
|
printf ("Testing function %s (%08x - %08x)\n", prof_func[i].name, start_addr, end_addr);
|
|
func[i] = analyse_function (prof_func[i].name, orig_time, start_addr,
|
|
end_addr, config.cuc.memory_order);
|
|
func_v[i] = 0;
|
}
|
}
|
|
|
while (1) {
|
while (1) {
|
char *s;
|
char *s;
|
printf ("(cuc) ");
|
printf ("(cuc) ");
|
Line 932... |
Line 499... |
*s = '\0';
|
*s = '\0';
|
|
|
if (strcmp (tmp1, "q") == 0 || strcmp (tmp1, "quit") == 0) {
|
if (strcmp (tmp1, "q") == 0 || strcmp (tmp1, "quit") == 0) {
|
break;
|
break;
|
} else if (strcmp (tmp1, "p") == 0 || strcmp (tmp1, "profile") == 0) {
|
} else if (strcmp (tmp1, "p") == 0 || strcmp (tmp1, "profile") == 0) {
|
printf ("----------------------------------------------------------------------------\n");
|
int ntime = 0;
|
printf ("|function name |addr |# calls |avg cycles | old% | impr. f. |\n");
|
int size = 0;
|
printf ("|-------------------------+--------+--------+------------+------+----------|\n");
|
printf ("-----------------------------------------------------------------------------\n");
|
|
printf ("|function name |calls|avg cycles |old%| max. f. | impr. f.| options |\n");
|
|
printf ("|--------------------+-----+------------+----+----------|---------+---------|\n");
|
for (j = 0; j < prof_nfuncs; j++) {
|
for (j = 0; j < prof_nfuncs; j++) {
|
int bestcyc = 0, besti = 0;
|
int bestcyc = 0, besti = 0;
|
|
char tmp[100];
|
for (i = 0; i < prof_nfuncs; i++)
|
for (i = 0; i < prof_nfuncs; i++)
|
if (prof_func[i].cum_cycles > bestcyc) {
|
if (prof_func[i].cum_cycles > bestcyc) {
|
bestcyc = prof_func[i].cum_cycles;
|
bestcyc = prof_func[i].cum_cycles;
|
besti = i;
|
besti = i;
|
}
|
}
|
i = besti;
|
i = besti;
|
printf ("| %-24s|%08X|%8i|%12.1f| %3.0f%% |",
|
printf ("|%-20s|%5i|%12.1f|%3.0f%%| ",
|
prof_func[i].name, prof_func[i].addr, prof_func[i].calls,
|
strstrip (tmp, prof_func[i].name, 20), prof_func[i].calls,
|
((double)prof_func[i].cum_cycles / prof_func[i].calls),
|
((double)prof_func[i].cum_cycles / prof_func[i].calls),
|
(100. * prof_func[i].cum_cycles / prof_cycles));
|
(100. * prof_func[i].cum_cycles / prof_cycles));
|
if (func[i]) {
|
if (func[i]) {
|
printf ("%9.2f |\n", 1.f * prof_func[i].cum_cycles / func[i]->timings.new_time);
|
double f = 1.0;
|
} else printf (" N/A |\n");
|
if (func_v[i]) {
|
prof_func[i].cum_cycles = -1;
|
int nt = calc_cycles (func[i]);
|
|
int s = calc_size (func[i]);
|
|
f = func[i]->orig_time / nt;
|
|
ntime += nt * func[i]->num_runs;
|
|
size += s;
|
|
} else ntime += prof_func[i].cum_cycles;
|
|
printf ("%8.1f |%8.1f | %-8s|\n", 1.f * prof_func[i].cum_cycles / func[i]->timings.new_time, f, format_func_options (tmp, func[i]));
|
|
} else {
|
|
printf (" N/A | N/A | |\n");
|
|
ntime += prof_func[i].cum_cycles;
|
|
}
|
|
prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
|
}
|
}
|
printf ("----------------------------------------------------------------------------\n");
|
for (i = 0; i < prof_nfuncs; i++)
|
printf ("Total %i functions, %i cycles.\n", prof_nfuncs, prof_cycles);
|
prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
|
|
printf ("-----------------------------------------------------------------------------\n");
|
|
printf ("Total %i cycles (was %i), total added gates = %i.\n", ntime, prof_cycles, size);
|
} else if (strncmp (tmp1, "d", 1) == 0 || strncmp (tmp1, "debug", 5) == 0) {
|
} else if (strncmp (tmp1, "d", 1) == 0 || strncmp (tmp1, "debug", 5) == 0) {
|
|
/* debug command */
|
sscanf (tmp1, "%*s %i", &cuc_debug);
|
sscanf (tmp1, "%*s %i", &cuc_debug);
|
if (cuc_debug < 0) cuc_debug = 0;
|
if (cuc_debug < 0) cuc_debug = 0;
|
if (cuc_debug > 9) cuc_debug = 9;
|
if (cuc_debug > 9) cuc_debug = 9;
|
} else if (strcmp (tmp1, "g") == 0 || strcmp (tmp1, "generate") == 0) {
|
} else if (strcmp (tmp1, "g") == 0 || strcmp (tmp1, "generate") == 0) {
|
for (i = 0; i < prof_nfuncs; i++);
|
/* generate command */
|
|
for (i = 0; i < prof_nfuncs; i++)
|
|
if (func[i] && func_v[i]) generate_function (func[i], prof_func[i].name);
|
|
} else if (strncmp (tmp1, "s", 1) == 0 || strncmp (tmp1, "select", 6) == 0) {
|
|
/* select command */
|
|
char tmp[50], ch;
|
|
int p, o, b, f;
|
|
p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
|
|
if (p < 1) printf ("Invalid parameters.\n");
|
|
else {
|
|
/* Check if we have valid option */
|
|
for (f = 0; f < prof_nfuncs; f++)
|
|
if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
|
|
if (f < prof_nfuncs) {
|
|
if (p == 1) {
|
|
if (func[f]) {
|
|
func_v[f] = 1;
|
|
printf ("Function %s selected for translation.\n", prof_func[f].name);
|
|
} else printf ("Function %s not suitable for translation.\n", prof_func[f].name);
|
|
} else {
|
|
if (!func_v[f])
|
|
printf ("Function %s not yet selected for translation.\n", prof_func[f].name);
|
|
if (p < 3) goto invalid_option;
|
|
for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
|
|
if (!option_char[o]) goto invalid_option;
|
|
if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
|
|
if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
|
|
|
|
/* select an option */
|
|
func[f]->bb[b].selected_tim = o;
|
|
if (func[f]->bb[b].tim[o].nshared) {
|
|
printf ("Option has shared instructions: ");
|
|
print_shared (func[f], func[f]->bb[b].tim[o].shared, func[f]->bb[b].tim[o].nshared);
|
|
printf ("\n");
|
|
}
|
|
continue;
|
|
invalid_option:
|
|
printf ("Invalid option.\n");
|
|
}
|
|
} else printf ("Invalid function.\n");
|
|
}
|
|
} else if (strncmp (tmp1, "u", 1) == 0 || strncmp (tmp1, "unselect", 8) == 0) {
|
|
/* unselect command */
|
|
char tmp[50], ch;
|
|
int p, o, b, f;
|
|
p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
|
|
if (p < 1) printf ("Invalid parameters.\n");
|
|
else {
|
|
/* Check if we have valid option */
|
|
for (f = 0; f < prof_nfuncs; f++)
|
|
if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
|
|
if (f < prof_nfuncs) {
|
|
if (p == 1) {
|
|
if (func[f]) {
|
|
func_v[f] = 0;
|
|
printf ("Function %s unselected for translation.\n", prof_func[f].name);
|
|
} else printf ("Function %s not suitable for translation.\n", prof_func[f].name);
|
|
} else {
|
|
if (p < 3) goto invalid_option;
|
|
for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
|
|
if (!option_char[o]) goto invalid_option;
|
|
if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
|
|
if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
|
|
|
|
/* select an option */
|
|
func[f]->bb[b].selected_tim = -1;
|
|
}
|
|
} else printf ("Invalid function.\n");
|
|
}
|
} else if (strcmp (tmp1, "o") == 0 || strcmp (tmp1, "options") == 0) {
|
} else if (strcmp (tmp1, "o") == 0 || strcmp (tmp1, "options") == 0) {
|
|
int any = 0;
|
|
/* options command */
|
printf ("Available options:\n");
|
printf ("Available options:\n");
|
for (i = 0; i < prof_nfuncs; i++)
|
for (i = 0; i < prof_nfuncs; i++)
|
if (func[i]) options_cmd (func[i], prof_func[i].name);
|
if (func[i]) {
|
|
options_cmd (i, func[i]);
|
|
any = 1;
|
|
}
|
|
if (any) printf ("--------------------------------------------------------\n");
|
|
else printf ("Sorry. No available options.\n");
|
} else {
|
} else {
|
|
/* help command */
|
if (strcmp (tmp1, "h") != 0 && strcmp (tmp1, "help") != 0)
|
if (strcmp (tmp1, "h") != 0 && strcmp (tmp1, "help") != 0)
|
printf ("Unknown command.\n");
|
printf ("Unknown command.\n");
|
printf ("OpenRISC Custom Unit Compiler command prompt\n");
|
printf ("OpenRISC Custom Unit Compiler command prompt\n");
|
|
printf ("Available commands:\n");
|
printf ("h|help displays this help\n");
|
printf ("h|help displays this help\n");
|
printf ("q|quit returns to or1ksim prompt\n");
|
printf ("q|quit returns to or1ksim prompt\n");
|
printf ("p|profile displays function profiling\n");
|
printf ("p|profile displays function profiling\n");
|
printf ("d|debug # sets debug level (0-9)\n");
|
printf ("d|debug # sets debug level (0-9)\n");
|
printf ("o|options displays available options\n");
|
printf ("o|options displays available options\n");
|
|
printf (" s | select func [option] selects an option/function\n");
|
|
printf (" u | unselect func [option] unselects an option/function\n");
|
printf ("g|generate generates verilog file\n");
|
printf ("g|generate generates verilog file\n");
|
}
|
}
|
}
|
}
|
|
|
/* Dispose memory */
|
/* Dispose memory */
|