示例#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;
}
示例#2
0
文件: codeopt.c 项目: 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);
    }
}
示例#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;
}
示例#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;
}
示例#5
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;
}
示例#6
0
void CS_GenRegInfo (CodeSeg* S)
/* Generate register infos for all instructions */
{
    unsigned I;
    RegContents Regs;		/* Initial register contents */
    RegContents* CurrentRegs;   /* Current register contents */
    int WasJump;                /* True if last insn was a jump */
    int Done;                   /* All runs done flag */

    /* Be sure to delete all register infos */
    CS_FreeRegInfo (S);

    /* We may need two runs to get back references right */
    do {

	/* Assume we're done after this run */
	Done = 1;

	/* On entry, the register contents are unknown */
	RC_Invalidate (&Regs);
	CurrentRegs = &Regs;

	/* Walk over all insns and note just the changes from one insn to the
	 * next one.
	 */
	WasJump = 0;
	for (I = 0; I < CS_GetEntryCount (S); ++I) {

	    CodeEntry* P;

	    /* Get the next instruction */
	    CodeEntry* E = CollAtUnchecked (&S->Entries, I);

	    /* If the instruction has a label, we need some special handling */
	    unsigned LabelCount = CE_GetLabelCount (E);
	    if (LabelCount > 0) {

		/* Loop over all entry points that jump here. If these entry
		 * points already have register info, check if all values are
		 * known and identical. If all values are identical, and the
		 * preceeding instruction was not an unconditional branch, check
		 * if the register value on exit of the preceeding instruction
		 * is also identical. If all these values are identical, the
		 * value of a register is known, otherwise it is unknown.
		 */
		CodeLabel* Label = CE_GetLabel (E, 0);
		unsigned Entry;
		if (WasJump) {
		    /* Preceeding insn was an unconditional branch */
		    CodeEntry* J = CL_GetRef(Label, 0);
		    if (J->RI) {
			Regs = J->RI->Out2;
		    } else {
			RC_Invalidate (&Regs);
		    }
		    Entry = 1;
		} else {
		    Regs = *CurrentRegs;
		    Entry = 0;
		}

		while (Entry < CL_GetRefCount (Label)) {
		    /* Get this entry */
		    CodeEntry* J = CL_GetRef (Label, Entry);
		    if (J->RI == 0) {
			/* No register info for this entry. This means that the
			 * instruction that jumps here is at higher addresses and
			 * the jump is a backward jump. We need a second run to
			 * get the register info right in this case. Until then,
			 * assume unknown register contents.
			 */
			Done = 0;
			RC_Invalidate (&Regs);
			break;
		    }
		    if (J->RI->Out2.RegA != Regs.RegA) {
	 		Regs.RegA = UNKNOWN_REGVAL;
		    }
		    if (J->RI->Out2.RegX != Regs.RegX) {
			Regs.RegX = UNKNOWN_REGVAL;
		    }
		    if (J->RI->Out2.RegY != Regs.RegY) {
			Regs.RegY = UNKNOWN_REGVAL;
		    }
		    if (J->RI->Out2.SRegLo != Regs.SRegLo) {
			Regs.SRegLo = UNKNOWN_REGVAL;
		    }
		    if (J->RI->Out2.SRegHi != Regs.SRegHi) {
			Regs.SRegHi = UNKNOWN_REGVAL;
		    }
       	       	    if (J->RI->Out2.Tmp1 != Regs.Tmp1) {
			Regs.Tmp1 = UNKNOWN_REGVAL;
		    }
		    ++Entry;
		}

		/* Use this register info */
		CurrentRegs = &Regs;

	    }

	    /* Generate register info for this instruction */
	    CE_GenRegInfo (E, CurrentRegs);

	    /* Remember for the next insn if this insn was an uncondition branch */
	    WasJump = (E->Info & OF_UBRA) != 0;

	    /* Output registers for this insn are input for the next */
	    CurrentRegs = &E->RI->Out;

	    /* If this insn is a branch on zero flag, we may have more info on
	     * register contents for one of both flow directions, but only if
	     * there is a previous instruction.
	     */
	    if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {

		/* Get the branch condition */
		bc_t BC = GetBranchCond (E->OPC);

		/* Check the previous instruction */
		switch (P->OPC) {

	 	    case OP65_ADC:
		    case OP65_AND:
		    case OP65_DEA:
		    case OP65_EOR:
		    case OP65_INA:
		    case OP65_LDA:
		    case OP65_ORA:
		    case OP65_PLA:
		    case OP65_SBC:
			/* A is zero in one execution flow direction */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegA = 0;
		      	} else {
			    E->RI->Out.RegA = 0;
			}
			break;

		    case OP65_CMP:
			/* If this is an immidiate compare, the A register has
			 * the value of the compare later.
			 */
			if (CE_IsConstImm (P)) {
			    if (BC == BC_EQ) {
				E->RI->Out2.RegA = (unsigned char)P->Num;
			    } else {
				E->RI->Out.RegA = (unsigned char)P->Num;
		      	    }
    			}
			break;

		    case OP65_CPX:
			/* If this is an immidiate compare, the X register has
			 * the value of the compare later.
			 */
			if (CE_IsConstImm (P)) {
			    if (BC == BC_EQ) {
				E->RI->Out2.RegX = (unsigned char)P->Num;
			    } else {
				E->RI->Out.RegX = (unsigned char)P->Num;
			    }
			}
			break;

		    case OP65_CPY:
			/* If this is an immidiate compare, the Y register has
			 * the value of the compare later.
	 		 */
			if (CE_IsConstImm (P)) {
			    if (BC == BC_EQ) {
				E->RI->Out2.RegY = (unsigned char)P->Num;
			    } else {
				E->RI->Out.RegY = (unsigned char)P->Num;
			    }
			}
			break;

		    case OP65_DEX:
		    case OP65_INX:
		    case OP65_LDX:
		    case OP65_PLX:
			/* X is zero in one execution flow direction */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegX = 0;
			} else {
			    E->RI->Out.RegX = 0;
		      	}
			break;

		    case OP65_DEY:
		    case OP65_INY:
    		    case OP65_LDY:
		    case OP65_PLY:
			/* X is zero in one execution flow direction */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegY = 0;
			} else {
			    E->RI->Out.RegY = 0;
			}
			break;

		    case OP65_TAX:
		    case OP65_TXA:
			/* If the branch is a beq, both A and X are zero at the
			 * branch target, otherwise they are zero at the next
			 * insn.
			 */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
			} else {
			    E->RI->Out.RegA = E->RI->Out.RegX = 0;
			}
			break;

		    case OP65_TAY:
		    case OP65_TYA:
			/* If the branch is a beq, both A and Y are zero at the
			 * branch target, otherwise they are zero at the next
			 * insn.
			 */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
			} else {
			    E->RI->Out.RegA = E->RI->Out.RegY = 0;
			}
			break;

		    default:
			break;

		}
	    }
	}
    } while (!Done);

}
示例#7
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);
}
示例#8
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;
}