The PIC Port was assuming ifx was always true. (A recent [valid] change
[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(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       r = pic14_regWithIdx(PCOR(pcc->pcop)->rIdx);
1540       return r->name;
1541       break;
1542     case PO_GPR_TEMP:
1543     case PO_GPR_BIT:
1544       r = pic14_regWithIdx(PCOR(pcc->pcop)->r->rIdx);
1545       //fprintf(stderr,"getop: getting %s\nfrom:\n",r->name); //pcc->pcop->name);
1546       pBlockRegs(stderr,pcc->pc.pb);
1547       return r->name;
1548
1549     default:
1550       if  (pcc->pcop->name)
1551         return pcc->pcop->name;
1552
1553     }
1554   }
1555
1556   return "NO operand";
1557 }
1558
1559 /*-----------------------------------------------------------------*/
1560 /*-----------------------------------------------------------------*/
1561 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
1562 {
1563
1564   fprintf(of,"pcodeopprint\n");
1565 }
1566
1567 char *pCode2str(char *str, int size, pCode *pc)
1568 {
1569   char *s = str;
1570
1571   switch(pc->type) {
1572
1573   case PC_OPCODE:
1574
1575     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
1576
1577     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
1578
1579       if(PCI(pc)->bit_inst) {
1580         if(PCI(pc)->pcop->type == PO_BIT) {
1581           if( (((pCodeOpBit *)(PCI(pc)->pcop))->inBitSpace) )
1582             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
1583                           PCI(pc)->pcop->name ,
1584                           PCI(pc)->pcop->name );
1585           else
1586             SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)), 
1587                           (((pCodeOpBit *)(PCI(pc)->pcop))->bit ));
1588         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
1589           SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
1590         }else
1591           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", get_op(PCI(pc)));
1592         //PCI(pc)->pcop->t.bit );
1593       } else {
1594
1595         if(PCI(pc)->pcop->type == PO_BIT) {
1596           if( PCI(pc)->num_ops == 2)
1597             SAFE_snprintf(&s,&size,"(%s >> 3),%c",get_op(PCI(pc)),((PCI(pc)->dest) ? 'F':'W'));
1598           else
1599             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",get_op(PCI(pc)));
1600
1601         }else {
1602           SAFE_snprintf(&s,&size,"%s",get_op(PCI(pc)));
1603
1604           if( PCI(pc)->num_ops == 2)
1605             SAFE_snprintf(&s,&size,",%c", ( (PCI(pc)->dest) ? 'F':'W'));
1606         }
1607       }
1608
1609     }
1610     break;
1611
1612   case PC_COMMENT:
1613     /* assuming that comment ends with a \n */
1614     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
1615     break;
1616
1617   case PC_LABEL:
1618     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
1619     break;
1620   case PC_FUNCTION:
1621     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
1622     break;
1623   case PC_WILD:
1624     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
1625     break;
1626
1627   }
1628
1629   return str;
1630
1631 }
1632
1633 /*-----------------------------------------------------------------*/
1634 /* genericPrint - the contents of a pCode to a file                */
1635 /*-----------------------------------------------------------------*/
1636 static void genericPrint(FILE *of, pCode *pc)
1637 {
1638
1639   if(!pc || !of)
1640     return;
1641
1642   switch(pc->type) {
1643   case PC_COMMENT:
1644     fprintf(of,";%s\n", ((pCodeComment *)pc)->comment);
1645     break;
1646
1647   case PC_OPCODE:
1648     // If the opcode has a label, print that first
1649     {
1650       pBranch *pbl = pc->label;
1651       while(pbl) {
1652         if(pbl->pc->type == PC_LABEL)
1653           pCodePrintLabel(of, pbl->pc);
1654         pbl = pbl->next;
1655       }
1656     }
1657
1658
1659     {
1660       char str[256];
1661       
1662       pCode2str(str, 256, pc);
1663
1664       fprintf(of,"%s",str);
1665     }
1666
1667     {
1668       pBranch *dpb = pc->to;   // debug
1669       while(dpb) {
1670         switch ( dpb->pc->type) {
1671         case PC_OPCODE:
1672           fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic);
1673           break;
1674         case PC_LABEL:
1675           fprintf(of, "\t;label %d", PCL(dpb->pc)->key);
1676           break;
1677         case PC_FUNCTION:
1678           fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]"));
1679           break;
1680         case PC_COMMENT:
1681         case PC_WILD:
1682           break;
1683         }
1684         dpb = dpb->next;
1685       }
1686       fprintf(of,"\n");
1687     }
1688
1689     break;
1690
1691   case PC_WILD:
1692     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
1693     if(pc->label)
1694       pCodePrintLabel(of, pc->label->pc);
1695
1696     if(PCW(pc)->operand) {
1697       fprintf(of,";\toperand  ");
1698       pCodeOpPrint(of,PCW(pc)->operand );
1699     }
1700     break;
1701
1702   case PC_LABEL:
1703   default:
1704     fprintf(of,"unknown pCode type %d\n",pc->type);
1705   }
1706
1707 }
1708
1709 /*-----------------------------------------------------------------*/
1710 /* pCodePrintFunction - prints function begin/end                  */
1711 /*-----------------------------------------------------------------*/
1712
1713 static void pCodePrintFunction(FILE *of, pCode *pc)
1714 {
1715
1716   if(!pc || !of)
1717     return;
1718
1719   if( ((pCodeFunction *)pc)->modname) 
1720     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
1721
1722   if(PCF(pc)->fname) {
1723     pBranch *exits = pc->to;
1724     int i=0;
1725     fprintf(of,"%s\t;Function start\n",PCF(pc)->fname);
1726     while(exits) {
1727       i++;
1728       exits = exits->next;
1729     }
1730     //if(i) i--;
1731     fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
1732     
1733   }else {
1734     if(pc->from && 
1735        pc->from->pc->type == PC_FUNCTION &&
1736        PCF(pc->from->pc)->fname) 
1737       fprintf(of,"; exit point of %s\n",PCF(pc->from->pc)->fname);
1738     else
1739       fprintf(of,"; exit point [can't find entry point]\n");
1740   }
1741 }
1742 /*-----------------------------------------------------------------*/
1743 /* pCodePrintLabel - prints label                                  */
1744 /*-----------------------------------------------------------------*/
1745
1746 static void pCodePrintLabel(FILE *of, pCode *pc)
1747 {
1748
1749   if(!pc || !of)
1750     return;
1751
1752   if(PCL(pc)->label) 
1753     fprintf(of,"%s\n",PCL(pc)->label);
1754   else if (PCL(pc)->key >=0) 
1755     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
1756   else
1757     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
1758
1759 }
1760 /*-----------------------------------------------------------------*/
1761 static void  unlinkpCodeFromBranch(pBranch *pb , pCode *pc)
1762 {
1763   pBranch *b, *bprev;
1764
1765   bprev = NULL;
1766   b = pb;
1767   while(b) {
1768     if(b->pc == pc) {
1769       if(bprev)
1770         bprev->next = b->next;
1771     }
1772     bprev = b;
1773     b = b->next;
1774   }
1775
1776 }
1777
1778 static pBranch * pBranchAppend(pBranch *h, pBranch *n)
1779 {
1780   pBranch *b;
1781
1782   if(!h)
1783     return n;
1784
1785   b = h;
1786   while(b->next)
1787     b = b->next;
1788
1789   b->next = n;
1790
1791   return h;
1792   
1793 }  
1794 /*-----------------------------------------------------------------*/
1795 /* pBranchLink - given two pcodes, this function will link them    */
1796 /*               together through their pBranches                  */
1797 /*-----------------------------------------------------------------*/
1798 static void pBranchLink(pCode *f, pCode *t)
1799 {
1800   pBranch *b;
1801
1802   // Declare a new branch object for the 'from' pCode.
1803
1804   _ALLOC(b,sizeof(pBranch));
1805   b->pc = t;                    // The link to the 'to' pCode.
1806   b->next = NULL;
1807
1808   f->to = pBranchAppend(f->to,b);
1809
1810   // Now do the same for the 'to' pCode.
1811
1812   _ALLOC(b,sizeof(pBranch));
1813   b->pc = f;
1814   b->next = NULL;
1815
1816   t->from = pBranchAppend(t->from,b);
1817   
1818 }
1819
1820 #if 0
1821 /*-----------------------------------------------------------------*/
1822 /* pBranchFind - find the pBranch in a pBranch chain that contains */
1823 /*               a pCode                                           */
1824 /*-----------------------------------------------------------------*/
1825 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
1826 {
1827   while(pb) {
1828
1829     if(pb->pc == pc)
1830       return pb;
1831
1832     pb = pb->next;
1833   }
1834
1835   return NULL;
1836 }
1837
1838 /*-----------------------------------------------------------------*/
1839 /* pCodeUnlink - Unlink the given pCode from its pCode chain.      */
1840 /*-----------------------------------------------------------------*/
1841 static void pCodeUnlink(pCode *pc)
1842 {
1843   pBranch *pb1,*pb2;
1844   pCode *pc1;
1845
1846   if(!pc->prev || !pc->next) {
1847     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
1848     exit(1);
1849   }
1850
1851   /* first remove the pCode from the chain */
1852   pc->prev->next = pc->next;
1853   pc->next->prev = pc->prev;
1854
1855   /* Now for the hard part... */
1856
1857   /* Remove the branches */
1858
1859   pb1 = pc->from;
1860   while(pb1) {
1861     pc1 = pb1->pc;    /* Get the pCode that branches to the
1862                        * one we're unlinking */
1863
1864     /* search for the link back to this pCode (the one we're
1865      * unlinking) */
1866     if(pb2 = pBranchFind(pc1->to,pc)) {
1867       pb2->pc = pc->to->pc;  // make the replacement
1868
1869       /* if the pCode we're unlinking contains multiple 'to'
1870        * branches (e.g. this a skip instruction) then we need
1871        * to copy these extra branches to the chain. */
1872       if(pc->to->next)
1873         pBranchAppend(pb2, pc->to->next);
1874     }
1875     
1876     pb1 = pb1->next;
1877   }
1878
1879
1880 }
1881 #endif
1882 /*-----------------------------------------------------------------*/
1883 /*-----------------------------------------------------------------*/
1884 static void genericAnalyze(pCode *pc)
1885 {
1886   switch(pc->type) {
1887   case PC_WILD:
1888   case PC_COMMENT:
1889     return;
1890   case PC_LABEL:
1891   case PC_FUNCTION:
1892   case PC_OPCODE:
1893     {
1894       // Go through the pCodes that are in pCode chain and link
1895       // them together through the pBranches. Note, the pCodes
1896       // are linked together as a contiguous stream like the 
1897       // assembly source code lines. The linking here mimics this
1898       // except that comments are not linked in.
1899       // 
1900       pCode *npc = pc->next;
1901       while(npc) {
1902         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
1903           pBranchLink(pc,npc);
1904           return;
1905         } else
1906           npc = npc->next;
1907       }
1908     }
1909   }
1910 }
1911
1912 /*-----------------------------------------------------------------*/
1913 int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
1914 {
1915   pBranch *pbr;
1916
1917   if(pc->type == PC_LABEL) {
1918     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
1919       return TRUE;
1920   }
1921   if(pc->type == PC_OPCODE) {
1922     pbr = pc->label;
1923     while(pbr) {
1924       if(pbr->pc->type == PC_LABEL) {
1925         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
1926           return TRUE;
1927       }
1928       pbr = pbr->next;
1929     }
1930   }
1931
1932   return FALSE;
1933 }
1934
1935 /*-----------------------------------------------------------------*/
1936 /* findLabel - Search the pCode for a particular label             */
1937 /*-----------------------------------------------------------------*/
1938 pCode * findLabel(pCodeOpLabel *pcop_label)
1939 {
1940   pBlock *pb;
1941   pCode  *pc;
1942
1943   if(!the_pFile)
1944     return NULL;
1945
1946   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1947     for(pc = pb->pcHead; pc; pc = pc->next) 
1948       if(compareLabel(pc,pcop_label))
1949         return pc;
1950     
1951   }
1952
1953   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
1954   return NULL;
1955 }
1956
1957 /*-----------------------------------------------------------------*/
1958 /* findNextInstruction - given a pCode, find the next instruction  */
1959 /*                       in the linked list                        */
1960 /*-----------------------------------------------------------------*/
1961 pCode * findNextInstruction(pCode *pc)
1962 {
1963
1964   while(pc) {
1965     if((pc->type == PC_OPCODE) || (pc->type == PC_WILD))
1966       return pc;
1967
1968     pc = pc->next;
1969   }
1970
1971   fprintf(stderr,"Couldn't find instruction\n");
1972   return NULL;
1973 }
1974
1975 /*-----------------------------------------------------------------*/
1976 /* findFunctionEnd - given a pCode find the end of the function    */
1977 /*                   that contains it     t                        */
1978 /*-----------------------------------------------------------------*/
1979 pCode * findFunctionEnd(pCode *pc)
1980 {
1981
1982   while(pc) {
1983     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
1984       return pc;
1985
1986     pc = pc->next;
1987   }
1988
1989   fprintf(stderr,"Couldn't find function end\n");
1990   return NULL;
1991 }
1992
1993 #if 0
1994 /*-----------------------------------------------------------------*/
1995 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
1996 /*                instruction with which it is associated.         */
1997 /*-----------------------------------------------------------------*/
1998 static void AnalyzeLabel(pCode *pc)
1999 {
2000
2001   pCodeUnlink(pc);
2002
2003 }
2004 #endif
2005
2006 static void AnalyzeGOTO(pCode *pc)
2007 {
2008
2009   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
2010
2011 }
2012
2013 static void AnalyzeSKIP(pCode *pc)
2014 {
2015
2016   pBranchLink(pc,findNextInstruction(pc->next));
2017   pBranchLink(pc,findNextInstruction(pc->next->next));
2018
2019 }
2020
2021 static void AnalyzeRETURN(pCode *pc)
2022 {
2023
2024   //  branch_link(pc,findFunctionEnd(pc->next));
2025
2026 }
2027
2028
2029 void AnalyzepBlock(pBlock *pb)
2030 {
2031   pCode *pc;
2032
2033   if(!pb)
2034     return;
2035
2036   /* Find all of the registers used in this pBlock */
2037   for(pc = pb->pcHead; pc; pc = pc->next) {
2038     if(pc->type == PC_OPCODE) {
2039       if(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_TEMP) {
2040
2041         /* Loop through all of the registers declared so far in
2042            this block and see if we find this new there */
2043
2044         regs *r = setFirstItem(pb->registers);
2045
2046         while(r) {
2047           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
2048             PCOR(PCI(pc)->pcop)->r = r;
2049             break;
2050           }
2051           r = setNextItem(pb->registers);
2052         }
2053
2054         if(!r) {
2055           /* register wasn't found */
2056           r = Safe_calloc(1, sizeof(regs));
2057           memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
2058           addSet(&pb->registers, r);
2059           PCOR(PCI(pc)->pcop)->r = r;
2060           fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
2061         } else 
2062           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
2063       }
2064     }
2065   }
2066 }
2067
2068 int OptimizepBlock(pBlock *pb)
2069 {
2070   pCode *pc;
2071   int matches =0;
2072
2073   if(!pb || !peepOptimizing)
2074     return 0;
2075
2076   fprintf(stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb));
2077   for(pc = pb->pcHead; pc; pc = pc->next)
2078     matches += pCodePeepMatchRule(pc);
2079
2080   return matches;
2081
2082 }
2083
2084 /*-----------------------------------------------------------------*/
2085 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2086 /*-----------------------------------------------------------------*/
2087 pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
2088 {
2089   pCode *pc;
2090
2091   for(pc = pcs; pc; pc = pc->next) {
2092
2093     if((pc->type == PC_OPCODE) && 
2094        (PCI(pc)->pcop) && 
2095        (PCI(pc)->pcop->type == PO_LABEL) &&
2096        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
2097       return pc;
2098   }
2099  
2100
2101   return NULL;
2102 }
2103
2104 /*-----------------------------------------------------------------*/
2105 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2106 /*                            pCode chain if they're not used.     */
2107 /*-----------------------------------------------------------------*/
2108 void pBlockRemoveUnusedLabels(pBlock *pb)
2109 {
2110   pCode *pc; pCodeLabel *pcl;
2111
2112   if(!pb)
2113     return;
2114
2115   for(pc = pb->pcHead; pc; pc = pc->next) {
2116
2117     if(pc->type == PC_LABEL)
2118       pcl = PCL(pc);
2119     else if (pc->label)
2120       pcl = PCL(pc->label->pc);
2121     else continue;
2122
2123       /* This pCode is a label, so search the pBlock to see if anyone
2124        * refers to it */
2125
2126     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))) {
2127       /* Couldn't find an instruction that refers to this label
2128        * So, unlink the pCode label from it's pCode chain
2129        * and destroy the label */
2130
2131       fprintf(stderr," !!! REMOVED A LABEL !!! key = %d\n", pcl->key);
2132
2133       if(pc->type == PC_LABEL) {
2134         //unlinkPC(pc);
2135         pCodeLabelDestruct(pc);
2136       } else {
2137         unlinkpCodeFromBranch(pc->label, pc);
2138         if(pc->label->next == NULL && pc->label->pc == NULL) {
2139           free(pc->label);
2140         }
2141       }
2142
2143     }
2144   }
2145
2146 }
2147
2148
2149 /*-----------------------------------------------------------------*/
2150 /* pBlockMergeLabels - remove the pCode labels from the pCode      */
2151 /*                     chain and put them into pBranches that are  */
2152 /*                     associated with the appropriate pCode       */
2153 /*                     instructions.                               */
2154 /*-----------------------------------------------------------------*/
2155 void pBlockMergeLabels(pBlock *pb)
2156 {
2157   pBranch *pbr;
2158   pCode *pc, *pcnext=NULL;
2159
2160   if(!pb)
2161     return;
2162
2163   /* First, Try to remove any unused labels */
2164   //pBlockRemoveUnusedLabels(pb);
2165
2166   /* Now loop through the pBlock and merge the labels with the opcodes */
2167
2168   for(pc = pb->pcHead; pc; pc = pc->next) {
2169
2170     if(pc->type == PC_LABEL) {
2171       fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
2172       if( !(pcnext = findNextInstruction(pc)) ) 
2173         return;  // Couldn't find an instruction associated with this label
2174
2175       // Unlink the pCode label from it's pCode chain
2176       unlinkPC(pc);
2177
2178       fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
2179       // And link it into the instruction's pBranch labels. (Note, since
2180       // it's possible to have multiple labels associated with one instruction
2181       // we must provide a means to accomodate the additional labels. Thus
2182       // the labels are placed into the singly-linked list "label" as 
2183       // opposed to being a single member of the pCodeInstruction.)
2184
2185       _ALLOC(pbr,sizeof(pBranch));
2186       pbr->pc = pc;
2187       pbr->next = NULL;
2188
2189       pcnext->label = pBranchAppend(pcnext->label,pbr);
2190       if(pcnext->prev) 
2191         pc = pcnext->prev;
2192       else
2193         pc = pcnext;
2194     }
2195
2196   }
2197   pBlockRemoveUnusedLabels(pb);
2198
2199 }
2200
2201 /*-----------------------------------------------------------------*/
2202 /*-----------------------------------------------------------------*/
2203 void OptimizepCode(char dbName)
2204 {
2205 #define MAX_PASSES 4
2206
2207   int matches = 0;
2208   int passes = 0;
2209   pBlock *pb;
2210
2211   if(!the_pFile)
2212     return;
2213
2214   fprintf(stderr," Optimizing pCode\n");
2215
2216   do {
2217     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2218       if('*' == dbName || getpBlock_dbName(pb) == dbName)
2219         matches += OptimizepBlock(pb);
2220     }
2221   }
2222   while(matches && ++passes < MAX_PASSES);
2223
2224 }
2225
2226 /*-----------------------------------------------------------------*/
2227 /* AnalyzepCode - parse the pCode that has been generated and form */
2228 /*                all of the logical connections.                  */
2229 /*                                                                 */
2230 /* Essentially what's done here is that the pCode flow is          */
2231 /* determined.                                                     */
2232 /*-----------------------------------------------------------------*/
2233
2234 void AnalyzepCode(char dbName)
2235 {
2236   pBlock *pb;
2237   pCode *pc;
2238   pBranch *pbr;
2239
2240   if(!the_pFile)
2241     return;
2242
2243   fprintf(stderr," Analyzing pCode");
2244
2245   /* First, merge the labels with the instructions */
2246   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2247     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2248
2249       fprintf(stderr," analyze and merging block %c\n",dbName);
2250       pBlockMergeLabels(pb);
2251       AnalyzepBlock(pb);
2252     }
2253   }
2254
2255   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2256     if('*' == dbName || getpBlock_dbName(pb) == dbName)
2257       OptimizepBlock(pb);
2258   }
2259
2260   /* Now build the call tree.
2261      First we examine all of the pCodes for functions.
2262      Keep in mind that the function boundaries coincide
2263      with pBlock boundaries. 
2264
2265      The algorithm goes something like this:
2266      We have two nested loops. The outer loop iterates
2267      through all of the pBlocks/functions. The inner
2268      loop iterates through all of the pCodes for
2269      a given pBlock. When we begin iterating through
2270      a pBlock, the variable pc_fstart, pCode of the start
2271      of a function, is cleared. We then search for pCodes
2272      of type PC_FUNCTION. When one is encountered, we
2273      initialize pc_fstart to this and at the same time
2274      associate a new pBranch object that signifies a 
2275      branch entry. If a return is found, then this signifies
2276      a function exit point. We'll link the pCodes of these
2277      returns to the matching pc_fstart.
2278
2279      When we're done, a doubly linked list of pBranches
2280      will exist. The head of this list is stored in
2281      `the_pFile', which is the meta structure for all
2282      of the pCode. Look at the printCallTree function
2283      on how the pBranches are linked together.
2284
2285    */
2286   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2287     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2288       pCode *pc_fstart=NULL;
2289       for(pc = pb->pcHead; pc; pc = pc->next) {
2290         if(pc->type == PC_FUNCTION) {
2291           if (PCF(pc)->fname) {
2292             // I'm not liking this....
2293             // Found the beginning of a function.
2294             _ALLOC(pbr,sizeof(pBranch));
2295             pbr->pc = pc_fstart = pc;
2296             pbr->next = NULL;
2297
2298             the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
2299
2300             // Here's a better way of doing the same:
2301             addSet(&pb->function_entries, pc);
2302
2303           } else {
2304             // Found an exit point in a function, e.g. return
2305             // (Note, there may be more than one return per function)
2306             if(pc_fstart)
2307               pBranchLink(pc_fstart, pc);
2308
2309             addSet(&pb->function_exits, pc);
2310           }
2311         } else  if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2312           addSet(&pb->function_calls,pc);
2313         }
2314       }
2315     }
2316   }
2317 }
2318
2319 /*-----------------------------------------------------------------*/
2320 /* ispCodeFunction - returns true if *pc is the pCode of a         */
2321 /*                   function                                      */
2322 /*-----------------------------------------------------------------*/
2323 bool ispCodeFunction(pCode *pc)
2324 {
2325
2326   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
2327     return 1;
2328
2329   return 0;
2330 }
2331
2332 /*-----------------------------------------------------------------*/
2333 /* findFunction - Search for a function by name (given the name)   */
2334 /*                in the set of all functions that are in a pBlock */
2335 /* (note - I expect this to change because I'm planning to limit   */
2336 /*  pBlock's to just one function declaration                      */
2337 /*-----------------------------------------------------------------*/
2338 pCode *findFunction(char *fname)
2339 {
2340   pBlock *pb;
2341   pCode *pc;
2342   if(!fname)
2343     return NULL;
2344
2345   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2346
2347     pc = setFirstItem(pb->function_entries);
2348     while(pc) {
2349     
2350       if((pc->type == PC_FUNCTION) &&
2351          (PCF(pc)->fname) && 
2352          (strcmp(fname, PCF(pc)->fname)==0))
2353         return pc;
2354
2355       pc = setNextItem(pb->function_entries);
2356
2357     }
2358
2359   }
2360   return NULL;
2361 }
2362
2363 void MarkUsedRegisters(set *regset)
2364 {
2365
2366   regs *r1,*r2;
2367
2368   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
2369     r2 = pic14_regWithIdx(r1->rIdx);
2370     r2->isFree = 0;
2371     r2->wasUsed = 1;
2372   }
2373 }
2374
2375 void pBlockStats(FILE *of, pBlock *pb)
2376 {
2377
2378   pCode *pc;
2379   regs  *r;
2380
2381   fprintf(of,"***\n  pBlock Stats\n***\n");
2382
2383   // for now just print the first element of each set
2384   pc = setFirstItem(pb->function_entries);
2385   if(pc) {
2386     fprintf(of,"entry\n");
2387     pc->print(of,pc);
2388   }
2389   pc = setFirstItem(pb->function_exits);
2390   if(pc) {
2391     fprintf(of,"has an exit\n");
2392     pc->print(of,pc);
2393   }
2394
2395   pc = setFirstItem(pb->function_calls);
2396   if(pc) {
2397     fprintf(of,"functions called\n");
2398
2399     while(pc) {
2400       pc->print(of,pc);
2401       pc = setNextItem(pb->function_calls);
2402     }
2403   }
2404
2405   r = setFirstItem(pb->registers);
2406   if(r) {
2407     int n = elementsInSet(pb->registers);
2408
2409     fprintf(of,"%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
2410
2411     while (r) {
2412       fprintf(of,"   %s\n",r->name);
2413       r = setNextItem(pb->registers);
2414     }
2415   }
2416 }
2417
2418 /*-----------------------------------------------------------------*/
2419 /*-----------------------------------------------------------------*/
2420 void sequencepCode(void)
2421 {
2422   pBlock *pb;
2423   pCode *pc;
2424
2425
2426   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2427
2428     pb->seq = GpCodeSequenceNumber+1;
2429
2430     for( pc = pb->pcHead; pc; pc = pc->next)
2431       pc->seq = ++GpCodeSequenceNumber;
2432   }
2433
2434 }
2435
2436 /*-----------------------------------------------------------------*/
2437 /*-----------------------------------------------------------------*/
2438 set *register_usage(pBlock *pb)
2439 {
2440   pCode *pc,*pcn;
2441   set *registers=NULL;
2442   set *registersInCallPath = NULL;
2443
2444   /* check recursion */
2445
2446   pc = setFirstItem(pb->function_entries);
2447
2448   if(!pc)
2449     return registers;
2450
2451   pb->visited = 1;
2452
2453   if(pc->type != PC_FUNCTION)
2454     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
2455
2456   pc = setFirstItem(pb->function_calls);
2457   for( ; pc; pc = setNextItem(pb->function_calls)) {
2458
2459     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2460       char *dest = get_op(PCI(pc));
2461
2462       pcn = findFunction(dest);
2463       if(pcn) 
2464         registersInCallPath = register_usage(pcn->pb);
2465     } else
2466       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2467
2468   }
2469
2470
2471   pBlockStats(stderr,pb);  // debug
2472
2473   // Mark the registers in this block as used.
2474
2475   MarkUsedRegisters(pb->registers);
2476   if(registersInCallPath) {
2477     /* registers were used in the functions this pBlock has called */
2478     /* so now, we need to see if these collide with the ones we are */
2479     /* using here */
2480
2481     regs *r1,*r2, *newreg;
2482
2483     fprintf(stderr,"comparing registers\n");
2484
2485     r1 = setFirstItem(registersInCallPath);
2486     while(r1) {
2487
2488       r2 = setFirstItem(pb->registers);
2489
2490       while(r2) {
2491
2492         if(r2->rIdx == r1->rIdx) {
2493           newreg = pic14_findFreeReg();
2494
2495
2496           if(!newreg) {
2497             fprintf(stderr,"Bummer, no more registers.\n");
2498             exit(1);
2499           }
2500
2501           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2502                   r1->rIdx, newreg->rIdx);
2503           r2->rIdx = newreg->rIdx;
2504           //if(r2->name) free(r2->name);
2505           if(newreg->name)
2506             r2->name = Safe_strdup(newreg->name);
2507           else
2508             r2->name = NULL;
2509           newreg->isFree = 0;
2510           newreg->wasUsed = 1;
2511         }
2512         r2 = setNextItem(pb->registers);
2513       }
2514
2515       r1 = setNextItem(registersInCallPath);
2516     }
2517
2518     /* Collisions have been resolved. Now free the registers in the call path */
2519     r1 = setFirstItem(registersInCallPath);
2520     while(r1) {
2521       newreg = pic14_regWithIdx(r1->rIdx);
2522       newreg->isFree = 1;
2523       r1 = setNextItem(registersInCallPath);
2524     }
2525
2526   }// else
2527   //    MarkUsedRegisters(pb->registers);
2528
2529   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2530
2531   if(registers) 
2532     fprintf(stderr,"returning regs\n");
2533   else
2534     fprintf(stderr,"not returning regs\n");
2535
2536   fprintf(stderr,"pBlock after register optim.\n");
2537   pBlockStats(stderr,pb);  // debug
2538
2539
2540   return registers;
2541 }
2542
2543 /*-----------------------------------------------------------------*/
2544 /* printCallTree - writes the call tree to a file                  */
2545 /*                                                                 */
2546 /*-----------------------------------------------------------------*/
2547 void pct2(FILE *of,pBlock *pb,int indent)
2548 {
2549   pCode *pc,*pcn;
2550   int i;
2551   //  set *registersInCallPath = NULL;
2552
2553   if(!of)
2554     return;// registers;
2555
2556   if(indent > 10)
2557     return; // registers;   //recursion ?
2558
2559   pc = setFirstItem(pb->function_entries);
2560
2561   if(!pc)
2562     return;
2563
2564   pb->visited = 0;
2565
2566   for(i=0;i<indent;i++)   // Indentation
2567     fputc(' ',of);
2568
2569   if(pc->type == PC_FUNCTION)
2570     fprintf(of,"%s\n",PCF(pc)->fname);
2571   else
2572     return;  // ???
2573
2574
2575   pc = setFirstItem(pb->function_calls);
2576   for( ; pc; pc = setNextItem(pb->function_calls)) {
2577
2578     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2579       char *dest = get_op(PCI(pc));
2580
2581       pcn = findFunction(dest);
2582       if(pcn) 
2583         pct2(of,pcn->pb,indent+1);
2584     } else
2585       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2586
2587   }
2588
2589
2590 }
2591
2592 #if 0
2593   fprintf(stderr,"pBlock before register optim.\n");
2594   pBlockStats(stderr,pb);  // debug
2595
2596   if(registersInCallPath) {
2597     /* registers were used in the functions this pBlock has called */
2598     /* so now, we need to see if these collide with the ones we are using here */
2599
2600     regs *r1,*r2, *newreg;
2601
2602     fprintf(stderr,"comparing registers\n");
2603
2604     r1 = setFirstItem(registersInCallPath);
2605     while(r1) {
2606
2607       r2 = setFirstItem(pb->registers);
2608
2609       while(r2) {
2610
2611         if(r2->rIdx == r1->rIdx) {
2612           newreg = pic14_findFreeReg();
2613
2614
2615           if(!newreg) {
2616             fprintf(stderr,"Bummer, no more registers.\n");
2617             exit(1);
2618           }
2619
2620           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2621                   r1->rIdx, newreg->rIdx);
2622           r2->rIdx = newreg->rIdx;
2623           //if(r2->name) free(r2->name);
2624           if(newreg->name)
2625             r2->name = Safe_strdup(newreg->name);
2626           else
2627             r2->name = NULL;
2628           newreg->isFree = 0;
2629           newreg->wasUsed = 1;
2630         }
2631         r2 = setNextItem(pb->registers);
2632       }
2633
2634       r1 = setNextItem(registersInCallPath);
2635     }
2636
2637     /* Collisions have been resolved. Now free the registers in the call path */
2638     r1 = setFirstItem(registersInCallPath);
2639     while(r1) {
2640       newreg = pic14_regWithIdx(r1->rIdx);
2641       newreg->isFree = 1;
2642       r1 = setNextItem(registersInCallPath);
2643     }
2644
2645   } else
2646     MarkUsedRegisters(pb->registers);
2647
2648   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2649
2650   if(registers) 
2651     fprintf(stderr,"returning regs\n");
2652   else
2653     fprintf(stderr,"not returning regs\n");
2654
2655   fprintf(stderr,"pBlock after register optim.\n");
2656   pBlockStats(stderr,pb);  // debug
2657
2658
2659   return registers;
2660
2661 #endif
2662
2663
2664 /*-----------------------------------------------------------------*/
2665 /* printCallTree - writes the call tree to a file                  */
2666 /*                                                                 */
2667 /*-----------------------------------------------------------------*/
2668
2669 void printCallTree(FILE *of)
2670 {
2671   pBranch *pbr;
2672   pBlock  *pb;
2673   pCode   *pc;
2674
2675   if(!the_pFile)
2676     return;
2677
2678   if(!of)
2679     of = stderr;
2680
2681   fprintf(of, "\npBlock statistics\n");
2682   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
2683     pBlockStats(stderr,pb);
2684
2685
2686
2687   fprintf(of,"Call Tree\n");
2688   pbr = the_pFile->functions;
2689   while(pbr) {
2690     if(pbr->pc) {
2691       pc = pbr->pc;
2692       if(!ispCodeFunction(pc))
2693         fprintf(of,"bug in call tree");
2694
2695
2696       fprintf(of,"Function: %s\n", PCF(pc)->fname);
2697
2698       while(pc->next && !ispCodeFunction(pc->next)) {
2699         pc = pc->next;
2700         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
2701           fprintf(of,"\t%s\n",get_op(PCI(pc)));
2702       }
2703     }
2704
2705     pbr = pbr->next;
2706   }
2707
2708
2709   /* Re-allocate the registers so that there are no collisions
2710    * between local variables when one function call another */
2711
2712   pic14_deallocateAllRegs();
2713
2714   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2715     if(!pb->visited)
2716       register_usage(pb);
2717   }
2718
2719   fprintf(of,"\n**************\n\na better call tree\n");
2720   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2721     if(pb->visited)
2722       pct2(of,pb,0);
2723   }
2724
2725   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2726     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
2727   }
2728 }