Exemplo n.º 1
0
unsigned OptPush2 (CodeSeg* S)
/* A sequence
 *
 *     jsr     ldaxidx
 *     jsr     pushax
 *
 * may get replaced by
 *
 *     jsr     pushwidx
 *
 */
{
    unsigned I;
    unsigned Changes = 0;

    /* Generate register info */
    CS_GenRegInfo (S);

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

     	CodeEntry* L[2];

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

     	/* Check for the sequence */
       	if (CE_IsCallTo (L[0], "ldaxidx")               &&
            (L[1] = CS_GetNextEntry (S, I)) != 0        &&
            !CE_HasLabel (L[1])                         &&
       	    CE_IsCallTo (L[1], "pushax")) {

	    /* Insert new code behind the pushax */
	    CodeEntry* X;

	    /* jsr pushwidx */
	    X = NewCodeEntry (OP65_JSR, AM65_ABS, "pushwidx", 0, L[1]->LI);
	    CS_InsertEntry (S, X, I+2);

	    /* Delete the old code */
	    CS_DelEntries (S, I, 2);

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

	}

	/* Next entry */
	++I;

    }

    /* Free the register info */
    CS_FreeRegInfo (S);

    /* Return the number of changes made */
    return Changes;
}
Exemplo n.º 2
0
Arquivo: codeopt.c Projeto: coyxc/cc65
void RunOpt (CodeSeg* S)
/* Run the optimizer */
{
    const char* StatFileName;

    /* If we shouldn't run the optimizer, bail out */
    if (!S->Optimize) {
        return;
    }

    /* Check if we are requested to write optimizer statistics */
    StatFileName = getenv ("CC65_OPTSTATS");
    if (StatFileName) {
        ReadOptStats (StatFileName);
    }

    /* Print the name of the function we are working on */
    if (S->Func) {
        Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
    } else {
        Print (stdout, 1, "Running optimizer for global code segment\n");
    }

    /* If requested, open an output file */
    OpenDebugFile (S);
    WriteDebugOutput (S, 0);

    /* Generate register info for all instructions */
    CS_GenRegInfo (S);

    /* Run groups of optimizations */
    RunOptGroup1 (S);
    RunOptGroup2 (S);
    RunOptGroup3 (S);
    RunOptGroup4 (S);
    RunOptGroup5 (S);
    RunOptGroup6 (S);
    RunOptGroup7 (S);

    /* Free register info */
    CS_FreeRegInfo (S);

    /* Close output file if necessary */
    if (DebugOptOutput) {
        CloseOutputFile ();
    }

    /* Write statistics */
    if (StatFileName) {
        WriteOptStats (StatFileName);
    }
}
Exemplo n.º 3
0
unsigned Opt65C02Stores (CodeSeg* S)
/* Use STZ where 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 for a store with a register value of zero and an addressing
	 * mode available with STZ.
	 */
       	if (((E->OPC == OP65_STA && E->RI->In.RegA == 0) ||
	     (E->OPC == OP65_STX && E->RI->In.RegX == 0) ||
	     (E->OPC == OP65_STY && E->RI->In.RegY == 0))     	&&
            (E->AM == AM65_ZP  || E->AM == AM65_ABS ||
             E->AM == AM65_ZPX || E->AM == AM65_ABSX)) {

            /* Replace by STZ */
            CodeEntry* X = NewCodeEntry (OP65_STZ, E->AM, E->Arg, 0, E->LI);
            CS_InsertEntry (S, X, I+1);

            /* Delete the old stuff */
            CS_DelEntry (S, I);

	    /* We had changes */
	    ++Changes;
	}

     	/* Next entry */
	++I;

    }

    /* Free register info */
    CS_FreeRegInfo (S);

    /* Return the number of changes made */
    return Changes;
}
Exemplo n.º 4
0
unsigned Opt65C02Ind (CodeSeg* S)
/* Try to use the indirect addressing mode where 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 for addressing mode indirect indexed Y where Y is zero.
	 * Note: All opcodes that are available as (zp),y are also available
	 * as (zp), so we can ignore the actual opcode here.
	 */
	if (E->AM == AM65_ZP_INDY && E->RI->In.RegY == 0) {

	    /* Replace it by indirect addressing mode */
	    CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZP_IND, E->Arg, 0, E->LI);
	    CS_InsertEntry (S, X, I+1);
	    CS_DelEntry (S, I);

	    /* We had changes */
	    ++Changes;

	}

     	/* Next entry */
	++I;

    }

    /* Free register info */
    CS_FreeRegInfo (S);

    /* Return the number of changes made */
    return Changes;
}
Exemplo n.º 5
0
Arquivo: codeopt.c Projeto: coyxc/cc65
static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
/* Run one optimizer function Max times or until there are no more changes */
{
    unsigned Changes, C;

    /* Don't run the function if it is disabled or if it is prohibited by the
    ** code size factor
    */
    if (F->Disabled || F->CodeSizeFactor > S->CodeSizeFactor) {
        return 0;
    }

    /* Run this until there are no more changes */
    Changes = 0;
    do {

        /* Run the function */
        C = F->Func (S);
        Changes += C;

        /* Do statistics */
        ++F->TotalRuns;
        ++F->LastRuns;
        F->TotalChanges += C;
        F->LastChanges  += C;

        /* If we had changes, output stuff and regenerate register info */
        if (C) {
            if (Debug) {
                printf ("Applied %s: %u changes\n", F->Name, C);
            }
            WriteDebugOutput (S, F->Name);
            CS_GenRegInfo (S);
        }

    } while (--Max && C > 0);

    /* Return the number of changes */
    return Changes;
}
Exemplo n.º 6
0
unsigned Opt65C02BitOps (CodeSeg* S)
/* Use special bit op instructions of the C02 */
{
    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 for the sequence */
	if (L[0]->OPC == OP65_LDA      	       	                &&
            (L[0]->AM == AM65_ZP || L[0]->AM == AM65_ABS)       &&
            !CS_RangeHasLabel (S, I+1, 2)                       &&
            CS_GetEntries (S, L+1, I+1, 2)                      &&
            (L[1]->OPC == OP65_AND || L[1]->OPC == OP65_ORA)    &&
            CE_IsConstImm (L[1])                                &&
            L[2]->OPC == OP65_STA                               &&
            L[2]->AM == L[0]->AM                                &&
            strcmp (L[2]->Arg, L[0]->Arg) == 0                  &&
            !RegAUsed (S, I+3)) {

            char Buf[32];
            CodeEntry* X;

            /* Use TRB for AND and TSB for ORA */
            if (L[1]->OPC == OP65_AND) {

                /* LDA #XX */
                sprintf (Buf, "$%02X", (int) ((~L[1]->Num) & 0xFF));
                X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, L[1]->LI);
                CS_InsertEntry (S, X, I+3);

                /* TRB */
                X = NewCodeEntry (OP65_TRB, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
                CS_InsertEntry (S, X, I+4);

            } else {

                /* LDA #XX */
                sprintf (Buf, "$%02X", (int) L[1]->Num);
                X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, L[1]->LI);
                CS_InsertEntry (S, X, I+3);

                /* TSB */
                X = NewCodeEntry (OP65_TSB, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
                CS_InsertEntry (S, X, I+4);
            }

            /* Delete the old stuff */
            CS_DelEntries (S, I, 3);

	    /* We had changes */
	    ++Changes;
	}

     	/* Next entry */
	++I;

    }

    /* Free register info */
    CS_FreeRegInfo (S);

    /* Return the number of changes made */
    return Changes;
}
Exemplo n.º 7
0
Arquivo: codeopt.c Projeto: coyxc/cc65
static unsigned OptStackPtrOps (CodeSeg* S)
/* Merge adjacent calls to decsp into one. NOTE: This function won't merge all
** known cases!
*/
{
    unsigned Changes = 0;
    unsigned I;

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

        unsigned Dec1;
        unsigned Dec2;
        const CodeEntry* N;

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

        /* Check for decspn or subysp */
        if (E->OPC == OP65_JSR                          &&
            (Dec1 = IsDecSP (E)) > 0                    &&
            (N = CS_GetNextEntry (S, I)) != 0           &&
            (Dec2 = IsDecSP (N)) > 0                    &&
            (Dec1 += Dec2) <= 255                       &&
            !CE_HasLabel (N)) {

            CodeEntry* X;
            char Buf[20];

            /* We can combine the two */
            if (Dec1 <= 8) {
                /* Insert a call to decsp */
                xsprintf (Buf, sizeof (Buf), "decsp%u", Dec1);
                X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, N->LI);
                CS_InsertEntry (S, X, I+2);
            } else {
                /* Insert a call to subysp */
                const char* Arg = MakeHexArg (Dec1);
                X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI);
                CS_InsertEntry (S, X, I+2);
                X = NewCodeEntry (OP65_JSR, AM65_ABS, "subysp", 0, N->LI);
                CS_InsertEntry (S, X, I+3);
            }

            /* Delete the old code */
            CS_DelEntries (S, I, 2);

            /* Regenerate register info */
            CS_GenRegInfo (S);

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

        } else {

            /* Next entry */
            ++I;
        }

    }

    /* Return the number of changes made */
    return Changes;
}
Exemplo n.º 8
0
void CS_Output (CodeSeg* S)
/* Output the code segment data to the output file */
{
    unsigned I;
    const LineInfo* LI;

    /* Get the number of entries in this segment */
    unsigned Count = CS_GetEntryCount (S);

    /* If the code segment is empty, bail out here */
    if (Count == 0) {
	return;
    }

    /* Generate register info */
    CS_GenRegInfo (S);

    /* Output the segment directive */
    WriteOutput (".segment\t\"%s\"\n\n", S->SegName);

    /* Output all entries, prepended by the line information if it has changed */
    LI = 0;
    for (I = 0; I < Count; ++I) {
    	/* Get the next entry */
    	const CodeEntry* E = CollConstAt (&S->Entries, I);
    	/* Check if the line info has changed. If so, output the source line
    	 * if the option is enabled and output debug line info if the debug
    	 * option is enabled.
    	 */
    	if (E->LI != LI) {
    	    /* Line info has changed, remember the new line info */
    	    LI = E->LI;

    	    /* Add the source line as a comment. Beware: When line continuation
             * was used, the line may contain newlines.
             */
    	    if (AddSource) {
                const char* L = LI->Line;
                WriteOutput (";\n; ");
                while (*L) {
                    const char* N = strchr (L, '\n');
                    if (N) {
                        /* We have a newline, just write the first part */
                        WriteOutput ("%.*s\n; ", (int) (N - L), L);
                        L = N+1;
                    } else {
                        /* No Newline, write as is */
                        WriteOutput ("%s\n", L);
                        break;
                    }
                }
                WriteOutput (";\n");
    	    }

    	    /* Add line debug info */
	    if (DebugInfo) {
	       	WriteOutput ("\t.dbg\tline, \"%s\", %u\n",
	       	      	     GetInputName (LI), GetInputLine (LI));
	    }
	}
	/* Output the code */
	CE_Output (E);
    }

    /* If debug info is enabled, terminate the last line number information */
    if (DebugInfo) {
       	WriteOutput ("\t.dbg\tline\n");
    }

    /* Free register info */
    CS_FreeRegInfo (S);
}
Exemplo n.º 9
0
unsigned OptPush1 (CodeSeg* S)
/* Given a sequence
 *
 *     jsr     ldaxysp
 *     jsr     pushax
 *
 * If a/x are not used later, and Y is known, replace that by
 *
 *     ldy     #xx+2
 *     jsr     pushwysp
 *
 * saving 3 bytes and several cycles.
 */
{
    unsigned I;
    unsigned Changes = 0;

    /* Generate register info */
    CS_GenRegInfo (S);

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

     	CodeEntry* L[2];

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

     	/* Check for the sequence */
       	if (CE_IsCallTo (L[0], "ldaxysp")               &&
            RegValIsKnown (L[0]->RI->In.RegY)           &&
            L[0]->RI->In.RegY < 0xFE                    &&
            (L[1] = CS_GetNextEntry (S, I)) != 0        &&
            !CE_HasLabel (L[1])                         &&
       	    CE_IsCallTo (L[1], "pushax")                &&
       	    !RegAXUsed (S, I+2)) {

	    /* Insert new code behind the pushax */
	    const char* Arg;
	    CodeEntry* X;

	    /* ldy     #xx+1 */
	    Arg = MakeHexArg (L[0]->RI->In.RegY+2);
	    X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[0]->LI);
	    CS_InsertEntry (S, X, I+2);

	    /* jsr pushwysp */
	    X = NewCodeEntry (OP65_JSR, AM65_ABS, "pushwysp", 0, L[1]->LI);
	    CS_InsertEntry (S, X, I+3);

	    /* Delete the old code */
	    CS_DelEntries (S, I, 2);

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

	}

	/* Next entry */
	++I;

    }

    /* Free the register info */
    CS_FreeRegInfo (S);

    /* Return the number of changes made */
    return Changes;
}