Added more PIC regression testing.
[fw/sdcc] / src / pic / pcode.c
1 /*-------------------------------------------------------------------------
2
3    pcode.c - post code generation
4    Written By -  Scott Dattalo scott@dattalo.com
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 -------------------------------------------------------------------------*/
20
21 #include <stdio.h>
22
23 #include "common.h"   // Include everything in the SDCC src directory
24 #include "newalloc.h"
25
26
27 #include "pcode.h"
28 #include "ralloc.h"
29
30 #if defined(__BORLANDC__) || defined(_MSC_VER)
31 #define STRCASECMP stricmp
32 #else
33 #define STRCASECMP strcasecmp
34 #endif
35
36 // Eventually this will go into device dependent files:
37 pCodeOpReg pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,NULL};
38 pCodeOpReg pc_indf      = {{PO_INDF,    "INDF"}, -1, NULL,NULL};
39 pCodeOpReg pc_fsr       = {{PO_FSR,     "FSR"}, -1, NULL,NULL};
40 pCodeOpReg pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,NULL};
41 pCodeOpReg pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,NULL};
42
43 static int mnemonics_initialized = 0;
44
45
46 static hTab *pic14MnemonicsHash = NULL;
47
48
49
50 static pFile *the_pFile = NULL;
51 static int peepOptimizing = 1;
52 static int GpCodeSequenceNumber = 1;
53
54 /****************************************************************/
55 /*                      Forward declarations                    */
56 /****************************************************************/
57
58 static void unlinkPC(pCode *pc);
59 static void genericAnalyze(pCode *pc);
60 static void AnalyzeGOTO(pCode *pc);
61 static void AnalyzeSKIP(pCode *pc);
62 static void AnalyzeRETURN(pCode *pc);
63
64 static void genericDestruct(pCode *pc);
65 static void genericPrint(FILE *of,pCode *pc);
66
67 static void pCodePrintLabel(FILE *of, pCode *pc);
68 static void pCodePrintFunction(FILE *of, pCode *pc);
69 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
70 static char *get_op( pCodeInstruction *pcc);
71 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
72 int pCodePeepMatchRule(pCode *pc);
73
74
75 pCodeInstruction pciADDWF = {
76   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
77    genericAnalyze,
78    genericDestruct,
79    genericPrint},
80   POC_ADDWF,
81   "ADDWF",
82   NULL, // operand
83   2,    // num ops
84   1,0,  // dest, bit instruction
85   (PCC_W | PCC_REGISTER),   // inCond
86   (PCC_REGISTER | PCC_Z) // outCond
87 };
88
89 pCodeInstruction pciADDFW = {
90   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
91    genericAnalyze,
92    genericDestruct,
93    genericPrint},
94   POC_ADDWF,
95   "ADDWF",
96   NULL, // operand
97   2,    // num ops
98   0,0,  // dest, bit instruction
99   (PCC_W | PCC_REGISTER),   // inCond
100   (PCC_W | PCC_Z) // outCond
101 };
102
103 pCodeInstruction pciADDLW = {
104   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
105    genericAnalyze,
106    genericDestruct,
107    genericPrint},
108   POC_ADDLW,
109   "ADDLW",
110   NULL, // operand
111   1,    // num ops
112   0,0,  // dest, bit instruction
113   PCC_W,   // inCond
114   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
115 };
116
117 pCodeInstruction pciANDLW = {
118   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
119    genericAnalyze,
120    genericDestruct,
121    genericPrint},
122   POC_ANDLW,
123   "ANDLW",
124   NULL, // operand
125   1,    // num ops
126   0,0,  // dest, bit instruction
127   PCC_W,   // inCond
128   (PCC_W | PCC_Z) // outCond
129 };
130
131 pCodeInstruction pciANDWF = {
132   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
133    genericAnalyze,
134    genericDestruct,
135    genericPrint},
136   POC_ANDWF,
137   "ANDWF",
138   NULL, // operand
139   2,    // num ops
140   1,0,  // dest, bit instruction
141   (PCC_W | PCC_REGISTER),   // inCond
142   (PCC_REGISTER | PCC_Z) // outCond
143 };
144
145 pCodeInstruction pciANDFW = {
146   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
147    genericAnalyze,
148    genericDestruct,
149    genericPrint},
150   POC_ANDWF,
151   "ANDWF",
152   NULL, // operand
153   2,    // num ops
154   0,0,  // dest, bit instruction
155   (PCC_W | PCC_REGISTER),   // inCond
156   (PCC_W | PCC_Z) // outCond
157 };
158
159 pCodeInstruction pciBCF = {
160   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
161    genericAnalyze,
162    genericDestruct,
163    genericPrint},
164   POC_BCF,
165   "BCF",
166   NULL, // operand
167   2,    // num ops
168   0,1,  // dest, bit instruction
169   PCC_NONE,   // inCond
170   PCC_EXAMINE_PCOP // outCond
171 };
172
173 pCodeInstruction pciBSF = {
174   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
175    genericAnalyze,
176    genericDestruct,
177    genericPrint},
178   POC_BSF,
179   "BSF",
180   NULL, // operand
181   2,    // num ops
182   0,1,  // dest, bit instruction
183   PCC_NONE,   // inCond
184   PCC_EXAMINE_PCOP // outCond
185 };
186
187 pCodeInstruction pciBTFSC = {
188   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
189    AnalyzeSKIP,
190    genericDestruct,
191    genericPrint},
192   POC_BTFSC,
193   "BTFSC",
194   NULL, // operand
195   2,    // num ops
196   0,1,  // dest, bit instruction
197   PCC_EXAMINE_PCOP,   // inCond
198   PCC_NONE // outCond
199 };
200
201 pCodeInstruction pciBTFSS = {
202   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
203    AnalyzeSKIP,
204    genericDestruct,
205    genericPrint},
206   POC_BTFSS,
207   "BTFSS",
208   NULL, // operand
209   2,    // num ops
210   0,1,  // dest, bit instruction
211   PCC_EXAMINE_PCOP,   // inCond
212   PCC_NONE // outCond
213 };
214
215 pCodeInstruction pciCALL = {
216   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
217    genericAnalyze,
218    genericDestruct,
219    genericPrint},
220   POC_CALL,
221   "CALL",
222   NULL, // operand
223   1,    // num ops
224   0,0,  // dest, bit instruction
225   PCC_NONE, // inCond
226   PCC_NONE  // outCond
227 };
228
229 pCodeInstruction pciCOMF = {
230   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
231    genericAnalyze,
232    genericDestruct,
233    genericPrint},
234   POC_COMF,
235   "COMF",
236   NULL, // operand
237   2,    // num ops
238   1,0,  // dest, bit instruction
239   PCC_REGISTER,  // inCond
240   PCC_REGISTER   // outCond
241 };
242
243 pCodeInstruction pciCOMFW = {
244   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
245    genericAnalyze,
246    genericDestruct,
247    genericPrint},
248   POC_COMFW,
249   "COMF",
250   NULL, // operand
251   2,    // num ops
252   0,0,  // dest, bit instruction
253   PCC_REGISTER,  // inCond
254   PCC_W   // outCond
255 };
256
257 pCodeInstruction pciCLRF = {
258   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
259    genericAnalyze,
260    genericDestruct,
261    genericPrint},
262   POC_CLRF,
263   "CLRF",
264   NULL, // operand
265   1,    // num ops
266   0,0,  // dest, bit instruction
267   PCC_REGISTER, // inCond
268   PCC_REGISTER  // outCond
269 };
270
271 pCodeInstruction pciCLRW = {
272   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
273    genericAnalyze,
274    genericDestruct,
275    genericPrint},
276   POC_CLRW,
277   "CLRW",
278   NULL, // operand
279   0,    // num ops
280   0,0,  // dest, bit instruction
281   PCC_W, // inCond
282   PCC_W  // outCond
283 };
284
285 pCodeInstruction pciDECF = {
286   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
287    genericAnalyze,
288    genericDestruct,
289    genericPrint},
290   POC_DECF,
291   "DECF",
292   NULL, // operand
293   2,    // num ops
294   1,0,  // dest, bit instruction
295   PCC_REGISTER,   // inCond
296   PCC_REGISTER    // outCond
297 };
298
299 pCodeInstruction pciDECFW = {
300   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
301    genericAnalyze,
302    genericDestruct,
303    genericPrint},
304   POC_DECFW,
305   "DECF",
306   NULL, // operand
307   2,    // num ops
308   0,0,  // dest, bit instruction
309   PCC_REGISTER,   // inCond
310   PCC_W    // outCond
311 };
312
313 pCodeInstruction pciDECFSZ = {
314   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
315    AnalyzeSKIP,
316    genericDestruct,
317    genericPrint},
318   POC_DECFSZ,
319   "DECFSZ",
320   NULL, // operand
321   2,    // num ops
322   1,0,  // dest, bit instruction
323   PCC_REGISTER,   // inCond
324   PCC_REGISTER    // outCond
325 };
326
327 pCodeInstruction pciDECFSZW = {
328   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
329    AnalyzeSKIP,
330    genericDestruct,
331    genericPrint},
332   POC_DECFSZW,
333   "DECFSZ",
334   NULL, // operand
335   2,    // num ops
336   0,0,  // dest, bit instruction
337   PCC_REGISTER,   // inCond
338   PCC_W           // outCond
339 };
340
341 pCodeInstruction pciGOTO = {
342   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
343    AnalyzeGOTO,
344    genericDestruct,
345    genericPrint},
346   POC_GOTO,
347   "GOTO",
348   NULL, // operand
349   1,    // num ops
350   0,0,  // dest, bit instruction
351   PCC_NONE,   // inCond
352   PCC_NONE    // outCond
353 };
354
355
356 pCodeInstruction pciINCF = {
357   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
358    genericAnalyze,
359    genericDestruct,
360    genericPrint},
361   POC_INCF,
362   "INCF",
363   NULL, // operand
364   2,    // num ops
365   1,0,  // dest, bit instruction
366   PCC_REGISTER,   // inCond
367   PCC_REGISTER    // outCond
368 };
369
370 pCodeInstruction pciINCFW = {
371   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
372    genericAnalyze,
373    genericDestruct,
374    genericPrint},
375   POC_INCFW,
376   "INCF",
377   NULL, // operand
378   2,    // num ops
379   0,0,  // dest, bit instruction
380   PCC_REGISTER,   // inCond
381   PCC_W    // outCond
382 };
383
384 pCodeInstruction pciINCFSZ = {
385   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
386    AnalyzeSKIP,
387    genericDestruct,
388    genericPrint},
389   POC_INCFSZ,
390   "INCFSZ",
391   NULL, // operand
392   2,    // num ops
393   1,0,  // dest, bit instruction
394   PCC_REGISTER,   // inCond
395   PCC_REGISTER    // outCond
396 };
397
398 pCodeInstruction pciINCFSZW = {
399   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
400    AnalyzeSKIP,
401    genericDestruct,
402    genericPrint},
403   POC_INCFSZW,
404   "INCFSZ",
405   NULL, // operand
406   2,    // num ops
407   0,0,  // dest, bit instruction
408   PCC_REGISTER,   // inCond
409   PCC_W           // outCond
410 };
411
412 pCodeInstruction pciIORWF = {
413   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
414    genericAnalyze,
415    genericDestruct,
416    genericPrint},
417   POC_IORWF,
418   "IORWF",
419   NULL, // operand
420   2,    // num ops
421   1,0,  // dest, bit instruction
422   (PCC_W | PCC_REGISTER),   // inCond
423   (PCC_REGISTER | PCC_Z) // outCond
424 };
425
426 pCodeInstruction pciIORFW = {
427   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
428    genericAnalyze,
429    genericDestruct,
430    genericPrint},
431   POC_IORWF,
432   "IORWF",
433   NULL, // operand
434   2,    // num ops
435   0,0,  // dest, bit instruction
436   (PCC_W | PCC_REGISTER),   // inCond
437   (PCC_W | PCC_Z) // outCond
438 };
439
440 pCodeInstruction pciIORLW = {
441   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
442    genericAnalyze,
443    genericDestruct,
444    genericPrint},
445   POC_IORLW,
446   "IORLW",
447   NULL, // operand
448   1,    // num ops
449   0,0,  // dest, bit instruction
450   PCC_W,   // inCond
451   (PCC_W | PCC_Z) // outCond
452 };
453
454 pCodeInstruction pciMOVF = {
455   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
456    genericAnalyze,
457    genericDestruct,
458    genericPrint},
459   POC_MOVF,
460   "MOVF",
461   NULL, // operand
462   2,    // num ops
463   1,0,  // dest, bit instruction
464   PCC_REGISTER,   // inCond
465   PCC_Z // outCond
466 };
467
468 pCodeInstruction pciMOVFW = {
469   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
470    genericAnalyze,
471    genericDestruct,
472    genericPrint},
473   POC_MOVFW,
474   "MOVF",
475   NULL, // operand
476   2,    // num ops
477   0,0,  // dest, bit instruction
478   PCC_REGISTER,   // inCond
479   (PCC_W | PCC_Z) // outCond
480 };
481
482 pCodeInstruction pciMOVWF = {
483   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
484    genericAnalyze,
485    genericDestruct,
486    genericPrint},
487   POC_MOVWF,
488   "MOVWF",
489   NULL, // operand
490   1,    // num ops
491   0,0,  // dest, bit instruction
492   PCC_W,   // inCond
493   0 // outCond
494 };
495
496 pCodeInstruction pciMOVLW = {
497   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
498    genericAnalyze,
499    genericDestruct,
500    genericPrint},
501   POC_MOVLW,
502   "MOVLW",
503   NULL, // operand
504   1,    // num ops
505   0,0,  // dest, bit instruction
506   PCC_NONE,   // inCond
507   PCC_W // outCond
508 };
509
510 pCodeInstruction pciNEGF = {
511   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
512    genericAnalyze,
513    genericDestruct,
514    genericPrint},
515   POC_NEGF,
516   "NEGF",
517   NULL, // operand
518   1,    // num ops
519   0,0,  // dest, bit instruction
520   PCC_REGISTER,   // inCond
521   PCC_NONE // outCond
522 };
523
524
525 pCodeInstruction pciRETLW = {
526   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
527    AnalyzeRETURN,
528    genericDestruct,
529    genericPrint},
530   POC_RETLW,
531   "RETLW",
532   NULL, // operand
533   1,    // num ops
534   0,0,  // dest, bit instruction
535   PCC_NONE,   // inCond
536   PCC_W // outCond
537 };
538
539 pCodeInstruction pciRETURN = {
540   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
541    AnalyzeRETURN,
542    genericDestruct,
543    genericPrint},
544   POC_RETURN,
545   "RETURN",
546   NULL, // operand
547   0,    // num ops
548   0,0,  // dest, bit instruction
549   PCC_NONE,   // inCond
550   PCC_W // outCond
551 };
552
553
554 pCodeInstruction pciRLF = {
555   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
556    genericAnalyze,
557    genericDestruct,
558    genericPrint},
559   POC_RLF,
560   "RLF",
561   NULL, // operand
562   2,    // num ops
563   1,0,  // dest, bit instruction
564   (PCC_C | PCC_REGISTER),   // inCond
565   (PCC_REGISTER | PCC_Z | PCC_C | PCC_DC) // outCond
566 };
567
568 pCodeInstruction pciRLFW = {
569   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
570    genericAnalyze,
571    genericDestruct,
572    genericPrint},
573   POC_RLFW,
574   "RLF",
575   NULL, // operand
576   2,    // num ops
577   0,0,  // dest, bit instruction
578   (PCC_C | PCC_REGISTER),   // inCond
579   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
580 };
581
582 pCodeInstruction pciRRF = {
583   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
584    genericAnalyze,
585    genericDestruct,
586    genericPrint},
587   POC_RRF,
588   "RRF",
589   NULL, // operand
590   2,    // num ops
591   1,0,  // dest, bit instruction
592   (PCC_C | PCC_REGISTER),   // inCond
593   (PCC_REGISTER | PCC_Z | PCC_C | PCC_DC) // outCond
594 };
595
596 pCodeInstruction pciRRFW = {
597   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
598    genericAnalyze,
599    genericDestruct,
600    genericPrint},
601   POC_RRFW,
602   "RRF",
603   NULL, // operand
604   2,    // num ops
605   0,0,  // dest, bit instruction
606   (PCC_C | PCC_REGISTER),   // inCond
607   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
608 };
609
610 pCodeInstruction pciSUBWF = {
611   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
612    genericAnalyze,
613    genericDestruct,
614    genericPrint},
615   POC_SUBWF,
616   "SUBWF",
617   NULL, // operand
618   2,    // num ops
619   1,0,  // dest, bit instruction
620   (PCC_W | PCC_REGISTER),   // inCond
621   (PCC_REGISTER | PCC_Z) // outCond
622 };
623
624 pCodeInstruction pciSUBFW = {
625   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
626    genericAnalyze,
627    genericDestruct,
628    genericPrint},
629   POC_SUBWF,
630   "SUBWF",
631   NULL, // operand
632   2,    // num ops
633   0,0,  // dest, bit instruction
634   (PCC_W | PCC_REGISTER),   // inCond
635   (PCC_W | PCC_Z) // outCond
636 };
637
638 pCodeInstruction pciSUBLW = {
639   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
640    genericAnalyze,
641    genericDestruct,
642    genericPrint},
643   POC_SUBLW,
644   "SUBLW",
645   NULL, // operand
646   1,    // num ops
647   0,0,  // dest, bit instruction
648   PCC_W,   // inCond
649   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
650 };
651
652 pCodeInstruction pciSWAPF = {
653   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
654    genericAnalyze,
655    genericDestruct,
656    genericPrint},
657   POC_SWAPF,
658   "SWAPF",
659   NULL, // operand
660   2,    // num ops
661   1,0,  // dest, bit instruction
662   (PCC_REGISTER),   // inCond
663   (PCC_REGISTER) // outCond
664 };
665
666 pCodeInstruction pciSWAPFW = {
667   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
668    genericAnalyze,
669    genericDestruct,
670    genericPrint},
671   POC_SWAPFW,
672   "SWAPF",
673   NULL, // operand
674   2,    // num ops
675   0,0,  // dest, bit instruction
676   (PCC_REGISTER),   // inCond
677   (PCC_W) // outCond
678 };
679 pCodeInstruction pciTRIS = {
680   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
681    genericAnalyze,
682    genericDestruct,
683    genericPrint},
684   POC_TRIS,
685   "TRIS",
686   NULL, // operand
687   1,    // num ops
688   0,0,  // dest, bit instruction
689   PCC_NONE,   // inCond
690   PCC_NONE
691 };
692
693
694 pCodeInstruction pciXORWF = {
695   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
696    genericAnalyze,
697    genericDestruct,
698    genericPrint},
699   POC_XORWF,
700   "XORWF",
701   NULL, // operand
702   2,    // num ops
703   1,0,  // dest, bit instruction
704   (PCC_W | PCC_REGISTER),   // inCond
705   (PCC_REGISTER | PCC_Z) // outCond
706 };
707
708 pCodeInstruction pciXORFW = {
709   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
710    genericAnalyze,
711    genericDestruct,
712    genericPrint},
713   POC_XORWF,
714   "XORWF",
715   NULL, // operand
716   2,    // num ops
717   0,0,  // dest, bit instruction
718   (PCC_W | PCC_REGISTER),   // inCond
719   (PCC_W | PCC_Z) // outCond
720 };
721
722 pCodeInstruction pciXORLW = {
723   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
724    genericAnalyze,
725    genericDestruct,
726    genericPrint},
727   POC_XORLW,
728   "XORLW",
729   NULL, // operand
730   1,    // num ops
731   0,0,  // dest, bit instruction
732   PCC_W,   // inCond
733   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
734 };
735
736
737 #define MAX_PIC14MNEMONICS 100
738 pCodeInstruction *pic14Mnemonics[MAX_PIC14MNEMONICS];
739
740 /*-----------------------------------------------------------------*/
741 /* SAFE_snprintf - like snprintf except the string pointer is      */
742 /*                 after the string has been printed to. This is   */
743 /*                 useful for printing to string as though if it   */
744 /*                 were a stream.                                  */
745 /*-----------------------------------------------------------------*/
746 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
747 {
748   va_list val;
749   int len;
750
751   if(!str || !*str)
752     return;
753
754   va_start(val, format);
755 #if 0
756   // Alas, vsnprintf is not ANSI standard, and does not exist
757   // on Solaris (and probably other non-Gnu flavored Unixes).
758   vsnprintf(*str, *size, format, val);
759 #else
760   // This, of course, is *not* safe, despite the name.
761   vsprintf(*str, format, val);
762 #endif
763     
764   va_end (val);
765
766   len = strlen(*str);
767   *str += len;
768   *size -= len;
769
770 }
771
772 void  pCodeInitRegisters(void)
773 {
774
775   pc_fsr.rIdx = 4;
776   pc_fsr.r = pic14_regWithIdx(4);
777
778 }
779
780 /*-----------------------------------------------------------------*/
781 /*  mnem2key - convert a pic mnemonic into a hash key              */
782 /*   (BTW - this spreads the mnemonics quite well)                 */
783 /*                                                                 */
784 /*-----------------------------------------------------------------*/
785
786 int mnem2key(char const *mnem)
787 {
788   int key = 0;
789
790   if(!mnem)
791     return 0;
792
793   while(*mnem) {
794
795     key += toupper(*mnem++) +1;
796
797   }
798
799   return (key & 0x1f);
800
801 }
802
803 void pic14initMnemonics(void)
804 {
805   int i = 0;
806   int key;
807   //  char *str;
808   pCodeInstruction *pci;
809
810   if(mnemonics_initialized)
811     return;
812
813   pic14Mnemonics[POC_ADDLW] = &pciADDLW;
814   pic14Mnemonics[POC_ADDWF] = &pciADDWF;
815   pic14Mnemonics[POC_ADDFW] = &pciADDFW;
816   pic14Mnemonics[POC_ANDLW] = &pciANDLW;
817   pic14Mnemonics[POC_ANDWF] = &pciANDWF;
818   pic14Mnemonics[POC_ANDFW] = &pciANDFW;
819   pic14Mnemonics[POC_BCF] = &pciBCF;
820   pic14Mnemonics[POC_BSF] = &pciBSF;
821   pic14Mnemonics[POC_BTFSC] = &pciBTFSC;
822   pic14Mnemonics[POC_BTFSS] = &pciBTFSS;
823   pic14Mnemonics[POC_CALL] = &pciCALL;
824   pic14Mnemonics[POC_COMF] = &pciCOMF;
825   pic14Mnemonics[POC_COMFW] = &pciCOMFW;
826   pic14Mnemonics[POC_CLRF] = &pciCLRF;
827   pic14Mnemonics[POC_CLRW] = &pciCLRW;
828   pic14Mnemonics[POC_DECF] = &pciDECF;
829   pic14Mnemonics[POC_DECFW] = &pciDECFW;
830   pic14Mnemonics[POC_DECFSZ] = &pciDECFSZ;
831   pic14Mnemonics[POC_DECFSZW] = &pciDECFSZW;
832   pic14Mnemonics[POC_GOTO] = &pciGOTO;
833   pic14Mnemonics[POC_INCF] = &pciINCF;
834   pic14Mnemonics[POC_INCFW] = &pciINCFW;
835   pic14Mnemonics[POC_INCFSZ] = &pciINCFSZ;
836   pic14Mnemonics[POC_INCFSZW] = &pciINCFSZW;
837   pic14Mnemonics[POC_IORLW] = &pciIORLW;
838   pic14Mnemonics[POC_IORWF] = &pciIORWF;
839   pic14Mnemonics[POC_IORFW] = &pciIORFW;
840   pic14Mnemonics[POC_MOVF] = &pciMOVF;
841   pic14Mnemonics[POC_MOVFW] = &pciMOVFW;
842   pic14Mnemonics[POC_MOVLW] = &pciMOVLW;
843   pic14Mnemonics[POC_MOVWF] = &pciMOVWF;
844   pic14Mnemonics[POC_NEGF] = &pciNEGF;
845   pic14Mnemonics[POC_RETLW] = &pciRETLW;
846   pic14Mnemonics[POC_RETURN] = &pciRETURN;
847   pic14Mnemonics[POC_RLF] = &pciRLF;
848   pic14Mnemonics[POC_RLFW] = &pciRLFW;
849   pic14Mnemonics[POC_RRF] = &pciRRF;
850   pic14Mnemonics[POC_RRFW] = &pciRRFW;
851   pic14Mnemonics[POC_SUBLW] = &pciSUBLW;
852   pic14Mnemonics[POC_SUBWF] = &pciSUBWF;
853   pic14Mnemonics[POC_SUBFW] = &pciSUBFW;
854   pic14Mnemonics[POC_SWAPF] = &pciSWAPF;
855   pic14Mnemonics[POC_SWAPFW] = &pciSWAPFW;
856   pic14Mnemonics[POC_TRIS] = &pciTRIS;
857   pic14Mnemonics[POC_XORLW] = &pciXORLW;
858   pic14Mnemonics[POC_XORWF] = &pciXORWF;
859   pic14Mnemonics[POC_XORFW] = &pciXORFW;
860
861   for(i=0; i<MAX_PIC14MNEMONICS; i++)
862     if(pic14Mnemonics[i])
863       hTabAddItem(&pic14MnemonicsHash, mnem2key(pic14Mnemonics[i]->mnemonic), pic14Mnemonics[i]);
864   pci = hTabFirstItem(pic14MnemonicsHash, &key);
865
866   while(pci) {
867     fprintf( stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic);
868     pci = hTabNextItem(pic14MnemonicsHash, &key);
869   }
870
871   mnemonics_initialized = 1;
872 }
873
874 int getpCode(char *mnem,unsigned dest)
875 {
876
877   pCodeInstruction *pci;
878   int key = mnem2key(mnem);
879
880   if(!mnemonics_initialized)
881     pic14initMnemonics();
882
883   pci = hTabFirstItemWK(pic14MnemonicsHash, key);
884
885   while(pci) {
886
887     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
888       if((pci->num_ops <= 1) || (pci->dest == dest))
889         return(pci->op);
890     }
891
892     pci = hTabNextItemWK (pic14MnemonicsHash);
893   
894   }
895
896   return -1;
897 }
898
899 char getpBlock_dbName(pBlock *pb)
900 {
901   if(!pb)
902     return 0;
903
904   if(pb->cmemmap)
905     return pb->cmemmap->dbName;
906
907   return pb->dbName;
908 }
909 /*-----------------------------------------------------------------*/
910 /* movepBlock2Head - given the dbname of a pBlock, move all        */
911 /*                   instances to the front of the doubly linked   */
912 /*                   list of pBlocks                               */
913 /*-----------------------------------------------------------------*/
914
915 void movepBlock2Head(char dbName)
916 {
917   pBlock *pb;
918
919   pb = the_pFile->pbHead;
920
921   while(pb) {
922
923     if(getpBlock_dbName(pb) == dbName) {
924       pBlock *pbn = pb->next;
925       pb->next = the_pFile->pbHead;
926       the_pFile->pbHead->prev = pb;
927       the_pFile->pbHead = pb;
928
929       if(pb->prev)
930         pb->prev->next = pbn;
931
932       // If the pBlock that we just moved was the last
933       // one in the link of all of the pBlocks, then we
934       // need to point the tail to the block just before
935       // the one we moved.
936       // Note: if pb->next is NULL, then pb must have 
937       // been the last pBlock in the chain.
938
939       if(pbn)
940         pbn->prev = pb->prev;
941       else
942         the_pFile->pbTail = pb->prev;
943
944       pb = pbn;
945
946     } else
947       pb = pb->next;
948
949   }
950
951 }
952
953 void copypCode(FILE *of, char dbName)
954 {
955   pBlock *pb;
956
957   if(!of || !the_pFile)
958     return;
959
960   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
961     if(getpBlock_dbName(pb) == dbName)
962       printpBlock(of,pb);
963   }
964
965 }
966 void pcode_test(void)
967 {
968
969   printf("pcode is alive!\n");
970
971   //initMnemonics();
972
973   if(the_pFile) {
974
975     pBlock *pb;
976     FILE *pFile;
977     char buffer[100];
978
979     /* create the file name */
980     strcpy(buffer,srcFileName);
981     strcat(buffer,".p");
982
983     if( !(pFile = fopen(buffer, "w" ))) {
984       werror(E_FILE_OPEN_ERR,buffer);
985       exit(1);
986     }
987
988     fprintf(pFile,"pcode dump\n\n");
989
990     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
991       fprintf(pFile,"\n\tNew pBlock\n\n");
992       if(pb->cmemmap)
993         fprintf(pFile,"%s",pb->cmemmap->sname);
994       else
995         fprintf(pFile,"internal pblock");
996
997       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
998       printpBlock(pFile,pb);
999     }
1000   }
1001 }
1002 static int RegCond(pCodeOp *pcop)
1003 {
1004
1005   if(!pcop)
1006     return 0;
1007
1008   if(pcop->type == PO_BIT  && !strcmp(pcop->name, pc_status.pcop.name)) {
1009     switch(PCOB(pcop)->bit) {
1010     case PIC_C_BIT:
1011       return PCC_C;
1012     case PIC_DC_BIT:
1013         return PCC_DC;
1014     case PIC_Z_BIT:
1015       return PCC_Z;
1016     }
1017
1018   }
1019
1020   return 0;
1021 }
1022
1023 /*-----------------------------------------------------------------*/
1024 /* newpCode - create and return a newly initialized pCode          */
1025 /*                                                                 */
1026 /*  fixme - rename this                                            */
1027 /*                                                                 */
1028 /* The purpose of this routine is to create a new Instruction      */
1029 /* pCode. This is called by gen.c while the assembly code is being */
1030 /* generated.                                                      */
1031 /*                                                                 */
1032 /* Inouts:                                                         */
1033 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
1034 /*                  (note that the op is analogous to but not the  */
1035 /*                  same thing as the opcode of the instruction.)  */
1036 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
1037 /*                                                                 */
1038 /* Outputs:                                                        */
1039 /*  a pointer to the new malloc'd pCode is returned.               */
1040 /*                                                                 */
1041 /*                                                                 */
1042 /*                                                                 */
1043 /*-----------------------------------------------------------------*/
1044 pCode *newpCode (PIC_OPCODE op, pCodeOp *pcop)
1045 {
1046   pCodeInstruction *pci ;
1047
1048   if(!mnemonics_initialized)
1049     pic14initMnemonics();
1050     
1051   pci = Safe_calloc(1, sizeof(pCodeInstruction));
1052
1053   if((op>=0) && (op < MAX_PIC14MNEMONICS) && pic14Mnemonics[op]) {
1054     memcpy(pci, pic14Mnemonics[op], sizeof(pCodeInstruction));
1055     pci->pcop = pcop;
1056
1057     if(pci->inCond == PCC_EXAMINE_PCOP)
1058       pci->inCond   = RegCond(pcop);
1059
1060     if(pci->outCond == PCC_EXAMINE_PCOP)
1061       pci->outCond   = RegCond(pcop);
1062
1063     return (pCode *)pci;
1064   }
1065
1066   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
1067   exit(1);
1068
1069   return NULL;
1070 }       
1071
1072 /*-----------------------------------------------------------------*/
1073 /* newpCodeWild - create a "wild" as in wild card pCode            */
1074 /*                                                                 */
1075 /* Wild pcodes are used during the peep hole optimizer to serve    */
1076 /* as place holders for any instruction. When a snippet of code is */
1077 /* compared to a peep hole rule, the wild card opcode will match   */
1078 /* any instruction. However, the optional operand and label are    */
1079 /* additional qualifiers that must also be matched before the      */
1080 /* line (of assembly code) is declared matched. Note that the      */
1081 /* operand may be wild too.                                        */
1082 /*                                                                 */
1083 /*   Note, a wild instruction is specified just like a wild var:   */
1084 /*      %4     ; A wild instruction,                               */
1085 /*  See the peeph.def file for additional examples                 */
1086 /*                                                                 */
1087 /*-----------------------------------------------------------------*/
1088
1089 pCode *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
1090 {
1091
1092   pCodeWild *pcw;
1093     
1094   pcw = Safe_calloc(1,sizeof(pCodeWild));
1095
1096   pcw->pc.type = PC_WILD;
1097   pcw->pc.prev = pcw->pc.next = NULL;
1098   pcw->pc.from = pcw->pc.to = pcw->pc.label = NULL;
1099   pcw->pc.pb = NULL;
1100
1101   pcw->pc.analyze = genericAnalyze;
1102   pcw->pc.destruct = genericDestruct;
1103   pcw->pc.print = genericPrint;
1104
1105   pcw->id = pCodeID;              // this is the 'n' in %n
1106   pcw->operand = optional_operand;
1107   pcw->label   = optional_label;
1108
1109   return ( (pCode *)pcw);
1110   
1111 }
1112
1113 /*-----------------------------------------------------------------*/
1114 /* newPcodeCharP - create a new pCode from a char string           */
1115 /*-----------------------------------------------------------------*/
1116
1117 pCode *newpCodeCharP(char *cP)
1118 {
1119
1120   pCodeComment *pcc ;
1121     
1122   pcc = Safe_calloc(1,sizeof(pCodeComment));
1123
1124   pcc->pc.type = PC_COMMENT;
1125   pcc->pc.prev = pcc->pc.next = NULL;
1126   pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
1127   pcc->pc.pb = NULL;
1128
1129   pcc->pc.analyze = genericAnalyze;
1130   pcc->pc.destruct = genericDestruct;
1131   pcc->pc.print = genericPrint;
1132
1133   if(cP)
1134     pcc->comment = Safe_strdup(cP);
1135   else
1136     pcc->comment = NULL;
1137
1138   return ( (pCode *)pcc);
1139
1140 }
1141
1142 /*-----------------------------------------------------------------*/
1143 /* newpCodeGLabel - create a new global label                      */
1144 /*-----------------------------------------------------------------*/
1145
1146
1147 pCode *newpCodeFunction(char *mod,char *f)
1148 {
1149   pCodeFunction *pcf;
1150
1151   _ALLOC(pcf,sizeof(pCodeFunction));
1152
1153   pcf->pc.type = PC_FUNCTION;
1154   pcf->pc.prev = pcf->pc.next = NULL;
1155   pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
1156   pcf->pc.pb = NULL;
1157
1158   pcf->pc.analyze = genericAnalyze;
1159   pcf->pc.destruct = genericDestruct;
1160   pcf->pc.print = pCodePrintFunction;
1161
1162   if(mod) {
1163     _ALLOC_ATOMIC(pcf->modname,strlen(mod)+1);
1164     strcpy(pcf->modname,mod);
1165   } else
1166     pcf->modname = NULL;
1167
1168   if(f) {
1169     _ALLOC_ATOMIC(pcf->fname,strlen(f)+1);
1170     strcpy(pcf->fname,f);
1171   } else
1172     pcf->fname = NULL;
1173
1174   return ( (pCode *)pcf);
1175
1176 }
1177
1178 static void pCodeLabelDestruct(pCode *pc)
1179 {
1180
1181   if(!pc)
1182     return;
1183
1184   unlinkPC(pc);
1185
1186   if((pc->type == PC_LABEL) && PCL(pc)->label)
1187     free(PCL(pc)->label);
1188
1189   free(pc);
1190
1191 }
1192
1193 pCode *newpCodeLabel(int key)
1194 {
1195
1196   char *s = buffer;
1197   pCodeLabel *pcl;
1198     
1199   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
1200
1201   pcl->pc.type = PC_LABEL;
1202   pcl->pc.prev = pcl->pc.next = NULL;
1203   pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
1204   pcl->pc.pb = NULL;
1205
1206   pcl->pc.analyze = genericAnalyze;
1207   pcl->pc.destruct = pCodeLabelDestruct;
1208   pcl->pc.print = pCodePrintLabel;
1209
1210   pcl->key = key;
1211
1212   pcl->label = NULL;
1213   if(key>0) {
1214     sprintf(s,"_%05d_DS_",key);
1215     if(s)
1216       pcl->label = Safe_strdup(s);
1217   }
1218
1219
1220   return ( (pCode *)pcl);
1221
1222 }
1223 pCode *newpCodeLabelStr(char *str)
1224 {
1225   pCode *pc = newpCodeLabel(-1);
1226
1227   if(str)
1228     PCL(pc)->label = Safe_strdup(str);
1229   else
1230     PCL(pc)->label = NULL;
1231
1232   return pc;
1233 }
1234
1235 /*-----------------------------------------------------------------*/
1236 /* newpBlock - create and return a pointer to a new pBlock         */
1237 /*-----------------------------------------------------------------*/
1238 pBlock *newpBlock(void)
1239 {
1240
1241   pBlock *PpB;
1242
1243   PpB = Safe_calloc(1,sizeof(pBlock) );
1244   PpB->next = PpB->prev = NULL;
1245
1246   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
1247   PpB->registers = NULL;
1248   PpB->visited = 0;
1249
1250   return PpB;
1251
1252 }
1253
1254 /*-----------------------------------------------------------------*/
1255 /* newpCodeChai0n - create a new chain of pCodes                    */
1256 /*-----------------------------------------------------------------*
1257  *
1258  *  This function will create a new pBlock and the pointer to the
1259  *  pCode that is passed in will be the first pCode in the block.
1260  *-----------------------------------------------------------------*/
1261
1262
1263 pBlock *newpCodeChain(memmap *cm,char c, pCode *pc)
1264 {
1265
1266   pBlock *pB  = newpBlock();
1267
1268   pB->pcHead  = pB->pcTail = pc;
1269   pB->cmemmap = cm;
1270   pB->dbName  = c;
1271
1272   return pB;
1273 }
1274
1275 /*-----------------------------------------------------------------*/
1276 /* newpCodeOpLabel - Create a new label given the key              */
1277 /*  Note, a negative key means that the label is part of wild card */
1278 /*  (and hence a wild card label) used in the pCodePeep            */
1279 /*   optimizations).                                               */
1280 /*-----------------------------------------------------------------*/
1281
1282 pCodeOp *newpCodeOpLabel(int key)
1283 {
1284   char *s = buffer;
1285   pCodeOp *pcop;
1286
1287   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
1288   pcop->type = PO_LABEL;
1289
1290   pcop->name = NULL;
1291   if(key>0) {
1292     sprintf(s,"_%05d_DS_",key);
1293     if(s)
1294       pcop->name = Safe_strdup(s);
1295   } 
1296
1297
1298   ((pCodeOpLabel *)pcop)->key = key;
1299
1300   return pcop;
1301 }
1302
1303 pCodeOp *newpCodeOpLit(int lit)
1304 {
1305   char *s = buffer;
1306   pCodeOp *pcop;
1307
1308
1309   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
1310   pcop->type = PO_LITERAL;
1311   pcop->name = NULL;
1312   if(lit>=0) {
1313     sprintf(s,"0x%02x",lit);
1314     if(s)
1315       pcop->name = Safe_strdup(s);
1316   } 
1317
1318
1319   ((pCodeOpLit *)pcop)->lit = lit;
1320
1321   return pcop;
1322 }
1323
1324 pCodeOp *newpCodeOpWild(int id, pCodePeep *pcp, pCodeOp *subtype)
1325 {
1326   char *s = buffer;
1327   pCodeOp *pcop;
1328
1329
1330   if(!pcp || !subtype) {
1331     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
1332     exit(1);
1333   }
1334
1335   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
1336   pcop->type = PO_WILD;
1337   sprintf(s,"%%%d",id);
1338   pcop->name = Safe_strdup(s);
1339
1340   PCOW(pcop)->id = id;
1341   PCOW(pcop)->pcp = pcp;
1342   PCOW(pcop)->subtype = subtype;
1343   PCOW(pcop)->matched = NULL;
1344
1345   return pcop;
1346 }
1347
1348 pCodeOp *newpCodeOpBit(char *s, int bit, int inBitSpace)
1349 {
1350   pCodeOp *pcop;
1351
1352   pcop = Safe_calloc(1,sizeof(pCodeOpBit) );
1353   pcop->type = PO_BIT;
1354   if(s)
1355     pcop->name = Safe_strdup(s);   
1356   else
1357     pcop->name = NULL;
1358
1359   PCOB(pcop)->bit = bit;
1360   PCOB(pcop)->inBitSpace = inBitSpace;
1361
1362   return pcop;
1363 }
1364
1365 pCodeOp *newpCodeOpReg(int rIdx)
1366 {
1367   pCodeOp *pcop;
1368
1369   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
1370
1371   PCOR(pcop)->rIdx = rIdx;
1372   PCOR(pcop)->r = pic14_regWithIdx(rIdx);
1373   pcop->type = PCOR(pcop)->r->pc_type;
1374
1375   return pcop;
1376 }
1377
1378 /*-----------------------------------------------------------------*/
1379 /*-----------------------------------------------------------------*/
1380
1381 pCodeOp *newpCodeOp(char *name, PIC_OPTYPE type)
1382 {
1383   pCodeOp *pcop;
1384
1385   switch(type) {
1386   case PO_BIT:
1387     pcop = newpCodeOpBit(name, -1,0);
1388     break;
1389
1390   case PO_LITERAL:
1391     pcop = newpCodeOpLit(-1);
1392     break;
1393
1394   case PO_LABEL:
1395     pcop = newpCodeOpLabel(-1);
1396     break;
1397
1398   default:
1399     pcop = Safe_calloc(1,sizeof(pCodeOp) );
1400     pcop->type = type;
1401     if(name)
1402       pcop->name = Safe_strdup(name);   
1403     else
1404       pcop->name = NULL;
1405   }
1406
1407   return pcop;
1408 }
1409
1410 /*-----------------------------------------------------------------*/
1411 /* addpCode2pBlock - place the pCode into the pBlock linked list   */
1412 /*-----------------------------------------------------------------*/
1413 void addpCode2pBlock(pBlock *pb, pCode *pc)
1414 {
1415   if(!pb->pcHead) {
1416     /* If this is the first pcode to be added to a block that
1417      * was initialized with a NULL pcode, then go ahead and
1418      * make this pcode the head and tail */
1419     pb->pcHead  = pb->pcTail = pc;
1420   } else {
1421     pb->pcTail->next = pc;
1422     pc->prev = pb->pcTail;
1423     pc->next = NULL;
1424     pc->pb = pb;
1425     pb->pcTail = pc;
1426   }
1427 }
1428
1429 /*-----------------------------------------------------------------*/
1430 /* addpBlock - place a pBlock into the pFile                       */
1431 /*-----------------------------------------------------------------*/
1432 void addpBlock(pBlock *pb)
1433 {
1434
1435   if(!the_pFile) {
1436     /* First time called, we'll pass through here. */
1437     _ALLOC(the_pFile,sizeof(the_pFile));
1438     the_pFile->pbHead = the_pFile->pbTail = pb;
1439     the_pFile->functions = NULL;
1440     return;
1441   }
1442
1443   the_pFile->pbTail->next = pb;
1444   pb->prev = the_pFile->pbTail;
1445   pb->next = NULL;
1446   the_pFile->pbTail = pb;
1447 }
1448
1449 /*-----------------------------------------------------------------*/
1450 /* printpCode - write the contents of a pCode to a file            */
1451 /*-----------------------------------------------------------------*/
1452 void printpCode(FILE *of, pCode *pc)
1453 {
1454
1455   if(!pc || !of)
1456     return;
1457
1458   if(pc->print) {
1459     pc->print(of,pc);
1460     return;
1461   }
1462
1463   fprintf(of,"warning - unable to print pCode\n");
1464 }
1465
1466 /*-----------------------------------------------------------------*/
1467 /* printpBlock - write the contents of a pBlock to a file          */
1468 /*-----------------------------------------------------------------*/
1469 void printpBlock(FILE *of, pBlock *pb)
1470 {
1471   pCode *pc;
1472
1473   if(!pb)
1474     return;
1475
1476   if(!of)
1477     of = stderr;
1478
1479   for(pc = pb->pcHead; pc; pc = pc->next)
1480     printpCode(of,pc);
1481
1482 }
1483
1484 /*-----------------------------------------------------------------*/
1485 /*                                                                 */
1486 /*       pCode processing                                          */
1487 /*                                                                 */
1488 /*                                                                 */
1489 /*                                                                 */
1490 /*-----------------------------------------------------------------*/
1491
1492 static void unlinkPC(pCode *pc)
1493 {
1494
1495
1496   if(pc) {
1497
1498     if(pc->prev) 
1499       pc->prev->next = pc->next;
1500     if(pc->next)
1501       pc->next->prev = pc->prev;
1502
1503     pc->prev = pc->next = NULL;
1504   }
1505 }
1506 static void genericDestruct(pCode *pc)
1507 {
1508   fprintf(stderr,"warning, calling default pCode destructor\n");
1509
1510   unlinkPC(pc);
1511
1512   free(pc);
1513
1514 }
1515
1516
1517 void pBlockRegs(FILE *of, pBlock *pb)
1518 {
1519
1520   regs  *r;
1521
1522   r = setFirstItem(pb->registers);
1523   while (r) {
1524     r = setNextItem(pb->registers);
1525   }
1526 }
1527
1528
1529 static char *get_op( pCodeInstruction *pcc)
1530 {
1531   regs *r;
1532
1533   if(pcc && pcc->pcop) {
1534
1535
1536     switch(pcc->pcop->type) {
1537
1538     case PO_FSR:
1539     case PO_GPR_TEMP:
1540     case PO_GPR_BIT:
1541       r = pic14_regWithIdx(PCOR(pcc->pcop)->r->rIdx);
1542       //fprintf(stderr,"getop: getting %s\nfrom:\n",r->name); //pcc->pcop->name);
1543       pBlockRegs(stderr,pcc->pc.pb);
1544       return r->name;
1545
1546     default:
1547       if  (pcc->pcop->name)
1548         return pcc->pcop->name;
1549
1550     }
1551   }
1552
1553   return "NO operand";
1554 }
1555
1556 /*-----------------------------------------------------------------*/
1557 /*-----------------------------------------------------------------*/
1558 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
1559 {
1560
1561   fprintf(of,"pcodeopprint\n");
1562 }
1563
1564 char *pCode2str(char *str, int size, pCode *pc)
1565 {
1566   char *s = str;
1567
1568   switch(pc->type) {
1569
1570   case PC_OPCODE:
1571
1572     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
1573
1574     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
1575
1576       if(PCI(pc)->bit_inst) {
1577         if(PCI(pc)->pcop->type == PO_BIT) {
1578           if( (((pCodeOpBit *)(PCI(pc)->pcop))->inBitSpace) )
1579             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
1580                           PCI(pc)->pcop->name ,
1581                           PCI(pc)->pcop->name );
1582           else
1583             SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)), 
1584                           (((pCodeOpBit *)(PCI(pc)->pcop))->bit ));
1585         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
1586           SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
1587         }else
1588           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", get_op(PCI(pc)));
1589         //PCI(pc)->pcop->t.bit );
1590       } else {
1591
1592         if(PCI(pc)->pcop->type == PO_BIT) {
1593           if( PCI(pc)->num_ops == 2)
1594             SAFE_snprintf(&s,&size,"(%s >> 3),%c",get_op(PCI(pc)),((PCI(pc)->dest) ? 'F':'W'));
1595           else
1596             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",get_op(PCI(pc)));
1597
1598         }else {
1599           SAFE_snprintf(&s,&size,"%s",get_op(PCI(pc)));
1600
1601           if( PCI(pc)->num_ops == 2)
1602             SAFE_snprintf(&s,&size,",%c", ( (PCI(pc)->dest) ? 'F':'W'));
1603         }
1604       }
1605
1606     }
1607     break;
1608
1609   case PC_COMMENT:
1610     /* assuming that comment ends with a \n */
1611     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
1612     break;
1613
1614   case PC_LABEL:
1615     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
1616     break;
1617   case PC_FUNCTION:
1618     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
1619     break;
1620   case PC_WILD:
1621     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
1622     break;
1623
1624   }
1625
1626   return str;
1627
1628 }
1629
1630 /*-----------------------------------------------------------------*/
1631 /* genericPrint - the contents of a pCode to a file                */
1632 /*-----------------------------------------------------------------*/
1633 static void genericPrint(FILE *of, pCode *pc)
1634 {
1635
1636   if(!pc || !of)
1637     return;
1638
1639   switch(pc->type) {
1640   case PC_COMMENT:
1641     fprintf(of,";%s\n", ((pCodeComment *)pc)->comment);
1642     break;
1643
1644   case PC_OPCODE:
1645     // If the opcode has a label, print that first
1646     {
1647       pBranch *pbl = pc->label;
1648       while(pbl) {
1649         if(pbl->pc->type == PC_LABEL)
1650           pCodePrintLabel(of, pbl->pc);
1651         pbl = pbl->next;
1652       }
1653     }
1654
1655
1656     {
1657       char str[256];
1658       
1659       pCode2str(str, 256, pc);
1660
1661       fprintf(of,"%s",str);
1662     }
1663
1664     {
1665       pBranch *dpb = pc->to;   // debug
1666       while(dpb) {
1667         switch ( dpb->pc->type) {
1668         case PC_OPCODE:
1669           fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic);
1670           break;
1671         case PC_LABEL:
1672           fprintf(of, "\t;label %d", PCL(dpb->pc)->key);
1673           break;
1674         case PC_FUNCTION:
1675           fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]"));
1676           break;
1677         case PC_COMMENT:
1678         case PC_WILD:
1679           break;
1680         }
1681         dpb = dpb->next;
1682       }
1683       fprintf(of,"\n");
1684     }
1685
1686     break;
1687
1688   case PC_WILD:
1689     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
1690     if(pc->label)
1691       pCodePrintLabel(of, pc->label->pc);
1692
1693     if(PCW(pc)->operand) {
1694       fprintf(of,";\toperand  ");
1695       pCodeOpPrint(of,PCW(pc)->operand );
1696     }
1697     break;
1698
1699   case PC_LABEL:
1700   default:
1701     fprintf(of,"unknown pCode type %d\n",pc->type);
1702   }
1703
1704 }
1705
1706 /*-----------------------------------------------------------------*/
1707 /* pCodePrintFunction - prints function begin/end                  */
1708 /*-----------------------------------------------------------------*/
1709
1710 static void pCodePrintFunction(FILE *of, pCode *pc)
1711 {
1712
1713   if(!pc || !of)
1714     return;
1715
1716   if( ((pCodeFunction *)pc)->modname) 
1717     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
1718
1719   if(PCF(pc)->fname) {
1720     pBranch *exits = pc->to;
1721     int i=0;
1722     fprintf(of,"%s\t;Function start\n",PCF(pc)->fname);
1723     while(exits) {
1724       i++;
1725       exits = exits->next;
1726     }
1727     //if(i) i--;
1728     fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
1729     
1730   }else {
1731     if(pc->from && 
1732        pc->from->pc->type == PC_FUNCTION &&
1733        PCF(pc->from->pc)->fname) 
1734       fprintf(of,"; exit point of %s\n",PCF(pc->from->pc)->fname);
1735     else
1736       fprintf(of,"; exit point [can't find entry point]\n");
1737   }
1738 }
1739 /*-----------------------------------------------------------------*/
1740 /* pCodePrintLabel - prints label                                  */
1741 /*-----------------------------------------------------------------*/
1742
1743 static void pCodePrintLabel(FILE *of, pCode *pc)
1744 {
1745
1746   if(!pc || !of)
1747     return;
1748
1749   if(PCL(pc)->label) 
1750     fprintf(of,"%s\n",PCL(pc)->label);
1751   else if (PCL(pc)->key >=0) 
1752     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
1753   else
1754     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
1755
1756 }
1757 /*-----------------------------------------------------------------*/
1758 static void  unlinkpCodeFromBranch(pBranch *pb , pCode *pc)
1759 {
1760   pBranch *b, *bprev;
1761
1762   bprev = NULL;
1763   b = pb;
1764   while(b) {
1765     if(b->pc == pc) {
1766       if(bprev)
1767         bprev->next = b->next;
1768     }
1769     bprev = b;
1770     b = b->next;
1771   }
1772
1773 }
1774
1775 static pBranch * pBranchAppend(pBranch *h, pBranch *n)
1776 {
1777   pBranch *b;
1778
1779   if(!h)
1780     return n;
1781
1782   b = h;
1783   while(b->next)
1784     b = b->next;
1785
1786   b->next = n;
1787
1788   return h;
1789   
1790 }  
1791 /*-----------------------------------------------------------------*/
1792 /* pBranchLink - given two pcodes, this function will link them    */
1793 /*               together through their pBranches                  */
1794 /*-----------------------------------------------------------------*/
1795 static void pBranchLink(pCode *f, pCode *t)
1796 {
1797   pBranch *b;
1798
1799   // Declare a new branch object for the 'from' pCode.
1800
1801   _ALLOC(b,sizeof(pBranch));
1802   b->pc = t;                    // The link to the 'to' pCode.
1803   b->next = NULL;
1804
1805   f->to = pBranchAppend(f->to,b);
1806
1807   // Now do the same for the 'to' pCode.
1808
1809   _ALLOC(b,sizeof(pBranch));
1810   b->pc = f;
1811   b->next = NULL;
1812
1813   t->from = pBranchAppend(t->from,b);
1814   
1815 }
1816
1817 #if 0
1818 /*-----------------------------------------------------------------*/
1819 /* pBranchFind - find the pBranch in a pBranch chain that contains */
1820 /*               a pCode                                           */
1821 /*-----------------------------------------------------------------*/
1822 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
1823 {
1824   while(pb) {
1825
1826     if(pb->pc == pc)
1827       return pb;
1828
1829     pb = pb->next;
1830   }
1831
1832   return NULL;
1833 }
1834
1835 /*-----------------------------------------------------------------*/
1836 /* pCodeUnlink - Unlink the given pCode from its pCode chain.      */
1837 /*-----------------------------------------------------------------*/
1838 static void pCodeUnlink(pCode *pc)
1839 {
1840   pBranch *pb1,*pb2;
1841   pCode *pc1;
1842
1843   if(!pc->prev || !pc->next) {
1844     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
1845     exit(1);
1846   }
1847
1848   /* first remove the pCode from the chain */
1849   pc->prev->next = pc->next;
1850   pc->next->prev = pc->prev;
1851
1852   /* Now for the hard part... */
1853
1854   /* Remove the branches */
1855
1856   pb1 = pc->from;
1857   while(pb1) {
1858     pc1 = pb1->pc;    /* Get the pCode that branches to the
1859                        * one we're unlinking */
1860
1861     /* search for the link back to this pCode (the one we're
1862      * unlinking) */
1863     if(pb2 = pBranchFind(pc1->to,pc)) {
1864       pb2->pc = pc->to->pc;  // make the replacement
1865
1866       /* if the pCode we're unlinking contains multiple 'to'
1867        * branches (e.g. this a skip instruction) then we need
1868        * to copy these extra branches to the chain. */
1869       if(pc->to->next)
1870         pBranchAppend(pb2, pc->to->next);
1871     }
1872     
1873     pb1 = pb1->next;
1874   }
1875
1876
1877 }
1878 #endif
1879 /*-----------------------------------------------------------------*/
1880 /*-----------------------------------------------------------------*/
1881 static void genericAnalyze(pCode *pc)
1882 {
1883   switch(pc->type) {
1884   case PC_WILD:
1885   case PC_COMMENT:
1886     return;
1887   case PC_LABEL:
1888   case PC_FUNCTION:
1889   case PC_OPCODE:
1890     {
1891       // Go through the pCodes that are in pCode chain and link
1892       // them together through the pBranches. Note, the pCodes
1893       // are linked together as a contiguous stream like the 
1894       // assembly source code lines. The linking here mimics this
1895       // except that comments are not linked in.
1896       // 
1897       pCode *npc = pc->next;
1898       while(npc) {
1899         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
1900           pBranchLink(pc,npc);
1901           return;
1902         } else
1903           npc = npc->next;
1904       }
1905     }
1906   }
1907 }
1908
1909 /*-----------------------------------------------------------------*/
1910 int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
1911 {
1912   pBranch *pbr;
1913
1914   if(pc->type == PC_LABEL) {
1915     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
1916       return TRUE;
1917   }
1918   if(pc->type == PC_OPCODE) {
1919     pbr = pc->label;
1920     while(pbr) {
1921       if(pbr->pc->type == PC_LABEL) {
1922         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
1923           return TRUE;
1924       }
1925       pbr = pbr->next;
1926     }
1927   }
1928
1929   return FALSE;
1930 }
1931
1932 /*-----------------------------------------------------------------*/
1933 /* findLabel - Search the pCode for a particular label             */
1934 /*-----------------------------------------------------------------*/
1935 pCode * findLabel(pCodeOpLabel *pcop_label)
1936 {
1937   pBlock *pb;
1938   pCode  *pc;
1939
1940   if(!the_pFile)
1941     return NULL;
1942
1943   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1944     for(pc = pb->pcHead; pc; pc = pc->next) 
1945       if(compareLabel(pc,pcop_label))
1946         return pc;
1947     
1948   }
1949
1950   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
1951   return NULL;
1952 }
1953
1954 /*-----------------------------------------------------------------*/
1955 /* findNextInstruction - given a pCode, find the next instruction  */
1956 /*                       in the linked list                        */
1957 /*-----------------------------------------------------------------*/
1958 pCode * findNextInstruction(pCode *pc)
1959 {
1960
1961   while(pc) {
1962     if((pc->type == PC_OPCODE) || (pc->type == PC_WILD))
1963       return pc;
1964
1965     pc = pc->next;
1966   }
1967
1968   fprintf(stderr,"Couldn't find instruction\n");
1969   return NULL;
1970 }
1971
1972 /*-----------------------------------------------------------------*/
1973 /* findFunctionEnd - given a pCode find the end of the function    */
1974 /*                   that contains it     t                        */
1975 /*-----------------------------------------------------------------*/
1976 pCode * findFunctionEnd(pCode *pc)
1977 {
1978
1979   while(pc) {
1980     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
1981       return pc;
1982
1983     pc = pc->next;
1984   }
1985
1986   fprintf(stderr,"Couldn't find function end\n");
1987   return NULL;
1988 }
1989
1990 #if 0
1991 /*-----------------------------------------------------------------*/
1992 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
1993 /*                instruction with which it is associated.         */
1994 /*-----------------------------------------------------------------*/
1995 static void AnalyzeLabel(pCode *pc)
1996 {
1997
1998   pCodeUnlink(pc);
1999
2000 }
2001 #endif
2002
2003 static void AnalyzeGOTO(pCode *pc)
2004 {
2005
2006   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
2007
2008 }
2009
2010 static void AnalyzeSKIP(pCode *pc)
2011 {
2012
2013   pBranchLink(pc,findNextInstruction(pc->next));
2014   pBranchLink(pc,findNextInstruction(pc->next->next));
2015
2016 }
2017
2018 static void AnalyzeRETURN(pCode *pc)
2019 {
2020
2021   //  branch_link(pc,findFunctionEnd(pc->next));
2022
2023 }
2024
2025
2026 void AnalyzepBlock(pBlock *pb)
2027 {
2028   pCode *pc;
2029
2030   if(!pb)
2031     return;
2032
2033   /* Find all of the registers used in this pBlock */
2034   for(pc = pb->pcHead; pc; pc = pc->next) {
2035     if(pc->type == PC_OPCODE) {
2036       if(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_TEMP) {
2037
2038         /* Loop through all of the registers declared so far in
2039            this block and see if we find this new there */
2040
2041         regs *r = setFirstItem(pb->registers);
2042
2043         while(r) {
2044           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
2045             PCOR(PCI(pc)->pcop)->r = r;
2046             break;
2047           }
2048           r = setNextItem(pb->registers);
2049         }
2050
2051         if(!r) {
2052           /* register wasn't found */
2053           r = Safe_calloc(1, sizeof(regs));
2054           memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
2055           addSet(&pb->registers, r);
2056           PCOR(PCI(pc)->pcop)->r = r;
2057           fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
2058         } else 
2059           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
2060       }
2061     }
2062   }
2063 }
2064
2065 int OptimizepBlock(pBlock *pb)
2066 {
2067   pCode *pc;
2068   int matches =0;
2069
2070   if(!pb || !peepOptimizing)
2071     return 0;
2072
2073   fprintf(stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb));
2074   for(pc = pb->pcHead; pc; pc = pc->next)
2075     matches += pCodePeepMatchRule(pc);
2076
2077   return matches;
2078
2079 }
2080
2081 /*-----------------------------------------------------------------*/
2082 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2083 /*-----------------------------------------------------------------*/
2084 pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
2085 {
2086   pCode *pc;
2087
2088   for(pc = pcs; pc; pc = pc->next) {
2089
2090     if((pc->type == PC_OPCODE) && 
2091        (PCI(pc)->pcop) && 
2092        (PCI(pc)->pcop->type == PO_LABEL) &&
2093        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
2094       return pc;
2095   }
2096  
2097
2098   return NULL;
2099 }
2100
2101 /*-----------------------------------------------------------------*/
2102 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2103 /*                            pCode chain if they're not used.     */
2104 /*-----------------------------------------------------------------*/
2105 void pBlockRemoveUnusedLabels(pBlock *pb)
2106 {
2107   pCode *pc; pCodeLabel *pcl;
2108
2109   if(!pb)
2110     return;
2111
2112   for(pc = pb->pcHead; pc; pc = pc->next) {
2113
2114     if(pc->type == PC_LABEL)
2115       pcl = PCL(pc);
2116     else if (pc->label)
2117       pcl = PCL(pc->label->pc);
2118     else continue;
2119
2120       /* This pCode is a label, so search the pBlock to see if anyone
2121        * refers to it */
2122
2123     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))) {
2124       /* Couldn't find an instruction that refers to this label
2125        * So, unlink the pCode label from it's pCode chain
2126        * and destroy the label */
2127
2128       fprintf(stderr," !!! REMOVED A LABEL !!! key = %d\n", pcl->key);
2129
2130       if(pc->type == PC_LABEL) {
2131         //unlinkPC(pc);
2132         pCodeLabelDestruct(pc);
2133       } else {
2134         unlinkpCodeFromBranch(pc->label, pc);
2135         if(pc->label->next == NULL && pc->label->pc == NULL) {
2136           free(pc->label);
2137         }
2138       }
2139
2140     }
2141   }
2142
2143 }
2144
2145
2146 /*-----------------------------------------------------------------*/
2147 /* pBlockMergeLabels - remove the pCode labels from the pCode      */
2148 /*                     chain and put them into pBranches that are  */
2149 /*                     associated with the appropriate pCode       */
2150 /*                     instructions.                               */
2151 /*-----------------------------------------------------------------*/
2152 void pBlockMergeLabels(pBlock *pb)
2153 {
2154   pBranch *pbr;
2155   pCode *pc, *pcnext=NULL;
2156
2157   if(!pb)
2158     return;
2159
2160   /* First, Try to remove any unused labels */
2161   //pBlockRemoveUnusedLabels(pb);
2162
2163   /* Now loop through the pBlock and merge the labels with the opcodes */
2164
2165   for(pc = pb->pcHead; pc; pc = pc->next) {
2166
2167     if(pc->type == PC_LABEL) {
2168       fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
2169       if( !(pcnext = findNextInstruction(pc)) ) 
2170         return;  // Couldn't find an instruction associated with this label
2171
2172       // Unlink the pCode label from it's pCode chain
2173       unlinkPC(pc);
2174
2175       fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
2176       // And link it into the instruction's pBranch labels. (Note, since
2177       // it's possible to have multiple labels associated with one instruction
2178       // we must provide a means to accomodate the additional labels. Thus
2179       // the labels are placed into the singly-linked list "label" as 
2180       // opposed to being a single member of the pCodeInstruction.)
2181
2182       _ALLOC(pbr,sizeof(pBranch));
2183       pbr->pc = pc;
2184       pbr->next = NULL;
2185
2186       pcnext->label = pBranchAppend(pcnext->label,pbr);
2187       if(pcnext->prev) 
2188         pc = pcnext->prev;
2189       else
2190         pc = pcnext;
2191     }
2192
2193   }
2194   pBlockRemoveUnusedLabels(pb);
2195
2196 }
2197
2198 /*-----------------------------------------------------------------*/
2199 /*-----------------------------------------------------------------*/
2200 void OptimizepCode(char dbName)
2201 {
2202 #define MAX_PASSES 4
2203
2204   int matches = 0;
2205   int passes = 0;
2206   pBlock *pb;
2207
2208   if(!the_pFile)
2209     return;
2210
2211   fprintf(stderr," Optimizing pCode\n");
2212
2213   do {
2214     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2215       if('*' == dbName || getpBlock_dbName(pb) == dbName)
2216         matches += OptimizepBlock(pb);
2217     }
2218   }
2219   while(matches && ++passes < MAX_PASSES);
2220
2221 }
2222
2223 /*-----------------------------------------------------------------*/
2224 /* AnalyzepCode - parse the pCode that has been generated and form */
2225 /*                all of the logical connections.                  */
2226 /*                                                                 */
2227 /* Essentially what's done here is that the pCode flow is          */
2228 /* determined.                                                     */
2229 /*-----------------------------------------------------------------*/
2230
2231 void AnalyzepCode(char dbName)
2232 {
2233   pBlock *pb;
2234   pCode *pc;
2235   pBranch *pbr;
2236
2237   if(!the_pFile)
2238     return;
2239
2240   fprintf(stderr," Analyzing pCode");
2241
2242   /* First, merge the labels with the instructions */
2243   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2244     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2245
2246       fprintf(stderr," analyze and merging block %c\n",dbName);
2247       pBlockMergeLabels(pb);
2248       AnalyzepBlock(pb);
2249     }
2250   }
2251
2252   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2253     if('*' == dbName || getpBlock_dbName(pb) == dbName)
2254       OptimizepBlock(pb);
2255   }
2256
2257   /* Now build the call tree.
2258      First we examine all of the pCodes for functions.
2259      Keep in mind that the function boundaries coincide
2260      with pBlock boundaries. 
2261
2262      The algorithm goes something like this:
2263      We have two nested loops. The outer loop iterates
2264      through all of the pBlocks/functions. The inner
2265      loop iterates through all of the pCodes for
2266      a given pBlock. When we begin iterating through
2267      a pBlock, the variable pc_fstart, pCode of the start
2268      of a function, is cleared. We then search for pCodes
2269      of type PC_FUNCTION. When one is encountered, we
2270      initialize pc_fstart to this and at the same time
2271      associate a new pBranch object that signifies a 
2272      branch entry. If a return is found, then this signifies
2273      a function exit point. We'll link the pCodes of these
2274      returns to the matching pc_fstart.
2275
2276      When we're done, a doubly linked list of pBranches
2277      will exist. The head of this list is stored in
2278      `the_pFile', which is the meta structure for all
2279      of the pCode. Look at the printCallTree function
2280      on how the pBranches are linked together.
2281
2282    */
2283   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2284     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2285       pCode *pc_fstart=NULL;
2286       for(pc = pb->pcHead; pc; pc = pc->next) {
2287         if(pc->type == PC_FUNCTION) {
2288           if (PCF(pc)->fname) {
2289             // I'm not liking this....
2290             // Found the beginning of a function.
2291             _ALLOC(pbr,sizeof(pBranch));
2292             pbr->pc = pc_fstart = pc;
2293             pbr->next = NULL;
2294
2295             the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
2296
2297             // Here's a better way of doing the same:
2298             addSet(&pb->function_entries, pc);
2299
2300           } else {
2301             // Found an exit point in a function, e.g. return
2302             // (Note, there may be more than one return per function)
2303             if(pc_fstart)
2304               pBranchLink(pc_fstart, pc);
2305
2306             addSet(&pb->function_exits, pc);
2307           }
2308         } else  if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2309           addSet(&pb->function_calls,pc);
2310         }
2311       }
2312     }
2313   }
2314 }
2315
2316 /*-----------------------------------------------------------------*/
2317 /* ispCodeFunction - returns true if *pc is the pCode of a         */
2318 /*                   function                                      */
2319 /*-----------------------------------------------------------------*/
2320 bool ispCodeFunction(pCode *pc)
2321 {
2322
2323   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
2324     return 1;
2325
2326   return 0;
2327 }
2328
2329 /*-----------------------------------------------------------------*/
2330 /* findFunction - Search for a function by name (given the name)   */
2331 /*                in the set of all functions that are in a pBlock */
2332 /* (note - I expect this to change because I'm planning to limit   */
2333 /*  pBlock's to just one function declaration                      */
2334 /*-----------------------------------------------------------------*/
2335 pCode *findFunction(char *fname)
2336 {
2337   pBlock *pb;
2338   pCode *pc;
2339   if(!fname)
2340     return NULL;
2341
2342   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2343
2344     pc = setFirstItem(pb->function_entries);
2345     while(pc) {
2346     
2347       if((pc->type == PC_FUNCTION) &&
2348          (PCF(pc)->fname) && 
2349          (strcmp(fname, PCF(pc)->fname)==0))
2350         return pc;
2351
2352       pc = setNextItem(pb->function_entries);
2353
2354     }
2355
2356   }
2357   return NULL;
2358 }
2359
2360 void MarkUsedRegisters(set *regset)
2361 {
2362
2363   regs *r1,*r2;
2364
2365   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
2366     r2 = pic14_regWithIdx(r1->rIdx);
2367     r2->isFree = 0;
2368     r2->wasUsed = 1;
2369   }
2370 }
2371
2372 void pBlockStats(FILE *of, pBlock *pb)
2373 {
2374
2375   pCode *pc;
2376   regs  *r;
2377
2378   fprintf(of,"***\n  pBlock Stats\n***\n");
2379
2380   // for now just print the first element of each set
2381   pc = setFirstItem(pb->function_entries);
2382   if(pc) {
2383     fprintf(of,"entry\n");
2384     pc->print(of,pc);
2385   }
2386   pc = setFirstItem(pb->function_exits);
2387   if(pc) {
2388     fprintf(of,"has an exit\n");
2389     pc->print(of,pc);
2390   }
2391
2392   pc = setFirstItem(pb->function_calls);
2393   if(pc) {
2394     fprintf(of,"functions called\n");
2395
2396     while(pc) {
2397       pc->print(of,pc);
2398       pc = setNextItem(pb->function_calls);
2399     }
2400   }
2401
2402   r = setFirstItem(pb->registers);
2403   if(r) {
2404     int n = elementsInSet(pb->registers);
2405
2406     fprintf(of,"%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
2407
2408     while (r) {
2409       fprintf(of,"   %s\n",r->name);
2410       r = setNextItem(pb->registers);
2411     }
2412   }
2413 }
2414
2415 /*-----------------------------------------------------------------*/
2416 /*-----------------------------------------------------------------*/
2417 void sequencepCode(void)
2418 {
2419   pBlock *pb;
2420   pCode *pc;
2421
2422
2423   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2424
2425     pb->seq = GpCodeSequenceNumber+1;
2426
2427     for( pc = pb->pcHead; pc; pc = pc->next)
2428       pc->seq = ++GpCodeSequenceNumber;
2429   }
2430
2431 }
2432
2433 /*-----------------------------------------------------------------*/
2434 /*-----------------------------------------------------------------*/
2435 set *register_usage(pBlock *pb)
2436 {
2437   pCode *pc,*pcn;
2438   set *registers=NULL;
2439   set *registersInCallPath = NULL;
2440
2441   /* check recursion */
2442
2443   pc = setFirstItem(pb->function_entries);
2444
2445   if(!pc)
2446     return registers;
2447
2448   pb->visited = 1;
2449
2450   if(pc->type != PC_FUNCTION)
2451     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
2452
2453   pc = setFirstItem(pb->function_calls);
2454   for( ; pc; pc = setNextItem(pb->function_calls)) {
2455
2456     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2457       char *dest = get_op(PCI(pc));
2458
2459       pcn = findFunction(dest);
2460       if(pcn) 
2461         registersInCallPath = register_usage(pcn->pb);
2462     } else
2463       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2464
2465   }
2466
2467
2468   pBlockStats(stderr,pb);  // debug
2469   if(registersInCallPath) {
2470     /* registers were used in the functions this pBlock has called */
2471     /* so now, we need to see if these collide with the ones we are */
2472     /* using here */
2473
2474     regs *r1,*r2, *newreg;
2475
2476     fprintf(stderr,"comparing registers\n");
2477
2478     r1 = setFirstItem(registersInCallPath);
2479     while(r1) {
2480
2481       r2 = setFirstItem(pb->registers);
2482
2483       while(r2) {
2484
2485         if(r2->rIdx == r1->rIdx) {
2486           newreg = pic14_findFreeReg();
2487
2488
2489           if(!newreg) {
2490             fprintf(stderr,"Bummer, no more registers.\n");
2491             exit(1);
2492           }
2493
2494           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2495                   r1->rIdx, newreg->rIdx);
2496           r2->rIdx = newreg->rIdx;
2497           //if(r2->name) free(r2->name);
2498           if(newreg->name)
2499             r2->name = Safe_strdup(newreg->name);
2500           else
2501             r2->name = NULL;
2502           newreg->isFree = 0;
2503           newreg->wasUsed = 1;
2504         }
2505         r2 = setNextItem(pb->registers);
2506       }
2507
2508       r1 = setNextItem(registersInCallPath);
2509     }
2510
2511     /* Collisions have been resolved. Now free the registers in the call path */
2512     r1 = setFirstItem(registersInCallPath);
2513     while(r1) {
2514       newreg = pic14_regWithIdx(r1->rIdx);
2515       newreg->isFree = 1;
2516       r1 = setNextItem(registersInCallPath);
2517     }
2518
2519   } else
2520     MarkUsedRegisters(pb->registers);
2521
2522   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2523
2524   if(registers) 
2525     fprintf(stderr,"returning regs\n");
2526   else
2527     fprintf(stderr,"not returning regs\n");
2528
2529   fprintf(stderr,"pBlock after register optim.\n");
2530   pBlockStats(stderr,pb);  // debug
2531
2532
2533   return registers;
2534 }
2535
2536 /*-----------------------------------------------------------------*/
2537 /* printCallTree - writes the call tree to a file                  */
2538 /*                                                                 */
2539 /*-----------------------------------------------------------------*/
2540 void pct2(FILE *of,pBlock *pb,int indent)
2541 {
2542   pCode *pc,*pcn;
2543   int i;
2544   //  set *registersInCallPath = NULL;
2545
2546   if(!of)
2547     return;// registers;
2548
2549   if(indent > 10)
2550     return; // registers;   //recursion ?
2551
2552   pc = setFirstItem(pb->function_entries);
2553
2554   if(!pc)
2555     return;
2556
2557   pb->visited = 0;
2558
2559   for(i=0;i<indent;i++)   // Indentation
2560     fputc(' ',of);
2561
2562   if(pc->type == PC_FUNCTION)
2563     fprintf(of,"%s\n",PCF(pc)->fname);
2564   else
2565     return;  // ???
2566
2567
2568   pc = setFirstItem(pb->function_calls);
2569   for( ; pc; pc = setNextItem(pb->function_calls)) {
2570
2571     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2572       char *dest = get_op(PCI(pc));
2573
2574       pcn = findFunction(dest);
2575       if(pcn) 
2576         pct2(of,pcn->pb,indent+1);
2577     } else
2578       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2579
2580   }
2581
2582
2583 }
2584
2585 #if 0
2586   fprintf(stderr,"pBlock before register optim.\n");
2587   pBlockStats(stderr,pb);  // debug
2588
2589   if(registersInCallPath) {
2590     /* registers were used in the functions this pBlock has called */
2591     /* so now, we need to see if these collide with the ones we are using here */
2592
2593     regs *r1,*r2, *newreg;
2594
2595     fprintf(stderr,"comparing registers\n");
2596
2597     r1 = setFirstItem(registersInCallPath);
2598     while(r1) {
2599
2600       r2 = setFirstItem(pb->registers);
2601
2602       while(r2) {
2603
2604         if(r2->rIdx == r1->rIdx) {
2605           newreg = pic14_findFreeReg();
2606
2607
2608           if(!newreg) {
2609             fprintf(stderr,"Bummer, no more registers.\n");
2610             exit(1);
2611           }
2612
2613           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2614                   r1->rIdx, newreg->rIdx);
2615           r2->rIdx = newreg->rIdx;
2616           //if(r2->name) free(r2->name);
2617           if(newreg->name)
2618             r2->name = Safe_strdup(newreg->name);
2619           else
2620             r2->name = NULL;
2621           newreg->isFree = 0;
2622           newreg->wasUsed = 1;
2623         }
2624         r2 = setNextItem(pb->registers);
2625       }
2626
2627       r1 = setNextItem(registersInCallPath);
2628     }
2629
2630     /* Collisions have been resolved. Now free the registers in the call path */
2631     r1 = setFirstItem(registersInCallPath);
2632     while(r1) {
2633       newreg = pic14_regWithIdx(r1->rIdx);
2634       newreg->isFree = 1;
2635       r1 = setNextItem(registersInCallPath);
2636     }
2637
2638   } else
2639     MarkUsedRegisters(pb->registers);
2640
2641   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2642
2643   if(registers) 
2644     fprintf(stderr,"returning regs\n");
2645   else
2646     fprintf(stderr,"not returning regs\n");
2647
2648   fprintf(stderr,"pBlock after register optim.\n");
2649   pBlockStats(stderr,pb);  // debug
2650
2651
2652   return registers;
2653
2654 #endif
2655
2656
2657 /*-----------------------------------------------------------------*/
2658 /* printCallTree - writes the call tree to a file                  */
2659 /*                                                                 */
2660 /*-----------------------------------------------------------------*/
2661
2662 void printCallTree(FILE *of)
2663 {
2664   pBranch *pbr;
2665   pBlock  *pb;
2666   pCode   *pc;
2667
2668   if(!the_pFile)
2669     return;
2670
2671   if(!of)
2672     of = stderr;
2673
2674   fprintf(of, "\npBlock statistics\n");
2675   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
2676     pBlockStats(stderr,pb);
2677
2678
2679
2680   fprintf(of,"Call Tree\n");
2681   pbr = the_pFile->functions;
2682   while(pbr) {
2683     if(pbr->pc) {
2684       pc = pbr->pc;
2685       if(!ispCodeFunction(pc))
2686         fprintf(of,"bug in call tree");
2687
2688
2689       fprintf(of,"Function: %s\n", PCF(pc)->fname);
2690
2691       while(pc->next && !ispCodeFunction(pc->next)) {
2692         pc = pc->next;
2693         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
2694           fprintf(of,"\t%s\n",get_op(PCI(pc)));
2695       }
2696     }
2697
2698     pbr = pbr->next;
2699   }
2700
2701
2702   /* Re-allocate the registers so that there are no collisions
2703    * between local variables when one function call another */
2704
2705   pic14_deallocateAllRegs();
2706
2707   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2708     if(!pb->visited)
2709       register_usage(pb);
2710   }
2711
2712   fprintf(of,"\n**************\n\na better call tree\n");
2713   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2714     if(pb->visited)
2715       pct2(of,pb,0);
2716   }
2717
2718   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2719     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
2720   }
2721 }