コード例 #1
0
ファイル: coptcmp.c プロジェクト: eakmeister/cc65
unsigned OptBoolTrans (CodeSeg* S)
/* Try to remove the call to boolean transformer routines where the call is
 * not really needed.
 */
{
    unsigned Changes = 0;

    /* Walk over the entries */
    unsigned I = 0;
    while (I < CS_GetEntryCount (S)) {

	CodeEntry* N;
	cmp_t Cond;

      	/* Get next entry */
       	CodeEntry* E = CS_GetEntry (S, I);

	/* Check for a boolean transformer */
	if (E->OPC == OP65_JSR                           &&
	    (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
	    (N = CS_GetNextEntry (S, I)) != 0            &&
	    (N->Info & OF_ZBRA) != 0) {

	    /* Make the boolean transformer unnecessary by changing the
	     * the conditional jump to evaluate the condition flags that
	     * are set after the compare directly. Note: jeq jumps if
	     * the condition is not met, jne jumps if the condition is met.
     	     * Invert the code if we jump on condition not met.
	     */
       	    if (GetBranchCond (N->OPC) == BC_EQ) {
	       	/* Jumps if condition false, invert condition */
	       	Cond = CmpInvertTab [Cond];
  	    }

	    /* Check if we can replace the code by something better */
	    ReplaceCmp (S, I+1, Cond);

	    /* Remove the call to the bool transformer */
	    CS_DelEntry (S, I);

	    /* Remember, we had changes */
	    ++Changes;

	}

	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
コード例 #2
0
ファイル: coptcmp.c プロジェクト: eakmeister/cc65
unsigned OptCmp3 (CodeSeg* S)
/* Search for
 *
 *     	lda/and/ora/eor	...
 *  	cmp #$00
 *  	jeq/jne
 * or
 *     	lda/and/ora/eor	...
 *  	cmp #$00
 *  	jsr boolxx
 *
 * and remove the cmp.
 */
{
    unsigned Changes = 0;

    /* Walk over the entries */
    unsigned I = 0;
    while (I < CS_GetEntryCount (S)) {

	CodeEntry* L[3];

      	/* Get next entry */
       	L[0] = CS_GetEntry (S, I);

     	/* Check for the sequence */
       	if ((L[0]->OPC == OP65_ADC ||
       	     L[0]->OPC == OP65_AND ||
             L[0]->OPC == OP65_ASL ||
       	     L[0]->OPC == OP65_DEA ||
       	     L[0]->OPC == OP65_EOR ||
       	     L[0]->OPC == OP65_INA ||
       	     L[0]->OPC == OP65_LDA ||
             L[0]->OPC == OP65_LSR ||
       	     L[0]->OPC == OP65_ORA ||
       	     L[0]->OPC == OP65_PLA ||
       	     L[0]->OPC == OP65_SBC ||
       	     L[0]->OPC == OP65_TXA ||
       	     L[0]->OPC == OP65_TYA)         &&
	    !CS_RangeHasLabel (S, I+1, 2)   &&
	    CS_GetEntries (S, L+1, I+1, 2)  &&
	    L[1]->OPC == OP65_CMP           &&
	    CE_IsKnownImm (L[1], 0)) {

            int Delete = 0;

	    /* Check for the call to boolxx. We only remove the compare if
       	     * the carry flag is not evaluated later, because the load will
             * not set the carry flag.
	     */
	    if (L[2]->OPC == OP65_JSR) {
	    	switch (FindBoolCmpCond (L[2]->Arg)) {

	    	    case CMP_EQ:
	    	    case CMP_NE:
	    	    case CMP_GT:
	    	    case CMP_GE:
	    	    case CMP_LT:
	    	    case CMP_LE:
	    	        /* Remove the compare */
                        Delete = 1;
	    	        break;

	    	    case CMP_UGT:
	     	    case CMP_UGE:
	    	    case CMP_ULT:
	    	    case CMP_ULE:
	    	    case CMP_INV:
	    	        /* Leave it alone */
	    	        break;
	    	}

	    } else if ((L[2]->Info & OF_FBRA) != 0) {
                /* The following insn branches on the condition of the load,
                 * so the compare instruction might be removed. For safety,
                 * do some more checks if the carry isn't used later, since
                 * the compare does set the carry, but the load does not.
                 */
                CodeEntry* E;
                CodeEntry* N;
                if ((E = CS_GetNextEntry (S, I+2)) != 0         &&
                    L[2]->JumpTo != 0                           &&
                    (N = L[2]->JumpTo->Owner) != 0              &&
                    N->OPC != OP65_BCC                          &&
                    N->OPC != OP65_BCS                          &&
                    N->OPC != OP65_JCC                          &&
                    N->OPC != OP65_JCS                          &&
                    (N->OPC != OP65_JSR                 ||
                    FindBoolCmpCond (N->Arg) == CMP_INV)) {

                    /* The following insn branches on the condition of a load,
                     * and there's no use of the carry flag in sight, so the
                     * compare instruction can be removed.
                     */
                    Delete = 1;
                }
            }

            /* Delete the compare if we can */
            if (Delete) {
                CS_DelEntry (S, I+1);
                ++Changes;
            }
	}

	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
コード例 #3
0
ファイル: codeent.c プロジェクト: Aliandrana/cc65
void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
/* Generate register info for this instruction. If an old info exists, it is
** overwritten.
*/
{
    /* Pointers to the register contents */
    RegContents* In;
    RegContents* Out;

    /* Function register usage */
    unsigned short Use, Chg;

    /* If we don't have a register info struct, allocate one. */
    if (E->RI == 0) {
        E->RI = NewRegInfo (InputRegs);
    } else {
        if (InputRegs) {
            E->RI->In  = *InputRegs;
        } else {
            RC_Invalidate (&E->RI->In);
        }
        E->RI->Out2 = E->RI->Out = E->RI->In;
    }

    /* Get pointers to the register contents */
    In  = &E->RI->In;
    Out = &E->RI->Out;

    /* Handle the different instructions */
    switch (E->OPC) {

        case OP65_ADC:
            /* We don't know the value of the carry, so the result is
            ** always unknown.
            */
            Out->RegA = UNKNOWN_REGVAL;
            break;

        case OP65_AND:
            if (RegValIsKnown (In->RegA)) {
                if (CE_IsConstImm (E)) {
                    Out->RegA = In->RegA & (short) E->Num;
                } else if (E->AM == AM65_ZP) {
                    switch (GetKnownReg (E->Use & REG_ZP, In)) {
                        case REG_TMP1:
                            Out->RegA = In->RegA & In->Tmp1;
                            break;
                        case REG_PTR1_LO:
                            Out->RegA = In->RegA & In->Ptr1Lo;
                            break;
                        case REG_PTR1_HI:
                            Out->RegA = In->RegA & In->Ptr1Hi;
                            break;
                        case REG_SREG_LO:
                            Out->RegA = In->RegA & In->SRegLo;
                            break;
                        case REG_SREG_HI:
                            Out->RegA = In->RegA & In->SRegHi;
                            break;
                        default:
                            Out->RegA = UNKNOWN_REGVAL;
                            break;
                    }
                } else {
                    Out->RegA = UNKNOWN_REGVAL;
                }
            } else if (CE_IsKnownImm (E, 0)) {
                /* A and $00 does always give zero */
                Out->RegA = 0;
            }
            break;

        case OP65_ASL:
            if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA << 1) & 0xFF;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Chg & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->Tmp1 = (In->Tmp1 << 1) & 0xFF;
                        break;
                    case REG_PTR1_LO:
                        Out->Ptr1Lo = (In->Ptr1Lo << 1) & 0xFF;
                        break;
                    case REG_PTR1_HI:
                        Out->Ptr1Hi = (In->Ptr1Hi << 1) & 0xFF;
                        break;
                    case REG_SREG_LO:
                        Out->SRegLo = (In->SRegLo << 1) & 0xFF;
                        break;
                    case REG_SREG_HI:
                        Out->SRegHi = (In->SRegHi << 1) & 0xFF;
                        break;
                }
            } else if (E->AM == AM65_ZPX) {
                /* Invalidates all ZP registers */
                RC_InvalidateZP (Out);
            }
            break;

        case OP65_BCC:
            break;

        case OP65_BCS:
            break;

        case OP65_BEQ:
            break;

        case OP65_BIT:
            break;

        case OP65_BMI:
            break;

        case OP65_BNE:
            break;

        case OP65_BPL:
            break;

        case OP65_BRA:
            break;

        case OP65_BRK:
            break;

        case OP65_BVC:
            break;

        case OP65_BVS:
            break;

        case OP65_CLC:
            break;

        case OP65_CLD:
            break;

        case OP65_CLI:
            break;

        case OP65_CLV:
            break;

        case OP65_CMP:
            break;

        case OP65_CPX:
            break;

        case OP65_CPY:
            break;

        case OP65_DEA:
            if (RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA - 1) & 0xFF;
            }
            break;

        case OP65_DEC:
            if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA - 1) & 0xFF;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Chg & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->Tmp1 = (In->Tmp1 - 1) & 0xFF;
                        break;
                    case REG_PTR1_LO:
                        Out->Ptr1Lo = (In->Ptr1Lo - 1) & 0xFF;
                        break;
                    case REG_PTR1_HI:
                        Out->Ptr1Hi = (In->Ptr1Hi - 1) & 0xFF;
                        break;
                    case REG_SREG_LO:
                        Out->SRegLo = (In->SRegLo - 1) & 0xFF;
                        break;
                    case REG_SREG_HI:
                        Out->SRegHi = (In->SRegHi - 1) & 0xFF;
                        break;
                }
            } else if (E->AM == AM65_ZPX) {
                /* Invalidates all ZP registers */
                RC_InvalidateZP (Out);
            }
            break;

        case OP65_DEX:
            if (RegValIsKnown (In->RegX)) {
                Out->RegX = (In->RegX - 1) & 0xFF;
            }
            break;

        case OP65_DEY:
            if (RegValIsKnown (In->RegY)) {
                Out->RegY = (In->RegY - 1) & 0xFF;
            }
            break;

        case OP65_EOR:
            if (RegValIsKnown (In->RegA)) {
                if (CE_IsConstImm (E)) {
                    Out->RegA = In->RegA ^ (short) E->Num;
                } else if (E->AM == AM65_ZP) {
                    switch (GetKnownReg (E->Use & REG_ZP, In)) {
                        case REG_TMP1:
                            Out->RegA = In->RegA ^ In->Tmp1;
                            break;
                        case REG_PTR1_LO:
                            Out->RegA = In->RegA ^ In->Ptr1Lo;
                            break;
                        case REG_PTR1_HI:
                            Out->RegA = In->RegA ^ In->Ptr1Hi;
                            break;
                        case REG_SREG_LO:
                            Out->RegA = In->RegA ^ In->SRegLo;
                            break;
                        case REG_SREG_HI:
                            Out->RegA = In->RegA ^ In->SRegHi;
                            break;
                        default:
                            Out->RegA = UNKNOWN_REGVAL;
                            break;
                    }
                } else {
                    Out->RegA = UNKNOWN_REGVAL;
                }
            }
            break;

        case OP65_INA:
            if (RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA + 1) & 0xFF;
            }
            break;

        case OP65_INC:
            if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA + 1) & 0xFF;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Chg & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->Tmp1 = (In->Tmp1 + 1) & 0xFF;
                        break;
                    case REG_PTR1_LO:
                        Out->Ptr1Lo = (In->Ptr1Lo + 1) & 0xFF;
                        break;
                    case REG_PTR1_HI:
                        Out->Ptr1Hi = (In->Ptr1Hi + 1) & 0xFF;
                        break;
                    case REG_SREG_LO:
                        Out->SRegLo = (In->SRegLo + 1) & 0xFF;
                        break;
                    case REG_SREG_HI:
                        Out->SRegHi = (In->SRegHi + 1) & 0xFF;
                        break;
                }
            } else if (E->AM == AM65_ZPX) {
                /* Invalidates all ZP registers */
                RC_InvalidateZP (Out);
            }
            break;

        case OP65_INX:
            if (RegValIsKnown (In->RegX)) {
                Out->RegX = (In->RegX + 1) & 0xFF;
            }
            break;

        case OP65_INY:
            if (RegValIsKnown (In->RegY)) {
                Out->RegY = (In->RegY + 1) & 0xFF;
            }
            break;

        case OP65_JCC:
            break;

        case OP65_JCS:
            break;

        case OP65_JEQ:
            break;

        case OP65_JMI:
            break;

        case OP65_JMP:
            break;

        case OP65_JNE:
            break;

        case OP65_JPL:
            break;

        case OP65_JSR:
            /* Get the code info for the function */
            GetFuncInfo (E->Arg, &Use, &Chg);
            if (Chg & REG_A) {
                Out->RegA = UNKNOWN_REGVAL;
            }
            if (Chg & REG_X) {
                Out->RegX = UNKNOWN_REGVAL;
            }
            if (Chg & REG_Y) {
                Out->RegY = UNKNOWN_REGVAL;
            }
            if (Chg & REG_TMP1) {
                Out->Tmp1 = UNKNOWN_REGVAL;
            }
            if (Chg & REG_PTR1_LO) {
                Out->Ptr1Lo = UNKNOWN_REGVAL;
            }
            if (Chg & REG_PTR1_HI) {
                Out->Ptr1Hi = UNKNOWN_REGVAL;
            }
            if (Chg & REG_SREG_LO) {
                Out->SRegLo = UNKNOWN_REGVAL;
            }
            if (Chg & REG_SREG_HI) {
                Out->SRegHi = UNKNOWN_REGVAL;
            }
            /* ## FIXME: Quick hack for some known functions: */
            if (strcmp (E->Arg, "complax") == 0) {
                if (RegValIsKnown (In->RegA)) {
                    Out->RegA = (In->RegA ^ 0xFF);
                }
                if (RegValIsKnown (In->RegX)) {
                    Out->RegX = (In->RegX ^ 0xFF);
                }
            } else if (strcmp (E->Arg, "tosandax") == 0) {
                if (In->RegA == 0) {
                    Out->RegA = 0;
                }
                if (In->RegX == 0) {
                    Out->RegX = 0;
                }
            } else if (strcmp (E->Arg, "tosaslax") == 0) {
                if (RegValIsKnown (In->RegA) && (In->RegA & 0x0F) >= 8) {
                    printf ("Hey!\n");
                    Out->RegA = 0;
                }
            } else if (strcmp (E->Arg, "tosorax") == 0) {
                if (In->RegA == 0xFF) {
                    Out->RegA = 0xFF;
                }
                if (In->RegX == 0xFF) {
                    Out->RegX = 0xFF;
                }
            } else if (strcmp (E->Arg, "tosshlax") == 0) {
                if ((In->RegA & 0x0F) >= 8) {
                    Out->RegA = 0;
                }
            } else if (FindBoolCmpCond (E->Arg) != CMP_INV ||
                       FindTosCmpCond (E->Arg) != CMP_INV) {
                /* Result is boolean value, so X is zero on output */
                Out->RegX = 0;
            }
            break;

        case OP65_JVC:
            break;

        case OP65_JVS:
            break;

        case OP65_LDA:
            if (CE_IsConstImm (E)) {
                Out->RegA = (unsigned char) E->Num;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Use & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->RegA = In->Tmp1;
                        break;
                    case REG_PTR1_LO:
                        Out->RegA = In->Ptr1Lo;
                        break;
                    case REG_PTR1_HI:
                        Out->RegA = In->Ptr1Hi;
                        break;
                    case REG_SREG_LO:
                        Out->RegA = In->SRegLo;
                        break;
                    case REG_SREG_HI:
                        Out->RegA = In->SRegHi;
                        break;
                    default:
                        Out->RegA = UNKNOWN_REGVAL;
                        break;
                }
            } else {
                /* A is now unknown */
                Out->RegA = UNKNOWN_REGVAL;
            }
            break;

        case OP65_LDX:
            if (CE_IsConstImm (E)) {
                Out->RegX = (unsigned char) E->Num;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Use & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->RegX = In->Tmp1;
                        break;
                    case REG_PTR1_LO:
                        Out->RegX = In->Ptr1Lo;
                        break;
                    case REG_PTR1_HI:
                        Out->RegX = In->Ptr1Hi;
                        break;
                    case REG_SREG_LO:
                        Out->RegX = In->SRegLo;
                        break;
                    case REG_SREG_HI:
                        Out->RegX = In->SRegHi;
                        break;
                    default:
                        Out->RegX = UNKNOWN_REGVAL;
                        break;
                }
            } else {
                /* X is now unknown */
                Out->RegX = UNKNOWN_REGVAL;
            }
            break;

        case OP65_LDY:
            if (CE_IsConstImm (E)) {
                Out->RegY = (unsigned char) E->Num;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Use & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->RegY = In->Tmp1;
                        break;
                    case REG_PTR1_LO:
                        Out->RegY = In->Ptr1Lo;
                        break;
                    case REG_PTR1_HI:
                        Out->RegY = In->Ptr1Hi;
                        break;
                    case REG_SREG_LO:
                        Out->RegY = In->SRegLo;
                        break;
                    case REG_SREG_HI:
                        Out->RegY = In->SRegHi;
                        break;
                    default:
                        Out->RegY = UNKNOWN_REGVAL;
                        break;
                }
            } else {
                /* Y is now unknown */
                Out->RegY = UNKNOWN_REGVAL;
            }
            break;

        case OP65_LSR:
            if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA >> 1) & 0xFF;
            } else if (E->AM == AM65_ZP) {
コード例 #4
0
ファイル: codeent.c プロジェクト: Aliandrana/cc65
int CE_UseLoadFlags (CodeEntry* E)
/* Return true if the instruction uses any flags that are set by a load of
** a register (N and Z).
*/
{
    /* Follow unconditional branches, but beware of endless loops. After this,
    ** E will point to the first entry that is not a branch.
    */
    if (E->Info & OF_UBRA) {
        Collection C = AUTO_COLLECTION_INITIALIZER;

        /* Follow the chain */
        while (E->Info & OF_UBRA) {

            /* Remember the entry so we can detect loops */
            CollAppend (&C, E);

            /* Check the target */
            if (E->JumpTo == 0 || CollIndex (&C, E->JumpTo->Owner) >= 0) {
                /* Unconditional jump to external symbol, or endless loop. */
                DoneCollection (&C);
                return 0;       /* Flags not used */
            }

            /* Follow the chain */
            E = E->JumpTo->Owner;
        }

        /* Delete the collection */
        DoneCollection (&C);
    }

    /* A branch will use the flags */
    if (E->Info & OF_FBRA) {
        return 1;
    }

    /* Call of a boolean transformer routine will also use the flags */
    if (E->OPC == OP65_JSR) {
        /* Get the condition that is evaluated and check it */
        switch (FindBoolCmpCond (E->Arg)) {
            case CMP_EQ:
            case CMP_NE:
            case CMP_GT:
            case CMP_GE:
            case CMP_LT:
            case CMP_LE:
            case CMP_UGT:
            case CMP_ULE:
                /* Will use the N or Z flags */
                return 1;


            case CMP_UGE:       /* Uses only carry */
            case CMP_ULT:       /* Dito */
            default:            /* No bool transformer subroutine */
                return 0;
        }
    }

    /* Anything else */
    return 0;
}