]> git.sur5r.net Git - cc65/blobdiff - src/cc65/codeseg.c
Place all declarations that are local to a function into the local function
[cc65] / src / cc65 / codeseg.c
index 6fee2f809ddfc07990a81bfcbefb79aee29b7457..d52b36fcdba0d90f7190ff16d11dd8f88b594db1 100644 (file)
 
 
 
+static void CS_PrintFunctionHeader (const CodeSeg* S, FILE* F)
+/* Print a comment with the function signature to the given file */
+{
+    /* Get the associated function */
+    const SymEntry* Func = S->Func;
+
+    /* If this is a global code segment, do nothing */
+    if (Func) {
+        fprintf (F,
+                 "; ---------------------------------------------------------------\n"
+                 "; ");
+        PrintFuncSig (F, Func->Name, Func->Type);
+        fprintf (F,
+                 "\n"
+                 "; ---------------------------------------------------------------\n"
+                 "\n");
+    }
+}
+
+
+
 static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E)
 /* Move all labels from the label pool to the given entry and remove them
  * from the pool.
@@ -160,7 +181,8 @@ static void CS_RemoveLabelFromHash (CodeSeg* S, CodeLabel* L)
 
 
 
-static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name, int UserCode)
+static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name,
+                                      void (*ErrorFunc) (const char*, ...))
 /* Add a code label for the next instruction to follow */
 {
     /* Calculate the hash from the name */
@@ -173,11 +195,7 @@ static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name, int UserCod
     if (L) {
        /* We found it - be sure it does not already have an owner */
        if (L->Owner) {
-           if (UserCode) {
-               Error ("ASM label `%s' is already defined", Name);
-           } else {
-               Internal ("CS_AddLabelInternal: Label `%s' already defined", Name);
-           }
+           ErrorFunc ("ASM label `%s' is already defined", Name);
        }
     } else {
        /* Not found - create a new one */
@@ -186,11 +204,7 @@ static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name, int UserCod
 
     /* Safety. This call is quite costly, but safety is better */
     if (CollIndex (&S->Labels, L) >= 0) {
-       if (UserCode) {
-           Error ("ASM label `%s' is already defined", Name);
-       } else {
-           Internal ("CS_AddLabelInternal: Label `%s' already defined", Name);
-       }
+       ErrorFunc ("ASM label `%s' is already defined", Name);
     }
 
     /* We do now have a valid label. Remember it for later */
@@ -220,7 +234,7 @@ static const char* SkipSpace (const char* S)
 
 
 static const char* ReadToken (const char* L, const char* Term,
-                             char* Buf, unsigned BufSize)
+                             char* Buf, unsigned BufSize)
 /* Read the next token into Buf, return the updated line pointer. The
  * token is terminated by one of the characters given in term.
  */
@@ -230,8 +244,14 @@ static const char* ReadToken (const char* L, const char* Term,
     unsigned ParenCount = 0;
     while (*L && (ParenCount > 0 || strchr (Term, *L) == 0)) {
        if (I < BufSize-1) {
-           Buf[I++] = *L;
+           Buf[I] = *L;
+       } else if (I == BufSize-1) {
+           /* Cannot store this character, this is an input error (maybe
+            * identifier too long or similar).
+            */
+           Error ("ASM code error: syntax error");
        }
+       ++I;
        if (*L == ')') {
            --ParenCount;
        } else if (*L == '(') {
@@ -257,11 +277,11 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
  * white space, for example.
  */
 {
-    char                       Mnemo[16];
+    char                       Mnemo[64];
     const OPCDesc*     OPC;
     am_t               AM = 0;         /* Initialize to keep gcc silent */
     char               Arg[64];
-    char               Reg;
+    char               Reg;
     CodeEntry*         E;
     CodeLabel*         Label;
 
@@ -275,7 +295,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
        L = SkipSpace (L+1);
 
        /* Add the label */
-       CS_AddLabelInternal (S, Mnemo, 1);
+       CS_AddLabelInternal (S, Mnemo, Error);
 
        /* If we have reached end of line, bail out, otherwise a mnemonic
         * may follow.
@@ -347,7 +367,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
                    L = SkipSpace (L+1);
                    if (toupper (*L) != 'Y') {
                        Error ("ASM code error: `Y' expected");
-                       return 0;
+                       return 0;
                    }
                    L = SkipSpace (L+1);
                    if (*L != '\0') {
@@ -418,10 +438,12 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
     }
 
     /* If the instruction is a branch, check for the label and generate it
-     * if it does not exist. Ignore anything but local labels here.
+     * if it does not exist. This may lead to unused labels (if the label
+     * is actually an external one) which are removed by the CS_MergeLabels
+     * function later.
      */
     Label = 0;
-    if (AM == AM65_BRA && Arg[0] == 'L') {
+    if (AM == AM65_BRA) {
 
        /* Generate the hash over the label, then search for the label */
        unsigned Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE;
@@ -724,10 +746,40 @@ unsigned CS_GetEntryIndex (CodeSeg* S, struct CodeEntry* E)
 
 
 
+int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count)
+/* Return true if any of the code entries in the given range has a label
+ * attached. If the code segment does not span the given range, check the
+ * possible span instead.
+ */
+{
+    unsigned EntryCount = CS_GetEntryCount(S);
+
+    /* Adjust count. We expect at least Start to be valid. */
+    CHECK (Start < EntryCount);
+    if (Start + Count > EntryCount) {
+       Count = EntryCount - Start;
+    }
+
+    /* Check each entry. Since we have validated the index above, we may
+     * use the unchecked access function in the loop which is faster.
+     */
+    while (Count--) {
+       const CodeEntry* E = CollAtUnchecked (&S->Entries, Start++);
+       if (CE_HasLabel (E)) {
+           return 1;
+       }
+    }
+
+    /* No label in the complete range */
+    return 0;
+}
+
+
+
 CodeLabel* CS_AddLabel (CodeSeg* S, const char* Name)
 /* Add a code label for the next instruction to follow */
 {
-    return CS_AddLabelInternal (S, Name, 0);
+    return CS_AddLabelInternal (S, Name, Internal);
 }
 
 
@@ -805,6 +857,44 @@ void CS_MergeLabels (CodeSeg* S)
  */
 {
     unsigned I;
+    unsigned J;
+
+    /* First, remove all labels from the label symbol table that don't have an
+     * owner (this means that they are actually external labels but we didn't
+     * know that previously since they may have also been forward references).
+     */
+    for (I = 0; I < CS_LABEL_HASH_SIZE; ++I) {
+
+       /* Get the first label in this hash chain */
+       CodeLabel** L = &S->LabelHash[I];
+       while (*L) {
+           if ((*L)->Owner == 0) {
+
+               /* The label does not have an owner, remove it from the chain */
+               CodeLabel* X = *L;
+                       *L = X->Next;
+
+               /* Cleanup any entries jumping to this label */
+               for (J = 0; J < CL_GetRefCount (X); ++J) {
+                   /* Get the entry referencing this label */
+                   CodeEntry* E = CL_GetRef (X, J);
+                   /* And remove the reference */
+                   E->JumpTo = 0;
+               }
+
+               /* Print some debugging output */
+               if (Debug) {
+                   printf ("Removing unused global label `%s'", X->Name);
+               }
+
+               /* And free the label */
+               FreeCodeLabel (X);
+           } else {
+               /* Label is owned, point to next code label pointer */
+               L = &((*L)->Next);
+           }
+       }
+    }
 
     /* Walk over all code entries */
     for (I = 0; I < CS_GetEntryCount (S); ++I) {
@@ -812,39 +902,39 @@ void CS_MergeLabels (CodeSeg* S)
                CodeLabel* RefLab;
                unsigned   J;
 
-       /* Get a pointer to the next entry */
-       CodeEntry* E = CS_GetEntry (S, I);
+       /* Get a pointer to the next entry */
+       CodeEntry* E = CS_GetEntry (S, I);
 
        /* If this entry has zero labels, continue with the next one */
-       unsigned LabelCount = CE_GetLabelCount (E);
-       if (LabelCount == 0) {
-           continue;
-       }
-
-       /* We have at least one label. Use the first one as reference label. */
-       RefLab = CE_GetLabel (E, 0);
-
-       /* Walk through the remaining labels and change references to these
-        * labels to a reference to the one and only label. Delete the labels
-        * that are no longer used. To increase performance, walk backwards
-        * through the list.
-        */
+       unsigned LabelCount = CE_GetLabelCount (E);
+       if (LabelCount == 0) {
+           continue;
+       }
+
+       /* We have at least one label. Use the first one as reference label. */
+       RefLab = CE_GetLabel (E, 0);
+
+       /* Walk through the remaining labels and change references to these
+        * labels to a reference to the one and only label. Delete the labels
+        * that are no longer used. To increase performance, walk backwards
+        * through the list.
+        */
        for (J = LabelCount-1; J >= 1; --J) {
 
-           /* Get the next label */
-           CodeLabel* L = CE_GetLabel (E, J);
+           /* Get the next label */
+           CodeLabel* L = CE_GetLabel (E, J);
 
-           /* Move all references from this label to the reference label */
+           /* Move all references from this label to the reference label */
            CL_MoveRefs (L, RefLab);
 
                    /* Remove the label completely. */
                    CS_DelLabel (S, L);
        }
 
-       /* The reference label is the only remaining label. Check if there
-        * are any references to this label, and delete it if this is not
-        * the case.
-        */
+       /* The reference label is the only remaining label. Check if there
+        * are any references to this label, and delete it if this is not
+        * the case.
+        */
                if (CollCount (&RefLab->JumpFrom) == 0) {
            /* Delete the label */
                    CS_DelLabel (S, RefLab);
@@ -1003,6 +1093,41 @@ void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
 
 
 
+void CS_OutputPrologue (const CodeSeg* S, FILE* F)
+/* If the given code segment is a code segment for a function, output the
+ * assembler prologue into the file. That is: Output a comment header, switch
+ * to the correct segment and enter the local function scope. If the code
+ * segment is global, do nothing.
+ */
+{
+    /* Get the function associated with the code segment */
+    SymEntry* Func = S->Func;
+
+    /* If the code segment is associated with a function, print a function
+     * header and enter a local scope. Be sure to switch to the correct
+     * segment before outputing the function label.
+     */
+    if (Func) {
+               CS_PrintFunctionHeader (S, F);
+        fprintf (F, ".segment\t\"%s\"\n\n.proc\t_%s\n\n", S->SegName, Func->Name);
+    }
+
+}
+
+
+
+void CS_OutputEpilogue (const CodeSeg* S, FILE* F)
+/* If the given code segment is a code segment for a function, output the
+ * assembler epilogue into the file. That is: Close the local function scope.
+ */
+{
+    if (S->Func) {
+       fprintf (F, "\n.endproc\n\n");
+    }
+}
+
+
+
 void CS_Output (const CodeSeg* S, FILE* F)
 /* Output the code segment data to a file */
 {
@@ -1020,11 +1145,6 @@ void CS_Output (const CodeSeg* S, FILE* F)
     /* Output the segment directive */
     fprintf (F, ".segment\t\"%s\"\n\n", S->SegName);
 
-    /* If this is a segment for a function, enter a function */
-    if (S->Func) {
-       fprintf (F, ".proc\t_%s\n\n", S->Func->Name);
-    }
-
     /* Output all entries, prepended by the line information if it has changed */
     LI = 0;
     for (I = 0; I < Count; ++I) {
@@ -1057,11 +1177,6 @@ void CS_Output (const CodeSeg* S, FILE* F)
     if (DebugInfo) {
        fprintf (F, "\t.dbg\tline\n");
     }
-
-    /* If this is a segment for a function, leave the function */
-    if (S->Func) {
-       fprintf (F, "\n.endproc\n\n");
-    }
 }
 
 
@@ -1084,217 +1199,232 @@ void CS_GenRegInfo (CodeSeg* S)
     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);
 
-    /* On entry, the register contents are unknown */
-    RC_Invalidate (&Regs);
-    CurrentRegs = &Regs;
-
-    /* First pass. 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;
+    /* We may need two runs to get back references right */
+    do {
 
-       /* Get the next instruction */
-       CodeEntry* E = CollAtUnchecked (&S->Entries, I);
+       /* Assume we're done after this run */
+       Done = 1;
 
-       /* If the instruction has a label, we need some special handling */
-       unsigned LabelCount = CE_GetLabelCount (E);
-       if (LabelCount > 0) {
+       /* On entry, the register contents are unknown */
+       RC_Invalidate (&Regs);
+       CurrentRegs = &Regs;
 
-           /* 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;
+       /* 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 {
-                   RC_Invalidate (&Regs);
+                   Regs = *CurrentRegs;
+                   Entry = 0;
                }
-               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, bail out */
-                   RC_Invalidate (&Regs);
-                   break;
-               }
-               if (J->RI->Out2.RegA != Regs.RegA) {
-                   Regs.RegA = -1;
-               }
-               if (J->RI->Out2.RegX != Regs.RegX) {
-                   Regs.RegX = -1;
-               }
-               if (J->RI->Out2.RegY != Regs.RegY) {
-                   Regs.RegY = -1;
-               }
-               if (J->RI->Out2.SRegLo != Regs.SRegLo) {
-                   Regs.SRegLo = -1;
-               }
-               if (J->RI->Out2.SRegHi != Regs.SRegHi) {
-                   Regs.SRegHi = -1;
+               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 = -1;
+                   }
+                   if (J->RI->Out2.RegX != Regs.RegX) {
+                       Regs.RegX = -1;
+                   }
+                   if (J->RI->Out2.RegY != Regs.RegY) {
+                       Regs.RegY = -1;
+                   }
+                   if (J->RI->Out2.SRegLo != Regs.SRegLo) {
+                       Regs.SRegLo = -1;
+                   }
+                   if (J->RI->Out2.SRegHi != Regs.SRegHi) {
+                       Regs.SRegHi = -1;
+                   }
+                   ++Entry;
                }
-               ++Entry;
-           }
 
-           /* Use this register info */
-           CurrentRegs = &Regs;
+               /* Use this register info */
+               CurrentRegs = &Regs;
 
-       }
+           }
 
-       /* Generate register info for this instruction */
-        CE_GenRegInfo (E, CurrentRegs);
+           /* 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;
+           /* 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;
+           /* 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_KnownImm (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_KnownImm (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_KnownImm (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;
+           /* 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_KnownImm (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_KnownImm (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_KnownImm (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;
+                   default:
+                       break;
 
+               }
            }
        }
-    }
+    } while (!Done);
+
 }