Beispiel #1
0
unsigned OptCmp6 (CodeSeg* S)
/* Search for calls to compare subroutines followed by a conditional branch
 * and replace them by cheaper versions, since the branch means that the
 * boolean value returned by these routines is not needed (we may also check
 * that explicitly, but for the current code generator it is always true).
 */
{
    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 the sequence */
       	if (E->OPC == OP65_JSR 	    		        &&
	    (Cond = FindTosCmpCond (E->Arg)) != CMP_INV	&&
	    (N = CS_GetNextEntry (S, I)) != 0           &&
	    (N->Info & OF_ZBRA) != 0                    &&
       	    !CE_HasLabel (N)) {

       	    /* The tos... functions will return a boolean value in a/x and
	     * the Z flag says if this value is zero or not. We will call
	     * a cheaper subroutine instead, one that does not return a
	     * boolean value but only valid flags. 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];
  	    }

	    /* Replace the subroutine call. */
	    E = NewCodeEntry (OP65_JSR, AM65_ABS, "tosicmp", 0, E->LI);
	    CS_InsertEntry (S, E, I+1);
	    CS_DelEntry (S, I);

	    /* Replace the conditional branch */
	    ReplaceCmp (S, I+1, Cond);

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

	}

  	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #2
0
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;
}
Beispiel #3
0
unsigned OptCmp9 (CodeSeg* S)
/* Search for the sequence
 *
 *    sbc       xx
 *    bvs/bvc   L
 *    eor       #$80
 * L: asl       a
 *    bcc/bcs   somewhere
 *
 * If A is not used later (which should be the case), we can branch on the N
 * flag instead of the carry flag and remove the asl.
 */
{
    unsigned Changes = 0;
    unsigned I;

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

       	CodeEntry* L[5];

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

     	/* Check for the sequence */
       	if (L[0]->OPC == OP65_SBC                       &&
       	    CS_GetEntries (S, L+1, I+1, 4)	        &&
            (L[1]->OPC == OP65_BVC              ||
             L[1]->OPC == OP65_BVS)                     &&
            L[1]->JumpTo != 0                           &&
            L[1]->JumpTo->Owner == L[3]                 &&
            L[2]->OPC == OP65_EOR                       &&
            CE_IsKnownImm (L[2], 0x80)                  &&
            L[3]->OPC == OP65_ASL                       &&
            L[3]->AM == AM65_ACC                        &&
            (L[4]->OPC == OP65_BCC              ||
             L[4]->OPC == OP65_BCS              ||
             L[4]->OPC == OP65_JCC              ||
             L[4]->OPC == OP65_JCS)                     &&
            !CE_HasLabel (L[4])                         &&
            !RegAUsed (S, I+4)) {

	    /* Replace the branch condition */
	    switch (GetBranchCond (L[4]->OPC)) {
                case BC_CC:     CE_ReplaceOPC (L[4], OP65_JPL); break;
                case BC_CS:     CE_ReplaceOPC (L[4], OP65_JMI); break;
                default:        Internal ("Unknown branch condition in OptCmp9");
            }

            /* Delete the asl insn */
            CS_DelEntry (S, I+3);

            /* Next sequence is somewhat ahead (if any) */
            I += 3;

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

     	/* Next entry */
	++I;
    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #4
0
unsigned OptCmp8 (CodeSeg* S)
/* Check for register compares where the contents of the register and therefore
 * the result of the compare is known.
 */
{
    unsigned Changes = 0;
    unsigned I;

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

	int RegVal;

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

     	/* Check for a compare against an immediate value */
       	if ((E->Info & OF_CMP) != 0           &&
	    (RegVal = GetCmpRegVal (E)) >= 0  &&
	    CE_IsConstImm (E)) {

	    /* We are able to evaluate the compare at compile time. Check if
	     * one or more branches are ahead.
	     */
	    unsigned JumpsChanged = 0;
	    CodeEntry* N;
	    while ((N = CS_GetNextEntry (S, I)) != 0 &&   /* Followed by something.. */
	       	   (N->Info & OF_CBRA) != 0          &&   /* ..that is a cond branch.. */
	       	   !CE_HasLabel (N)) {                    /* ..and has no label */

	       	/* Evaluate the branch condition */
	       	int Cond;
     		switch (GetBranchCond (N->OPC)) {
     	       	    case BC_CC:
     	       	        Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
     	       	        break;

     	       	    case BC_CS:
     	       	        Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
     	       	        break;

     	       	    case BC_EQ:
     	       	        Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
     	       	        break;

     	       	    case BC_MI:
       	       	        Cond = ((signed char)RegVal) < ((signed char)E->Num);
     	       	        break;

     	       	    case BC_NE:
     	       	        Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
	       	        break;

	       	    case BC_PL:
       	       	        Cond = ((signed char)RegVal) >= ((signed char)E->Num);
	       	        break;

	       	    case BC_VC:
	       	    case BC_VS:
		        /* Not set by the compare operation, bail out (Note:
			 * Just skipping anything here is rather stupid, but
			 * the sequence is never generated by the compiler,
			 * so it's quite safe to skip).
			 */
		        goto NextEntry;

		    default:
		        Internal ("Unknown branch condition");

		}

	       	/* If the condition is false, we may remove the jump. Otherwise
	       	 * the branch will always be taken, so we may replace it by a
	       	 * jump (and bail out).
	       	 */
		if (!Cond) {
		    CS_DelEntry (S, I+1);
		} else {
		    CodeLabel* L = N->JumpTo;
		    const char* LabelName = L? L->Name : N->Arg;
		    CodeEntry* X = NewCodeEntry (OP65_JMP, AM65_BRA, LabelName, L, N->LI);
		    CS_InsertEntry (S, X, I+2);
		    CS_DelEntry (S, I+1);
		}

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

	    /* If we have made changes above, we may also remove the compare */
	    if (JumpsChanged) {
		CS_DelEntry (S, I);
	    }

	}

NextEntry:
     	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #5
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);

}