]> git.sur5r.net Git - cc65/blob - src/cc65/codeseg.c
More work to make user asm labels work
[cc65] / src / cc65 / codeseg.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 codeseg.c                                 */
4 /*                                                                           */
5 /*                          Code segment structure                           */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37 #include <ctype.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "check.h"
42 #include "global.h"
43 #include "hashstr.h"
44 #include "strutil.h"
45 #include "xmalloc.h"
46 #include "xsprintf.h"
47
48 /* cc65 */
49 #include "asmlabel.h"
50 #include "codeent.h"
51 #include "codeinfo.h"
52 #include "datatype.h"
53 #include "error.h"
54 #include "symentry.h"
55 #include "codeseg.h"
56
57
58
59 /*****************************************************************************/
60 /*                             Helper functions                              */
61 /*****************************************************************************/
62
63
64
65 static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E)
66 /* Move all labels from the label pool to the given entry and remove them
67  * from the pool.
68  */
69 {
70     /* Transfer the labels if we have any */
71     unsigned I;
72     unsigned LabelCount = CollCount (&S->Labels);
73     for (I = 0; I < LabelCount; ++I) {
74
75         /* Get the label */
76         CodeLabel* L = CollAt (&S->Labels, I);
77
78         /* Attach it to the entry */
79         CE_AttachLabel (E, L);
80     }
81
82     /* Delete the transfered labels */
83     CollDeleteAll (&S->Labels);
84 }
85
86
87
88 static void CS_MoveLabelsToPool (CodeSeg* S, CodeEntry* E)
89 /* Move the labels of the code entry E to the label pool of the code segment */
90 {
91     unsigned LabelCount = CE_GetLabelCount (E);
92     while (LabelCount--) {
93         CodeLabel* L = CE_GetLabel (E, LabelCount);
94         L->Owner = 0;
95         CollAppend (&S->Labels, L);
96     }
97     CollDeleteAll (&E->Labels);
98 }
99
100
101
102 static CodeLabel* CS_FindLabel (CodeSeg* S, const char* Name, unsigned Hash)
103 /* Find the label with the given name. Return the label or NULL if not found */
104 {
105     /* Get the first hash chain entry */
106     CodeLabel* L = S->LabelHash[Hash];
107
108     /* Search the list */
109     while (L) {
110         if (strcmp (Name, L->Name) == 0) {
111             /* Found */
112             break;
113         }
114         L = L->Next;
115     }
116     return L;
117 }
118
119
120
121 static CodeLabel* CS_NewCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
122 /* Create a new label and insert it into the label hash table */
123 {
124     /* Create a new label */
125     CodeLabel* L = NewCodeLabel (Name, Hash);
126
127     /* Enter the label into the hash table */
128     L->Next = S->LabelHash[L->Hash];
129     S->LabelHash[L->Hash] = L;
130
131     /* Return the new label */
132     return L;
133 }
134
135
136
137 static void CS_RemoveLabelFromHash (CodeSeg* S, CodeLabel* L)
138 /* Remove the given code label from the hash list */
139 {
140     /* Get the first entry in the hash chain */
141     CodeLabel* List = S->LabelHash[L->Hash];
142     CHECK (List != 0);
143
144     /* First, remove the label from the hash chain */
145     if (List == L) {
146         /* First entry in hash chain */
147         S->LabelHash[L->Hash] = L->Next;
148     } else {
149         /* Must search through the chain */
150         while (List->Next != L) {
151             /* If we've reached the end of the chain, something is *really* wrong */
152             CHECK (List->Next != 0);
153             /* Next entry */
154             List = List->Next;
155         }
156         /* The next entry is the one, we have been searching for */
157         List->Next = L->Next;
158     }
159 }
160
161
162
163 static CodeLabel* CS_AddLabelInternal (CodeSeg* S, const char* Name, int UserCode)
164 /* Add a code label for the next instruction to follow */
165 {
166     /* Calculate the hash from the name */
167     unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE;
168
169     /* Try to find the code label if it does already exist */
170     CodeLabel* L = CS_FindLabel (S, Name, Hash);
171
172     /* Did we find it? */
173     if (L) {
174         /* We found it - be sure it does not already have an owner */
175         if (L->Owner) {
176             if (UserCode) {
177                 Error ("ASM label `%s' is already defined", Name);
178             } else {
179                 Internal ("CS_AddLabelInternal: Label `%s' already defined", Name);
180             }
181         }
182     } else {
183         /* Not found - create a new one */
184         L = CS_NewCodeLabel (S, Name, Hash);
185     }
186
187     /* Safety. This call is quite costly, but safety is better */
188     if (CollIndex (&S->Labels, L) >= 0) {
189         if (UserCode) {
190             Error ("ASM label `%s' is already defined", Name);
191         } else {
192             Internal ("CS_AddLabelInternal: Label `%s' already defined", Name);
193         }
194     }
195
196     /* We do now have a valid label. Remember it for later */
197     CollAppend (&S->Labels, L);
198
199     /* Return the label */
200     return L;
201 }
202
203
204
205 /*****************************************************************************/
206 /*                    Functions for parsing instructions                     */
207 /*****************************************************************************/
208
209
210
211 static const char* SkipSpace (const char* S)
212 /* Skip white space and return an updated pointer */
213 {
214     while (IsSpace (*S)) {
215         ++S;
216     }
217     return S;
218 }
219
220
221
222 static const char* ReadToken (const char* L, const char* Term,
223                               char* Buf, unsigned BufSize)
224 /* Read the next token into Buf, return the updated line pointer. The
225  * token is terminated by one of the characters given in term.
226  */
227 {
228     /* Read/copy the token */
229     unsigned I = 0;
230     unsigned ParenCount = 0;
231     while (*L && (ParenCount > 0 || strchr (Term, *L) == 0)) {
232         if (I < BufSize-1) {
233             Buf[I] = *L;
234         } else if (I == BufSize-1) {
235             /* Cannot store this character, this is an input error (maybe
236              * identifier too long or similar).
237              */
238             Error ("ASM code error: syntax error");
239         }
240         ++I;
241         if (*L == ')') {
242             --ParenCount;
243         } else if (*L == '(') {
244             ++ParenCount;
245         }
246         ++L;
247     }
248
249     /* Terminate the buffer contents */
250     Buf[I] = '\0';
251
252     /* Return the updated line pointer */
253     return L;
254 }
255
256
257
258 static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
259 /* Parse an instruction nnd generate a code entry from it. If the line contains
260  * errors, output an error message and return NULL.
261  * For simplicity, we don't accept the broad range of input a "real" assembler
262  * does. The instruction and the argument are expected to be separated by
263  * white space, for example.
264  */
265 {
266     char                Mnemo[64];
267     const OPCDesc*      OPC;
268     am_t                AM = 0;         /* Initialize to keep gcc silent */
269     char                Arg[64];
270     char                Reg;
271     CodeEntry*          E;
272     CodeLabel*          Label;
273
274     /* Read the first token and skip white space after it */
275     L = SkipSpace (ReadToken (L, " \t:", Mnemo, sizeof (Mnemo)));
276
277     /* Check if we have a label */
278     if (*L == ':') {
279
280         /* Skip the colon and following white space */
281         L = SkipSpace (L+1);
282
283         /* Add the label */
284         CS_AddLabelInternal (S, Mnemo, 1);
285
286         /* If we have reached end of line, bail out, otherwise a mnemonic
287          * may follow.
288          */
289         if (*L == '\0') {
290             return 0;
291         }
292
293         L = SkipSpace (ReadToken (L, " \t", Mnemo, sizeof (Mnemo)));
294     }
295
296     /* Try to find the opcode description for the mnemonic */
297     OPC = FindOP65 (Mnemo);
298
299     /* If we didn't find the opcode, print an error and bail out */
300     if (OPC == 0) {
301         Error ("ASM code error: %s is not a valid mnemonic", Mnemo);
302         return 0;
303     }
304
305     /* Get the addressing mode */
306     Arg[0] = '\0';
307     switch (*L) {
308
309         case '\0':
310             /* Implicit */
311             AM = AM65_IMP;
312             break;
313
314         case '#':
315             /* Immidiate */
316             StrCopy (Arg, sizeof (Arg), L+1);
317             AM = AM65_IMM;
318             break;
319
320         case '(':
321             /* Indirect */
322             L = ReadToken (L+1, ",)", Arg, sizeof (Arg));
323
324             /* Check for errors */
325             if (*L == '\0') {
326                 Error ("ASM code error: syntax error");
327                 return 0;
328             }
329
330             /* Check the different indirect modes */
331             if (*L == ',') {
332                 /* Expect zp x indirect */
333                 L = SkipSpace (L+1);
334                 if (toupper (*L) != 'X') {
335                     Error ("ASM code error: `X' expected");
336                     return 0;
337                 }
338                 L = SkipSpace (L+1);
339                 if (*L != ')') {
340                     Error ("ASM code error: `)' expected");
341                     return 0;
342                 }
343                 L = SkipSpace (L+1);
344                 if (*L != '\0') {
345                     Error ("ASM code error: syntax error");
346                     return 0;
347                 }
348                 AM = AM65_ZPX_IND;
349             } else if (*L == ')') {
350                 /* zp indirect or zp indirect, y */
351                 L = SkipSpace (L+1);
352                 if (*L == ',') {
353                     L = SkipSpace (L+1);
354                     if (toupper (*L) != 'Y') {
355                         Error ("ASM code error: `Y' expected");
356                         return 0;
357                     }
358                     L = SkipSpace (L+1);
359                     if (*L != '\0') {
360                         Error ("ASM code error: syntax error");
361                         return 0;
362                     }
363                     AM = AM65_ZP_INDY;
364                 } else if (*L == '\0') {
365                     AM = AM65_ZP_IND;
366                 } else {
367                     Error ("ASM code error: syntax error");
368                     return 0;
369                 }
370             }
371             break;
372
373         case 'a':
374         case 'A':
375             /* Accumulator? */
376             if (L[1] == '\0') {
377                 AM = AM65_ACC;
378                 break;
379             }
380             /* FALLTHROUGH */
381
382         default:
383             /* Absolute, maybe indexed */
384             L = ReadToken (L, ",", Arg, sizeof (Arg));
385             if (*L == '\0') {
386                 /* Absolute, zeropage or branch */
387                 if ((OPC->Info & OF_BRA) != 0) {
388                     /* Branch */
389                     AM = AM65_BRA;
390                 } else if (GetZPInfo(Arg) != 0) {
391                     AM = AM65_ZP;
392                 } else {
393                     AM = AM65_ABS;
394                 }
395             } else if (*L == ',') {
396                 /* Indexed */
397                 L = SkipSpace (L+1);
398                 if (*L == '\0') {
399                     Error ("ASM code error: syntax error");
400                     return 0;
401                 } else {
402                     Reg = toupper (*L);
403                     L = SkipSpace (L+1);
404                     if (Reg == 'X') {
405                         if (GetZPInfo(Arg) != 0) {
406                             AM = AM65_ZPX;
407                         } else {
408                             AM = AM65_ABSX;
409                         }
410                     } else if (Reg == 'Y') {
411                         AM = AM65_ABSY;
412                     } else {
413                         Error ("ASM code error: syntax error");
414                         return 0;
415                     }
416                     if (*L != '\0') {
417                         Error ("ASM code error: syntax error");
418                         return 0;
419                     }
420                 }
421             }
422             break;
423
424     }
425
426     /* If the instruction is a branch, check for the label and generate it
427      * if it does not exist. This may lead to unused labels (if the label
428      * is actually an external one) which are removed by the CS_MergeLabels
429      * function later.
430      */
431     Label = 0;
432     if (AM == AM65_BRA) {
433
434         /* Generate the hash over the label, then search for the label */
435         unsigned Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE;
436         Label = CS_FindLabel (S, Arg, Hash);
437
438         /* If we don't have the label, it's a forward ref - create it */
439         if (Label == 0) {
440             /* Generate a new label */
441             Label = CS_NewCodeLabel (S, Arg, Hash);
442         }
443     }
444
445     /* We do now have the addressing mode in AM. Allocate a new CodeEntry
446      * structure and initialize it.
447      */
448     E = NewCodeEntry (OPC->OPC, AM, Arg, Label, LI);
449
450     /* Return the new code entry */
451     return E;
452 }
453
454
455
456 /*****************************************************************************/
457 /*                                   Code                                    */
458 /*****************************************************************************/
459
460
461
462 CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
463 /* Create a new code segment, initialize and return it */
464 {
465     unsigned I;
466     const type* RetType;
467
468     /* Allocate memory */
469     CodeSeg* S = xmalloc (sizeof (CodeSeg));
470
471     /* Initialize the fields */
472     S->SegName  = xstrdup (SegName);
473     S->Func     = Func;
474     InitCollection (&S->Entries);
475     InitCollection (&S->Labels);
476     for (I = 0; I < sizeof(S->LabelHash) / sizeof(S->LabelHash[0]); ++I) {
477         S->LabelHash[I] = 0;
478     }
479
480     /* If we have a function given, get the return type of the function.
481      * Assume ANY return type besides void will use the A and X registers.
482      */
483     if (S->Func && !IsTypeVoid ((RetType = GetFuncReturn (Func->Type)))) {
484         if (SizeOf (RetType) == SizeOf (type_long)) {
485             S->ExitRegs = REG_EAX;
486         } else {
487             S->ExitRegs = REG_AX;
488         }
489     } else {
490         S->ExitRegs = REG_NONE;
491     }
492
493     /* Return the new struct */
494     return S;
495 }
496
497
498
499 void CS_AddEntry (CodeSeg* S, struct CodeEntry* E)
500 /* Add an entry to the given code segment */
501 {
502     /* Transfer the labels if we have any */
503     CS_MoveLabelsToEntry (S, E);
504
505     /* Add the entry to the list of code entries in this segment */
506     CollAppend (&S->Entries, E);
507 }
508
509
510
511 void CS_AddVLine (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap)
512 /* Add a line to the given code segment */
513 {
514     const char* L;
515     CodeEntry*  E;
516     char        Token[64];
517
518     /* Format the line */
519     char Buf [256];
520     xvsprintf (Buf, sizeof (Buf), Format, ap);
521
522     /* Skip whitespace */
523     L = SkipSpace (Buf);
524
525     /* Check which type of instruction we have */
526     E = 0;      /* Assume no insn created */
527     switch (*L) {
528
529         case '\0':
530             /* Empty line, just ignore it */
531             break;
532
533         case ';':
534             /* Comment or hint, ignore it for now */
535             break;
536
537         case '.':
538             /* Control instruction */
539             ReadToken (L, " \t", Token, sizeof (Token));
540             Error ("ASM code error: Pseudo instruction `%s' not supported", Token);
541             break;
542
543         default:
544             E = ParseInsn (S, LI, L);
545             break;
546     }
547
548     /* If we have a code entry, transfer the labels and insert it */
549     if (E) {
550         CS_AddEntry (S, E);
551     }
552 }
553
554
555
556 void CS_AddLine (CodeSeg* S, LineInfo* LI, const char* Format, ...)
557 /* Add a line to the given code segment */
558 {
559     va_list ap;
560     va_start (ap, Format);
561     CS_AddVLine (S, LI, Format, ap);
562     va_end (ap);
563 }
564
565
566
567 void CS_InsertEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index)
568 /* Insert the code entry at the index given. Following code entries will be
569  * moved to slots with higher indices.
570  */
571 {
572     /* Insert the entry into the collection */
573     CollInsert (&S->Entries, E, Index);
574 }
575
576
577
578 void CS_DelEntry (CodeSeg* S, unsigned Index)
579 /* Delete an entry from the code segment. This includes moving any associated
580  * labels, removing references to labels and even removing the referenced labels
581  * if the reference count drops to zero.
582  */
583 {
584     /* Get the code entry for the given index */
585     CodeEntry* E = CS_GetEntry (S, Index);
586
587     /* If the entry has a labels, we have to move this label to the next insn.
588      * If there is no next insn, move the label into the code segement label
589      * pool. The operation is further complicated by the fact that the next
590      * insn may already have a label. In that case change all reference to
591      * this label and delete the label instead of moving it.
592      */
593     unsigned Count = CE_GetLabelCount (E);
594     if (Count > 0) {
595
596         /* The instruction has labels attached. Check if there is a next
597          * instruction.
598          */
599         if (Index == CS_GetEntryCount (S)-1) {
600
601             /* No next instruction, move to the codeseg label pool */
602             CS_MoveLabelsToPool (S, E);
603
604         } else {
605
606             /* There is a next insn, get it */
607             CodeEntry* N = CS_GetEntry (S, Index+1);
608
609             /* Move labels to the next entry */
610             CS_MoveLabels (S, E, N);
611
612         }
613     }
614
615     /* If this insn references a label, remove the reference. And, if the
616      * the reference count for this label drops to zero, remove this label.
617      */
618     if (E->JumpTo) {
619         /* Remove the reference */
620         CS_RemoveLabelRef (S, E);
621     }
622
623     /* Delete the pointer to the insn */
624     CollDelete (&S->Entries, Index);
625
626     /* Delete the instruction itself */
627     FreeCodeEntry (E);
628 }
629
630
631
632 void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count)
633 /* Delete a range of code entries. This includes removing references to labels,
634  * labels attached to the entries and so on.
635  */
636 {
637     /* Start deleting the entries from the rear, because this involves less
638      * memory moving.
639      */
640     while (Count--) {
641         CS_DelEntry (S, Start + Count);
642     }
643 }
644
645
646
647 void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos)
648 /* Move a range of entries from one position to another. Start is the index
649  * of the first entry to move, Count is the number of entries and NewPos is
650  * the index of the target entry. The entry with the index Start will later
651  * have the index NewPos. All entries with indices NewPos and above are
652  * moved to higher indices. If the code block is moved to the end of the
653  * current code, and if pending labels exist, these labels will get attached
654  * to the first instruction of the moved block (the first one after the
655  * current code end)
656  */
657 {
658     /* If NewPos is at the end of the code segment, move any labels from the
659      * label pool to the first instruction of the moved range.
660      */
661     if (NewPos == CS_GetEntryCount (S)) {
662         CS_MoveLabelsToEntry (S, CS_GetEntry (S, Start));
663     }
664
665     /* Move the code block to the destination */
666     CollMoveMultiple (&S->Entries, Start, Count, NewPos);
667 }
668
669
670
671 struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index)
672 /* Get the code entry preceeding the one with the index Index. If there is no
673  * preceeding code entry, return NULL.
674  */
675 {
676     if (Index == 0) {
677         /* This is the first entry */
678         return 0;
679     } else {
680         /* Previous entry available */
681         return CollAtUnchecked (&S->Entries, Index-1);
682     }
683 }
684
685
686
687 struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index)
688 /* Get the code entry following the one with the index Index. If there is no
689  * following code entry, return NULL.
690  */
691 {
692     if (Index >= CollCount (&S->Entries)-1) {
693         /* This is the last entry */
694         return 0;
695     } else {
696         /* Code entries left */
697         return CollAtUnchecked (&S->Entries, Index+1);
698     }
699 }
700
701
702
703 int CS_GetEntries (CodeSeg* S, struct CodeEntry** List,
704                    unsigned Start, unsigned Count)
705 /* Get Count code entries into List starting at index start. Return true if
706  * we got the lines, return false if not enough lines were available.
707  */
708 {
709     /* Check if enough entries are available */
710     if (Start + Count > CollCount (&S->Entries)) {
711         return 0;
712     }
713
714     /* Copy the entries */
715     while (Count--) {
716         *List++ = CollAtUnchecked (&S->Entries, Start++);
717     }
718
719     /* We have the entries */
720     return 1;
721 }
722
723
724
725 unsigned CS_GetEntryIndex (CodeSeg* S, struct CodeEntry* E)
726 /* Return the index of a code entry */
727 {
728     int Index = CollIndex (&S->Entries, E);
729     CHECK (Index >= 0);
730     return Index;
731 }
732
733
734
735 CodeLabel* CS_AddLabel (CodeSeg* S, const char* Name)
736 /* Add a code label for the next instruction to follow */
737 {
738     return CS_AddLabelInternal (S, Name, 0);
739 }
740
741
742
743 CodeLabel* CS_GenLabel (CodeSeg* S, struct CodeEntry* E)
744 /* If the code entry E does already have a label, return it. Otherwise
745  * create a new label, attach it to E and return it.
746  */
747 {
748     CodeLabel* L;
749
750     if (CE_HasLabel (E)) {
751
752         /* Get the label from this entry */
753         L = CE_GetLabel (E, 0);
754
755     } else {
756
757         /* Get a new name */
758         const char* Name = LocalLabelName (GetLocalLabel ());
759
760         /* Generate the hash over the name */
761         unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE;
762
763         /* Create a new label */
764         L = CS_NewCodeLabel (S, Name, Hash);
765
766         /* Attach this label to the code entry */
767         CE_AttachLabel (E, L);
768
769     }
770
771     /* Return the label */
772     return L;
773 }
774
775
776
777 void CS_DelLabel (CodeSeg* S, CodeLabel* L)
778 /* Remove references from this label and delete it. */
779 {
780     unsigned Count, I;
781
782     /* First, remove the label from the hash chain */
783     CS_RemoveLabelFromHash (S, L);
784
785     /* Remove references from insns jumping to this label */
786     Count = CollCount (&L->JumpFrom);
787     for (I = 0; I < Count; ++I) {
788         /* Get the insn referencing this label */
789         CodeEntry* E = CollAt (&L->JumpFrom, I);
790         /* Remove the reference */
791         E->JumpTo = 0;
792     }
793     CollDeleteAll (&L->JumpFrom);
794
795     /* Remove the reference to the owning instruction if it has one. The
796      * function may be called for a label without an owner when deleting
797      * unfinished parts of the code. This is unfortunate since it allows
798      * errors to slip through.
799      */
800     if (L->Owner) {
801         CollDeleteItem (&L->Owner->Labels, L);
802     }
803
804     /* All references removed, delete the label itself */
805     FreeCodeLabel (L);
806 }
807
808
809
810 void CS_MergeLabels (CodeSeg* S)
811 /* Merge code labels. That means: For each instruction, remove all labels but
812  * one and adjust references accordingly.
813  */
814 {
815     unsigned I;
816
817     /* First, remove all labels from the label symbol table that don't have an
818      * owner (this means that they are actually external labels but we didn't
819      * know that previously since they may have also been forward references).
820      */
821     for (I = 0; I < CS_LABEL_HASH_SIZE; ++I) {
822
823         /* Get the first label in this hash chain */
824         CodeLabel** L = &S->LabelHash[I];
825         while (*L) {
826             if ((*L)->Owner == 0) {
827                 /* The label does not have an owner, remove it from the chain */
828                 CodeLabel* X = *L;
829                 *L = X->Next;
830                 if (Debug) {
831                     printf ("Removing unused global label `%s'", X->Name);
832                 }
833                 FreeCodeLabel (X);
834             } else {
835                 /* Label is owned, point to next code label pointer */
836                 L = &((*L)->Next);
837             }
838         }
839     }
840
841     /* Walk over all code entries */
842     for (I = 0; I < CS_GetEntryCount (S); ++I) {
843
844         CodeLabel* RefLab;
845         unsigned   J;
846
847         /* Get a pointer to the next entry */
848         CodeEntry* E = CS_GetEntry (S, I);
849
850         /* If this entry has zero labels, continue with the next one */
851         unsigned LabelCount = CE_GetLabelCount (E);
852         if (LabelCount == 0) {
853             continue;
854         }
855
856         /* We have at least one label. Use the first one as reference label. */
857         RefLab = CE_GetLabel (E, 0);
858
859         /* Walk through the remaining labels and change references to these
860          * labels to a reference to the one and only label. Delete the labels
861          * that are no longer used. To increase performance, walk backwards
862          * through the list.
863          */
864         for (J = LabelCount-1; J >= 1; --J) {
865
866             /* Get the next label */
867             CodeLabel* L = CE_GetLabel (E, J);
868
869             /* Move all references from this label to the reference label */
870             CL_MoveRefs (L, RefLab);
871
872             /* Remove the label completely. */
873             CS_DelLabel (S, L);
874         }
875
876         /* The reference label is the only remaining label. Check if there
877          * are any references to this label, and delete it if this is not
878          * the case.
879          */
880         if (CollCount (&RefLab->JumpFrom) == 0) {
881             /* Delete the label */
882             CS_DelLabel (S, RefLab);
883         }
884     }
885 }
886
887
888
889 void CS_MoveLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New)
890 /* Move all labels from Old to New. The routine will move the labels itself
891  * if New does not have any labels, and move references if there is at least
892  * a label for new. If references are moved, the old label is deleted
893  * afterwards.
894  */
895 {
896     /* Get the number of labels to move */
897     unsigned OldLabelCount = CE_GetLabelCount (Old);
898
899     /* Does the new entry have itself a label? */
900     if (CE_HasLabel (New)) {
901
902         /* The new entry does already have a label - move references */
903         CodeLabel* NewLabel = CE_GetLabel (New, 0);
904         while (OldLabelCount--) {
905
906             /* Get the next label */
907             CodeLabel* OldLabel = CE_GetLabel (Old, OldLabelCount);
908
909             /* Move references */
910             CL_MoveRefs (OldLabel, NewLabel);
911
912             /* Delete the label */
913             CS_DelLabel (S, OldLabel);
914
915         }
916
917     } else {
918
919         /* The new entry does not have a label, just move them */
920         while (OldLabelCount--) {
921
922             /* Move the label to the new entry */
923             CE_MoveLabel (CE_GetLabel (Old, OldLabelCount), New);
924
925         }
926
927     }
928 }
929
930
931
932 void CS_RemoveLabelRef (CodeSeg* S, struct CodeEntry* E)
933 /* Remove the reference between E and the label it jumps to. The reference
934  * will be removed on both sides and E->JumpTo will be 0 after that. If
935  * the reference was the only one for the label, the label will get
936  * deleted.
937  */
938 {
939     /* Get a pointer to the label and make sure it exists */
940     CodeLabel* L = E->JumpTo;
941     CHECK (L != 0);
942
943     /* Delete the entry from the label */
944     CollDeleteItem (&L->JumpFrom, E);
945
946     /* The entry jumps no longer to L */
947     E->JumpTo = 0;
948
949     /* If there are no more references, delete the label */
950     if (CollCount (&L->JumpFrom) == 0) {
951         CS_DelLabel (S, L);
952     }
953 }
954
955
956
957 void CS_MoveLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L)
958 /* Change the reference of E to L instead of the current one. If this
959  * was the only reference to the old label, the old label will get
960  * deleted.
961  */
962 {
963     /* Get the old label */
964     CodeLabel* OldLabel = E->JumpTo;
965
966     /* Be sure that code entry references a label */
967     PRECONDITION (OldLabel != 0);
968
969     /* Remove the reference to our label */
970     CS_RemoveLabelRef (S, E);
971
972     /* Use the new label */
973     CL_AddRef (L, E);
974 }
975
976
977
978 void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
979 /* Delete all entries including the given one */
980 {
981     /* Get the number of entries in this segment */
982     unsigned Count = CS_GetEntryCount (S);
983
984     /* First pass: Delete all references to labels. If the reference count
985      * for a label drops to zero, delete it.
986      */
987     unsigned C = Count;
988     while (Last < C--) {
989
990         /* Get the next entry */
991         CodeEntry* E = CS_GetEntry (S, C);
992
993         /* Check if this entry has a label reference */
994         if (E->JumpTo) {
995             /* If the label is a label in the label pool and this is the last
996              * reference to the label, remove the label from the pool.
997              */
998             CodeLabel* L = E->JumpTo;
999             int Index = CollIndex (&S->Labels, L);
1000             if (Index >= 0 && CollCount (&L->JumpFrom) == 1) {
1001                 /* Delete it from the pool */
1002                 CollDelete (&S->Labels, Index);
1003             }
1004
1005             /* Remove the reference to the label */
1006             CS_RemoveLabelRef (S, E);
1007         }
1008
1009     }
1010
1011     /* Second pass: Delete the instructions. If a label attached to an
1012      * instruction still has references, it must be references from outside
1013      * the deleted area. Don't delete the label in this case, just make it
1014      * ownerless and move it to the label pool.
1015      */
1016     C = Count;
1017     while (Last < C--) {
1018
1019         /* Get the next entry */
1020         CodeEntry* E = CS_GetEntry (S, C);
1021
1022         /* Check if this entry has a label attached */
1023         if (CE_HasLabel (E)) {
1024             /* Move the labels to the pool and clear the owner pointer */
1025             CS_MoveLabelsToPool (S, E);
1026         }
1027
1028         /* Delete the pointer to the entry */
1029         CollDelete (&S->Entries, C);
1030
1031         /* Delete the entry itself */
1032         FreeCodeEntry (E);
1033     }
1034 }
1035
1036
1037
1038 void CS_Output (const CodeSeg* S, FILE* F)
1039 /* Output the code segment data to a file */
1040 {
1041     unsigned I;
1042     const LineInfo* LI;
1043
1044     /* Get the number of entries in this segment */
1045     unsigned Count = CS_GetEntryCount (S);
1046
1047     /* If the code segment is empty, bail out here */
1048     if (Count == 0) {
1049         return;
1050     }
1051
1052     /* Output the segment directive */
1053     fprintf (F, ".segment\t\"%s\"\n\n", S->SegName);
1054
1055     /* If this is a segment for a function, enter a function */
1056     if (S->Func) {
1057         fprintf (F, ".proc\t_%s\n\n", S->Func->Name);
1058     }
1059
1060     /* Output all entries, prepended by the line information if it has changed */
1061     LI = 0;
1062     for (I = 0; I < Count; ++I) {
1063         /* Get the next entry */
1064         const CodeEntry* E = CollConstAt (&S->Entries, I);
1065         /* Check if the line info has changed. If so, output the source line
1066          * if the option is enabled and output debug line info if the debug
1067          * option is enabled.
1068          */
1069         if (E->LI != LI) {
1070             /* Line info has changed, remember the new line info */
1071             LI = E->LI;
1072
1073             /* Add the source line as a comment */
1074             if (AddSource) {
1075                 fprintf (F, ";\n; %s\n;\n", LI->Line);
1076             }
1077
1078             /* Add line debug info */
1079             if (DebugInfo) {
1080                 fprintf (F, "\t.dbg\tline, \"%s\", %u\n",
1081                          GetInputName (LI), GetInputLine (LI));
1082             }
1083         }
1084         /* Output the code */
1085         CE_Output (E, F);
1086     }
1087
1088     /* If debug info is enabled, terminate the last line number information */
1089     if (DebugInfo) {
1090         fprintf (F, "\t.dbg\tline\n");
1091     }
1092
1093     /* If this is a segment for a function, leave the function */
1094     if (S->Func) {
1095         fprintf (F, "\n.endproc\n\n");
1096     }
1097 }
1098
1099
1100
1101 void CS_FreeRegInfo (CodeSeg* S)
1102 /* Free register infos for all instructions */
1103 {
1104     unsigned I;
1105     for (I = 0; I < CS_GetEntryCount (S); ++I) {
1106         CE_FreeRegInfo (CS_GetEntry(S, I));
1107     }
1108 }
1109
1110
1111
1112 void CS_GenRegInfo (CodeSeg* S)
1113 /* Generate register infos for all instructions */
1114 {
1115     unsigned I;
1116     RegContents Regs;           /* Initial register contents */
1117     RegContents* CurrentRegs;   /* Current register contents */
1118     int WasJump;                /* True if last insn was a jump */
1119
1120     /* Be sure to delete all register infos */
1121     CS_FreeRegInfo (S);
1122
1123     /* On entry, the register contents are unknown */
1124     RC_Invalidate (&Regs);
1125     CurrentRegs = &Regs;
1126
1127     /* First pass. Walk over all insns and note just the changes from one
1128      * insn to the next one.
1129      */
1130     WasJump = 0;
1131     for (I = 0; I < CS_GetEntryCount (S); ++I) {
1132
1133         CodeEntry* P;
1134
1135         /* Get the next instruction */
1136         CodeEntry* E = CollAtUnchecked (&S->Entries, I);
1137
1138         /* If the instruction has a label, we need some special handling */
1139         unsigned LabelCount = CE_GetLabelCount (E);
1140         if (LabelCount > 0) {
1141
1142             /* Loop over all entry points that jump here. If these entry
1143              * points already have register info, check if all values are
1144              * known and identical. If all values are identical, and the
1145              * preceeding instruction was not an unconditional branch, check
1146              * if the register value on exit of the preceeding instruction
1147              * is also identical. If all these values are identical, the
1148              * value of a register is known, otherwise it is unknown.
1149              */
1150             CodeLabel* Label = CE_GetLabel (E, 0);
1151             unsigned Entry;
1152             if (WasJump) {
1153                 /* Preceeding insn was an unconditional branch */
1154                 CodeEntry* J = CL_GetRef(Label, 0);
1155                 if (J->RI) {
1156                     Regs = J->RI->Out2;
1157                 } else {
1158                     RC_Invalidate (&Regs);
1159                 }
1160                 Entry = 1;
1161             } else {
1162                 Regs = *CurrentRegs;
1163                 Entry = 0;
1164             }
1165
1166             while (Entry < CL_GetRefCount (Label)) {
1167                 /* Get this entry */
1168                 CodeEntry* J = CL_GetRef (Label, Entry);
1169                 if (J->RI == 0) {
1170                     /* No register info for this entry, bail out */
1171                     RC_Invalidate (&Regs);
1172                     break;
1173                 }
1174                 if (J->RI->Out2.RegA != Regs.RegA) {
1175                     Regs.RegA = -1;
1176                 }
1177                 if (J->RI->Out2.RegX != Regs.RegX) {
1178                     Regs.RegX = -1;
1179                 }
1180                 if (J->RI->Out2.RegY != Regs.RegY) {
1181                     Regs.RegY = -1;
1182                 }
1183                 if (J->RI->Out2.SRegLo != Regs.SRegLo) {
1184                     Regs.SRegLo = -1;
1185                 }
1186                 if (J->RI->Out2.SRegHi != Regs.SRegHi) {
1187                     Regs.SRegHi = -1;
1188                 }
1189                 ++Entry;
1190             }
1191
1192             /* Use this register info */
1193             CurrentRegs = &Regs;
1194
1195         }
1196
1197         /* Generate register info for this instruction */
1198         CE_GenRegInfo (E, CurrentRegs);
1199
1200         /* Remember for the next insn if this insn was an uncondition branch */
1201         WasJump = (E->Info & OF_UBRA) != 0;
1202
1203         /* Output registers for this insn are input for the next */
1204         CurrentRegs = &E->RI->Out;
1205
1206         /* If this insn is a branch on zero flag, we may have more info on
1207          * register contents for one of both flow directions, but only if
1208          * there is a previous instruction.
1209          */
1210         if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {
1211
1212             /* Get the branch condition */
1213             bc_t BC = GetBranchCond (E->OPC);
1214
1215             /* Check the previous instruction */
1216             switch (P->OPC) {
1217
1218                 case OP65_ADC:
1219                 case OP65_AND:
1220                 case OP65_DEA:
1221                 case OP65_EOR:
1222                 case OP65_INA:
1223                 case OP65_LDA:
1224                 case OP65_ORA:
1225                 case OP65_PLA:
1226                 case OP65_SBC:
1227                     /* A is zero in one execution flow direction */
1228                     if (BC == BC_EQ) {
1229                         E->RI->Out2.RegA = 0;
1230                     } else {
1231                         E->RI->Out.RegA = 0;
1232                     }
1233                     break;
1234
1235                 case OP65_CMP:
1236                     /* If this is an immidiate compare, the A register has
1237                      * the value of the compare later.
1238                      */
1239                     if (CE_KnownImm (P)) {
1240                         if (BC == BC_EQ) {
1241                             E->RI->Out2.RegA = (unsigned char)P->Num;
1242                         } else {
1243                             E->RI->Out.RegA = (unsigned char)P->Num;
1244                         }
1245                     }
1246                     break;
1247
1248                 case OP65_CPX:
1249                     /* If this is an immidiate compare, the X register has
1250                      * the value of the compare later.
1251                      */
1252                     if (CE_KnownImm (P)) {
1253                         if (BC == BC_EQ) {
1254                             E->RI->Out2.RegX = (unsigned char)P->Num;
1255                         } else {
1256                             E->RI->Out.RegX = (unsigned char)P->Num;
1257                         }
1258                     }
1259                     break;
1260
1261                 case OP65_CPY:
1262                     /* If this is an immidiate compare, the Y register has
1263                      * the value of the compare later.
1264                      */
1265                     if (CE_KnownImm (P)) {
1266                         if (BC == BC_EQ) {
1267                             E->RI->Out2.RegY = (unsigned char)P->Num;
1268                         } else {
1269                             E->RI->Out.RegY = (unsigned char)P->Num;
1270                         }
1271                     }
1272                     break;
1273
1274                 case OP65_DEX:
1275                 case OP65_INX:
1276                 case OP65_LDX:
1277                 case OP65_PLX:
1278                     /* X is zero in one execution flow direction */
1279                     if (BC == BC_EQ) {
1280                         E->RI->Out2.RegX = 0;
1281                     } else {
1282                         E->RI->Out.RegX = 0;
1283                     }
1284                     break;
1285
1286                 case OP65_DEY:
1287                 case OP65_INY:
1288                 case OP65_LDY:
1289                 case OP65_PLY:
1290                     /* X is zero in one execution flow direction */
1291                     if (BC == BC_EQ) {
1292                         E->RI->Out2.RegY = 0;
1293                     } else {
1294                         E->RI->Out.RegY = 0;
1295                     }
1296                     break;
1297
1298                 case OP65_TAX:
1299                 case OP65_TXA:
1300                     /* If the branch is a beq, both A and X are zero at the
1301                      * branch target, otherwise they are zero at the next
1302                      * insn.
1303                      */
1304                     if (BC == BC_EQ) {
1305                         E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
1306                     } else {
1307                         E->RI->Out.RegA = E->RI->Out.RegX = 0;
1308                     }
1309                     break;
1310
1311                 case OP65_TAY:
1312                 case OP65_TYA:
1313                     /* If the branch is a beq, both A and Y are zero at the
1314                      * branch target, otherwise they are zero at the next
1315                      * insn.
1316                      */
1317                     if (BC == BC_EQ) {
1318                         E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
1319                     } else {
1320                         E->RI->Out.RegA = E->RI->Out.RegY = 0;
1321                     }
1322                     break;
1323
1324                 default:
1325                     break;
1326
1327             }
1328         }
1329     }
1330 }
1331
1332
1333