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