/*}}}*/ PRIVATE void tbinchop (const int low, const int high) { const int midpoint = (high + low) / 2; const int thislabel = newlab (); caseentry *thisselection = &(casetable[midpoint]); treenode *snode; /* Jump if exp <= value */ const int old = switch_to_temp_workspace (); snode = newdopnode (S_GR, NOPOSN, selectorexp, thisselection->selectionexp, selectortype); switch_to_prev_workspace (old); tguard (snode, TRUE, thislabel); /* selectorexp */ /* ldc selection */ /* gt */ /* cj thislabel */ /* At this point, we know exp > value */ tjumptable (midpoint + 1, high, TRUE); /* ... higher cases */ setlab (thislabel); /* thislabel: */ tjumptable (low, midpoint, TRUE); /* ... lower cases */ }
static void assemble() { int v[501]; int f = 0; int i; Labv = v; clear: for (i = 0; i <= 500; i++) Labv[i] = 0; Cp = 0; next: rch(); sw: switch (Ch) { default: if (Ch == EOF) return; printf("\nBAD CH %c AT P = %d\n", Ch, P); goto next; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': setlab(rdn()); Cp = 0; goto sw; case '$': case ' ': case '\n': goto next; case 'L': f = 0; break; case 'S': f = 1; break; case 'A': f = 2; break; case 'J': f = 3; break; case 'T': f = 4; break; case 'F': f = 5; break; case 'K': f = 6; break; case 'X': f = 7; break; case 'C': rch(); stc(rdn()); goto sw; case 'D': rch(); if (Ch == 'L') { rch(); stw(0); labref(rdn(), P - 1); } else stw(rdn()); goto sw; case 'G': rch(); A = rdn() + G; if (Ch == 'L') rch(); else printf("\nBAD CODE AT P = %d\n", P); M[A] = 0; labref(rdn(), A); goto sw; case 'Z': for (i = 0; i <= 500; i++) if (Labv[i] > 0) printf("L%d UNSET\n", i); goto clear; } W = f << FSHIFT; rch(); if (Ch == 'I') { W = W + IBIT; rch(); } if (Ch == 'P') { W = W + PBIT; rch(); } if (Ch == 'G') { W = W + GBIT; rch(); } if (Ch == 'L') { rch(); stw(W + DBIT); stw(0); labref(rdn(), P - 1); } else { int a = rdn(); if ((a & ABITS) == a) stw(W + a); else { stw(W + DBIT); stw(a); } } goto sw; }
/***************************************************************************** * * tcase generates code for a case process tptr * *****************************************************************************/ PUBLIC void tcase (treenode * tptr) { /*{{{ save globals */ caseentry *const oldcasetable = casetable; const int olddefaultlab = defaultlab; const int olddefaultjumpdest = defaultjumpdest; const int oldselectortype = selectortype; treenode *const oldselectorexp = selectorexp; /*}}} */ BOOL makedefault = TRUE; treenode *selectionlist = RHSOf (tptr); const int joinlab = newlab (); int maxcase = 0; treenode *defaultp = NULL; /*{{{ initialise globals */ defaultlab = NO_LABEL; defaultjumpdest = FALSE; selectorexp = LHSOf (tptr); selectortype = ntypeof (selectorexp); /* make sure that we don't call memalloc with zero bytes */ casetable = (caseentry *) memalloc (sizeof (caseentry) * casesin (selectionlist) + 1); /*}}} */ /*{{{ evaluate the selector, if neccessary */ tpreexp (selectorexp); simplify (P_EXP, selectorexp); /*}}} */ /*{{{ build up table of selections, and generate jumps into case body */ { treenode *slist; for (slist = selectionlist; !EndOfList (slist); slist = NextItem (slist)) { treenode *thisselection = skipspecifications (ThisItem (slist)); treenode *v = CondGuardOf (thisselection); const int l = newlab (); if (TagOf (v) == S_ELSE) { defaultlab = l; defaultp = ThisItem (slist); makedefault = FALSE; } else /*{{{ set up labels and values */ for (; !EndOfList (v); v = NextItem (v)) { treenode *thisconstant = ThisItem (v); caseentry *caseentryptr = &(casetable[maxcase]); caseentryptr->label = l; caseentryptr->jumpdest = FALSE; caseentryptr->lowvalue = LoValOf (thisconstant); caseentryptr->highvalue = HiValOf (thisconstant); caseentryptr->selectionexp = thisconstant; caseentryptr->selectionp = ThisItem (slist); maxcase++; } /*}}} */ } if (makedefault) defaultlab = newlab (); #if 0 sup_qsort (casetable, maxcase, sizeof (caseentry), fitsinword (selectortype) ? comparecases : doublecomparecases); #else sup_qsort (casetable, maxcase, sizeof (caseentry), (bytesinscalar (selectortype) <= 4) ? comparecases : doublecomparecases); #endif tjumptable (0, maxcase - 1, FALSE); } /*}}} */ /*{{{ generate case body */ { int casesdone = 0; /*{{{ generate default process */ setlab (defaultlab); if (makedefault) { if (NEED_ERRORS) /* bug TS/2071 29/01/93 */ tstop (tptr); } else { if (defaultjumpdest) genstartblock (); tselection (defaultp, joinlab); } /*}}} */ while (casesdone < maxcase) { treenode *thisprocess; int i; BOOL jdest; /* Find a process to generate */ for (i = 0; (i < maxcase) && (casetable[i].selectionp == NULL); i++) /* skip */ ; thisprocess = casetable[i].selectionp; /* Generate thisprocess */ setlab (casetable[i].label); jdest = casetable[i].jumpdest; /*{{{ find and delete other entries for this process */ { int j; for (j = i + 1; j < maxcase; j++) if (casetable[j].selectionp == thisprocess) { /* Delete the process, so we only generate it once */ jdest = jdest | casetable[j].jumpdest; casetable[j].selectionp = NULL; casesdone++; } } /*}}} */ if (jdest) genstartblock (); tselection (thisprocess, joinlab); casetable[i].selectionp = NULL; casesdone++; } setlab (joinlab); genstartblock (); } /*}}} */ /*{{{ restore globals */ memfree (casetable); casetable = oldcasetable; defaultlab = olddefaultlab; defaultjumpdest = olddefaultjumpdest; selectortype = oldselectortype; selectorexp = oldselectorexp; /*}}} */ }
/***************************************************************************** * * tjumptable generates the code for selecting cases given a sorted array * of case values and labels. Our case values are * case[low .. high]. * *****************************************************************************/ PRIVATE void tjumptable (const int low, const int high, const BOOL nomorejumptables) { const int numcases = (high - low) + 1; const BOOL singlelength = fitsinword (selectortype); #ifdef DEBUG { int i; DEBUG_MSG (("tjumptable: low: %d, high: %d, numcases: %d, nomorejumptables: %d\n", low, high, numcases, nomorejumptables)); for (i = low; i <= high; i++) { DEBUG_MSG (("tjumptable: casetable[%2d].lowvalue = %8X\n", i, casetable[i].lowvalue)); } } #endif if ((numcases <= DELTA) || isquadlength (selectortype)) { /* bug INSdi02177 */ /*{{{ too few cases - output jumps */ int i; BOOL optimisedlast = FALSE; for (i = low; i < low + numcases; i++) { /*{{{ output a jump for casetable[i] */ caseentry *thiscase = &(casetable[i]); const int old = switch_to_temp_workspace (); treenode *snode = newdopnode (S_EQ, NOPOSN, selectorexp, thiscase->selectionexp, selectortype); switch_to_prev_workspace (old); if ((i == high) && (thiscase->lowvalue != 0) && (thiscase->lowvalue != MOSTNEG_INT32) && fitsinword (selectortype) && (!isinconstanttable (thiscase->selectionexp))) { /*{{{ optimise the last case */ tguard (snode, TRUE, defaultlab); genbranch (I_J, thiscase->label); thiscase->jumpdest = TRUE; optimisedlast = TRUE; /*}}} */ } else { tguard (snode, FALSE, thiscase->label); } /*}}} */ } if (!optimisedlast) { genbranch (I_J, defaultlab); defaultjumpdest = TRUE; } /*}}} */ } else { /*{{{ look for biggest jump table */ int bestlow = 0; int besthigh = 0; int bestsize = 0; if (!nomorejumptables && (!singlelength || (numcases >= MIN_JTAB_SIZE))) { /*{{{ look for best jump table */ int i, j; const int minjumps = singlelength ? MIN_JTAB_SIZE - 1 : DELTA; for (i = low; i < (low + numcases - DELTA); i++) { /*{{{ set j to minimum value possible for better subrange */ j = i + ((bestsize > minjumps) ? bestsize : minjumps); /*}}} */ /*{{{ test all possible subranges starting at i, ending at or past j */ { const int maxaccept = ((high - i) + 1) * DENSITY; if (singlelength) { /*{{{ single length */ while (j <= high) { /* bug TS/1589 - 04/11/92 this is a bug in gcc 1.36; changing diff to be a BIT32 seems to fix the problem; and is OK as a permanent work-around. */ /* bug TS/1575 05/11/92 - cast to BIT32 for unsigned arith */ /*const INT32 diff = casetable[j].lowvalue - casetable[i].lowvalue); */ /*const INT32 diff = (INT32)((BIT32)casetable[j].lowvalue - (BIT32)casetable[i].lowvalue); */ const BIT32 diff = (BIT32) casetable[j].lowvalue - (BIT32) casetable[i].lowvalue; /*DEBUG_MSG(("i: %2d, j: %2d, lowvalue: %8X, diff: %8X\n", i, j, casetable[j].lowvalue, diff)); */ /*if ((diff < 0) || (diff > maxaccept)) *//* TS/1589 04/11/92 */ if (diff > (BIT32) maxaccept) { DEBUG_MSG (("tjumptable: bombing: diff: %8X\n", diff)); j = high; /* no chance so exit */ } else { const int size = (j - i) + 1; DEBUG_MSG (("tjumptable: ok: diff: %8X\n", diff)); if (diff <= (int) (DENSITY * size)) { /* better subrange */ bestlow = i; besthigh = j; bestsize = size; } } j = j + 1; } /*}}} */ } else { /*{{{ double length */ while (j <= high) { BIT32 hdiff, ldiff; Int64Minus (&hdiff, &ldiff, casetable[j].highvalue, casetable[j].lowvalue, casetable[i].highvalue, casetable[i].lowvalue); if ((hdiff != 0) || (ldiff > maxaccept)) { j = high; /* no chance so exit */ } else { const int size = (j - i) + 1; if (ldiff <= (int) (DENSITY * size)) { /* better subrange */ bestlow = i; besthigh = j; bestsize = size; } } j = j + 1; } /*}}} */ } } /*}}} */ } /*}}} */ } if (bestsize == 0) { tbinchop (low, high); } else { /*{{{ do jump table */ int lesslab = 0, greaterlab = 0; caseentry *lowestcase = &(casetable[bestlow]); caseentry *highestcase = &(casetable[besthigh]); DEBUG_MSG (("generating jump table: bestsize = %d\n", bestsize)); /*{{{ test for below boundary */ { treenode *lselnexp = lowestcase->selectionexp; if (!is_typed_mostneg (selectortype, LoValOf (lselnexp), HiValOf (lselnexp))) { int l; const int old = switch_to_temp_workspace (); treenode *snode = newdopnode (S_GE, NOPOSN, selectorexp, lselnexp, selectortype); switch_to_prev_workspace (old); if (bestlow == low) l = defaultlab; else { lesslab = newlab (); l = lesslab; } tguard (snode, TRUE, l); } } /*}}} */ /*{{{ test for above boundary */ { treenode *hselnexp = highestcase->selectionexp; if (!is_typed_mostpos (selectortype, LoValOf (hselnexp), HiValOf (hselnexp))) { int l; const int old = switch_to_temp_workspace (); treenode *snode = newdopnode (S_LE, NOPOSN, selectorexp, hselnexp, selectortype); switch_to_prev_workspace (old); if (besthigh == high) l = defaultlab; else { greaterlab = newlab (); l = greaterlab; } tguard (snode, TRUE, l); } } /*}}} */ /*{{{ output jump table */ { #if 0 const int jlab = newlab (); const int l = newlab (); #endif treenode *snode; if (lowestcase->lowvalue != 0) { /*{{{ selectorexp; ldc lowvalue; diff */ const int old = switch_to_temp_workspace (); snode = newdopnode (S_MINUS, NOPOSN, /* selectorexp */ selectorexp, /* ldc selection */ lowestcase->selectionexp, /* diff */ S_INT); switch_to_prev_workspace (old); /*}}} */ } else { /*{{{ selectorexp */ snode = selectorexp; /* selectorexp */ /*}}} */ } texp (snode, MANY_REGS); #if 0 /* subsumed into genstartjumptable to allow optimisation */ genloadcasescale (); /* ldc casescale */ /*{{{ T9000_gamma_badmul */ if (T9000_gamma_badmul (&tx_global)) { gensecondary (I_NOP); gencomment0 ("Workaround a slow multiplier"); } /*}}} */ gensecondary (I_PROD); /* prod */ genlabeldiff (I_LDC, jlab, l); /* ldc jlab - l */ gensecondary (I_LDPI); /* ldpi */ setlab (l); /* l: */ gensecondary (I_BSUB); /* bsub */ gensecondary (I_GCALL); /* gcall */ setlab (jlab); /* jlab: */ #endif genstartjumptable (); /* includes jump into table */ genjumptableentry (I_J, lowestcase->label); lowestcase->jumpdest = TRUE; /* j lowestcase */ /*{{{ other cases j othercases .. */ { int i; for (i = bestlow + 1; i <= besthigh; i++) { int j; /* bug TS/1575 05/11/92 - cast to BIT32 for unsigned arith */ const int blanks = (int) ((BIT32) casetable[i].lowvalue - (BIT32) casetable[i - 1].lowvalue) - 1; for (j = 0; j < blanks; j++) { genjumptableentry (I_J, defaultlab); defaultjumpdest = TRUE; } genjumptableentry (I_J, casetable[i].label); casetable[i].jumpdest = TRUE; } } /*}}} */ genendjumptable (); /*}}} */ } if (bestlow > low) { /*{{{ case on lower values */ setlab (lesslab); tjumptable (low, bestlow - 1, FALSE); /*}}} */ } if (besthigh < high) { /*{{{ case on higher values */ setlab (greaterlab); tjumptable (besthigh + 1, high, FALSE); /*}}} */ } /*}}} */ } /*}}} */ } }