URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [tags/] [nog_patch_50/] [or1ksim/] [cuc/] [bb.c] - Rev 883
Go to most recent revision | Compare with Previous | Blame | View Log
/* bb.c -- OpenRISC Custom Unit Compiler, Basic Block handling * Copyright (C) 2002 Marko Mlinar, markom@opencores.org * * This file is part of OpenRISC 1000 Architectural Simulator. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <assert.h> #include "cuc.h" #include "insn.h" #include "support/profile.h" /* Print out basic blocks */ void print_cuc_bb (cuc_func *f, char *s) { int i; printf ("------- %s -------\n", s); for (i = 0; i < f->num_bb; i++) { if (f->bb[i].insn) printf ("\n---- BB%-2x * %x ---- ", i, f->bb[i].cnt); else printf ("BB%-2x: %4x-%-4x", i, f->bb[i].first, f->bb[i].last); printf (" type %02x tmp %i ", f->bb[i].type, f->bb[i].tmp); if (f->bb[i].next[0] >= 0) printf ("next %2x ", f->bb[i].next[0]); else printf ("next * "); if (f->bb[i].next[1] >= 0) printf ("%2x ", f->bb[i].next[1]); else printf ("* "); if (f->bb[i].prev[0] >= 0) printf ("prev %2x ", f->bb[i].prev[0]); else printf ("prev * "); if (f->bb[i].prev[1] >= 0) printf ("%2x\n", f->bb[i].prev[1]); else printf ("*\n"); if (f->bb[i].insn) print_insns (f->bb[i].insn, f->bb[i].ninsn, 0); } printf ("\n"); } /* Copies src basic block into destination */ cuc_bb *cpy_bb (cuc_bb *dest, cuc_bb *src) { int i; *dest = *src; assert (dest->insn = malloc (sizeof (cuc_insn) * src->ninsn)); for (i = 0; i < src->ninsn; i++) dest->insn[i] = src->insn[i]; if (src->ntim) { assert (dest->tim = malloc (sizeof (cuc_timings) * src->ntim)); for (i = 0; i < src->ntim; i++) dest->tim[i] = src->tim[i]; } } /* Duplicates function */ cuc_func *dup_func (cuc_func *f) { cuc_func *n = (cuc_func *) malloc (sizeof (cuc_func)); int b, i; for (b = 0; b < f->num_bb; b++) cpy_bb (&n->bb[b], &f->bb[b]); n->num_bb = f->num_bb; assert (n->init_bb_reloc = (int *)malloc (sizeof (int) * f->num_init_bb)); for (b = 0; b < f->num_init_bb; b++) n->init_bb_reloc[b] = f->init_bb_reloc[b]; n->num_init_bb = f->num_init_bb; for (i = 0; i < MAX_REGS; i++) n->saved_regs[i] = f->saved_regs[i]; n->start_addr = f->start_addr; n->end_addr = f->end_addr; n->orig_time = f->orig_time; n->nmsched = f->nmsched; for (i = 0; i < f->nmsched; i++) { n->msched[i] = f->msched[i]; n->mtype[i] = f->mtype[i]; } return n; } /* Releases memory allocated by function */ void free_func (cuc_func *f) { int b, i; for (b = 0; b < f->num_bb; b++) { for (i = 0; i < f->bb[b].ninsn; i++) dispose_list (&f->bb[b].insn[i].dep); if (f->bb[b].insn) free (f->bb[b].insn); if (f->bb[b].tim && f->bb[b].ntim) free (f->bb[b].tim); } free (f); } /* Recalculates last_used_reg */ void recalc_last_used_reg (cuc_func *f, int b) { int i; cuc_bb *bb = &f->bb[b]; /* rebuild last used reg array */ if (bb->insn[0].index == II_LRBB) bb->last_used_reg[LRBB_REG] = 0; else bb->last_used_reg[LRBB_REG] = -1; for (i = 1; i < MAX_REGS - 1; i++) bb->last_used_reg[i] = -1; /* Create references */ for (i = 0; i < bb->ninsn; i++) { int k; /* Now check for destination operand(s) */ for (k = 0; k < MAX_OPERANDS; k++) if (bb->insn[i].opt[k] & OPT_DEST) if ((bb->insn[i].opt[k] & ~OPT_DEST) == OPT_REGISTER && (int)bb->insn[i].op[k] >= 0) { bb->last_used_reg[bb->insn[i].op[k]] = REF (b, i); } } } /* Set the BB limits */ void detect_bb (cuc_func *f) { int i, j, end_bb = 0, eb = 0; /* Mark block starts/ends */ for (i = 0; i < num_insn; i++) { if (end_bb) insn[i].type |= IT_BBSTART; end_bb = 0; if (insn[i].type & IT_BRANCH) { int jt = insn[i].op[0]; insn[i].type |= IT_BBEND; end_bb = 1; if (jt < 0 || jt >= num_insn) { fprintf (stderr, "Instruction #%i:Jump out of function '%s'.\n", i, insn[i].disasm); exit (1); } if (jt > 0) insn[jt - 1].type |= IT_BBEND; insn[jt].type |= IT_BBSTART; } } /* Initialize bb array */ insn[0].type |= IT_BBSTART; insn[num_insn - 1].type |= IT_BBEND; f->num_bb = 0; for (i = 0; i < num_insn; i++) { if (insn[i].type & IT_BBSTART) { f->bb[f->num_bb].first = i; f->bb[f->num_bb].cnt = 0; } /* Determine repetitions of a loop */ if (insn[i].type & IT_BBEND) { f->bb[f->num_bb].type = 0; f->bb[f->num_bb].last = i; f->bb[f->num_bb].next[0] = f->bb[f->num_bb].next[1] = -1; f->bb[f->num_bb].tmp = 0; f->bb[f->num_bb].ntim = 0; f->num_bb++; assert (f->num_bb < MAX_BB); } } if (cuc_debug >= 3) print_cuc_bb (f, "AFTER_INIT"); /* Build forward connections between BBs */ for (i = 0; i < f->num_bb; i++) if (insn[f->bb[i].last].type & IT_BRANCH) { int j; assert (insn[f->bb[i].last].index == II_BF); /* Find block this instruction jumps to */ for (j = 0; j < f->num_bb; j++) if (f->bb[j].first == insn[f->bb[i].last].op[0]) break; assert (j < f->num_bb); /* Convert the jump address to BB link */ insn[f->bb[i].last].op[0] = j; insn[f->bb[i].last].opt[0] = OPT_BB; /* Make a link */ f->bb[i].next[0] = j; if (++f->bb[j].tmp > 2) eb++; f->bb[i].next[1] = i + 1; if (++f->bb[i + 1].tmp > 2) eb++; } else if (f->bb[i].last == num_insn - 1) { /* Last instruction doesn't have to do anything */ f->bb[i].type |= BB_END; } else { f->bb[i].next[0] = i + 1; if (++f->bb[i + 1].tmp > 2) eb++; } if (cuc_debug >= 3) print_cuc_bb (f, "AFTER_NEXT"); /* Build backward connections, but first insert artificial blocks * to handle more than 2 connections */ cucdebug (6, "artificial %i %i\n", f->num_bb, eb); end_bb = f->num_bb + eb; for (i = f->num_bb - 1; i >= 0; i--) { j = f->bb[i].tmp; if (f->bb[i].tmp > 2) f->bb[i].tmp = -f->bb[i].tmp; f->bb[--end_bb] = f->bb[i]; reloc[i] = end_bb; while (j-- > 2) { f->bb[--end_bb].first = f->bb[i].first; f->bb[end_bb].last = -1; f->bb[end_bb].next[0] = -1; f->bb[end_bb].next[1] = -1; f->bb[end_bb].tmp = 0; f->bb[end_bb].cnt = f->bb[i].cnt; f->bb[end_bb].ntim = 0; } } f->num_bb += eb; /* relocate jump instructions */ for (i = 0; i < num_insn; i++) for (j = 0; j < MAX_OPERANDS; j++) if (insn[i].opt[j] & OPT_BB) insn[i].op[j] = reloc[insn[i].op[j]]; if (cuc_debug >= 3) print_cuc_bb (f, "AFTER_INSERT-reloc"); for (i = 0; i < f->num_bb; i++) { if (f->bb[i].next[0] >= 0) { int t = reloc[f->bb[i].next[0]]; if (f->bb[t].tmp < 0) { f->bb[t].tmp = -f->bb[t].tmp; t -= f->bb[t].tmp - 2; } else if (f->bb[t].tmp > 2) t -= f->bb[t].tmp-- - 2; f->bb[i].next[0] = t; } if (f->bb[i].next[1] >= 0) { int t = reloc[f->bb[i].next[1]]; if (f->bb[t].tmp < 0) { f->bb[t].tmp = -f->bb[t].tmp; t -= f->bb[t].tmp - 2; } else if (f->bb[t].tmp > 2) t -= f->bb[t].tmp-- - 2; f->bb[i].next[1] = t; } /* artificial blocks do not have relocations, hardcode them */ if (f->bb[i].last < 0) f->bb[i].next[0] = i + 1; } if (cuc_debug >= 3) print_cuc_bb (f, "AFTER_INSERT"); /* Uncoditional branched do not continue to next block */ for (i = 0; i < f->num_bb; i++) { cuc_insn *ii; if (f->bb[i].last < 0) continue; ii = &insn[f->bb[i].last]; /* Unconditional branch? */ if (ii->type & IT_BRANCH && ii->opt[1] & OPT_CONST) { change_insn_type (ii, II_NOP); if (f->bb[i].next[1] == i + 1) f->bb[i].next[0] = f->bb[i].next[1]; f->bb[i].next[1] = -1; } } if (cuc_debug >= 3) print_cuc_bb (f, "AFTER_UNCOND_JUMP"); /* Add backward connections */ for (i = 0; i < f->num_bb; i++) f->bb[i].prev[0] = f->bb[i].prev[1] = -1; for (i = 0; i < f->num_bb; i++) { if (f->bb[i].next[0] >= 0) { int t = f->bb[i].next[0]; if (f->bb[t].prev[0] < 0) f->bb[t].prev[0] = i; else { assert (f->bb[t].prev[1] < 0); f->bb[t].prev[1] = i; } } if (f->bb[i].next[1] >= 0) { int t = f->bb[i].next[1]; if (f->bb[t].prev[0] < 0) f->bb[t].prev[0] = i; else { assert (f->bb[t].prev[1] < 0); f->bb[t].prev[1] = i; } } } if (cuc_debug >= 3) print_cuc_bb (f, "AFTER_PREV"); } /* Build basic blocks */ void build_bb (cuc_func *f) { int i, j, k; for (i = 0; i < f->num_bb; i++) { if (f->bb[i].last < 0) f->bb[i].ninsn = MAX_REGS - 1; else f->bb[i].ninsn = f->bb[i].last - f->bb[i].first + 1 + MAX_REGS - 1; assert (f->bb[i].ninsn >= MAX_REGS - 1); f->bb[i].insn = (cuc_insn *) malloc (sizeof (cuc_insn) * f->bb[i].ninsn); assert (f->bb[i].insn); f->bb[i].nmemory = 0; f->bb[i].unrolled = 1; /* Save space for conditional moves, exclude r0, place lrbb instead */ change_insn_type (&f->bb[i].insn[0], II_LRBB); strcpy (f->bb[i].insn[0].disasm, "lrbb"); f->bb[i].insn[0].type = IT_UNUSED; f->bb[i].insn[0].dep = NULL; f->bb[i].insn[0].op[0] = LRBB_REG; f->bb[i].insn[0].opt[0] = OPT_REGISTER | OPT_DEST; f->bb[i].insn[0].opt[1] = OPT_LRBB; f->bb[i].insn[0].opt[2] = f->bb[i].insn[0].opt[3] = OPT_NONE; for (j = 1; j < MAX_REGS - 1; j++) { change_insn_type (&f->bb[i].insn[j], II_CMOV); strcpy (f->bb[i].insn[j].disasm, "cmov"); f->bb[i].insn[j].type = 0; f->bb[i].insn[j].dep = NULL; f->bb[i].insn[j].opt[0] = f->bb[i].insn[j].opt[1] = f->bb[i].insn[j].opt[2] = OPT_REGISTER; f->bb[i].insn[j].opt[0] |= OPT_DEST; f->bb[i].insn[j].op[0] = f->bb[i].insn[j].op[1] = f->bb[i].insn[j].op[2] = j; f->bb[i].insn[j].op[3] = LRBB_REG; f->bb[i].insn[j].opt[3] = OPT_REGISTER; } for (j = MAX_REGS - 1; j < f->bb[i].ninsn; j++) { f->bb[i].insn[j] = insn[f->bb[i].first + j - (MAX_REGS - 1)]; for (k = 0; k < MAX_OPERANDS; k++) if (f->bb[i].insn[j].opt[k] & OPT_REF) { int b1; for (b1 = 0; b1 < i; b1++) if (f->bb[b1].first <= f->bb[i].insn[j].op[k] && f->bb[i].insn[j].op[k] <= f->bb[b1].last) break; assert (b1 < f->num_bb); f->bb[i].insn[j].op[k] = REF (b1, f->bb[i].insn[j].op[k] - f->bb[b1].first + MAX_REGS - 1); } if (f->bb[i].insn[j].type & IT_MEMORY) f->bb[i].nmemory++; } } } /* type == 0; keep predecessor condition * type == 1; keep successor condition * type == 2; join loop unrolled blocks */ static void join_bb (cuc_func *f, int pred, int succ, int type) { int i, j, k, add, ninsn, add_cond = 0; unsigned long cond_op, cond_opt; cuc_insn *insn; //printf ("%i <= %i+%i (%i)\n", pred, pred, succ, type); //printf ("%i %i\n", f->bb[pred].ninsn, f->bb[succ].ninsn); add = f->bb[pred].ninsn; if (f->bb[pred].ninsn <= 0 || !(f->bb[pred].insn[f->bb[pred].ninsn - 1].type & IT_BRANCH)) type = 1; if (type == 0 && f->bb[succ].prev[0] == f->bb[succ].next[0]) add_cond = 1; ninsn = f->bb[pred].ninsn + f->bb[succ].ninsn + (type == 0 || type == 2 ? 1 : 0) + (add_cond ? MAX_REGS : 0); insn = (cuc_insn *) malloc (ninsn * sizeof (cuc_insn)); for (i = 0; i < add; i++) insn[i] = f->bb[pred].insn[i]; /* when type == 0, we copy the last (jump) instruction to the end */ if (type == 0 || type == 2) { insn[ninsn - 1] = insn[add - 1]; cond_op = insn[add - 1].op[1]; cond_opt = insn[add - 1].opt[1]; change_insn_type (&insn[add - 1], II_NOP); /* and when type == 2, we must add sfor instruction, to quit when either is true */ if (type == 2) { /* TODO */ assert (0); } } /* Copy second block */ for (i = 0; i < f->bb[succ].ninsn; i++) insn[i + f->bb[pred].ninsn] = f->bb[succ].insn[i]; for (i = 0; i < ninsn; i++) reloc[i] = -1; /* Add conditional instructions if required */ if (add_cond) { recalc_last_used_reg (f, pred); recalc_last_used_reg (f, succ); /* r0 -- add nop for it */ change_insn_type (&insn[add + f->bb[succ].ninsn], II_NOP); for (i = 1; i < MAX_REGS; i++) { cuc_insn *ii = &insn[add + f->bb[succ].ninsn + i]; int a = f->bb[pred].last_used_reg[i]; int b = f->bb[succ].last_used_reg[i]; if (b < 0) change_insn_type (ii, II_NOP); else if (a < 0) { change_insn_type (ii, II_ADD); ii->type = 0; ii->dep = NULL; ii->op[0] = i; ii->opt[0] = OPT_REGISTER | OPT_DEST; ii->op[1] = b; ii->opt[1] = OPT_REF; ii->op[2] = 0; ii->opt[2] = OPT_CONST; ii->op[3] = OPT_NONE; } else if (b >= 0) { change_insn_type (ii, II_CMOV); ii->type = 0; ii->dep = NULL; ii->op[0] = i; ii->opt[0] = OPT_REGISTER | OPT_DEST; ii->op[1] = a; ii->opt[1] = OPT_REF; ii->op[2] = b; ii->opt[2] = OPT_REF; ii->op[3] = cond_op; ii->opt[3] = cond_opt; reloc[REF_I(a)] = REF (pred, add + f->bb[succ].ninsn + i); } sprintf (ii->disasm, "cmov (join BB)"); } } f->bb[pred].type |= f->bb[succ].type; i = 0; assert (f->bb[pred].next[0] >= 0); switch (type) { case 0: if (f->bb[pred].next[0] == succ) f->bb[pred].next[0] = f->bb[succ].next[0]; if (f->bb[pred].next[1] == succ) f->bb[pred].next[1] = f->bb[succ].next[0]; assert (f->bb[succ].next[1] < 0); break; case 1: f->bb[pred].next[0] = f->bb[succ].next[0]; f->bb[pred].next[1] = f->bb[succ].next[1]; break; } if (f->bb[pred].next[0] == f->bb[pred].next[1]) f->bb[pred].next[1] = -1; f->bb[succ].type = BB_DEAD; /* Set max count */ if (f->bb[pred].cnt < f->bb[succ].cnt) f->bb[pred].cnt = f->bb[succ].cnt; f->bb[pred].ninsn = ninsn; free (f->bb[pred].insn); f->bb[pred].insn = NULL; free (f->bb[succ].insn); f->bb[succ].insn = NULL; f->bb[pred].insn = insn; for (i = 0; i < f->num_bb; i++) if (!(f->bb[i].type & BB_DEAD)) { if (f->bb[i].prev[0] == succ) f->bb[i].prev[0] = pred; if (f->bb[i].prev[1] == succ) f->bb[i].prev[1] = pred; if (f->bb[i].prev[0] == f->bb[i].prev[1]) f->bb[i].prev[1] = -1; for (j = 0; j < f->bb[i].ninsn; j++) for (k = 0; k < MAX_OPERANDS; k++) if (f->bb[i].insn[j].opt[k] & OPT_REF) { /* Check if we are referencing successor BB -> relocate to second part of the new block */ if (REF_BB (f->bb[i].insn[j].op[k]) == succ) { if (type == 0 && f->bb[i].insn[j].op[j] == REF (succ, ninsn - 1)) f->bb[i].insn[j].op[j] = REF (pred, f->bb[pred].ninsn); else { int t = f->bb[i].insn[j].op[k]; int ndest = REF (pred, REF_I (t) + add); /* We've found a reference to succ. block, being removed, relocate */ if (add_cond && i != succ && !(i == pred && j >= ninsn - MAX_REGS)) { //printf ("%x!\n", t); //printf ("%x!\n", f->INSN(ndest).op[0]); /* interblock dependency should have physical register attached */ assert (f->INSN(ndest).opt[0] == OPT_DEST | OPT_REGISTER); assert (f->INSN(ndest).op[0] >= 0); f->bb[i].insn[j].op[k] = REF (pred, add + f->bb[succ].ninsn + f->INSN(ndest).op[0]); } else f->bb[i].insn[j].op[k] = ndest; } } else if (REF_BB(f->bb[i].insn[j].op[k]) == pred) { if (i != pred && reloc[REF_I(f->bb[i].insn[j].op[k])] >= 0) { f->bb[i].insn[j].op[k] = reloc[REF_I(f->bb[i].insn[j].op[k])]; } } } } if (cuc_debug >= 3) print_cuc_bb (f, "join"); } /* Optimize basic blocks */ void optimize_bb (cuc_func *f) { int i, j; remove_lrbb: /* we can remove lrbb instructions from blocks with just one predecessor */ for (i = 0; i < f->num_bb; i++) if (!(f->bb[i].type & BB_DEAD)) { if (f->bb[i].prev[0] >= 0 && f->bb[i].prev[1] < 0) { /* exactly one predecessor */ for (j = 0; j < f->bb[i].ninsn; j++) if (f->bb[i].insn[j].index == II_LRBB) { cuc_insn *t; cucdebug (4, "-lrbb %i.%i\n", i, j); /* Change to add LRBB, 0, 0 */ change_insn_type (&f->bb[i].insn[j], II_ADD); f->bb[i].insn[j].type &= ~IT_VOLATILE; t = &f->bb[f->bb[i].prev[0]].insn[f->bb[f->bb[i].prev[0]].ninsn - 1]; f->bb[i].insn[j].opt[1] = f->bb[i].insn[j].opt[2] = OPT_CONST; f->bb[i].insn[j].op[1] = f->bb[i].insn[j].op[2] = 0; /* always use left block */ f->bb[i].insn[j].opt[3] = OPT_NONE; /* If the predecessor still has a conditional jump instruction, we must be careful. This could only have occured when we found out that next[0] == next[1] and have joined them. Now we will link lrbb and correct the situation */ if (t->type & IT_BRANCH) { /* We must set a reference to branch result */ f->bb[i].insn[j].opt[1] = t->opt[1]; f->bb[i].insn[j].op[1] = t->op[1]; change_insn_type (t, II_NOP); } } } } /* Type 0 joining 1. link between pred & succ 2. no memory accesses in succ 3. optional pred's second successors 4. max. one succ's successors */ for (i = 0; i < f->num_bb; i++) if (!(f->bb[i].type & BB_DEAD)) if (f->bb[i].prev[0] >= 0 && f->bb[i].prev[1] < 0 /* one predecessor */ && f->bb[i].next[1] < 0 /* max. one successor */ && f->bb[i].nmemory == 0) { /* and no memory acceses */ join_bb (f, f->bb[i].prev[0], i, 0); goto remove_lrbb; } /* Type 1 joining 1. link between pred & succ 2. no other pred's successors 3. no other succ's predecessors */ for (i = 0; i < f->num_bb; i++) if (!(f->bb[i].type & BB_DEAD)) if (f->bb[i].prev[0] >= 0 && f->bb[i].prev[1] < 0 /* one predecessor */ && f->bb[f->bb[i].prev[0]].next[0] >= 0 && f->bb[f->bb[i].prev[0]].next[1] < 0) { /* one successor */ join_bb (f, f->bb[i].prev[0], i, 1); goto remove_lrbb; } #if 1 /* Type 2 joining 1. link between pred & succ 2. succ has exactly one predeccessor 3. pred & succ share common successor 4. optional succ's second successor */ for (i = 0; i < f->num_bb; i++) if (!(f->bb[i].type & BB_DEAD)) if (f->bb[i].prev[0] >= 0 && f->bb[i].prev[1] < 0) { /* one predecessor */ int p = f->bb[i].prev[0]; if (f->bb[p].next[0] == i && f->bb[p].next[1] == f->bb[p].next[1]) join_bb (f, f->bb[i].prev[0], i, 2); goto remove_lrbb; } #endif } /* Removes BBs marked as dead */ void remove_dead_bb (cuc_func *f) { int i, j, k, d = 0; for (i = 0; i < f->num_bb; i++) if (f->bb[i].type & BB_DEAD) { if (f->bb[i].insn) free (f->bb[i].insn); f->bb[i].insn = NULL; reloc[i] = -1; } else { reloc[i] = d; f->bb[d++] = f->bb[i]; } f->num_bb = d; /* relocate initial blocks */ for (i = 0; i < f->num_init_bb; i++) f->init_bb_reloc[i] = reloc[f->init_bb_reloc[i]]; /* repair references */ for (i = 0; i < f->num_bb; i++) if (!(f->bb[i].type & BB_DEAD)) { if (f->bb[i].prev[0] >= 0) assert ((f->bb[i].prev[0] = reloc[f->bb[i].prev[0]]) >= 0); if (f->bb[i].prev[1] >= 0) assert ((f->bb[i].prev[1] = reloc[f->bb[i].prev[1]]) >= 0); if (f->bb[i].next[0] >= 0) assert ((f->bb[i].next[0] = reloc[f->bb[i].next[0]]) >= 0); if (f->bb[i].next[1] >= 0) assert ((f->bb[i].next[1] = reloc[f->bb[i].next[1]]) >= 0); if (f->bb[i].prev[0] == f->bb[i].prev[1]) f->bb[i].prev[1] = -1; if (f->bb[i].next[0] == f->bb[i].next[1]) f->bb[i].next[1] = -1; for (j = 0; j < f->bb[i].ninsn; j++) for (k = 0; k < MAX_OPERANDS; k++) if (f->bb[i].insn[j].opt[k] & OPT_BB && (signed)f->bb[i].insn[j].op[k] >= 0) assert ((f->bb[i].insn[j].op[k] = reloc[f->bb[i].insn[j].op[k]]) >= 0); else if (f->bb[i].insn[j].opt[k] & OPT_REF) { int t = f->bb[i].insn[j].op[k]; assert (reloc[REF_BB(t)] >= 0); f->bb[i].insn[j].op[k] = REF (reloc[REF_BB(t)], REF_I (t)); } } } /* Recursive calculation of dependencies */ static int reg_dep_rec (cuc_func *f, int cur) { int i, j; cuc_insn *insn = f->bb[cur].insn; //printf ("\n %i", cur); /* Spread only, do not loop */ if (f->bb[cur].tmp) return; f->bb[cur].tmp = 1; //printf ("! "); for (i = 0; i < f->bb[cur].ninsn; i++) { /* Check for destination operand(s) */ for (j = 0; j < MAX_OPERANDS; j++) if (insn[i].opt[j] & OPT_DEST) if ((insn[i].opt[j] & ~OPT_DEST) == OPT_REGISTER && (signed)insn[i].op[j] >= 0) { //printf ("%i:%i,%x ", insn[i].op[j], i, REF (cur, i)); assert (insn[i].op[j] > 0 && insn[i].op[j] < MAX_REGS); /* r0 should never be dest */ f->bb[cur].last_used_reg[insn[i].op[j]] = REF (cur, i); } } if (f->bb[cur].next[0] >= 0) reg_dep_rec (f, f->bb[cur].next[0]); if (f->bb[cur].next[1] >= 0) reg_dep_rec (f, f->bb[cur].next[1]); } /* Detect register dependencies */ void reg_dep (cuc_func *f) { int i, b, c; /* Set dead blocks */ for (b = 0; b < f->num_bb; b++) { f->bb[b].tmp = 0; for (i = 0; i < MAX_REGS; i++) f->bb[b].last_used_reg[i] = -1; } /* Start with first block and set dependecies of all reachable blocks */ /* At the same time set last_used_regs */ reg_dep_rec (f, 0); for (i = 0; i < f->num_bb; i++) if (f->bb[i].tmp) f->bb[i].tmp = 0; else f->bb[i].type |= BB_DEAD; /* Detect loops; mark BBs where loops must be broken */ for (c = 0; c < f->num_bb; c++) { int min = 3, minb; /* search though all non-visited for minimum number of unvisited predecessors */ for (b = 0; b < f->num_bb; b++) if (!f->bb[b].tmp) { int tmp = 0; if (f->bb[b].prev[0] >= 0 && !f->bb[f->bb[b].prev[0]].tmp) tmp++; if (f->bb[b].prev[1] >= 0 && !f->bb[f->bb[b].prev[1]].tmp) tmp++; if (tmp < min) { minb = b; min = tmp; if (tmp == 0) break; /* We already have the best one */ } } b = minb; f->bb[b].tmp = 1; /* Mark visited */ cucdebug (3, "minb %i min %i\n", minb, min); if (min) { /* We just broke the loop */ f->bb[b].type |= BB_INLOOP; } } /* Set real predecessors in cmov instructions to previous blocks */ for (b = 0; b < f->num_bb; b++) for (i = 1; i < MAX_REGS - 1; i++) { int pa, pb; assert (f->bb[b].insn[i].index == II_CMOV); assert (f->bb[b].insn[i].opt[0] == OPT_REGISTER | OPT_DEST); assert (f->bb[b].insn[i].op[0] == i); if (f->bb[b].prev[0] < 0) pa = -1; else pa = f->bb[f->bb[b].prev[0]].last_used_reg[i]; if (f->bb[b].prev[1] < 0) pb = -1; else pb = f->bb[f->bb[b].prev[1]].last_used_reg[i]; /* We do some very simple optimizations right away to make things more readable */ if (pa < 0 && pb < 0) { /* Was not used at all */ change_insn_type (&f->bb[b].insn[i], II_ADD); f->bb[b].insn[i].op[2] = 0; f->bb[b].insn[i].opt[2] = OPT_CONST; f->bb[b].insn[i].opt[3] = OPT_NONE; } else if (pa < 0) { change_insn_type (&f->bb[b].insn[i], II_ADD); assert (f->INSN(pb).opt[0] == (OPT_REGISTER | OPT_DEST)); f->bb[b].insn[i].op[1] = pb; f->bb[b].insn[i].opt[1] = OPT_REF; f->bb[b].insn[i].op[2] = 0; f->bb[b].insn[i].opt[2] = OPT_CONST; f->bb[b].insn[i].opt[3] = OPT_NONE; } else if (pb < 0) { change_insn_type (&f->bb[b].insn[i], II_ADD); assert (f->INSN(pa).opt[0] == (OPT_REGISTER | OPT_DEST)); f->bb[b].insn[i].op[1] = pa; f->bb[b].insn[i].opt[1] = OPT_REF; f->bb[b].insn[i].op[2] = 0; f->bb[b].insn[i].opt[2] = OPT_CONST; f->bb[b].insn[i].opt[3] = OPT_NONE; } else { int t = REF (b, 0); /* lrbb should be first instruction */ assert (f->INSN(t).index == II_LRBB); f->bb[b].insn[i].op[1] = pa; f->bb[b].insn[i].opt[1] = OPT_REF; assert (f->INSN(pa).opt[0] == (OPT_REGISTER | OPT_DEST)); f->bb[b].insn[i].op[2] = pb; f->bb[b].insn[i].opt[2] = OPT_REF; assert (f->INSN(pb).opt[0] == (OPT_REGISTER | OPT_DEST)); /* Update op[3] -- flag register */ assert (f->bb[b].insn[i].opt[3] == OPT_REGISTER); assert (f->bb[b].insn[i].op[3] == LRBB_REG); assert (t >= 0); f->bb[b].insn[i].opt[3] = OPT_REF; /* Convert already used regs to references */ f->bb[b].insn[i].op[3] = t; assert (f->INSN(t).opt[0] == (OPT_REGISTER | OPT_DEST)); } } /* assign register references */ for (b = 0; b < f->num_bb; b++) { /* rebuild last used reg array */ f->bb[b].last_used_reg[0] = -1; if (f->bb[b].insn[0].index == II_LRBB) f->bb[b].last_used_reg[LRBB_REG] = 0; else f->bb[b].last_used_reg[LRBB_REG] = -1; for (i = 1; i < MAX_REGS - 1; i++) f->bb[b].last_used_reg[i] = -1; /* Create references */ for (i = 0; i < f->bb[b].ninsn; i++) { int k; /* Check for source operands first */ for (k = 0; k < MAX_OPERANDS; k++) { if (!(f->bb[b].insn[i].opt[k] & OPT_DEST)) if (f->bb[b].insn[i].opt[k] & OPT_REGISTER) { int t = f->bb[b].last_used_reg[f->bb[b].insn[i].op[k]]; if (f->bb[b].insn[i].op[k] == 0) { /* Convert r0 to const0 */ f->bb[b].insn[i].opt[k] = OPT_CONST; f->bb[b].insn[i].op[k] = 0; } else if (t >= 0) { f->bb[b].insn[i].opt[k] = OPT_REF; /* Convert already used regs to references */ f->bb[b].insn[i].op[k] = t; assert (f->INSN(t).opt[0] == (OPT_REGISTER | OPT_DEST)); //f->INSN(t).op[0] = -1; } } else if (f->bb[b].insn[i].opt[k] & OPT_REF) { //f->INSN(f->bb[b].insn[i].op[k]).op[0] = -1; /* Mark referenced */ f->INSN(f->bb[b].insn[i].op[k]).type &= ~IT_UNUSED; } } /* Now check for destination operand(s) */ for (k = 0; k < MAX_OPERANDS; k++) if (f->bb[b].insn[i].opt[k] & OPT_DEST) if ((f->bb[b].insn[i].opt[k] & ~OPT_DEST) == OPT_REGISTER && (int)f->bb[b].insn[i].op[k] >= 0) { int t = f->bb[b].last_used_reg[f->bb[b].insn[i].op[k]]; assert (f->bb[b].insn[i].op[k] != 0); /* r0 should never be dest */ f->bb[b].last_used_reg[f->bb[b].insn[i].op[k]] = REF (b, i); } } } /* Remove all unused lrbb */ 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); /* SSAs with final register value are marked as outputs */ assert (f->bb[f->num_bb - 1].type & BB_END); for (i = 0; i < MAX_REGS; i++) if (!call_saved[i]) { int t = f->bb[f->num_bb - 1].last_used_reg[i]; /* Mark them volatile, so optimizer does not remove them */ if (t >= 0) f->bb[REF_BB(t)].insn[REF_I(t)].type |= IT_OUTPUT; } } /* Scans sequence of BBs and set bb[].cnt */ void generate_bb_seq (cuc_func *f, char *mp_filename, char *bb_filename) { FILE *fi, *fo; struct mprofentry_struct *buf; const int bufsize = 256; unsigned long *bb_start; unsigned long *bb_end; int b, i, r; int curbb, prevbb = -1; unsigned long addr = -1; unsigned long prevaddr = -1; assert (fi = fopen (mp_filename, "rb")); assert (fo = fopen (bb_filename, "wb+")); assert (bb_start = (unsigned long *) malloc (sizeof (unsigned long) * f->num_bb)); assert (bb_end = (unsigned long *) malloc (sizeof (unsigned long) * f->num_bb)); for (b = 0; b < f->num_bb; b++) { bb_start[b] = f->start_addr + f->bb[b].first * 4; bb_end[b] = f->start_addr + f->bb[b].last * 4; //printf ("%i %x %x\n", b, bb_start[b], bb_end[b]); f->bb[0].cnt = 0; } buf = (struct mprofentry_struct *) malloc (sizeof (struct mprofentry_struct) * bufsize); assert (buf); //printf ("BBSEQ:\n"); do { r = fread (buf, sizeof (struct mprofentry_struct), bufsize, fi); //printf ("r%i : ", r); for (i = 0; i < r; i++) { if (buf[i].type & MPROF_FETCH) { //printf ("%x, ", buf[i].addr); if (buf[i].addr >= f->start_addr && buf[i].addr <= f->end_addr) { assert (buf[i].type & MPROF_32); prevaddr = addr; addr = buf[i].addr; for (b = 0; b < f->num_bb; b++) if (bb_start[b] <= addr && addr <= bb_end[b]) break; assert (b < f->num_bb); curbb = b; if (prevaddr + 4 != addr) prevbb = -1; } else curbb = -1; #warning TODO: do not count interrupts if (curbb != prevbb && curbb >= 0) { fwrite (&curbb, sizeof (unsigned long), 1, fo); //printf (" [%i] ", curbb); f->bb[curbb].cnt++; prevbb = curbb; } } } //printf ("\n"); } while (r == bufsize); //printf ("\n"); f->num_runs = f->bb[0].cnt; fclose (fi); fclose (fo); free (buf); free (bb_end); free (bb_start); /* Initialize basic block relocations */ f->num_init_bb = f->num_bb; //printf ("num_init_bb = %i\n", f->num_init_bb); assert (f->init_bb_reloc = (int *)malloc (sizeof (int) * f->num_init_bb)); for (b = 0; b < f->num_init_bb; b++) f->init_bb_reloc[b] = b; } /* Scans sequence of BBs and set counts for pre/unrolled loop for BB b */ void count_bb_seq (cuc_func *f, int b, char *bb_filename, int *counts, int preroll, int unroll) { FILE *fi; const int bufsize = 256; int i, r; int *buf; int cnt = 0; int times = preroll - 1 + unroll; assert (fi = fopen (bb_filename, "rb")); for (i = 0; i < times; i++) counts[i] = 0; assert (buf = (int *) malloc (sizeof (int) * bufsize)); do { r = fread (buf, sizeof (int), bufsize, fi); for (i = 0; i < r; i++) { /* count consecutive acesses */ if (f->init_bb_reloc[buf[i]] == b) { counts[cnt]++; if (++cnt >= times) cnt = preroll - 1; } else cnt = 0; } } while (r == bufsize); log ("Counts %i,%i :", preroll, unroll); for (i = 0; i < times; i++) log ("%x ", counts[i]); log ("\n"); fclose (fi); free (buf); } /* 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); } } /* Unroll loop b unroll times and return new function. Original function is unmodified. */ static cuc_func *unroll_loop (cuc_func *f, int b, int unroll) { int b1, t, i, j, prevb, prevart_b; cuc_func *n = dup_func (f); cuc_bb *ob = &f->bb[b]; cuc_insn *ii; assert (unroll > 1); //printf ("unroll BB%i x %i (num_bb %i)\n", b, unroll, n->num_bb); unroll--; assert (n->num_bb + unroll * 2 < MAX_BB); prevb = b; prevart_b = b; /* Duplicate the BB */ for (t = 0; t < unroll; t++) { cuc_bb *pb = &n->bb[prevart_b]; /* Add new block and set links */ b1 = n->num_bb++; cpy_bb (&n->bb[b1], ob); /* Only one should be in loop, so we remove any INLOOP flags from duplicates */ n->bb[b1].type &= ~(BB_END | BB_INLOOP); /* Set predecessor's successor */ if (n->bb[prevb].next[0] == b) { n->bb[prevb].next[0] = b1; if (pb->next[0] < 0) pb->next[0] = b1 + 1; else pb->next[1] = b1 + 1; n->bb[b1].next[1] = b1 + 1; } else if (n->bb[prevb].next[1] == b) { if (pb->next[0] < 0) pb->next[0] = b1 + 1; else pb->next[1] = b1 + 1; n->bb[b1].next[0] = b1 + 1; n->bb[prevb].next[1] = b1; } else assert (0); /* Set predecessor */ n->bb[b1].prev[0] = prevb; n->bb[b1].prev[1] = -1; /* Relocate backward references to current instance and forward references to previous one */ relocate_bb (&n->bb[b1], b, b1, prevb); /* add artificial block, just to join accesses */ b1 = n->num_bb++; cpy_bb (&n->bb[b1], ob); n->bb[b1].cnt = 0; for (i = 0; i < ob->ninsn - 1; i++) { ii = &n->bb[b1].insn[i]; if (ob->insn[i].opt[0] & OPT_DEST) { change_insn_type (ii, II_CMOV); ii->op[0] = -1; ii->opt[0] = OPT_REGISTER | OPT_DEST; ii->op[1] = REF (prevart_b, i); ii->opt[1] = OPT_REF; ii->op[2] = REF (b1 - 1, i); ii->opt[2] = OPT_REF; /* Take left one, if we should have finished the first iteration*/ if (pb->insn[pb->ninsn - 1].type & IT_BRANCH) { ii->op[3] = pb->insn[pb->ninsn - 1].op[1]; ii->opt[3] = pb->insn[pb->ninsn - 1].opt[1]; } else { assert (pb->insn[pb->ninsn - 1].type & IT_COND); ii->op[3] = REF (prevart_b, pb->ninsn - 1); ii->opt[3] = OPT_REF; } ii->dep = NULL; ii->type = 0; } else { change_insn_type (ii, II_NOP); } } /* Add sfor instruction at the end, prioritizing flags */ ii = &n->bb[b1].insn[ob->ninsn - 1]; change_insn_type (ii, II_SFOR); ii->op[0] = FLAG_REG; ii->opt[0] = OPT_REGISTER | OPT_DEST; if (pb->insn[pb->ninsn - 1].type & IT_BRANCH) { ii->op[1] = pb->insn[pb->ninsn - 1].op[1]; ii->opt[1] = pb->insn[pb->ninsn - 1].opt[1]; } else { ii->op[1] = REF (prevart_b, pb->ninsn - 1); ii->opt[1] = OPT_REF; } if (n->bb[b1 - 1].insn[pb->ninsn - 1].type & IT_BRANCH) { ii->op[2] = n->bb[b1 - 1].insn[pb->ninsn - 1].op[1]; ii->opt[2] = n->bb[b1 - 1].insn[pb->ninsn - 1].opt[1]; } else { ii->op[2] = REF (b1 - 1, pb->ninsn - 1); ii->opt[2] = OPT_REF; } ii->opt[3] = OPT_NONE; ii->type = IT_COND; /* Only one should be in loop, so we remove any INLOOP flags from duplicates */ n->bb[b1].type &= ~(BB_END | BB_INLOOP); n->bb[b1].prev[0] = prevart_b; n->bb[b1].prev[1] = b1 - 1; n->bb[b1].next[0] = ob->next[0] == b ? ob->next[1] : ob->next[0]; n->bb[b1].next[1] = -1; prevb = b1 - 1; prevart_b = b1; } if (ob->type & BB_END) { n->bb[prevart_b].type |= BB_END; n->bb[b].type &= ~BB_END; } //print_cuc_bb (n, "unroll1"); /* repair BB after loop, to point back to latest artificial BB */ b1 = n->bb[prevart_b].next[0]; if (b1 >= 0) { if (n->bb[b1].prev[0] == b) n->bb[b1].prev[0] = b1; else if (n->bb[b1].prev[1] == b) n->bb[b1].prev[1] = b1; else assert (0); } /* Relink back to start of the loop */ /* Set predecessor's successor */ if (n->bb[prevb].next[0] == b) n->bb[prevb].next[0] = b; else if (n->bb[prevb].next[1] == b) n->bb[prevb].next[1] = b; else assert (0); /* Set predecessor */ if (n->bb[b].prev[0] == b) n->bb[b].prev[0] = prevb; else if (n->bb[b].prev[1] == b) n->bb[b].prev[1] = prevb; else assert (0); //print_cuc_bb (n, "unroll2"); /* Relocate backward references to current instance and forward references to previous one */ relocate_bb (&n->bb[b], b, b, prevb); /* Relocate all other blocks to point to latest prevart_b */ for (i = 0; i < f->num_bb; i++) if (i != b) relocate_bb (&n->bb[i], b, prevart_b, prevart_b); return n; } /* Preroll loop b preroll times and return new function. Original function is unmodified. */ static cuc_func *preroll_loop (cuc_func *f, int b, int preroll) { int b1, t, i, j, prevb, prevart_b; cuc_func *n = dup_func (f); cuc_bb *ob = &f->bb[b]; cuc_insn *ii; assert (preroll > 1); //printf ("preroll BB%i x %i (num_bb %i)\n", b, preroll, n->num_bb); preroll--; assert (n->num_bb + preroll * 2 < MAX_BB); prevb = b; prevart_b = b; /* Duplicate the BB */ for (t = 0; t < preroll; t++) { cuc_bb *pb = &n->bb[prevart_b]; /* Add new block and set links */ b1 = n->num_bb++; cpy_bb (&n->bb[b1], ob); /* Only one should be in loop, so we remove any INLOOP flags from duplicates */ n->bb[b1].type &= ~(BB_END | BB_INLOOP); /* Set predecessor's successor */ if (n->bb[prevb].next[0] == b) { n->bb[prevb].next[0] = b1; if (pb->next[0] < 0) pb->next[0] = b1 + 1; else pb->next[1] = b1 + 1; n->bb[b1].next[1] = b1 + 1; } else if (n->bb[prevb].next[1] == b) { if (pb->next[0] < 0) pb->next[0] = b1 + 1; else pb->next[1] = b1 + 1; n->bb[b1].next[0] = b1 + 1; n->bb[prevb].next[1] = b1; } else assert (0); /* Set predecessor */ n->bb[b1].prev[0] = prevb; n->bb[b1].prev[1] = -1; /* Relocate backward references to current instance and forward references to previous one */ relocate_bb (&n->bb[b1], b, b1, prevb); /* add artificial block, just to join accesses */ b1 = n->num_bb++; cpy_bb (&n->bb[b1], ob); n->bb[b1].cnt = 0; for (i = 0; i < ob->ninsn - 1; i++) { ii = &n->bb[b1].insn[i]; if (ob->insn[i].opt[0] & OPT_DEST) { change_insn_type (ii, II_CMOV); ii->op[0] = -1; ii->opt[0] = OPT_REGISTER | OPT_DEST; ii->op[1] = REF (prevart_b, i); ii->opt[1] = OPT_REF; ii->op[2] = REF (b1 - 1, i); ii->opt[2] = OPT_REF; /* Take left one, if we should have finished the first iteration*/ if (pb->insn[pb->ninsn - 1].type & IT_BRANCH) { ii->op[3] = pb->insn[pb->ninsn - 1].op[1]; ii->opt[3] = pb->insn[pb->ninsn - 1].opt[1]; } else { assert (pb->insn[pb->ninsn - 1].type & IT_COND); ii->op[3] = REF (prevart_b, pb->ninsn - 1); ii->opt[3] = OPT_REF; } ii->dep = NULL; ii->type = 0; } else { change_insn_type (ii, II_NOP); } } /* Add sfor instruction at the end, prioritizing flags */ ii = &n->bb[b1].insn[ob->ninsn - 1]; change_insn_type (ii, II_SFOR); ii->op[0] = FLAG_REG; ii->opt[0] = OPT_REGISTER | OPT_DEST; if (pb->insn[pb->ninsn - 1].type & IT_BRANCH) { ii->op[1] = pb->insn[pb->ninsn - 1].op[1]; ii->opt[1] = pb->insn[pb->ninsn - 1].opt[1]; } else { ii->op[1] = REF (prevart_b, pb->ninsn - 1); ii->opt[1] = OPT_REF; } if (n->bb[b1 - 1].insn[pb->ninsn - 1].type & IT_BRANCH) { ii->op[2] = n->bb[b1 - 1].insn[pb->ninsn - 1].op[1]; ii->opt[2] = n->bb[b1 - 1].insn[pb->ninsn - 1].opt[1]; } else { ii->op[2] = REF (b1 - 1, pb->ninsn - 1); ii->opt[2] = OPT_REF; } ii->opt[3] = OPT_NONE; ii->type = IT_COND; /* Only one should be in loop, so we remove any INLOOP flags from duplicates */ n->bb[b1].type &= ~(BB_END | BB_INLOOP); n->bb[b1].prev[0] = prevart_b; n->bb[b1].prev[1] = b1 - 1; n->bb[b1].next[0] = ob->next[0] == b ? ob->next[1] : ob->next[0]; n->bb[b1].next[1] = -1; prevb = b1 - 1; prevart_b = b1; } if (ob->type & BB_END) { n->bb[prevart_b].type |= BB_END; n->bb[b].type &= ~BB_END; } //print_cuc_bb (n, "preroll1"); /* repair BB after loop, to point back to latest artificial BB */ b1 = n->bb[prevart_b].next[0]; if (b1 >= 0) { if (n->bb[b1].prev[0] == b) n->bb[b1].prev[0] = b1; else if (n->bb[b1].prev[1] == b) n->bb[b1].prev[1] = b1; else assert (0); } /* Relink to itself */ /* Set predecessor's successor */ if (n->bb[prevb].next[0] == b) n->bb[prevb].next[0] = prevb; else if (n->bb[prevb].next[1] == b) n->bb[prevb].next[1] = prevb; else assert (0); n->bb[prevb].prev[1] = prevb; if (n->bb[b].prev[0] == b) { n->bb[b].prev[0] = n->bb[b].prev[1]; n->bb[b].prev[1] = -1; } else if (n->bb[b].prev[1] == b) { n->bb[b].prev[1] = -1; } //print_cuc_bb (n, "preroll2"); /* Relocate backward references to current instance and forward references to previous one */ relocate_bb (&n->bb[b], b, b, prevb); /* Relocate all other blocks to point to latest prevart_b */ for (i = 0; i < f->num_bb; i++) if (i != b) relocate_bb (&n->bb[i], b, prevart_b, prevart_b); return n; } /* Unroll loop b unroll times and return new function. Original function is unmodified. */ cuc_func *preunroll_loop (cuc_func *f, int b, int preroll, int unroll, char *bb_filename) { int b1, i; cuc_func *n, *t; int *counts; int *bb_reloc; if (preroll > 1) { t = preroll_loop (f, b, preroll); b1 = t->num_bb - 2; if (unroll > 1) { //print_cuc_bb (t, "preunroll1"); n = unroll_loop (t, b1, unroll); free_func (t); } else n = t; } else { b1 = b; if (unroll > 1) n = unroll_loop (f, b1, unroll); else n = dup_func (n); } /* Assign new count to functions */ assert (counts = (int *)malloc (sizeof (int) * (preroll - 1 + unroll))); count_bb_seq (n, b, bb_filename, counts, preroll, unroll); for (i = 0; i < preroll - 1 + unroll; i++) { if (i == 0) b1 = b; else b1 = f->num_bb + (i - 1) * 2; n->bb[b1].cnt = counts[i]; } //print_cuc_bb (n, "preunroll"); free (counts); return n; }
Go to most recent revision | Compare with Previous | Blame | View Log