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