diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index 8fd94874d..3430dbeae 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -131,6 +131,7 @@ static const FuncInfo FuncInfoTable[] = { { "shreax3", REG_AX, REG_AX }, { "shreax4", REG_AX, REG_AX }, { "staspidx", REG_A | REG_Y, REG_Y }, + { "stax0sp", REG_AX, REG_Y }, { "tosicmp", REG_AX, REG_AXY }, { "tosdiva0", REG_AX, REG_AXY }, { "tosdivax", REG_AX, REG_AXY }, diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 6be5b91e3..328da9893 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -1032,7 +1032,7 @@ static unsigned OptCmp6 (CodeSeg* S) CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ - if ((E->OPC == OP65_LDX || E->OPC == OP65_TAX) && + if ((E->OPC == OP65_LDX) && CS_GetEntries (S, L, I+1, 2) && L[0]->OPC == OP65_TXA && !CE_HasLabel (L[0]) && @@ -1072,12 +1072,18 @@ static unsigned OptTest1 (CodeSeg* S) * ora xxx * beq/bne ... * - * if X is zero, the sequence may be changed + * if X is zero, the sequence may be changed to * * cmp #$00 * beq/bne ... * * which may be optimized further by another step. + * + * If A is zero, the sequence may be changed to + * + * txa + * beq/bne ... + * */ { unsigned Changes = 0; @@ -1097,7 +1103,6 @@ static unsigned OptTest1 (CodeSeg* S) /* 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 && @@ -1105,16 +1110,34 @@ static unsigned OptTest1 (CodeSeg* S) !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+2); + /* Check if X is zero */ + if (L[0]->RI->In.RegX == 0) { - /* Remove the two other insns */ - CS_DelEntry (S, I+1); - CS_DelEntry (S, I); + /* Insert the compare */ + CodeEntry* N = NewCodeEntry (OP65_CMP, AM65_IMM, "$00", 0, L[0]->LI); + CS_InsertEntry (S, N, I+2); - /* We had changes */ - ++Changes; + /* Remove the two other insns */ + CS_DelEntry (S, I+1); + CS_DelEntry (S, I); + + /* We had changes */ + ++Changes; + + /* Check if A is zero */ + } else if (L[1]->RI->In.RegA == 0) { + + /* Insert the txa */ + CodeEntry* N = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[1]->LI); + CS_InsertEntry (S, N, I+2); + + /* Remove the two other insns */ + CS_DelEntry (S, I+1); + CS_DelEntry (S, I); + + /* We had changes */ + ++Changes; + } } /* Next entry */ @@ -1131,10 +1154,6 @@ static unsigned OptTest1 (CodeSeg* S) - - - - /*****************************************************************************/ /* nega optimizations */ /*****************************************************************************/ @@ -1967,8 +1986,9 @@ static OptFunc OptFuncs [] = { OptEntry (OptUnusedLoads, optMain), OptEntry (OptDuplicateLoads, optMain), OptEntry (OptStoreLoad, optMain), + OptEntry (OptTransfers, optMain), /* Optimize branch distance */ - OptEntry (OptBranchDist, optMain), + OptEntry (OptBranchDist, optPost), }; diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c index 33b8f660d..24bc260db 100644 --- a/src/cc65/coptind.c +++ b/src/cc65/coptind.c @@ -44,18 +44,6 @@ -/*****************************************************************************/ -/* Macros */ -/*****************************************************************************/ - - - -/* Macro to increment and decrement register contents if they're valid */ -#define INC(reg,val) if ((reg) >= 0) (reg) = ((reg) + val) & 0xFF -#define DEC(reg,val) if ((reg) >= 0) (reg) = ((reg) - val) & 0xFF - - - /*****************************************************************************/ /* Replace jumps to RTS by RTS */ /*****************************************************************************/ @@ -611,20 +599,26 @@ unsigned OptUnusedLoads (CodeSeg* S) CodeEntry* E = CS_GetEntry (S, I); /* Check if it's a register load or transfer insn */ - if ((E->Info & (OF_LOAD | OF_XFR)) != 0 && - (N = CS_GetNextEntry (S, I)) != 0 && + if ((E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0 && + (N = CS_GetNextEntry (S, I)) != 0 && (N->Info & OF_FBRA) == 0) { /* Check which sort of load or transfer it is */ unsigned R; switch (E->OPC) { + case OP65_DEA: + case OP65_INA: + case OP65_LDA: case OP65_TXA: - case OP65_TYA: - case OP65_LDA: R = REG_A; break; - case OP65_TAX: - case OP65_LDX: R = REG_X; break; - case OP65_TAY: - case OP65_LDY: R = REG_Y; break; + case OP65_TYA: R = REG_A; break; + case OP65_DEX: + case OP65_INX: + case OP65_LDX: + case OP65_TAX: R = REG_X; break; + case OP65_DEY: + case OP65_INY: + case OP65_LDY: + case OP65_TAY: R = REG_Y; break; default: goto NextEntry; /* OOPS */ } @@ -858,6 +852,76 @@ unsigned OptStoreLoad (CodeSeg* S) +unsigned OptTransfers (CodeSeg* S) +/* Remove transfers from one register to another and back */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* N; + CodeEntry* X; + CodeEntry* P; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check if it is a store instruction followed by a load from the + * same address which is itself not followed by a conditional branch. + */ + if ((E->Info & OF_XFR) != 0 && + (N = CS_GetNextEntry (S, I)) != 0 && + !CE_HasLabel (N) && + (N->Info & OF_XFR) != 0) { + + /* Check if it's a transfer and back */ + if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+2)) || + (E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+2)) || + (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (S, I+2)) || + (E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+1))) { + + /* If the next insn is a conditional branch, check if the insn + * preceeding the first xfr will set the flags right, otherwise we + * may not remove the sequence. + */ + if ((X = CS_GetNextEntry (S, I+1)) == 0) { + goto NextEntry; + } + if ((X->Info & OF_FBRA) != 0) { + if (I == 0) { + /* No preceeding entry */ + goto NextEntry; + } + P = CS_GetEntry (S, I-1); + if ((P->Info & OF_SETF) == 0) { + /* Does not set the flags */ + goto NextEntry; + } + } + + /* Remove both transfers */ + CS_DelEntry (S, I+1); + CS_DelEntry (S, I); + + /* Remember, we had changes */ + ++Changes; + } + } + +NextEntry: + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + /*****************************************************************************/ /* Optimize branch types */ /*****************************************************************************/ diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h index 30d9d1577..04530f194 100644 --- a/src/cc65/coptind.h +++ b/src/cc65/coptind.h @@ -95,6 +95,9 @@ unsigned OptDuplicateLoads (CodeSeg* S); unsigned OptStoreLoad (CodeSeg* S); /* Remove a store followed by a load from the same location. */ +unsigned OptTransfers (CodeSeg* S); +/* Remove transfers from one register to another and back */ + unsigned OptBranchDist (CodeSeg* S); /* Change branches for the distance needed. */ diff --git a/src/cc65/opcodes.c b/src/cc65/opcodes.c index f70207871..fa8b1d575 100644 --- a/src/cc65/opcodes.c +++ b/src/cc65/opcodes.c @@ -57,141 +57,27 @@ /* Opcode description table */ const OPCDesc OPCTable[OPCODE_COUNT] = { - /* Opcodes for the virtual stack machine */ - { OPC_CALL, /* opcode */ - "call", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM | OF_CALL /* flags */ - }, - { OPC_ENTER, /* opcode */ - "enter", /* mnemonic */ - 1, /* size */ - REG_Y, /* use */ - REG_AXY, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_JMP, /* opcode */ - "jump", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM | OF_UBRA /* flags */ - }, - { OPC_LDA, /* opcode */ - "lda", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_A, /* chg */ - OF_CPU_VM | OF_LOAD /* flags */ - }, - { OPC_LDAX, /* opcode */ - "ldax", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_AX, /* chg */ - OF_CPU_VM | OF_LOAD /* flags */ - }, - { OPC_LDEAX, /* opcode */ - "ldeax", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_EAX, /* chg */ - OF_CPU_VM | OF_LOAD /* flags */ - }, - { OPC_LEA, /* opcode */ - "lea", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_AX, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_LEAVE, /* opcode */ - "leave", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_PHA, /* opcode */ - "pha", /* mnemonic */ - 1, /* size */ - REG_A, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_PHAX, /* opcode */ - "phax", /* mnemonic */ - 1, /* size */ - REG_AX, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_PHEAX, /* opcode */ - "pheax", /* mnemonic */ - 1, /* size */ - REG_EAX, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_RET, /* opcode */ - "ret", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM | OF_RET /* flags */ - }, - { OPC_SPACE, /* opcode */ - "space", /* mnemonic */ - 1, /* size */ - REG_NONE, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_STA, /* opcode */ - "sta", /* mnemonic */ - 1, /* size */ - REG_A, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_STAX, /* opcode */ - "stax", /* mnemonic */ - 1, /* size */ - REG_AX, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM /* flags */ - }, - { OPC_STEAX, /* opcode */ - "steax", /* mnemonic */ - 1, /* size */ - REG_EAX, /* use */ - REG_NONE, /* chg */ - OF_CPU_VM /* flags */ - }, - /* 65XX opcodes */ { OP65_ADC, /* opcode */ "adc", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_AND, /* opcode */ "and", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_ASL, /* opcode */ "asl", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_BCC, /* opcode */ "bcc", /* mnemonic */ @@ -219,7 +105,7 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 0, /* size */ REG_A, /* use */ REG_NONE, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_BMI, /* opcode */ "bmi", /* mnemonic */ @@ -303,84 +189,84 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 0, /* size */ REG_A, /* use */ REG_NONE, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_CPX, /* opcode */ "cpx", /* mnemonic */ 0, /* size */ REG_X, /* use */ REG_NONE, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_CPY, /* opcode */ "cpy", /* mnemonic */ 0, /* size */ REG_Y, /* use */ REG_NONE, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_DEA, /* opcode */ "dea", /* mnemonic */ 1, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_REG_INCDEC | OF_SETF /* flags */ }, { OP65_DEC, /* opcode */ "dec", /* mnemonic */ 0, /* size */ REG_NONE, /* use */ REG_NONE, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_DEX, /* opcode */ "dex", /* mnemonic */ 1, /* size */ REG_X, /* use */ REG_X, /* chg */ - OF_NONE /* flags */ + OF_REG_INCDEC | OF_SETF /* flags */ }, { OP65_DEY, /* opcode */ "dey", /* mnemonic */ 1, /* size */ REG_Y, /* use */ REG_Y, /* chg */ - OF_NONE /* flags */ + OF_REG_INCDEC | OF_SETF /* flags */ }, { OP65_EOR, /* opcode */ "eor", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_INA, /* opcode */ "ina", /* mnemonic */ 1, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_REG_INCDEC | OF_SETF /* flags */ }, { OP65_INC, /* opcode */ "inc", /* mnemonic */ 0, /* size */ REG_NONE, /* use */ REG_NONE, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_INX, /* opcode */ "inx", /* mnemonic */ 1, /* size */ REG_X, /* use */ REG_X, /* chg */ - OF_NONE /* flags */ + OF_REG_INCDEC | OF_SETF /* flags */ }, { OP65_INY, /* opcode */ "iny", /* mnemonic */ 1, /* size */ REG_Y, /* use */ REG_Y, /* chg */ - OF_NONE /* flags */ + OF_REG_INCDEC | OF_SETF /* flags */ }, { OP65_JCC, /* opcode */ "jcc", /* mnemonic */ @@ -457,28 +343,28 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 0, /* size */ REG_NONE, /* use */ REG_A, /* chg */ - OF_LOAD /* flags */ + OF_LOAD | OF_SETF /* flags */ }, { OP65_LDX, /* opcode */ "ldx", /* mnemonic */ 0, /* size */ REG_NONE, /* use */ REG_X, /* chg */ - OF_LOAD /* flags */ + OF_LOAD | OF_SETF /* flags */ }, { OP65_LDY, /* opcode */ "ldy", /* mnemonic */ 0, /* size */ REG_NONE, /* use */ REG_Y, /* chg */ - OF_LOAD /* flags */ + OF_LOAD | OF_SETF /* flags */ }, { OP65_LSR, /* opcode */ "lsr", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_NOP, /* opcode */ "nop", /* mnemonic */ @@ -492,7 +378,7 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_PHA, /* opcode */ "pha", /* mnemonic */ @@ -527,7 +413,7 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 1, /* size */ REG_NONE, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_PLP, /* opcode */ "plp", /* mnemonic */ @@ -541,49 +427,49 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 1, /* size */ REG_NONE, /* use */ REG_X, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_PLY, /* opcode */ "ply", /* mnemonic */ 1, /* size */ REG_NONE, /* use */ REG_Y, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_ROL, /* opcode */ "rol", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_ROR, /* opcode */ "ror", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_RTI, /* opcode */ "rti", /* mnemonic */ 1, /* size */ REG_NONE, /* use */ REG_NONE, /* chg */ - OF_RET /* flags */ + OF_RET /* flags */ }, { OP65_RTS, /* opcode */ "rts", /* mnemonic */ 1, /* size */ REG_NONE, /* use */ REG_NONE, /* chg */ - OF_RET /* flags */ + OF_RET /* flags */ }, { OP65_SBC, /* opcode */ "sbc", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_A, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_SEC, /* opcode */ "sec", /* mnemonic */ @@ -632,42 +518,42 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 1, /* size */ REG_A, /* use */ REG_X, /* chg */ - OF_XFR /* flags */ + OF_XFR | OF_SETF /* flags */ }, { OP65_TAY, /* opcode */ "tay", /* mnemonic */ 1, /* size */ REG_A, /* use */ REG_Y, /* chg */ - OF_XFR /* flags */ + OF_XFR | OF_SETF /* flags */ }, { OP65_TRB, /* opcode */ "trb", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_NONE, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_TSB, /* opcode */ "tsb", /* mnemonic */ 0, /* size */ REG_A, /* use */ REG_NONE, /* chg */ - OF_NONE /* flags */ + OF_SETF /* flags */ }, { OP65_TSX, /* opcode */ "tsx", /* mnemonic */ 1, /* size */ REG_NONE, /* use */ REG_X, /* chg */ - OF_XFR /* flags */ + OF_XFR | OF_SETF /* flags */ }, { OP65_TXA, /* opcode */ "txa", /* mnemonic */ 1, /* size */ REG_X, /* use */ REG_A, /* chg */ - OF_XFR /* flags */ + OF_XFR | OF_SETF /* flags */ }, { OP65_TXS, /* opcode */ "txs", /* mnemonic */ @@ -681,7 +567,7 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { 1, /* size */ REG_Y, /* use */ REG_A, /* chg */ - OF_XFR /* flags */ + OF_XFR | OF_SETF /* flags */ }, }; @@ -695,7 +581,7 @@ const OPCDesc OPCTable[OPCODE_COUNT] = { static int FindCmp (const void* Key, const void* Desc) /* Compare function for FindOpcode */ -{ +{ return strcmp (Key, ((OPCDesc*)Desc)->Mnemo); } diff --git a/src/cc65/opcodes.h b/src/cc65/opcodes.h index 990a878e5..209bc31a0 100644 --- a/src/cc65/opcodes.h +++ b/src/cc65/opcodes.h @@ -52,24 +52,6 @@ /* Definitions for the possible opcodes */ typedef enum { - /* Opcodes for the virtual stack machine */ - OPC_CALL, - OPC_ENTER, - OPC_JMP, - OPC_LDA, - OPC_LDAX, - OPC_LDEAX, - OPC_LEA, - OPC_LEAVE, - OPC_PHA, - OPC_PHAX, - OPC_PHEAX, - OPC_RET, - OPC_SPACE, - OPC_STA, - OPC_STAX, - OPC_STEAX, - /* 65XX opcodes */ OP65_ADC, OP65_AND, @@ -193,19 +175,18 @@ typedef enum { /* Opcode info */ #define OF_NONE 0x0000U /* No additional information */ -#define OF_CPU_6502 0x0000U /* 6502 opcode */ -#define OF_CPU_VM 0x0001U /* Virtual machine opcode */ -#define OF_MASK_CPU 0x0001U /* Mask for the cpu field */ -#define OF_UBRA 0x0010U /* Unconditional branch */ -#define OF_CBRA 0x0020U /* Conditional branch */ -#define OF_ZBRA 0x0040U /* Branch on zero flag condition */ -#define OF_FBRA 0x0080U /* Branch on cond set by a load */ -#define OF_LBRA 0x0100U /* Jump/branch is long */ -#define OF_RET 0x0200U /* Return from function */ -#define OF_LOAD 0x0400U /* Register load */ -#define OF_STORE 0x0800U /* Register store */ -#define OF_XFR 0x1000U /* Transfer instruction */ -#define OF_CALL 0x2000U /* A subroutine call */ +#define OF_UBRA 0x0001U /* Unconditional branch */ +#define OF_CBRA 0x0002U /* Conditional branch */ +#define OF_ZBRA 0x0004U /* Branch on zero flag condition */ +#define OF_FBRA 0x0008U /* Branch on cond set by a load */ +#define OF_LBRA 0x0010U /* Jump/branch is long */ +#define OF_RET 0x0020U /* Return from function */ +#define OF_LOAD 0x0040U /* Register load */ +#define OF_STORE 0x0080U /* Register store */ +#define OF_XFR 0x0100U /* Transfer instruction */ +#define OF_CALL 0x0200U /* A subroutine call */ +#define OF_REG_INCDEC 0x0400U /* A register increment or decrement */ +#define OF_SETF 0x0800U /* Insn will set all load flags (not carry) */ /* Combined infos */ #define OF_BRA (OF_UBRA | OF_CBRA) /* Operation is a jump/branch */