} else if (val > 0) {
/* Scale up */
- if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
+ if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
- /* Factor is 2, 4 or 8, use special function */
+ /* Factor is 2, 4, 8 and 16, use special function */
switch (flags & CF_TYPE) {
case CF_CHAR:
/* FALLTHROUGH */
case CF_INT:
- if (CodeSizeFactor >= (p2+1)*130U) {
+ if (CodeSizeFactor >= (p2+1)*130U) {
AddCodeLine ("stx tmp1");
while (p2--) {
AddCodeLine ("asl a");
- AddCodeLine ("rol tmp1");
+ AddCodeLine ("rol tmp1");
}
AddCodeLine ("ldx tmp1");
} else {
/* Scale down */
val = -val;
- if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
+ if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
- /* Factor is 2, 4 or 8, use special function */
+ /* Factor is 2, 4, 8 and 16 use special function */
switch (flags & CF_TYPE) {
case CF_CHAR:
case CF_CHAR:
case CF_INT:
- if (val >= 1 && val <= 3) {
+ if (val >= 1 && val <= 4) {
if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr shrax%ld", val);
} else {
break;
case CF_LONG:
- if (val >= 1 && val <= 3) {
+ if (val >= 1 && val <= 4) {
if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr shreax%ld", val);
} else {
case CF_CHAR:
case CF_INT:
- if (val >= 1 && val <= 3) {
+ if (val >= 1 && val <= 4) {
if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr shlax%ld", val);
} else {
break;
case CF_LONG:
- if (val >= 1 && val <= 3) {
+ if (val >= 1 && val <= 4) {
if (flags & CF_UNSIGNED) {
AddCodeLine ("jsr shleax%ld", val);
} else {
*/
if (flags & CF_CONST) {
+ /* <= is not very effective on the 6502, so try to convert
+ * it into < if the value is in a valid range.
+ */
+
/* Look at the type */
switch (flags & CF_TYPE) {
case CF_CHAR:
if (flags & CF_FORCECHAR) {
- AddCodeLine ("cmp #$%02X", (unsigned char)val);
if (flags & CF_UNSIGNED) {
- AddCodeLine ("jsr boolule");
+ if (val < 255) {
+ AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
+ AddCodeLine ("jsr boolult");
+ } else {
+ AddCodeLine ("cmp #$%02X", (unsigned char)val);
+ AddCodeLine ("jsr boolule");
+ }
} else {
- AddCodeLine ("jsr boolle");
+ if (val < 127) {
+ AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
+ AddCodeLine ("jsr boollt");
+ } else {
+ AddCodeLine ("cmp #$%02X", (unsigned char)val);
+ AddCodeLine ("jsr boolle");
+ }
}
return;
}
case CF_INT:
if (flags & CF_UNSIGNED) {
unsigned L = GetLocalLabel();
+ const char* Name = "boolule";
+ if (val < 65535) {
+ ++val;
+ Name = "boolult";
+ }
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
- AddCodeLine ("bne %s", LocalLabelName (L));
- AddCodeLine ("cmp #$%02X", (unsigned char)val);
- g_defcodelabel (L);
- AddCodeLine ("jsr boolule");
+ AddCodeLine ("bne %s", LocalLabelName (L));
+ AddCodeLine ("cmp #$%02X", (unsigned char)val);
+ g_defcodelabel (L);
+ AddCodeLine ("jsr %s", Name);
return;
}
break;
{ "shrax1", REG_AX, REG_AX },
{ "shrax2", REG_AX, REG_AX },
{ "shrax3", REG_AX, REG_AX },
+ { "shrax4", REG_AX, REG_AX },
{ "shreax1", REG_AX, REG_AX },
{ "shreax2", REG_AX, REG_AX },
{ "shreax3", REG_AX, REG_AX },
+ { "shreax4", REG_AX, REG_AX },
{ "staspidx", REG_A | REG_Y, REG_Y },
{ "tosicmp", REG_AX, REG_AXY },
{ "tosdiva0", REG_AX, REG_AXY },
{ "tosumula0", REG_AX, REG_AXY },
{ "tosumulax", REG_AX, REG_AXY },
{ "tosumuleax", REG_AX, REG_AXY },
-};
+};
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
/* Table with names of zero page locations used by the compiler */
* @L: ...
*/
if ((N = CS_GetNextEntry (S, I)) == 0) {
- /* No such entry */
- Internal ("Invalid program flow");
+ /* No such entry */
+ Internal ("Invalid program flow");
}
L = CS_GenLabel (S, N);
N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
-static int IsBitOp (const CodeEntry* E)
-/* Check if E is one of the bit operations (and, or, eor) */
-{
- return (E->OPC == OP65_AND || E->OPC == OP65_ORA || E->OPC == OP65_EOR);
-}
-
-
-
static int IsCmpToZero (const CodeEntry* E)
/* Check if the given instrcuction is a compare to zero instruction */
{
*/
if (CE_HasLabel (E)) {
CS_MoveLabels (S, E, L[0]);
- }
+ }
/* Remember, we had changes */
++Changes;
CodeEntry* E = CS_GetEntry (S, I);
/* Check for the sequence */
- if ((E->OPC == OP65_LDA || IsBitOp (E)) &&
+ if ((E->OPC == OP65_ADC ||
+ E->OPC == OP65_AND ||
+ E->OPC == OP65_DEA ||
+ E->OPC == OP65_EOR ||
+ E->OPC == OP65_INA ||
+ E->OPC == OP65_LDA ||
+ E->OPC == OP65_ORA ||
+ E->OPC == OP65_PLA ||
+ E->OPC == OP65_SBC ||
+ E->OPC == OP65_TXA ||
+ E->OPC == OP65_TYA) &&
CS_GetEntries (S, L, I+1, 2) &&
IsCmpToZero (L[0]) &&
!CE_HasLabel (L[0]) &&
CS_MoveEntry (S, I, I+4);
/* We will replace the ldx/cpx by lda/cmp */
- CE_ReplaceOPC (L[0], OP65_LDA);
+ CE_ReplaceOPC (L[0], OP65_LDA);
CE_ReplaceOPC (L[1], OP65_CMP);
/* Beware: If the first LDA instruction had a label, we have
* lda (sp),y
* cpx #a
* bne L1
- * cmp #b
+ * cmp #b
* jne/jeq L2
*/
{
* ldy #o
* lda (sp),y
* dey
- * ora (sp),y
+ * ora (sp),y
* jne/jeq ...
*/
CE_ReplaceOPC (L[4], OP65_ORA);
}
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+/*****************************************************************************/
+/* Optimize tests */
+/*****************************************************************************/
+
+
+
+static unsigned OptTest1 (CodeSeg* S)
+/* On a sequence
+ *
+ * stx xxx
+ * ora xxx
+ * beq/bne ...
+ *
+ * if X is zero, the sequence may be changed
+ *
+ * cmp #$00
+ * beq/bne ...
+ *
+ * which may be optimized further by another step.
+ */
+{
+ unsigned Changes = 0;
+ unsigned I;
+
+ /* Generate register info for this step */
+ CS_GenRegInfo (S);
+
+ /* Walk over the entries */
+ I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* L[3];
+
+ /* Get next entry */
+ L[0] = CS_GetEntry (S, I);
+
+ /* Check if it's the sequence we're searching for */
+ if (L[0]->OPC == OP65_STX &&
+ L[0]->RI->In.RegX == 0 &&
+ CS_GetEntries (S, L+1, I+1, 2) &&
+ !CE_HasLabel (L[1]) &&
+ L[1]->OPC == OP65_ORA &&
+ strcmp (L[0]->Arg, L[1]->Arg) == 0 &&
+ !CE_HasLabel (L[2]) &&
+ (L[2]->Info & OF_ZBRA) != 0) {
+
+ /* Insert the compare */
+ CodeEntry* N = NewCodeEntry (OP65_CMP, AM65_IMM, "$00", 0, L[0]->LI);
+ CS_InsertEntry (S, N, I);
+
+ /* Remove the two other insns */
+ CS_DelEntry (S, I+2);
+ CS_DelEntry (S, I+1);
+
+ /* We had changes */
+ ++Changes;
+ }
+
/* Next entry */
++I;
}
+ /* Free register info */
+ CS_FreeRegInfo (S);
+
/* Return the number of changes made */
return Changes;
}
+
+
+
+
/*****************************************************************************/
/* nega optimizations */
/*****************************************************************************/
static unsigned OptNegA1 (CodeSeg* S)
/* Check for
*
- * ldx #$00
+ * ldx #$00
* lda ..
* jsr bnega
*
E->AM == AM65_IMM &&
(E->Flags & CEF_NUMARG) != 0 &&
E->Num == 0 &&
- CS_GetEntries (S, L, I+1, 2) &&
+ CS_GetEntries (S, L, I+1, 2) &&
L[0]->OPC == OP65_LDA &&
(L[0]->Use & REG_X) == 0 &&
L[1]->OPC == OP65_JSR &&
CodeEntry* E = CS_GetEntry (S, I);
/* Check for the sequence */
- if (E->OPC == OP65_LDA &&
+ if ((E->OPC == OP65_ADC ||
+ E->OPC == OP65_AND ||
+ E->OPC == OP65_DEA ||
+ E->OPC == OP65_EOR ||
+ E->OPC == OP65_INA ||
+ E->OPC == OP65_LDA ||
+ E->OPC == OP65_ORA ||
+ E->OPC == OP65_PLA ||
+ E->OPC == OP65_SBC ||
+ E->OPC == OP65_TXA ||
+ E->OPC == OP65_TYA) &&
CS_GetEntries (S, L, I+1, 2) &&
L[0]->OPC == OP65_JSR &&
strcmp (L[0]->Arg, "bnega") == 0 &&
- !CE_HasLabel (L[0]) &&
+ !CE_HasLabel (L[0]) &&
(L[1]->Info & OF_ZBRA) != 0) {
/* Invert the branch */
static unsigned OptNegAX1 (CodeSeg* S)
+/* On a call to bnegax, if X is zero, the result depends only on the value in
+ * A, so change the call to a call to bnega. This will get further optimized
+ * later if possible.
+ */
+{
+ unsigned Changes = 0;
+ unsigned I;
+
+ /* Generate register info for this step */
+ CS_GenRegInfo (S);
+
+ /* Walk over the entries */
+ I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check if this is a call to bnegax, and if X is known and zero */
+ if (E->OPC == OP65_JSR &&
+ E->RI->In.RegX == 0 &&
+ strcmp (E->Arg, "bnegax") == 0) {
+
+ /* We're cheating somewhat here ... */
+ E->Arg[5] = '\0';
+ E->Use &= ~REG_X;
+
+ /* We had changes */
+ ++Changes;
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+
+ /* Free register info */
+ CS_FreeRegInfo (S);
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
+static unsigned OptNegAX2 (CodeSeg* S)
/* Search for the sequence:
*
* lda (xx),y
/* lda --> ora */
CE_ReplaceOPC (L[2], OP65_ORA);
- /* Invert the branch */
+ /* Invert the branch */
CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
/* Delete the entries no longer needed. Beware: Deleting entries
-static unsigned OptNegAX2 (CodeSeg* S)
+static unsigned OptNegAX3 (CodeSeg* S)
/* Search for the sequence:
*
* lda xx
-static unsigned OptNegAX3 (CodeSeg* S)
+static unsigned OptNegAX4 (CodeSeg* S)
/* Search for the sequence:
*
- * jsr _xxx
+ * jsr xxx
* jsr bnega(x)
* jeq/jne ...
*
* and replace it by:
*
- * jsr _xxx
+ * jsr xxx
* <boolean test>
* jne/jeq ...
*/
/* Check for the sequence */
if (E->OPC == OP65_JSR &&
- E->Arg[0] == '_' &&
CS_GetEntries (S, L, I+1, 2) &&
L[0]->OPC == OP65_JSR &&
strncmp (L[0]->Arg,"bnega",5) == 0 &&
if (ByteSized) {
/* Test bytes */
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
- CS_InsertEntry (S, X, I+2);
+ CS_InsertEntry (S, X, I+2);
} else {
/* Test words */
X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
{ OptNegAX1, "OptNegAX1", 0 },
{ OptNegAX2, "OptNegAX2", 0 },
{ OptNegAX3, "OptNegAX3", 0 },
+ { OptNegAX4, "OptNegAX4", 0 },
/* Optimize compares */
{ OptCmp1, "OptCmp1", 0 },
{ OptCmp2, "OptCmp2", 0 },
{ OptCmp3, "OptCmp3", 0 },
{ OptCmp4, "OptCmp4", 0 },
{ OptCmp5, "OptCmp5", 0 },
+ /* Optimize tests */
+ { OptTest1, "OptTest1", 0 },
/* Remove unused loads */
{ OptUnusedLoads, "OptUnusedLoads", 0 },
{ OptDuplicateLoads, "OptDuplicateLoads", 0 },