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; }
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; }
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) {
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; }