* src/SDCCpeeph.c (peepHole): Fixed all leaks. Added trace support for freeing...
[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   pcc->comment = Safe_strdup(cP);
1134
1135   return ( (pCode *)pcc);
1136
1137 }
1138
1139 /*-----------------------------------------------------------------*/
1140 /* newpCodeGLabel - create a new global label                      */
1141 /*-----------------------------------------------------------------*/
1142
1143
1144 pCode *newpCodeFunction(char *mod,char *f)
1145 {
1146   pCodeFunction *pcf;
1147
1148   _ALLOC(pcf,sizeof(pCodeFunction));
1149
1150   pcf->pc.type = PC_FUNCTION;
1151   pcf->pc.prev = pcf->pc.next = NULL;
1152   pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
1153   pcf->pc.pb = NULL;
1154
1155   pcf->pc.analyze = genericAnalyze;
1156   pcf->pc.destruct = genericDestruct;
1157   pcf->pc.print = pCodePrintFunction;
1158
1159   if(mod) {
1160     _ALLOC_ATOMIC(pcf->modname,strlen(mod)+1);
1161     strcpy(pcf->modname,mod);
1162   } else
1163     pcf->modname = NULL;
1164
1165   if(f) {
1166     _ALLOC_ATOMIC(pcf->fname,strlen(f)+1);
1167     strcpy(pcf->fname,f);
1168   } else
1169     pcf->fname = NULL;
1170
1171   return ( (pCode *)pcf);
1172
1173 }
1174
1175 static void pCodeLabelDestruct(pCode *pc)
1176 {
1177
1178   if(!pc)
1179     return;
1180
1181   unlinkPC(pc);
1182
1183   if((pc->type == PC_LABEL) && PCL(pc)->label)
1184     free(PCL(pc)->label);
1185
1186   free(pc);
1187
1188 }
1189
1190 pCode *newpCodeLabel(int key)
1191 {
1192
1193   char *s = buffer;
1194   pCodeLabel *pcl;
1195     
1196   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
1197
1198   pcl->pc.type = PC_LABEL;
1199   pcl->pc.prev = pcl->pc.next = NULL;
1200   pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
1201   pcl->pc.pb = NULL;
1202
1203   pcl->pc.analyze = genericAnalyze;
1204   pcl->pc.destruct = pCodeLabelDestruct;
1205   pcl->pc.print = pCodePrintLabel;
1206
1207   pcl->key = key;
1208
1209   if(key>0) {
1210     sprintf(s,"_%05d_DS_",key);
1211     pcl->label = Safe_strdup(s);
1212   } else
1213     pcl->label = NULL;
1214
1215   return ( (pCode *)pcl);
1216
1217 }
1218 pCode *newpCodeLabelStr(char *str)
1219 {
1220   pCode *pc = newpCodeLabel(-1);
1221
1222   PCL(pc)->label = Safe_strdup(str);
1223
1224   return pc;
1225 }
1226
1227 /*-----------------------------------------------------------------*/
1228 /* newpBlock - create and return a pointer to a new pBlock         */
1229 /*-----------------------------------------------------------------*/
1230 pBlock *newpBlock(void)
1231 {
1232
1233   pBlock *PpB;
1234
1235   PpB = Safe_calloc(1,sizeof(pBlock) );
1236   PpB->next = PpB->prev = NULL;
1237
1238   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
1239   PpB->registers = NULL;
1240   PpB->visited = 0;
1241
1242   return PpB;
1243
1244 }
1245
1246 /*-----------------------------------------------------------------*/
1247 /* newpCodeChai0n - create a new chain of pCodes                    */
1248 /*-----------------------------------------------------------------*
1249  *
1250  *  This function will create a new pBlock and the pointer to the
1251  *  pCode that is passed in will be the first pCode in the block.
1252  *-----------------------------------------------------------------*/
1253
1254
1255 pBlock *newpCodeChain(memmap *cm,char c, pCode *pc)
1256 {
1257
1258   pBlock *pB  = newpBlock();
1259
1260   pB->pcHead  = pB->pcTail = pc;
1261   pB->cmemmap = cm;
1262   pB->dbName  = c;
1263
1264   return pB;
1265 }
1266
1267 /*-----------------------------------------------------------------*/
1268 /* newpCodeOpLabel - Create a new label given the key              */
1269 /*  Note, a negative key means that the label is part of wild card */
1270 /*  (and hence a wild card label) used in the pCodePeep            */
1271 /*   optimizations).                                               */
1272 /*-----------------------------------------------------------------*/
1273
1274 pCodeOp *newpCodeOpLabel(int key)
1275 {
1276   char *s = buffer;
1277   pCodeOp *pcop;
1278
1279   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
1280   pcop->type = PO_LABEL;
1281
1282   if(key>0) {
1283     sprintf(s,"_%05d_DS_",key);
1284     pcop->name = Safe_strdup(s);
1285   } else
1286     pcop->name = NULL;
1287
1288   ((pCodeOpLabel *)pcop)->key = key;
1289
1290   return pcop;
1291 }
1292
1293 pCodeOp *newpCodeOpLit(int lit)
1294 {
1295   char *s = buffer;
1296   pCodeOp *pcop;
1297
1298
1299   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
1300   pcop->type = PO_LITERAL;
1301   if(lit>=0) {
1302     sprintf(s,"0x%02x",lit);
1303     pcop->name = Safe_strdup(s);
1304   } else
1305     pcop->name = NULL;
1306
1307   ((pCodeOpLit *)pcop)->lit = lit;
1308
1309   return pcop;
1310 }
1311
1312 pCodeOp *newpCodeOpWild(int id, pCodePeep *pcp, pCodeOp *subtype)
1313 {
1314   char *s = buffer;
1315   pCodeOp *pcop;
1316
1317
1318   if(!pcp || !subtype) {
1319     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
1320     exit(1);
1321   }
1322
1323   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
1324   pcop->type = PO_WILD;
1325   sprintf(s,"%%%d",id);
1326   pcop->name = Safe_strdup(s);
1327
1328   PCOW(pcop)->id = id;
1329   PCOW(pcop)->pcp = pcp;
1330   PCOW(pcop)->subtype = subtype;
1331   PCOW(pcop)->matched = NULL;
1332
1333   return pcop;
1334 }
1335
1336 pCodeOp *newpCodeOpBit(char *s, int bit, int inBitSpace)
1337 {
1338   pCodeOp *pcop;
1339
1340   pcop = Safe_calloc(1,sizeof(pCodeOpBit) );
1341   pcop->type = PO_BIT;
1342   pcop->name = Safe_strdup(s);   
1343
1344   PCOB(pcop)->bit = bit;
1345   PCOB(pcop)->inBitSpace = inBitSpace;
1346
1347   return pcop;
1348 }
1349
1350 pCodeOp *newpCodeOpReg(int rIdx)
1351 {
1352   pCodeOp *pcop;
1353
1354   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
1355
1356   PCOR(pcop)->rIdx = rIdx;
1357   PCOR(pcop)->r = pic14_regWithIdx(rIdx);
1358   pcop->type = PCOR(pcop)->r->pc_type;
1359
1360   return pcop;
1361 }
1362
1363 /*-----------------------------------------------------------------*/
1364 /*-----------------------------------------------------------------*/
1365
1366 pCodeOp *newpCodeOp(char *name, PIC_OPTYPE type)
1367 {
1368   pCodeOp *pcop;
1369
1370   switch(type) {
1371   case PO_BIT:
1372     pcop = newpCodeOpBit(name, -1,0);
1373     break;
1374
1375   case PO_LITERAL:
1376     pcop = newpCodeOpLit(-1);
1377     break;
1378
1379   case PO_LABEL:
1380     pcop = newpCodeOpLabel(-1);
1381     break;
1382
1383   default:
1384     pcop = Safe_calloc(1,sizeof(pCodeOp) );
1385     pcop->type = type;
1386     pcop->name = Safe_strdup(name);   
1387   }
1388
1389   return pcop;
1390 }
1391
1392 /*-----------------------------------------------------------------*/
1393 /* addpCode2pBlock - place the pCode into the pBlock linked list   */
1394 /*-----------------------------------------------------------------*/
1395 void addpCode2pBlock(pBlock *pb, pCode *pc)
1396 {
1397   if(!pb->pcHead) {
1398     /* If this is the first pcode to be added to a block that
1399      * was initialized with a NULL pcode, then go ahead and
1400      * make this pcode the head and tail */
1401     pb->pcHead  = pb->pcTail = pc;
1402   } else {
1403     pb->pcTail->next = pc;
1404     pc->prev = pb->pcTail;
1405     pc->next = NULL;
1406     pc->pb = pb;
1407     pb->pcTail = pc;
1408   }
1409 }
1410
1411 /*-----------------------------------------------------------------*/
1412 /* addpBlock - place a pBlock into the pFile                       */
1413 /*-----------------------------------------------------------------*/
1414 void addpBlock(pBlock *pb)
1415 {
1416
1417   if(!the_pFile) {
1418     /* First time called, we'll pass through here. */
1419     _ALLOC(the_pFile,sizeof(the_pFile));
1420     the_pFile->pbHead = the_pFile->pbTail = pb;
1421     the_pFile->functions = NULL;
1422     return;
1423   }
1424
1425   the_pFile->pbTail->next = pb;
1426   pb->prev = the_pFile->pbTail;
1427   pb->next = NULL;
1428   the_pFile->pbTail = pb;
1429 }
1430
1431 /*-----------------------------------------------------------------*/
1432 /* printpCode - write the contents of a pCode to a file            */
1433 /*-----------------------------------------------------------------*/
1434 void printpCode(FILE *of, pCode *pc)
1435 {
1436
1437   if(!pc || !of)
1438     return;
1439
1440   if(pc->print) {
1441     pc->print(of,pc);
1442     return;
1443   }
1444
1445   fprintf(of,"warning - unable to print pCode\n");
1446 }
1447
1448 /*-----------------------------------------------------------------*/
1449 /* printpBlock - write the contents of a pBlock to a file          */
1450 /*-----------------------------------------------------------------*/
1451 void printpBlock(FILE *of, pBlock *pb)
1452 {
1453   pCode *pc;
1454
1455   if(!pb)
1456     return;
1457
1458   if(!of)
1459     of = stderr;
1460
1461   for(pc = pb->pcHead; pc; pc = pc->next)
1462     printpCode(of,pc);
1463
1464 }
1465
1466 /*-----------------------------------------------------------------*/
1467 /*                                                                 */
1468 /*       pCode processing                                          */
1469 /*                                                                 */
1470 /*                                                                 */
1471 /*                                                                 */
1472 /*-----------------------------------------------------------------*/
1473
1474 static void unlinkPC(pCode *pc)
1475 {
1476
1477
1478   if(pc) {
1479
1480     if(pc->prev) 
1481       pc->prev->next = pc->next;
1482     if(pc->next)
1483       pc->next->prev = pc->prev;
1484
1485     pc->prev = pc->next = NULL;
1486   }
1487 }
1488 static void genericDestruct(pCode *pc)
1489 {
1490   fprintf(stderr,"warning, calling default pCode destructor\n");
1491
1492   unlinkPC(pc);
1493
1494   free(pc);
1495
1496 }
1497
1498
1499 void pBlockRegs(FILE *of, pBlock *pb)
1500 {
1501
1502   regs  *r;
1503
1504   r = setFirstItem(pb->registers);
1505   while (r) {
1506     r = setNextItem(pb->registers);
1507   }
1508 }
1509
1510
1511 static char *get_op( pCodeInstruction *pcc)
1512 {
1513   regs *r;
1514
1515   if(pcc && pcc->pcop) {
1516
1517
1518     switch(pcc->pcop->type) {
1519
1520     case PO_FSR:
1521     case PO_GPR_TEMP:
1522     case PO_GPR_BIT:
1523       r = pic14_regWithIdx(PCOR(pcc->pcop)->r->rIdx);
1524       //fprintf(stderr,"getop: getting %s\nfrom:\n",r->name); //pcc->pcop->name);
1525       pBlockRegs(stderr,pcc->pc.pb);
1526       return r->name;
1527
1528     default:
1529       if  (pcc->pcop->name)
1530         return pcc->pcop->name;
1531
1532     }
1533   }
1534
1535   return "NO operand";
1536 }
1537
1538 /*-----------------------------------------------------------------*/
1539 /*-----------------------------------------------------------------*/
1540 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
1541 {
1542
1543   fprintf(of,"pcodeopprint\n");
1544 }
1545
1546 char *pCode2str(char *str, int size, pCode *pc)
1547 {
1548   char *s = str;
1549
1550   switch(pc->type) {
1551
1552   case PC_OPCODE:
1553
1554     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
1555
1556     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
1557
1558       if(PCI(pc)->bit_inst) {
1559         if(PCI(pc)->pcop->type == PO_BIT) {
1560           if( (((pCodeOpBit *)(PCI(pc)->pcop))->inBitSpace) )
1561             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
1562                           PCI(pc)->pcop->name ,
1563                           PCI(pc)->pcop->name );
1564           else
1565             SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)), 
1566                           (((pCodeOpBit *)(PCI(pc)->pcop))->bit ));
1567         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
1568           SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
1569         }else
1570           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", get_op(PCI(pc)));
1571         //PCI(pc)->pcop->t.bit );
1572       } else {
1573
1574         if(PCI(pc)->pcop->type == PO_BIT) {
1575           if( PCI(pc)->num_ops == 2)
1576             SAFE_snprintf(&s,&size,"(%s >> 3),%c",get_op(PCI(pc)),((PCI(pc)->dest) ? 'F':'W'));
1577           else
1578             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",get_op(PCI(pc)));
1579
1580         }else {
1581           SAFE_snprintf(&s,&size,"%s",get_op(PCI(pc)));
1582
1583           if( PCI(pc)->num_ops == 2)
1584             SAFE_snprintf(&s,&size,",%c", ( (PCI(pc)->dest) ? 'F':'W'));
1585         }
1586       }
1587
1588     }
1589     break;
1590
1591   case PC_COMMENT:
1592     /* assuming that comment ends with a \n */
1593     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
1594     break;
1595
1596   case PC_LABEL:
1597     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
1598     break;
1599   case PC_FUNCTION:
1600     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
1601     break;
1602   case PC_WILD:
1603     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
1604     break;
1605
1606   }
1607
1608   return str;
1609
1610 }
1611
1612 /*-----------------------------------------------------------------*/
1613 /* genericPrint - the contents of a pCode to a file                */
1614 /*-----------------------------------------------------------------*/
1615 static void genericPrint(FILE *of, pCode *pc)
1616 {
1617
1618   if(!pc || !of)
1619     return;
1620
1621   switch(pc->type) {
1622   case PC_COMMENT:
1623     fprintf(of,";%s\n", ((pCodeComment *)pc)->comment);
1624     break;
1625
1626   case PC_OPCODE:
1627     // If the opcode has a label, print that first
1628     {
1629       pBranch *pbl = pc->label;
1630       while(pbl) {
1631         if(pbl->pc->type == PC_LABEL)
1632           pCodePrintLabel(of, pbl->pc);
1633         pbl = pbl->next;
1634       }
1635     }
1636
1637
1638     {
1639       char str[256];
1640       
1641       pCode2str(str, 256, pc);
1642
1643       fprintf(of,"%s",str);
1644     }
1645
1646     {
1647       pBranch *dpb = pc->to;   // debug
1648       while(dpb) {
1649         switch ( dpb->pc->type) {
1650         case PC_OPCODE:
1651           fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic);
1652           break;
1653         case PC_LABEL:
1654           fprintf(of, "\t;label %d", PCL(dpb->pc)->key);
1655           break;
1656         case PC_FUNCTION:
1657           fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]"));
1658           break;
1659         case PC_COMMENT:
1660         case PC_WILD:
1661           break;
1662         }
1663         dpb = dpb->next;
1664       }
1665       fprintf(of,"\n");
1666     }
1667
1668     break;
1669
1670   case PC_WILD:
1671     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
1672     if(pc->label)
1673       pCodePrintLabel(of, pc->label->pc);
1674
1675     if(PCW(pc)->operand) {
1676       fprintf(of,";\toperand  ");
1677       pCodeOpPrint(of,PCW(pc)->operand );
1678     }
1679     break;
1680
1681   case PC_LABEL:
1682   default:
1683     fprintf(of,"unknown pCode type %d\n",pc->type);
1684   }
1685
1686 }
1687
1688 /*-----------------------------------------------------------------*/
1689 /* pCodePrintFunction - prints function begin/end                  */
1690 /*-----------------------------------------------------------------*/
1691
1692 static void pCodePrintFunction(FILE *of, pCode *pc)
1693 {
1694
1695   if(!pc || !of)
1696     return;
1697
1698   if( ((pCodeFunction *)pc)->modname) 
1699     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
1700
1701   if(PCF(pc)->fname) {
1702     pBranch *exits = pc->to;
1703     int i=0;
1704     fprintf(of,"%s\t;Function start\n",PCF(pc)->fname);
1705     while(exits) {
1706       i++;
1707       exits = exits->next;
1708     }
1709     //if(i) i--;
1710     fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
1711     
1712   }else {
1713     if(pc->from && 
1714        pc->from->pc->type == PC_FUNCTION &&
1715        PCF(pc->from->pc)->fname) 
1716       fprintf(of,"; exit point of %s\n",PCF(pc->from->pc)->fname);
1717     else
1718       fprintf(of,"; exit point [can't find entry point]\n");
1719   }
1720 }
1721 /*-----------------------------------------------------------------*/
1722 /* pCodePrintLabel - prints label                                  */
1723 /*-----------------------------------------------------------------*/
1724
1725 static void pCodePrintLabel(FILE *of, pCode *pc)
1726 {
1727
1728   if(!pc || !of)
1729     return;
1730
1731   if(PCL(pc)->label) 
1732     fprintf(of,"%s\n",PCL(pc)->label);
1733   else if (PCL(pc)->key >=0) 
1734     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
1735   else
1736     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
1737
1738 }
1739 /*-----------------------------------------------------------------*/
1740 static void  unlinkpCodeFromBranch(pBranch *pb , pCode *pc)
1741 {
1742   pBranch *b, *bprev;
1743
1744   bprev = NULL;
1745   b = pb;
1746   while(b) {
1747     if(b->pc == pc) {
1748       if(bprev)
1749         bprev->next = b->next;
1750     }
1751     bprev = b;
1752     b = b->next;
1753   }
1754
1755 }
1756
1757 static pBranch * pBranchAppend(pBranch *h, pBranch *n)
1758 {
1759   pBranch *b;
1760
1761   if(!h)
1762     return n;
1763
1764   b = h;
1765   while(b->next)
1766     b = b->next;
1767
1768   b->next = n;
1769
1770   return h;
1771   
1772 }  
1773 /*-----------------------------------------------------------------*/
1774 /* pBranchLink - given two pcodes, this function will link them    */
1775 /*               together through their pBranches                  */
1776 /*-----------------------------------------------------------------*/
1777 static void pBranchLink(pCode *f, pCode *t)
1778 {
1779   pBranch *b;
1780
1781   // Declare a new branch object for the 'from' pCode.
1782
1783   _ALLOC(b,sizeof(pBranch));
1784   b->pc = t;                    // The link to the 'to' pCode.
1785   b->next = NULL;
1786
1787   f->to = pBranchAppend(f->to,b);
1788
1789   // Now do the same for the 'to' pCode.
1790
1791   _ALLOC(b,sizeof(pBranch));
1792   b->pc = f;
1793   b->next = NULL;
1794
1795   t->from = pBranchAppend(t->from,b);
1796   
1797 }
1798
1799 #if 0
1800 /*-----------------------------------------------------------------*/
1801 /* pBranchFind - find the pBranch in a pBranch chain that contains */
1802 /*               a pCode                                           */
1803 /*-----------------------------------------------------------------*/
1804 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
1805 {
1806   while(pb) {
1807
1808     if(pb->pc == pc)
1809       return pb;
1810
1811     pb = pb->next;
1812   }
1813
1814   return NULL;
1815 }
1816
1817 /*-----------------------------------------------------------------*/
1818 /* pCodeUnlink - Unlink the given pCode from its pCode chain.      */
1819 /*-----------------------------------------------------------------*/
1820 static void pCodeUnlink(pCode *pc)
1821 {
1822   pBranch *pb1,*pb2;
1823   pCode *pc1;
1824
1825   if(!pc->prev || !pc->next) {
1826     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
1827     exit(1);
1828   }
1829
1830   /* first remove the pCode from the chain */
1831   pc->prev->next = pc->next;
1832   pc->next->prev = pc->prev;
1833
1834   /* Now for the hard part... */
1835
1836   /* Remove the branches */
1837
1838   pb1 = pc->from;
1839   while(pb1) {
1840     pc1 = pb1->pc;    /* Get the pCode that branches to the
1841                        * one we're unlinking */
1842
1843     /* search for the link back to this pCode (the one we're
1844      * unlinking) */
1845     if(pb2 = pBranchFind(pc1->to,pc)) {
1846       pb2->pc = pc->to->pc;  // make the replacement
1847
1848       /* if the pCode we're unlinking contains multiple 'to'
1849        * branches (e.g. this a skip instruction) then we need
1850        * to copy these extra branches to the chain. */
1851       if(pc->to->next)
1852         pBranchAppend(pb2, pc->to->next);
1853     }
1854     
1855     pb1 = pb1->next;
1856   }
1857
1858
1859 }
1860 #endif
1861 /*-----------------------------------------------------------------*/
1862 /*-----------------------------------------------------------------*/
1863 static void genericAnalyze(pCode *pc)
1864 {
1865   switch(pc->type) {
1866   case PC_WILD:
1867   case PC_COMMENT:
1868     return;
1869   case PC_LABEL:
1870   case PC_FUNCTION:
1871   case PC_OPCODE:
1872     {
1873       // Go through the pCodes that are in pCode chain and link
1874       // them together through the pBranches. Note, the pCodes
1875       // are linked together as a contiguous stream like the 
1876       // assembly source code lines. The linking here mimics this
1877       // except that comments are not linked in.
1878       // 
1879       pCode *npc = pc->next;
1880       while(npc) {
1881         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
1882           pBranchLink(pc,npc);
1883           return;
1884         } else
1885           npc = npc->next;
1886       }
1887     }
1888   }
1889 }
1890
1891 /*-----------------------------------------------------------------*/
1892 int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
1893 {
1894   pBranch *pbr;
1895
1896   if(pc->type == PC_LABEL) {
1897     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
1898       return TRUE;
1899   }
1900   if(pc->type == PC_OPCODE) {
1901     pbr = pc->label;
1902     while(pbr) {
1903       if(pbr->pc->type == PC_LABEL) {
1904         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
1905           return TRUE;
1906       }
1907       pbr = pbr->next;
1908     }
1909   }
1910
1911   return FALSE;
1912 }
1913
1914 /*-----------------------------------------------------------------*/
1915 /* findLabel - Search the pCode for a particular label             */
1916 /*-----------------------------------------------------------------*/
1917 pCode * findLabel(pCodeOpLabel *pcop_label)
1918 {
1919   pBlock *pb;
1920   pCode  *pc;
1921
1922   if(!the_pFile)
1923     return NULL;
1924
1925   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1926     for(pc = pb->pcHead; pc; pc = pc->next) 
1927       if(compareLabel(pc,pcop_label))
1928         return pc;
1929     
1930   }
1931
1932   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
1933   return NULL;
1934 }
1935
1936 /*-----------------------------------------------------------------*/
1937 /* findNextInstruction - given a pCode, find the next instruction  */
1938 /*                       in the linked list                        */
1939 /*-----------------------------------------------------------------*/
1940 pCode * findNextInstruction(pCode *pc)
1941 {
1942
1943   while(pc) {
1944     if((pc->type == PC_OPCODE) || (pc->type == PC_WILD))
1945       return pc;
1946
1947     pc = pc->next;
1948   }
1949
1950   fprintf(stderr,"Couldn't find instruction\n");
1951   return NULL;
1952 }
1953
1954 /*-----------------------------------------------------------------*/
1955 /* findFunctionEnd - given a pCode find the end of the function    */
1956 /*                   that contains it     t                        */
1957 /*-----------------------------------------------------------------*/
1958 pCode * findFunctionEnd(pCode *pc)
1959 {
1960
1961   while(pc) {
1962     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
1963       return pc;
1964
1965     pc = pc->next;
1966   }
1967
1968   fprintf(stderr,"Couldn't find function end\n");
1969   return NULL;
1970 }
1971
1972 #if 0
1973 /*-----------------------------------------------------------------*/
1974 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
1975 /*                instruction with which it is associated.         */
1976 /*-----------------------------------------------------------------*/
1977 static void AnalyzeLabel(pCode *pc)
1978 {
1979
1980   pCodeUnlink(pc);
1981
1982 }
1983 #endif
1984
1985 static void AnalyzeGOTO(pCode *pc)
1986 {
1987
1988   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
1989
1990 }
1991
1992 static void AnalyzeSKIP(pCode *pc)
1993 {
1994
1995   pBranchLink(pc,findNextInstruction(pc->next));
1996   pBranchLink(pc,findNextInstruction(pc->next->next));
1997
1998 }
1999
2000 static void AnalyzeRETURN(pCode *pc)
2001 {
2002
2003   //  branch_link(pc,findFunctionEnd(pc->next));
2004
2005 }
2006
2007
2008 void AnalyzepBlock(pBlock *pb)
2009 {
2010   pCode *pc;
2011
2012   if(!pb)
2013     return;
2014
2015   /* Find all of the registers used in this pBlock */
2016   for(pc = pb->pcHead; pc; pc = pc->next) {
2017     if(pc->type == PC_OPCODE) {
2018       if(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_TEMP) {
2019
2020         /* Loop through all of the registers declared so far in
2021            this block and see if we find this new there */
2022
2023         regs *r = setFirstItem(pb->registers);
2024
2025         while(r) {
2026           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
2027             PCOR(PCI(pc)->pcop)->r = r;
2028             break;
2029           }
2030           r = setNextItem(pb->registers);
2031         }
2032
2033         if(!r) {
2034           /* register wasn't found */
2035           r = Safe_calloc(1, sizeof(regs));
2036           memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
2037           addSet(&pb->registers, r);
2038           PCOR(PCI(pc)->pcop)->r = r;
2039           fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
2040         } else 
2041           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
2042       }
2043     }
2044   }
2045 }
2046
2047 int OptimizepBlock(pBlock *pb)
2048 {
2049   pCode *pc;
2050   int matches =0;
2051
2052   if(!pb || !peepOptimizing)
2053     return 0;
2054
2055   fprintf(stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb));
2056   for(pc = pb->pcHead; pc; pc = pc->next)
2057     matches += pCodePeepMatchRule(pc);
2058
2059   return matches;
2060
2061 }
2062
2063 /*-----------------------------------------------------------------*/
2064 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2065 /*-----------------------------------------------------------------*/
2066 pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
2067 {
2068   pCode *pc;
2069
2070   for(pc = pcs; pc; pc = pc->next) {
2071
2072     if((pc->type == PC_OPCODE) && 
2073        (PCI(pc)->pcop) && 
2074        (PCI(pc)->pcop->type == PO_LABEL) &&
2075        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
2076       return pc;
2077   }
2078  
2079
2080   return NULL;
2081 }
2082
2083 /*-----------------------------------------------------------------*/
2084 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2085 /*                            pCode chain if they're not used.     */
2086 /*-----------------------------------------------------------------*/
2087 void pBlockRemoveUnusedLabels(pBlock *pb)
2088 {
2089   pCode *pc; pCodeLabel *pcl;
2090
2091   if(!pb)
2092     return;
2093
2094   for(pc = pb->pcHead; pc; pc = pc->next) {
2095
2096     if(pc->type == PC_LABEL)
2097       pcl = PCL(pc);
2098     else if (pc->label)
2099       pcl = PCL(pc->label->pc);
2100     else continue;
2101
2102       /* This pCode is a label, so search the pBlock to see if anyone
2103        * refers to it */
2104
2105     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))) {
2106       /* Couldn't find an instruction that refers to this label
2107        * So, unlink the pCode label from it's pCode chain
2108        * and destroy the label */
2109
2110       fprintf(stderr," !!! REMOVED A LABEL !!! key = %d\n", pcl->key);
2111
2112       if(pc->type == PC_LABEL) {
2113         //unlinkPC(pc);
2114         pCodeLabelDestruct(pc);
2115       } else {
2116         unlinkpCodeFromBranch(pc->label, pc);
2117         if(pc->label->next == NULL && pc->label->pc == NULL) {
2118           free(pc->label);
2119         }
2120       }
2121
2122     }
2123   }
2124
2125 }
2126
2127
2128 /*-----------------------------------------------------------------*/
2129 /* pBlockMergeLabels - remove the pCode labels from the pCode      */
2130 /*                     chain and put them into pBranches that are  */
2131 /*                     associated with the appropriate pCode       */
2132 /*                     instructions.                               */
2133 /*-----------------------------------------------------------------*/
2134 void pBlockMergeLabels(pBlock *pb)
2135 {
2136   pBranch *pbr;
2137   pCode *pc, *pcnext=NULL;
2138
2139   if(!pb)
2140     return;
2141
2142   /* First, Try to remove any unused labels */
2143   //pBlockRemoveUnusedLabels(pb);
2144
2145   /* Now loop through the pBlock and merge the labels with the opcodes */
2146
2147   for(pc = pb->pcHead; pc; pc = pc->next) {
2148
2149     if(pc->type == PC_LABEL) {
2150       fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
2151       if( !(pcnext = findNextInstruction(pc)) ) 
2152         return;  // Couldn't find an instruction associated with this label
2153
2154       // Unlink the pCode label from it's pCode chain
2155       unlinkPC(pc);
2156
2157       fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
2158       // And link it into the instruction's pBranch labels. (Note, since
2159       // it's possible to have multiple labels associated with one instruction
2160       // we must provide a means to accomodate the additional labels. Thus
2161       // the labels are placed into the singly-linked list "label" as 
2162       // opposed to being a single member of the pCodeInstruction.)
2163
2164       _ALLOC(pbr,sizeof(pBranch));
2165       pbr->pc = pc;
2166       pbr->next = NULL;
2167
2168       pcnext->label = pBranchAppend(pcnext->label,pbr);
2169       if(pcnext->prev) 
2170         pc = pcnext->prev;
2171       else
2172         pc = pcnext;
2173     }
2174
2175   }
2176   pBlockRemoveUnusedLabels(pb);
2177
2178 }
2179
2180 /*-----------------------------------------------------------------*/
2181 /*-----------------------------------------------------------------*/
2182 void OptimizepCode(char dbName)
2183 {
2184 #define MAX_PASSES 4
2185
2186   int matches = 0;
2187   int passes = 0;
2188   pBlock *pb;
2189
2190   if(!the_pFile)
2191     return;
2192
2193   fprintf(stderr," Optimizing pCode\n");
2194
2195   do {
2196     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2197       if('*' == dbName || getpBlock_dbName(pb) == dbName)
2198         matches += OptimizepBlock(pb);
2199     }
2200   }
2201   while(matches && ++passes < MAX_PASSES);
2202
2203 }
2204
2205 /*-----------------------------------------------------------------*/
2206 /* AnalyzepCode - parse the pCode that has been generated and form */
2207 /*                all of the logical connections.                  */
2208 /*                                                                 */
2209 /* Essentially what's done here is that the pCode flow is          */
2210 /* determined.                                                     */
2211 /*-----------------------------------------------------------------*/
2212
2213 void AnalyzepCode(char dbName)
2214 {
2215   pBlock *pb;
2216   pCode *pc;
2217   pBranch *pbr;
2218
2219   if(!the_pFile)
2220     return;
2221
2222   fprintf(stderr," Analyzing pCode");
2223
2224   /* First, merge the labels with the instructions */
2225   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2226     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2227
2228       fprintf(stderr," analyze and merging block %c\n",dbName);
2229       pBlockMergeLabels(pb);
2230       AnalyzepBlock(pb);
2231     }
2232   }
2233
2234   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2235     if('*' == dbName || getpBlock_dbName(pb) == dbName)
2236       OptimizepBlock(pb);
2237   }
2238
2239   /* Now build the call tree.
2240      First we examine all of the pCodes for functions.
2241      Keep in mind that the function boundaries coincide
2242      with pBlock boundaries. 
2243
2244      The algorithm goes something like this:
2245      We have two nested loops. The outer loop iterates
2246      through all of the pBlocks/functions. The inner
2247      loop iterates through all of the pCodes for
2248      a given pBlock. When we begin iterating through
2249      a pBlock, the variable pc_fstart, pCode of the start
2250      of a function, is cleared. We then search for pCodes
2251      of type PC_FUNCTION. When one is encountered, we
2252      initialize pc_fstart to this and at the same time
2253      associate a new pBranch object that signifies a 
2254      branch entry. If a return is found, then this signifies
2255      a function exit point. We'll link the pCodes of these
2256      returns to the matching pc_fstart.
2257
2258      When we're done, a doubly linked list of pBranches
2259      will exist. The head of this list is stored in
2260      `the_pFile', which is the meta structure for all
2261      of the pCode. Look at the printCallTree function
2262      on how the pBranches are linked together.
2263
2264    */
2265   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2266     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2267       pCode *pc_fstart=NULL;
2268       for(pc = pb->pcHead; pc; pc = pc->next) {
2269         if(pc->type == PC_FUNCTION) {
2270           if (PCF(pc)->fname) {
2271             // I'm not liking this....
2272             // Found the beginning of a function.
2273             _ALLOC(pbr,sizeof(pBranch));
2274             pbr->pc = pc_fstart = pc;
2275             pbr->next = NULL;
2276
2277             the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
2278
2279             // Here's a better way of doing the same:
2280             addSet(&pb->function_entries, pc);
2281
2282           } else {
2283             // Found an exit point in a function, e.g. return
2284             // (Note, there may be more than one return per function)
2285             if(pc_fstart)
2286               pBranchLink(pc_fstart, pc);
2287
2288             addSet(&pb->function_exits, pc);
2289           }
2290         } else  if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2291           addSet(&pb->function_calls,pc);
2292         }
2293       }
2294     }
2295   }
2296 }
2297
2298 /*-----------------------------------------------------------------*/
2299 /* ispCodeFunction - returns true if *pc is the pCode of a         */
2300 /*                   function                                      */
2301 /*-----------------------------------------------------------------*/
2302 bool ispCodeFunction(pCode *pc)
2303 {
2304
2305   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
2306     return 1;
2307
2308   return 0;
2309 }
2310
2311 /*-----------------------------------------------------------------*/
2312 /* findFunction - Search for a function by name (given the name)   */
2313 /*                in the set of all functions that are in a pBlock */
2314 /* (note - I expect this to change because I'm planning to limit   */
2315 /*  pBlock's to just one function declaration                      */
2316 /*-----------------------------------------------------------------*/
2317 pCode *findFunction(char *fname)
2318 {
2319   pBlock *pb;
2320   pCode *pc;
2321   if(!fname)
2322     return NULL;
2323
2324   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2325
2326     pc = setFirstItem(pb->function_entries);
2327     while(pc) {
2328     
2329       if((pc->type == PC_FUNCTION) &&
2330          (PCF(pc)->fname) && 
2331          (strcmp(fname, PCF(pc)->fname)==0))
2332         return pc;
2333
2334       pc = setNextItem(pb->function_entries);
2335
2336     }
2337
2338   }
2339   return NULL;
2340 }
2341
2342 void MarkUsedRegisters(set *regset)
2343 {
2344
2345   regs *r1,*r2;
2346
2347   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
2348     r2 = pic14_regWithIdx(r1->rIdx);
2349     r2->isFree = 0;
2350     r2->wasUsed = 1;
2351   }
2352 }
2353
2354 void pBlockStats(FILE *of, pBlock *pb)
2355 {
2356
2357   pCode *pc;
2358   regs  *r;
2359
2360   fprintf(of,"***\n  pBlock Stats\n***\n");
2361
2362   // for now just print the first element of each set
2363   pc = setFirstItem(pb->function_entries);
2364   if(pc) {
2365     fprintf(of,"entry\n");
2366     pc->print(of,pc);
2367   }
2368   pc = setFirstItem(pb->function_exits);
2369   if(pc) {
2370     fprintf(of,"has an exit\n");
2371     pc->print(of,pc);
2372   }
2373
2374   pc = setFirstItem(pb->function_calls);
2375   if(pc) {
2376     fprintf(of,"functions called\n");
2377
2378     while(pc) {
2379       pc->print(of,pc);
2380       pc = setNextItem(pb->function_calls);
2381     }
2382   }
2383
2384   r = setFirstItem(pb->registers);
2385   if(r) {
2386     int n = elementsInSet(pb->registers);
2387
2388     fprintf(of,"%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
2389
2390     while (r) {
2391       fprintf(of,"   %s\n",r->name);
2392       r = setNextItem(pb->registers);
2393     }
2394   }
2395 }
2396
2397 /*-----------------------------------------------------------------*/
2398 /*-----------------------------------------------------------------*/
2399 void sequencepCode(void)
2400 {
2401   pBlock *pb;
2402   pCode *pc;
2403
2404
2405   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2406
2407     pb->seq = GpCodeSequenceNumber+1;
2408
2409     for( pc = pb->pcHead; pc; pc = pc->next)
2410       pc->seq = ++GpCodeSequenceNumber;
2411   }
2412
2413 }
2414
2415 /*-----------------------------------------------------------------*/
2416 /*-----------------------------------------------------------------*/
2417 set *register_usage(pBlock *pb)
2418 {
2419   pCode *pc,*pcn;
2420   set *registers=NULL;
2421   set *registersInCallPath = NULL;
2422
2423   /* check recursion */
2424
2425   pc = setFirstItem(pb->function_entries);
2426
2427   if(!pc)
2428     return registers;
2429
2430   pb->visited = 1;
2431
2432   if(pc->type != PC_FUNCTION)
2433     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
2434
2435   pc = setFirstItem(pb->function_calls);
2436   for( ; pc; pc = setNextItem(pb->function_calls)) {
2437
2438     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2439       char *dest = get_op(PCI(pc));
2440
2441       pcn = findFunction(dest);
2442       if(pcn) 
2443         registersInCallPath = register_usage(pcn->pb);
2444     } else
2445       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2446
2447   }
2448
2449
2450   pBlockStats(stderr,pb);  // debug
2451   if(registersInCallPath) {
2452     /* registers were used in the functions this pBlock has called */
2453     /* so now, we need to see if these collide with the ones we are */
2454     /* using here */
2455
2456     regs *r1,*r2, *newreg;
2457
2458     fprintf(stderr,"comparing registers\n");
2459
2460     r1 = setFirstItem(registersInCallPath);
2461     while(r1) {
2462
2463       r2 = setFirstItem(pb->registers);
2464
2465       while(r2) {
2466
2467         if(r2->rIdx == r1->rIdx) {
2468           newreg = pic14_findFreeReg();
2469
2470
2471           if(!newreg) {
2472             fprintf(stderr,"Bummer, no more registers.\n");
2473             exit(1);
2474           }
2475
2476           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2477                   r1->rIdx, newreg->rIdx);
2478           r2->rIdx = newreg->rIdx;
2479           //if(r2->name) free(r2->name);
2480           r2->name = Safe_strdup(newreg->name);
2481           newreg->isFree = 0;
2482           newreg->wasUsed = 1;
2483         }
2484         r2 = setNextItem(pb->registers);
2485       }
2486
2487       r1 = setNextItem(registersInCallPath);
2488     }
2489
2490     /* Collisions have been resolved. Now free the registers in the call path */
2491     r1 = setFirstItem(registersInCallPath);
2492     while(r1) {
2493       newreg = pic14_regWithIdx(r1->rIdx);
2494       newreg->isFree = 1;
2495       r1 = setNextItem(registersInCallPath);
2496     }
2497
2498   } else
2499     MarkUsedRegisters(pb->registers);
2500
2501   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2502
2503   if(registers) 
2504     fprintf(stderr,"returning regs\n");
2505   else
2506     fprintf(stderr,"not returning regs\n");
2507
2508   fprintf(stderr,"pBlock after register optim.\n");
2509   pBlockStats(stderr,pb);  // debug
2510
2511
2512   return registers;
2513 }
2514
2515 /*-----------------------------------------------------------------*/
2516 /* printCallTree - writes the call tree to a file                  */
2517 /*                                                                 */
2518 /*-----------------------------------------------------------------*/
2519 void pct2(FILE *of,pBlock *pb,int indent)
2520 {
2521   pCode *pc,*pcn;
2522   int i;
2523   //  set *registersInCallPath = NULL;
2524
2525   if(!of)
2526     return;// registers;
2527
2528   if(indent > 10)
2529     return; // registers;   //recursion ?
2530
2531   pc = setFirstItem(pb->function_entries);
2532
2533   if(!pc)
2534     return;
2535
2536   pb->visited = 0;
2537
2538   for(i=0;i<indent;i++)   // Indentation
2539     fputc(' ',of);
2540
2541   if(pc->type == PC_FUNCTION)
2542     fprintf(of,"%s\n",PCF(pc)->fname);
2543   else
2544     return;  // ???
2545
2546
2547   pc = setFirstItem(pb->function_calls);
2548   for( ; pc; pc = setNextItem(pb->function_calls)) {
2549
2550     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2551       char *dest = get_op(PCI(pc));
2552
2553       pcn = findFunction(dest);
2554       if(pcn) 
2555         pct2(of,pcn->pb,indent+1);
2556     } else
2557       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2558
2559   }
2560
2561
2562 }
2563
2564 #if 0
2565   fprintf(stderr,"pBlock before register optim.\n");
2566   pBlockStats(stderr,pb);  // debug
2567
2568   if(registersInCallPath) {
2569     /* registers were used in the functions this pBlock has called */
2570     /* so now, we need to see if these collide with the ones we are using here */
2571
2572     regs *r1,*r2, *newreg;
2573
2574     fprintf(stderr,"comparing registers\n");
2575
2576     r1 = setFirstItem(registersInCallPath);
2577     while(r1) {
2578
2579       r2 = setFirstItem(pb->registers);
2580
2581       while(r2) {
2582
2583         if(r2->rIdx == r1->rIdx) {
2584           newreg = pic14_findFreeReg();
2585
2586
2587           if(!newreg) {
2588             fprintf(stderr,"Bummer, no more registers.\n");
2589             exit(1);
2590           }
2591
2592           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2593                   r1->rIdx, newreg->rIdx);
2594           r2->rIdx = newreg->rIdx;
2595           //if(r2->name) free(r2->name);
2596           r2->name = Safe_strdup(newreg->name);
2597           newreg->isFree = 0;
2598           newreg->wasUsed = 1;
2599         }
2600         r2 = setNextItem(pb->registers);
2601       }
2602
2603       r1 = setNextItem(registersInCallPath);
2604     }
2605
2606     /* Collisions have been resolved. Now free the registers in the call path */
2607     r1 = setFirstItem(registersInCallPath);
2608     while(r1) {
2609       newreg = pic14_regWithIdx(r1->rIdx);
2610       newreg->isFree = 1;
2611       r1 = setNextItem(registersInCallPath);
2612     }
2613
2614   } else
2615     MarkUsedRegisters(pb->registers);
2616
2617   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2618
2619   if(registers) 
2620     fprintf(stderr,"returning regs\n");
2621   else
2622     fprintf(stderr,"not returning regs\n");
2623
2624   fprintf(stderr,"pBlock after register optim.\n");
2625   pBlockStats(stderr,pb);  // debug
2626
2627
2628   return registers;
2629
2630 #endif
2631
2632
2633 /*-----------------------------------------------------------------*/
2634 /* printCallTree - writes the call tree to a file                  */
2635 /*                                                                 */
2636 /*-----------------------------------------------------------------*/
2637
2638 void printCallTree(FILE *of)
2639 {
2640   pBranch *pbr;
2641   pBlock  *pb;
2642   pCode   *pc;
2643
2644   if(!the_pFile)
2645     return;
2646
2647   if(!of)
2648     of = stderr;
2649
2650   fprintf(of, "\npBlock statistics\n");
2651   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
2652     pBlockStats(stderr,pb);
2653
2654
2655
2656   fprintf(of,"Call Tree\n");
2657   pbr = the_pFile->functions;
2658   while(pbr) {
2659     if(pbr->pc) {
2660       pc = pbr->pc;
2661       if(!ispCodeFunction(pc))
2662         fprintf(of,"bug in call tree");
2663
2664
2665       fprintf(of,"Function: %s\n", PCF(pc)->fname);
2666
2667       while(pc->next && !ispCodeFunction(pc->next)) {
2668         pc = pc->next;
2669         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
2670           fprintf(of,"\t%s\n",get_op(PCI(pc)));
2671       }
2672     }
2673
2674     pbr = pbr->next;
2675   }
2676
2677
2678   /* Re-allocate the registers so that there are no collisions
2679    * between local variables when one function call another */
2680
2681   pic14_deallocateAllRegs();
2682
2683   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2684     if(!pb->visited)
2685       register_usage(pb);
2686   }
2687
2688   fprintf(of,"\n**************\n\na better call tree\n");
2689   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2690     if(pb->visited)
2691       pct2(of,pb,0);
2692   }
2693
2694   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2695     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
2696   }
2697 }