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