+2004-09-06 Erik Petrich <epetrich AT ivorytower.norman.ok.us>
+
+ * src/port.h,
+ * src/mcs51/main.c,
+ * src/ds390/main.c,
+ * src/z80/main.c,
+ * src/hc08/main.c,
+ * src/pic/main.c,
+ * src/pic16/main.c,
+ * src/avr/main.c,
+ * src/xa51/main.c
+ * src/SDCCicode.c (geniCodeJumpTable): Better logic to determine if a
+ a jump table is the best form for a switch statement, including
+ automatic insertion of missing cases to make the case range
+ continuous. Developed in collaboration with Frieder Ferlemann.
+
2004-09-02 Erik Petrich <epetrich AT ivorytower.norman.ok.us>
* src/hc08/ralloc.c (canDefAccResult): multi-byte shift is unsafe for
int
geniCodeJumpTable (operand * cond, value * caseVals, ast * tree)
{
- int min = 0, max = 0, t, cnt = 0;
+ int min, max, cnt = 1;
+ int i, t;
value *vch;
iCode *ic;
operand *boundary;
set *labels = NULL;
int needRangeCheck = !optimize.noJTabBoundary
|| tree->values.switchVals.swDefault;
+ sym_link *cetype = getSpec (operandType (cond));
+ int sizeofMinCost, sizeofMaxCost;
+ int sizeofMatchJump, sizeofJumpTable;
+ int sizeIndex;
if (!tree || !caseVals)
return 0;
/* the criteria for creating a jump table is */
/* all integer numbers between the maximum & minimum must */
/* be present , the maximum value should not exceed 255 */
- min = max = (int) floatFromVal (vch = caseVals);
- SNPRINTF (buffer, sizeof(buffer),
- "_case_%d_%d",
- tree->values.switchVals.swNum,
- min);
- addSet (&labels, newiTempLabel (buffer));
-
- /* if there is only one case value then no need */
- if (!(vch = vch->next))
- return 0;
-
- while (vch)
+ /* If not all integer numbers are present the algorithm */
+ /* inserts jumps to the default label for the missing numbers */
+ /* and decides later whether it is worth it */
+ min = (int) floatFromVal (vch = caseVals);
+
+ while (vch->next)
{
- if (((t = (int) floatFromVal (vch)) - max) != 1)
- return 0;
- SNPRINTF (buffer, sizeof(buffer),
- "_case_%d_%d",
- tree->values.switchVals.swNum,
- t);
- addSet (&labels, newiTempLabel (buffer));
- max = t;
cnt++;
vch = vch->next;
}
-
- /* if the number of case statements <= 2 then */
- /* it is not economical to create the jump table */
- /* since two compares are needed for boundary conditions */
- if ((needRangeCheck && cnt <= 2) || max > (255 / 3))
+ max = (int) floatFromVal (vch);
+
+ /* Exit if the range is too large to handle with a jump table. */
+ if (1 + max - min > port->jumptableCost.maxCount)
return 0;
+
+ switch (getSize (operandType (cond)))
+ {
+ case 1: sizeIndex = 0; break;
+ case 2: sizeIndex = 1; break;
+ case 4: sizeIndex = 2; break;
+ default: return 0;
+ }
+
+ /* Compute the size cost of the range check and subtraction. */
+ sizeofMinCost = 0;
+ sizeofMaxCost = 0;
+ if (needRangeCheck)
+ {
+ if (!(min==0 && IS_UNSIGNED (cetype)))
+ sizeofMinCost = port->jumptableCost.sizeofRangeCompare[sizeIndex];
+ sizeofMaxCost = port->jumptableCost.sizeofRangeCompare[sizeIndex];
+ }
+ if (min)
+ sizeofMinCost += port->jumptableCost.sizeofSubtract;
+
+ /* If the size cost of handling a non-zero minimum exceeds the */
+ /* cost of extending the range down to zero, then it might be */
+ /* better to extend the range to zero. */
+ if (min > 0 && sizeofMinCost >= (min * port->jumptableCost.sizeofElement))
+ {
+ /* Only extend the jump table if it would still be manageable. */
+ if (1 + max <= port->jumptableCost.maxCount)
+ min = 0;
+ }
+
+ /* Compute the total size cost of a jump table. */
+ sizeofJumpTable = (1 + max - min) * port->jumptableCost.sizeofElement
+ + port->jumptableCost.sizeofDispatch
+ + sizeofMinCost + sizeofMaxCost;
+ /* Compute the total size cost of a match & jump sequence */
+ sizeofMatchJump = cnt * port->jumptableCost.sizeofMatchJump[sizeIndex];
+
+ /* If the size cost of the jump table is uneconomical then exit */
+ if (sizeofMatchJump < sizeofJumpTable)
+ return 0;
+
+ /* The jump table is preferable. */
+
+ /* First, a label for the default or missing cases. */
if (tree->values.switchVals.swDefault)
{
- SNPRINTF (buffer, sizeof(buffer), "_default_%d", tree->values.switchVals.swNum);
+ SNPRINTF (buffer, sizeof(buffer),
+ "_default_%d",
+ tree->values.switchVals.swNum);
}
else
{
- SNPRINTF (buffer, sizeof(buffer), "_swBrk_%d", tree->values.switchVals.swNum);
+ SNPRINTF (buffer, sizeof(buffer),
+ "_swBrk_%d",
+ tree->values.switchVals.swNum);
}
-
-
falseLabel = newiTempLabel (buffer);
+
+ /* Build the list of labels for the jump table. */
+ vch = caseVals;
+ t = (int) floatFromVal (vch);
+ for (i=min; i<=max; i++)
+ {
+ if (vch && t==i)
+ {
+ /* Explicit case: make a new label for it. */
+ SNPRINTF (buffer, sizeof(buffer),
+ "_case_%d_%d",
+ tree->values.switchVals.swNum,
+ i);
+ addSet (&labels, newiTempLabel (buffer));
+ vch = vch->next;
+ if (vch)
+ t = (int) floatFromVal (vch);
+ }
+ else
+ {
+ /* Implicit case: use the default label. */
+ addSet (&labels, falseLabel);
+ }
+ }
/* If cond is volatile, it might change after the boundary */
/* conditions are tested to an out of bounds value, causing */
cond = newcond;
}
- /* so we can create a jumptable */
/* first we rule out the boundary conditions */
/* if only optimization says so */
if (needRangeCheck)
{
avr_emitDebuggerSymbol
},
+ {
+ 255/3, /* maxCount */
+ 3, /* sizeofElement */
+ /* The rest of these costs are bogus. They approximate */
+ /* the behavior of src/SDCCicode.c 1.207 and earlier. */
+ {4,4,4}, /* sizeofMatchJump[] */
+ {0,0,0}, /* sizeofRangeCompare[] */
+ 0, /* sizeofSubtract */
+ 3, /* sizeofDispatch */
+ },
"_",
_avr_init,
_avr_parseOptions,
{
ds390_emitDebuggerSymbol
},
+ {
+ 255/4, /* maxCount */
+ 4, /* sizeofElement */
+ {8,12,20}, /* sizeofMatchJump[] */
+ {10,14,22}, /* sizeofRangeCompare[] */
+ 4, /* sizeofSubtract */
+ 7, /* sizeofDispatch */
+ },
"_",
_ds390_init,
_ds390_parseOptions,
{
ds390_emitDebuggerSymbol
},
+ {
+ 255/4, /* maxCount */
+ 4, /* sizeofElement */
+ {8,12,20}, /* sizeofMatchJump[] */
+ {10,14,22}, /* sizeofRangeCompare[] */
+ 4, /* sizeofSubtract */
+ 7, /* sizeofDispatch */
+ },
"",
_tininative_init,
_ds390_parseOptions,
{
ds390_emitDebuggerSymbol
},
+ {
+ 255/4, /* maxCount */
+ 4, /* sizeofElement */
+ {8,12,20}, /* sizeofMatchJump[] */
+ {10,14,22}, /* sizeofRangeCompare[] */
+ 4, /* sizeofSubtract */
+ 7, /* sizeofDispatch */
+ },
"_",
_ds390_init,
_ds390_parseOptions,
1, /* offsetSP */
},
},
+ {
+ 255/3, /* maxCount */
+ 3, /* sizeofElement */
+ {8,16,32}, /* sizeofMatchJump[] */
+ {8,16,32}, /* sizeofRangeCompare[] */
+ 5, /* sizeofSubtract */
+ 11, /* sizeofDispatch */
+ },
"_",
_hc08_init,
_hc08_parseOptions,
{
mcs51_emitDebuggerSymbol
},
+ {
+ 255/3, /* maxCount */
+ 3, /* sizeofElement */
+ {6,9,15}, /* sizeofMatchJump[] */
+ {9,18,36}, /* sizeofRangeCompare[] */
+ 4, /* sizeofSubtract */
+ 7, /* sizeofDispatch */
+ },
"_",
_mcs51_init,
_mcs51_parseOptions,
{
pic14_emitDebuggerSymbol
},
+ {
+ 255/3, /* maxCount */
+ 3, /* sizeofElement */
+ /* The rest of these costs are bogus. They approximate */
+ /* the behavior of src/SDCCicode.c 1.207 and earlier. */
+ {4,4,4}, /* sizeofMatchJump[] */
+ {0,0,0}, /* sizeofRangeCompare[] */
+ 0, /* sizeofSubtract */
+ 3, /* sizeofDispatch */
+ },
"_",
_pic14_init,
_pic14_parseOptions,
{
pic16_emitDebuggerSymbol
},
+ {
+ 255/3, /* maxCount */
+ 3, /* sizeofElement */
+ /* The rest of these costs are bogus. They approximate */
+ /* the behavior of src/SDCCicode.c 1.207 and earlier. */
+ {4,4,4}, /* sizeofMatchJump[] */
+ {0,0,0}, /* sizeofRangeCompare[] */
+ 0, /* sizeofSubtract */
+ 3, /* sizeofDispatch */
+ },
"_",
_pic16_init,
_pic16_parseOptions,
dwarf;
}
debugger;
-
+
+ struct
+ {
+ int maxCount;
+ int sizeofElement;
+ int sizeofMatchJump[3];
+ int sizeofRangeCompare[3];
+ int sizeofSubtract;
+ int sizeofDispatch;
+ }
+ jumptableCost;
+
/** Prefix to add to a C function (eg "_") */
const char *fun_prefix;
{
xa51_emitDebuggerSymbol
},
+ {
+ 255/3, /* maxCount */
+ 3, /* sizeofElement */
+ /* The rest of these costs are bogus. They approximate */
+ /* the behavior of src/SDCCicode.c 1.207 and earlier. */
+ {4,4,4}, /* sizeofMatchJump[] */
+ {0,0,0}, /* sizeofRangeCompare[] */
+ 0, /* sizeofSubtract */
+ 3, /* sizeofDispatch */
+ },
"_",
_xa51_init,
_xa51_parseOptions,
{
z80_emitDebuggerSymbol
},
+ {
+ 255, /* maxCount */
+ 3, /* sizeofElement */
+ /* The rest of these costs are bogus. They approximate */
+ /* the behavior of src/SDCCicode.c 1.207 and earlier. */
+ {4,4,4}, /* sizeofMatchJump[] */
+ {0,0,0}, /* sizeofRangeCompare[] */
+ 0, /* sizeofSubtract */
+ 3, /* sizeofDispatch */
+ },
"_",
_z80_init,
_parseOptions,
{
z80_emitDebuggerSymbol
},
+ {
+ 255, /* maxCount */
+ 3, /* sizeofElement */
+ /* The rest of these costs are bogus. They approximate */
+ /* the behavior of src/SDCCicode.c 1.207 and earlier. */
+ {4,4,4}, /* sizeofMatchJump[] */
+ {0,0,0}, /* sizeofRangeCompare[] */
+ 0, /* sizeofSubtract */
+ 3, /* sizeofDispatch */
+ },
"_",
_gbz80_init,
_parseOptions,