dd15d09c0b03d5b37671a65ac30be36d06ca3f16
[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 char *Safe_strdup(char *str)
741 {
742   char *copy;
743
744   if(!str)
745     return NULL;
746
747   copy = strdup(str);
748   if(!copy) {
749     fprintf(stderr, "out of memory %s,%d\n",__FUNCTION__,__LINE__);
750     exit(1);
751   }
752
753   return copy;
754     
755 }
756
757
758 /*-----------------------------------------------------------------*/
759 /* SAFE_snprintf - like snprintf except the string pointer is      */
760 /*                 after the string has been printed to. This is   */
761 /*                 useful for printing to string as though if it   */
762 /*                 were a stream.                                  */
763 /*-----------------------------------------------------------------*/
764 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
765 {
766   va_list val;
767   int len;
768
769   if(!str || !*str)
770     return;
771
772   va_start(val, format);
773 #if 0
774   // Alas, vsnprintf is not ANSI standard, and does not exist
775   // on Solaris (and probably other non-Gnu flavored Unixes).
776   vsnprintf(*str, *size, format, val);
777 #else
778   // This, of course, is *not* safe, despite the name.
779   vsprintf(*str, format, val);
780 #endif
781     
782   va_end (val);
783
784   len = strlen(*str);
785   *str += len;
786   *size -= len;
787
788 }
789
790 void  pCodeInitRegisters(void)
791 {
792
793   pc_fsr.rIdx = 4;
794   pc_fsr.r = pic14_regWithIdx(4);
795
796 }
797
798 /*-----------------------------------------------------------------*/
799 /*  mnem2key - convert a pic mnemonic into a hash key              */
800 /*   (BTW - this spreads the mnemonics quite well)                 */
801 /*                                                                 */
802 /*-----------------------------------------------------------------*/
803
804 int mnem2key(char const *mnem)
805 {
806   int key = 0;
807
808   if(!mnem)
809     return 0;
810
811   while(*mnem) {
812
813     key += toupper(*mnem++) +1;
814
815   }
816
817   return (key & 0x1f);
818
819 }
820
821 void pic14initMnemonics(void)
822 {
823   int i = 0;
824   int key;
825   //  char *str;
826   pCodeInstruction *pci;
827
828   if(mnemonics_initialized)
829     return;
830
831   pic14Mnemonics[POC_ADDLW] = &pciADDLW;
832   pic14Mnemonics[POC_ADDWF] = &pciADDWF;
833   pic14Mnemonics[POC_ADDFW] = &pciADDFW;
834   pic14Mnemonics[POC_ANDLW] = &pciANDLW;
835   pic14Mnemonics[POC_ANDWF] = &pciANDWF;
836   pic14Mnemonics[POC_ANDFW] = &pciANDFW;
837   pic14Mnemonics[POC_BCF] = &pciBCF;
838   pic14Mnemonics[POC_BSF] = &pciBSF;
839   pic14Mnemonics[POC_BTFSC] = &pciBTFSC;
840   pic14Mnemonics[POC_BTFSS] = &pciBTFSS;
841   pic14Mnemonics[POC_CALL] = &pciCALL;
842   pic14Mnemonics[POC_COMF] = &pciCOMF;
843   pic14Mnemonics[POC_COMFW] = &pciCOMFW;
844   pic14Mnemonics[POC_CLRF] = &pciCLRF;
845   pic14Mnemonics[POC_CLRW] = &pciCLRW;
846   pic14Mnemonics[POC_DECF] = &pciDECF;
847   pic14Mnemonics[POC_DECFW] = &pciDECFW;
848   pic14Mnemonics[POC_DECFSZ] = &pciDECFSZ;
849   pic14Mnemonics[POC_DECFSZW] = &pciDECFSZW;
850   pic14Mnemonics[POC_GOTO] = &pciGOTO;
851   pic14Mnemonics[POC_INCF] = &pciINCF;
852   pic14Mnemonics[POC_INCFW] = &pciINCFW;
853   pic14Mnemonics[POC_INCFSZ] = &pciINCFSZ;
854   pic14Mnemonics[POC_INCFSZW] = &pciINCFSZW;
855   pic14Mnemonics[POC_IORLW] = &pciIORLW;
856   pic14Mnemonics[POC_IORWF] = &pciIORWF;
857   pic14Mnemonics[POC_IORFW] = &pciIORFW;
858   pic14Mnemonics[POC_MOVF] = &pciMOVF;
859   pic14Mnemonics[POC_MOVFW] = &pciMOVFW;
860   pic14Mnemonics[POC_MOVLW] = &pciMOVLW;
861   pic14Mnemonics[POC_MOVWF] = &pciMOVWF;
862   pic14Mnemonics[POC_NEGF] = &pciNEGF;
863   pic14Mnemonics[POC_RETLW] = &pciRETLW;
864   pic14Mnemonics[POC_RETURN] = &pciRETURN;
865   pic14Mnemonics[POC_RLF] = &pciRLF;
866   pic14Mnemonics[POC_RLFW] = &pciRLFW;
867   pic14Mnemonics[POC_RRF] = &pciRRF;
868   pic14Mnemonics[POC_RRFW] = &pciRRFW;
869   pic14Mnemonics[POC_SUBLW] = &pciSUBLW;
870   pic14Mnemonics[POC_SUBWF] = &pciSUBWF;
871   pic14Mnemonics[POC_SUBFW] = &pciSUBFW;
872   pic14Mnemonics[POC_SWAPF] = &pciSWAPF;
873   pic14Mnemonics[POC_SWAPFW] = &pciSWAPFW;
874   pic14Mnemonics[POC_TRIS] = &pciTRIS;
875   pic14Mnemonics[POC_XORLW] = &pciXORLW;
876   pic14Mnemonics[POC_XORWF] = &pciXORWF;
877   pic14Mnemonics[POC_XORFW] = &pciXORFW;
878
879   for(i=0; i<MAX_PIC14MNEMONICS; i++)
880     if(pic14Mnemonics[i])
881       hTabAddItem(&pic14MnemonicsHash, mnem2key(pic14Mnemonics[i]->mnemonic), pic14Mnemonics[i]);
882   pci = hTabFirstItem(pic14MnemonicsHash, &key);
883
884   while(pci) {
885     fprintf( stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic);
886     pci = hTabNextItem(pic14MnemonicsHash, &key);
887   }
888
889   mnemonics_initialized = 1;
890 }
891
892 int getpCode(char *mnem,unsigned dest)
893 {
894
895   pCodeInstruction *pci;
896   int key = mnem2key(mnem);
897
898   if(!mnemonics_initialized)
899     pic14initMnemonics();
900
901   pci = hTabFirstItemWK(pic14MnemonicsHash, key);
902
903   while(pci) {
904
905     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
906       if((pci->num_ops <= 1) || (pci->dest == dest))
907         return(pci->op);
908     }
909
910     pci = hTabNextItemWK (pic14MnemonicsHash);
911   
912   }
913
914   return -1;
915 }
916
917 char getpBlock_dbName(pBlock *pb)
918 {
919   if(!pb)
920     return 0;
921
922   if(pb->cmemmap)
923     return pb->cmemmap->dbName;
924
925   return pb->dbName;
926 }
927 /*-----------------------------------------------------------------*/
928 /* movepBlock2Head - given the dbname of a pBlock, move all        */
929 /*                   instances to the front of the doubly linked   */
930 /*                   list of pBlocks                               */
931 /*-----------------------------------------------------------------*/
932
933 void movepBlock2Head(char dbName)
934 {
935   pBlock *pb;
936
937   pb = the_pFile->pbHead;
938
939   while(pb) {
940
941     if(getpBlock_dbName(pb) == dbName) {
942       pBlock *pbn = pb->next;
943       pb->next = the_pFile->pbHead;
944       the_pFile->pbHead->prev = pb;
945       the_pFile->pbHead = pb;
946
947       if(pb->prev)
948         pb->prev->next = pbn;
949
950       // If the pBlock that we just moved was the last
951       // one in the link of all of the pBlocks, then we
952       // need to point the tail to the block just before
953       // the one we moved.
954       // Note: if pb->next is NULL, then pb must have 
955       // been the last pBlock in the chain.
956
957       if(pbn)
958         pbn->prev = pb->prev;
959       else
960         the_pFile->pbTail = pb->prev;
961
962       pb = pbn;
963
964     } else
965       pb = pb->next;
966
967   }
968
969 }
970
971 void copypCode(FILE *of, char dbName)
972 {
973   pBlock *pb;
974
975   if(!of || !the_pFile)
976     return;
977
978   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
979     if(getpBlock_dbName(pb) == dbName)
980       printpBlock(of,pb);
981   }
982
983 }
984 void pcode_test(void)
985 {
986
987   printf("pcode is alive!\n");
988
989   //initMnemonics();
990
991   if(the_pFile) {
992
993     pBlock *pb;
994     FILE *pFile;
995     char buffer[100];
996
997     /* create the file name */
998     strcpy(buffer,srcFileName);
999     strcat(buffer,".p");
1000
1001     if( !(pFile = fopen(buffer, "w" ))) {
1002       werror(E_FILE_OPEN_ERR,buffer);
1003       exit(1);
1004     }
1005
1006     fprintf(pFile,"pcode dump\n\n");
1007
1008     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1009       fprintf(pFile,"\n\tNew pBlock\n\n");
1010       if(pb->cmemmap)
1011         fprintf(pFile,"%s",pb->cmemmap->sname);
1012       else
1013         fprintf(pFile,"internal pblock");
1014
1015       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
1016       printpBlock(pFile,pb);
1017     }
1018   }
1019 }
1020 static int RegCond(pCodeOp *pcop)
1021 {
1022
1023   if(!pcop)
1024     return 0;
1025
1026   if(pcop->type == PO_BIT  && !strcmp(pcop->name, pc_status.pcop.name)) {
1027     switch(PCOB(pcop)->bit) {
1028     case PIC_C_BIT:
1029       return PCC_C;
1030     case PIC_DC_BIT:
1031         return PCC_DC;
1032     case PIC_Z_BIT:
1033       return PCC_Z;
1034     }
1035
1036   }
1037
1038   return 0;
1039 }
1040
1041 /*-----------------------------------------------------------------*/
1042 /* newpCode - create and return a newly initialized pCode          */
1043 /*                                                                 */
1044 /*  fixme - rename this                                            */
1045 /*                                                                 */
1046 /* The purpose of this routine is to create a new Instruction      */
1047 /* pCode. This is called by gen.c while the assembly code is being */
1048 /* generated.                                                      */
1049 /*                                                                 */
1050 /* Inouts:                                                         */
1051 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
1052 /*                  (note that the op is analogous to but not the  */
1053 /*                  same thing as the opcode of the instruction.)  */
1054 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
1055 /*                                                                 */
1056 /* Outputs:                                                        */
1057 /*  a pointer to the new malloc'd pCode is returned.               */
1058 /*                                                                 */
1059 /*                                                                 */
1060 /*                                                                 */
1061 /*-----------------------------------------------------------------*/
1062 pCode *newpCode (PIC_OPCODE op, pCodeOp *pcop)
1063 {
1064   pCodeInstruction *pci ;
1065
1066   if(!mnemonics_initialized)
1067     pic14initMnemonics();
1068     
1069   pci = Safe_calloc(1, sizeof(pCodeInstruction));
1070
1071   if((op>=0) && (op < MAX_PIC14MNEMONICS) && pic14Mnemonics[op]) {
1072     memcpy(pci, pic14Mnemonics[op], sizeof(pCodeInstruction));
1073     pci->pcop = pcop;
1074
1075     if(pci->inCond == PCC_EXAMINE_PCOP)
1076       pci->inCond   = RegCond(pcop);
1077
1078     if(pci->outCond == PCC_EXAMINE_PCOP)
1079       pci->outCond   = RegCond(pcop);
1080
1081     return (pCode *)pci;
1082   }
1083
1084   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
1085   exit(1);
1086
1087   return NULL;
1088 }       
1089
1090 /*-----------------------------------------------------------------*/
1091 /* newpCodeWild - create a "wild" as in wild card pCode            */
1092 /*                                                                 */
1093 /* Wild pcodes are used during the peep hole optimizer to serve    */
1094 /* as place holders for any instruction. When a snippet of code is */
1095 /* compared to a peep hole rule, the wild card opcode will match   */
1096 /* any instruction. However, the optional operand and label are    */
1097 /* additional qualifiers that must also be matched before the      */
1098 /* line (of assembly code) is declared matched. Note that the      */
1099 /* operand may be wild too.                                        */
1100 /*                                                                 */
1101 /*   Note, a wild instruction is specified just like a wild var:   */
1102 /*      %4     ; A wild instruction,                               */
1103 /*  See the peeph.def file for additional examples                 */
1104 /*                                                                 */
1105 /*-----------------------------------------------------------------*/
1106
1107 pCode *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
1108 {
1109
1110   pCodeWild *pcw;
1111     
1112   pcw = Safe_calloc(1,sizeof(pCodeWild));
1113
1114   pcw->pc.type = PC_WILD;
1115   pcw->pc.prev = pcw->pc.next = NULL;
1116   pcw->pc.from = pcw->pc.to = pcw->pc.label = NULL;
1117   pcw->pc.pb = NULL;
1118
1119   pcw->pc.analyze = genericAnalyze;
1120   pcw->pc.destruct = genericDestruct;
1121   pcw->pc.print = genericPrint;
1122
1123   pcw->id = pCodeID;              // this is the 'n' in %n
1124   pcw->operand = optional_operand;
1125   pcw->label   = optional_label;
1126
1127   return ( (pCode *)pcw);
1128   
1129 }
1130
1131 /*-----------------------------------------------------------------*/
1132 /* newPcodeCharP - create a new pCode from a char string           */
1133 /*-----------------------------------------------------------------*/
1134
1135 pCode *newpCodeCharP(char *cP)
1136 {
1137
1138   pCodeComment *pcc ;
1139     
1140   pcc = Safe_calloc(1,sizeof(pCodeComment));
1141
1142   pcc->pc.type = PC_COMMENT;
1143   pcc->pc.prev = pcc->pc.next = NULL;
1144   pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
1145   pcc->pc.pb = NULL;
1146
1147   pcc->pc.analyze = genericAnalyze;
1148   pcc->pc.destruct = genericDestruct;
1149   pcc->pc.print = genericPrint;
1150
1151   pcc->comment = Safe_strdup(cP);
1152
1153   return ( (pCode *)pcc);
1154
1155 }
1156
1157 /*-----------------------------------------------------------------*/
1158 /* newpCodeGLabel - create a new global label                      */
1159 /*-----------------------------------------------------------------*/
1160
1161
1162 pCode *newpCodeFunction(char *mod,char *f)
1163 {
1164   pCodeFunction *pcf;
1165
1166   _ALLOC(pcf,sizeof(pCodeFunction));
1167
1168   pcf->pc.type = PC_FUNCTION;
1169   pcf->pc.prev = pcf->pc.next = NULL;
1170   pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
1171   pcf->pc.pb = NULL;
1172
1173   pcf->pc.analyze = genericAnalyze;
1174   pcf->pc.destruct = genericDestruct;
1175   pcf->pc.print = pCodePrintFunction;
1176
1177   if(mod) {
1178     _ALLOC_ATOMIC(pcf->modname,strlen(mod)+1);
1179     strcpy(pcf->modname,mod);
1180   } else
1181     pcf->modname = NULL;
1182
1183   if(f) {
1184     _ALLOC_ATOMIC(pcf->fname,strlen(f)+1);
1185     strcpy(pcf->fname,f);
1186   } else
1187     pcf->fname = NULL;
1188
1189   return ( (pCode *)pcf);
1190
1191 }
1192
1193 static void pCodeLabelDestruct(pCode *pc)
1194 {
1195
1196   if(!pc)
1197     return;
1198
1199   unlinkPC(pc);
1200
1201   if((pc->type == PC_LABEL) && PCL(pc)->label)
1202     free(PCL(pc)->label);
1203
1204   free(pc);
1205
1206 }
1207
1208 pCode *newpCodeLabel(int key)
1209 {
1210
1211   char *s = buffer;
1212   pCodeLabel *pcl;
1213     
1214   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
1215
1216   pcl->pc.type = PC_LABEL;
1217   pcl->pc.prev = pcl->pc.next = NULL;
1218   pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
1219   pcl->pc.pb = NULL;
1220
1221   pcl->pc.analyze = genericAnalyze;
1222   pcl->pc.destruct = pCodeLabelDestruct;
1223   pcl->pc.print = pCodePrintLabel;
1224
1225   pcl->key = key;
1226
1227   if(key>0) {
1228     sprintf(s,"_%05d_DS_",key);
1229     pcl->label = Safe_strdup(s);
1230   } else
1231     pcl->label = NULL;
1232
1233   return ( (pCode *)pcl);
1234
1235 }
1236 pCode *newpCodeLabelStr(char *str)
1237 {
1238   pCode *pc = newpCodeLabel(-1);
1239
1240   PCL(pc)->label = Safe_strdup(str);
1241
1242   return pc;
1243 }
1244
1245 /*-----------------------------------------------------------------*/
1246 /* newpBlock - create and return a pointer to a new pBlock         */
1247 /*-----------------------------------------------------------------*/
1248 pBlock *newpBlock(void)
1249 {
1250
1251   pBlock *PpB;
1252
1253   PpB = Safe_calloc(1,sizeof(pBlock) );
1254   PpB->next = PpB->prev = NULL;
1255
1256   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
1257   PpB->registers = NULL;
1258   PpB->visited = 0;
1259
1260   return PpB;
1261
1262 }
1263
1264 /*-----------------------------------------------------------------*/
1265 /* newpCodeChai0n - create a new chain of pCodes                    */
1266 /*-----------------------------------------------------------------*
1267  *
1268  *  This function will create a new pBlock and the pointer to the
1269  *  pCode that is passed in will be the first pCode in the block.
1270  *-----------------------------------------------------------------*/
1271
1272
1273 pBlock *newpCodeChain(memmap *cm,char c, pCode *pc)
1274 {
1275
1276   pBlock *pB  = newpBlock();
1277
1278   pB->pcHead  = pB->pcTail = pc;
1279   pB->cmemmap = cm;
1280   pB->dbName  = c;
1281
1282   return pB;
1283 }
1284
1285 /*-----------------------------------------------------------------*/
1286 /* newpCodeOpLabel - Create a new label given the key              */
1287 /*  Note, a negative key means that the label is part of wild card */
1288 /*  (and hence a wild card label) used in the pCodePeep            */
1289 /*   optimizations).                                               */
1290 /*-----------------------------------------------------------------*/
1291
1292 pCodeOp *newpCodeOpLabel(int key)
1293 {
1294   char *s = buffer;
1295   pCodeOp *pcop;
1296
1297   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
1298   pcop->type = PO_LABEL;
1299
1300   if(key>0) {
1301     sprintf(s,"_%05d_DS_",key);
1302     pcop->name = Safe_strdup(s);
1303   } else
1304     pcop->name = NULL;
1305
1306   ((pCodeOpLabel *)pcop)->key = key;
1307
1308   return pcop;
1309 }
1310
1311 pCodeOp *newpCodeOpLit(int lit)
1312 {
1313   char *s = buffer;
1314   pCodeOp *pcop;
1315
1316
1317   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
1318   pcop->type = PO_LITERAL;
1319   if(lit>=0) {
1320     sprintf(s,"0x%02x",lit);
1321     pcop->name = Safe_strdup(s);
1322   } else
1323     pcop->name = NULL;
1324
1325   ((pCodeOpLit *)pcop)->lit = lit;
1326
1327   return pcop;
1328 }
1329
1330 pCodeOp *newpCodeOpWild(int id, pCodePeep *pcp, pCodeOp *subtype)
1331 {
1332   char *s = buffer;
1333   pCodeOp *pcop;
1334
1335
1336   if(!pcp || !subtype) {
1337     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
1338     exit(1);
1339   }
1340
1341   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
1342   pcop->type = PO_WILD;
1343   sprintf(s,"%%%d",id);
1344   pcop->name = Safe_strdup(s);
1345
1346   PCOW(pcop)->id = id;
1347   PCOW(pcop)->pcp = pcp;
1348   PCOW(pcop)->subtype = subtype;
1349   PCOW(pcop)->matched = NULL;
1350
1351   return pcop;
1352 }
1353
1354 pCodeOp *newpCodeOpBit(char *s, int bit, int inBitSpace)
1355 {
1356   pCodeOp *pcop;
1357
1358   pcop = Safe_calloc(1,sizeof(pCodeOpBit) );
1359   pcop->type = PO_BIT;
1360   pcop->name = Safe_strdup(s);   
1361
1362   PCOB(pcop)->bit = bit;
1363   PCOB(pcop)->inBitSpace = inBitSpace;
1364
1365   return pcop;
1366 }
1367
1368 pCodeOp *newpCodeOpReg(int rIdx)
1369 {
1370   pCodeOp *pcop;
1371
1372   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
1373
1374   PCOR(pcop)->rIdx = rIdx;
1375   PCOR(pcop)->r = pic14_regWithIdx(rIdx);
1376   pcop->type = PCOR(pcop)->r->pc_type;
1377
1378   return pcop;
1379 }
1380
1381 /*-----------------------------------------------------------------*/
1382 /*-----------------------------------------------------------------*/
1383
1384 pCodeOp *newpCodeOp(char *name, PIC_OPTYPE type)
1385 {
1386   pCodeOp *pcop;
1387
1388   switch(type) {
1389   case PO_BIT:
1390     pcop = newpCodeOpBit(name, -1,0);
1391     break;
1392
1393   case PO_LITERAL:
1394     pcop = newpCodeOpLit(-1);
1395     break;
1396
1397   case PO_LABEL:
1398     pcop = newpCodeOpLabel(-1);
1399     break;
1400
1401   default:
1402     pcop = Safe_calloc(1,sizeof(pCodeOp) );
1403     pcop->type = type;
1404     pcop->name = Safe_strdup(name);   
1405   }
1406
1407   return pcop;
1408 }
1409
1410 /*-----------------------------------------------------------------*/
1411 /* addpCode2pBlock - place the pCode into the pBlock linked list   */
1412 /*-----------------------------------------------------------------*/
1413 void addpCode2pBlock(pBlock *pb, pCode *pc)
1414 {
1415   if(!pb->pcHead) {
1416     /* If this is the first pcode to be added to a block that
1417      * was initialized with a NULL pcode, then go ahead and
1418      * make this pcode the head and tail */
1419     pb->pcHead  = pb->pcTail = pc;
1420   } else {
1421     pb->pcTail->next = pc;
1422     pc->prev = pb->pcTail;
1423     pc->next = NULL;
1424     pc->pb = pb;
1425     pb->pcTail = pc;
1426   }
1427 }
1428
1429 /*-----------------------------------------------------------------*/
1430 /* addpBlock - place a pBlock into the pFile                       */
1431 /*-----------------------------------------------------------------*/
1432 void addpBlock(pBlock *pb)
1433 {
1434
1435   if(!the_pFile) {
1436     /* First time called, we'll pass through here. */
1437     _ALLOC(the_pFile,sizeof(the_pFile));
1438     the_pFile->pbHead = the_pFile->pbTail = pb;
1439     the_pFile->functions = NULL;
1440     return;
1441   }
1442
1443   the_pFile->pbTail->next = pb;
1444   pb->prev = the_pFile->pbTail;
1445   pb->next = NULL;
1446   the_pFile->pbTail = pb;
1447 }
1448
1449 /*-----------------------------------------------------------------*/
1450 /* printpCode - write the contents of a pCode to a file            */
1451 /*-----------------------------------------------------------------*/
1452 void printpCode(FILE *of, pCode *pc)
1453 {
1454
1455   if(!pc || !of)
1456     return;
1457
1458   if(pc->print) {
1459     pc->print(of,pc);
1460     return;
1461   }
1462
1463   fprintf(of,"warning - unable to print pCode\n");
1464 }
1465
1466 /*-----------------------------------------------------------------*/
1467 /* printpBlock - write the contents of a pBlock to a file          */
1468 /*-----------------------------------------------------------------*/
1469 void printpBlock(FILE *of, pBlock *pb)
1470 {
1471   pCode *pc;
1472
1473   if(!pb)
1474     return;
1475
1476   if(!of)
1477     of = stderr;
1478
1479   for(pc = pb->pcHead; pc; pc = pc->next)
1480     printpCode(of,pc);
1481
1482 }
1483
1484 /*-----------------------------------------------------------------*/
1485 /*                                                                 */
1486 /*       pCode processing                                          */
1487 /*                                                                 */
1488 /*                                                                 */
1489 /*                                                                 */
1490 /*-----------------------------------------------------------------*/
1491
1492 static void unlinkPC(pCode *pc)
1493 {
1494
1495
1496   if(pc) {
1497
1498     if(pc->prev) 
1499       pc->prev->next = pc->next;
1500     if(pc->next)
1501       pc->next->prev = pc->prev;
1502
1503     pc->prev = pc->next = NULL;
1504   }
1505 }
1506 static void genericDestruct(pCode *pc)
1507 {
1508   fprintf(stderr,"warning, calling default pCode destructor\n");
1509
1510   unlinkPC(pc);
1511
1512   free(pc);
1513
1514 }
1515
1516
1517 void pBlockRegs(FILE *of, pBlock *pb)
1518 {
1519
1520   regs  *r;
1521
1522   r = setFirstItem(pb->registers);
1523   while (r) {
1524     r = setNextItem(pb->registers);
1525   }
1526 }
1527
1528
1529 static char *get_op( pCodeInstruction *pcc)
1530 {
1531   regs *r;
1532
1533   if(pcc && pcc->pcop) {
1534
1535
1536     switch(pcc->pcop->type) {
1537
1538     case PO_FSR:
1539     case PO_GPR_TEMP:
1540     case PO_GPR_BIT:
1541       r = pic14_regWithIdx(PCOR(pcc->pcop)->r->rIdx);
1542       //fprintf(stderr,"getop: getting %s\nfrom:\n",r->name); //pcc->pcop->name);
1543       pBlockRegs(stderr,pcc->pc.pb);
1544       return r->name;
1545
1546     default:
1547       if  (pcc->pcop->name)
1548         return pcc->pcop->name;
1549
1550     }
1551   }
1552
1553   return "NO operand";
1554 }
1555
1556 /*-----------------------------------------------------------------*/
1557 /*-----------------------------------------------------------------*/
1558 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
1559 {
1560
1561   fprintf(of,"pcodeopprint\n");
1562 }
1563
1564 char *pCode2str(char *str, int size, pCode *pc)
1565 {
1566   char *s = str;
1567
1568   switch(pc->type) {
1569
1570   case PC_OPCODE:
1571
1572     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
1573
1574     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
1575
1576       if(PCI(pc)->bit_inst) {
1577         if(PCI(pc)->pcop->type == PO_BIT) {
1578           if( (((pCodeOpBit *)(PCI(pc)->pcop))->inBitSpace) )
1579             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
1580                           PCI(pc)->pcop->name ,
1581                           PCI(pc)->pcop->name );
1582           else
1583             SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)), 
1584                           (((pCodeOpBit *)(PCI(pc)->pcop))->bit ));
1585         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
1586           SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
1587         }else
1588           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", get_op(PCI(pc)));
1589         //PCI(pc)->pcop->t.bit );
1590       } else {
1591
1592         if(PCI(pc)->pcop->type == PO_BIT) {
1593           if( PCI(pc)->num_ops == 2)
1594             SAFE_snprintf(&s,&size,"(%s >> 3),%c",get_op(PCI(pc)),((PCI(pc)->dest) ? 'F':'W'));
1595           else
1596             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",get_op(PCI(pc)));
1597
1598         }else {
1599           SAFE_snprintf(&s,&size,"%s",get_op(PCI(pc)));
1600
1601           if( PCI(pc)->num_ops == 2)
1602             SAFE_snprintf(&s,&size,",%c", ( (PCI(pc)->dest) ? 'F':'W'));
1603         }
1604       }
1605
1606     }
1607     break;
1608
1609   case PC_COMMENT:
1610     /* assuming that comment ends with a \n */
1611     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
1612     break;
1613
1614   case PC_LABEL:
1615     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
1616     break;
1617   case PC_FUNCTION:
1618     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
1619     break;
1620   case PC_WILD:
1621     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
1622     break;
1623
1624   }
1625
1626   return str;
1627
1628 }
1629
1630 /*-----------------------------------------------------------------*/
1631 /* genericPrint - the contents of a pCode to a file                */
1632 /*-----------------------------------------------------------------*/
1633 static void genericPrint(FILE *of, pCode *pc)
1634 {
1635
1636   if(!pc || !of)
1637     return;
1638
1639   switch(pc->type) {
1640   case PC_COMMENT:
1641     fprintf(of,";%s\n", ((pCodeComment *)pc)->comment);
1642     break;
1643
1644   case PC_OPCODE:
1645     // If the opcode has a label, print that first
1646     {
1647       pBranch *pbl = pc->label;
1648       while(pbl) {
1649         if(pbl->pc->type == PC_LABEL)
1650           pCodePrintLabel(of, pbl->pc);
1651         pbl = pbl->next;
1652       }
1653     }
1654
1655
1656     {
1657       char str[256];
1658       
1659       pCode2str(str, 256, pc);
1660
1661       fprintf(of,"%s",str);
1662     }
1663
1664     {
1665       pBranch *dpb = pc->to;   // debug
1666       while(dpb) {
1667         switch ( dpb->pc->type) {
1668         case PC_OPCODE:
1669           fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic);
1670           break;
1671         case PC_LABEL:
1672           fprintf(of, "\t;label %d", PCL(dpb->pc)->key);
1673           break;
1674         case PC_FUNCTION:
1675           fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]"));
1676           break;
1677         case PC_COMMENT:
1678         case PC_WILD:
1679           break;
1680         }
1681         dpb = dpb->next;
1682       }
1683       fprintf(of,"\n");
1684     }
1685
1686     break;
1687
1688   case PC_WILD:
1689     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
1690     if(pc->label)
1691       pCodePrintLabel(of, pc->label->pc);
1692
1693     if(PCW(pc)->operand) {
1694       fprintf(of,";\toperand  ");
1695       pCodeOpPrint(of,PCW(pc)->operand );
1696     }
1697     break;
1698
1699   case PC_LABEL:
1700   default:
1701     fprintf(of,"unknown pCode type %d\n",pc->type);
1702   }
1703
1704 }
1705
1706 /*-----------------------------------------------------------------*/
1707 /* pCodePrintFunction - prints function begin/end                  */
1708 /*-----------------------------------------------------------------*/
1709
1710 static void pCodePrintFunction(FILE *of, pCode *pc)
1711 {
1712
1713   if(!pc || !of)
1714     return;
1715
1716   if( ((pCodeFunction *)pc)->modname) 
1717     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
1718
1719   if(PCF(pc)->fname) {
1720     pBranch *exits = pc->to;
1721     int i=0;
1722     fprintf(of,"%s\t;Function start\n",PCF(pc)->fname);
1723     while(exits) {
1724       i++;
1725       exits = exits->next;
1726     }
1727     //if(i) i--;
1728     fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
1729     
1730   }else {
1731     if(pc->from && 
1732        pc->from->pc->type == PC_FUNCTION &&
1733        PCF(pc->from->pc)->fname) 
1734       fprintf(of,"; exit point of %s\n",PCF(pc->from->pc)->fname);
1735     else
1736       fprintf(of,"; exit point [can't find entry point]\n");
1737   }
1738 }
1739 /*-----------------------------------------------------------------*/
1740 /* pCodePrintLabel - prints label                                  */
1741 /*-----------------------------------------------------------------*/
1742
1743 static void pCodePrintLabel(FILE *of, pCode *pc)
1744 {
1745
1746   if(!pc || !of)
1747     return;
1748
1749   if(PCL(pc)->label) 
1750     fprintf(of,"%s\n",PCL(pc)->label);
1751   else if (PCL(pc)->key >=0) 
1752     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
1753   else
1754     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
1755
1756 }
1757 /*-----------------------------------------------------------------*/
1758 static void  unlinkpCodeFromBranch(pBranch *pb , pCode *pc)
1759 {
1760   pBranch *b, *bprev;
1761
1762   bprev = NULL;
1763   b = pb;
1764   while(b) {
1765     if(b->pc == pc) {
1766       if(bprev)
1767         bprev->next = b->next;
1768     }
1769     bprev = b;
1770     b = b->next;
1771   }
1772
1773 }
1774
1775 static pBranch * pBranchAppend(pBranch *h, pBranch *n)
1776 {
1777   pBranch *b;
1778
1779   if(!h)
1780     return n;
1781
1782   b = h;
1783   while(b->next)
1784     b = b->next;
1785
1786   b->next = n;
1787
1788   return h;
1789   
1790 }  
1791 /*-----------------------------------------------------------------*/
1792 /* pBranchLink - given two pcodes, this function will link them    */
1793 /*               together through their pBranches                  */
1794 /*-----------------------------------------------------------------*/
1795 static void pBranchLink(pCode *f, pCode *t)
1796 {
1797   pBranch *b;
1798
1799   // Declare a new branch object for the 'from' pCode.
1800
1801   _ALLOC(b,sizeof(pBranch));
1802   b->pc = t;                    // The link to the 'to' pCode.
1803   b->next = NULL;
1804
1805   f->to = pBranchAppend(f->to,b);
1806
1807   // Now do the same for the 'to' pCode.
1808
1809   _ALLOC(b,sizeof(pBranch));
1810   b->pc = f;
1811   b->next = NULL;
1812
1813   t->from = pBranchAppend(t->from,b);
1814   
1815 }
1816
1817 #if 0
1818 /*-----------------------------------------------------------------*/
1819 /* pBranchFind - find the pBranch in a pBranch chain that contains */
1820 /*               a pCode                                           */
1821 /*-----------------------------------------------------------------*/
1822 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
1823 {
1824   while(pb) {
1825
1826     if(pb->pc == pc)
1827       return pb;
1828
1829     pb = pb->next;
1830   }
1831
1832   return NULL;
1833 }
1834
1835 /*-----------------------------------------------------------------*/
1836 /* pCodeUnlink - Unlink the given pCode from its pCode chain.      */
1837 /*-----------------------------------------------------------------*/
1838 static void pCodeUnlink(pCode *pc)
1839 {
1840   pBranch *pb1,*pb2;
1841   pCode *pc1;
1842
1843   if(!pc->prev || !pc->next) {
1844     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
1845     exit(1);
1846   }
1847
1848   /* first remove the pCode from the chain */
1849   pc->prev->next = pc->next;
1850   pc->next->prev = pc->prev;
1851
1852   /* Now for the hard part... */
1853
1854   /* Remove the branches */
1855
1856   pb1 = pc->from;
1857   while(pb1) {
1858     pc1 = pb1->pc;    /* Get the pCode that branches to the
1859                        * one we're unlinking */
1860
1861     /* search for the link back to this pCode (the one we're
1862      * unlinking) */
1863     if(pb2 = pBranchFind(pc1->to,pc)) {
1864       pb2->pc = pc->to->pc;  // make the replacement
1865
1866       /* if the pCode we're unlinking contains multiple 'to'
1867        * branches (e.g. this a skip instruction) then we need
1868        * to copy these extra branches to the chain. */
1869       if(pc->to->next)
1870         pBranchAppend(pb2, pc->to->next);
1871     }
1872     
1873     pb1 = pb1->next;
1874   }
1875
1876
1877 }
1878 #endif
1879 /*-----------------------------------------------------------------*/
1880 /*-----------------------------------------------------------------*/
1881 static void genericAnalyze(pCode *pc)
1882 {
1883   switch(pc->type) {
1884   case PC_WILD:
1885   case PC_COMMENT:
1886     return;
1887   case PC_LABEL:
1888   case PC_FUNCTION:
1889   case PC_OPCODE:
1890     {
1891       // Go through the pCodes that are in pCode chain and link
1892       // them together through the pBranches. Note, the pCodes
1893       // are linked together as a contiguous stream like the 
1894       // assembly source code lines. The linking here mimics this
1895       // except that comments are not linked in.
1896       // 
1897       pCode *npc = pc->next;
1898       while(npc) {
1899         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
1900           pBranchLink(pc,npc);
1901           return;
1902         } else
1903           npc = npc->next;
1904       }
1905     }
1906   }
1907 }
1908
1909 /*-----------------------------------------------------------------*/
1910 int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
1911 {
1912   pBranch *pbr;
1913
1914   if(pc->type == PC_LABEL) {
1915     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
1916       return TRUE;
1917   }
1918   if(pc->type == PC_OPCODE) {
1919     pbr = pc->label;
1920     while(pbr) {
1921       if(pbr->pc->type == PC_LABEL) {
1922         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
1923           return TRUE;
1924       }
1925       pbr = pbr->next;
1926     }
1927   }
1928
1929   return FALSE;
1930 }
1931
1932 /*-----------------------------------------------------------------*/
1933 /* findLabel - Search the pCode for a particular label             */
1934 /*-----------------------------------------------------------------*/
1935 pCode * findLabel(pCodeOpLabel *pcop_label)
1936 {
1937   pBlock *pb;
1938   pCode  *pc;
1939
1940   if(!the_pFile)
1941     return NULL;
1942
1943   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1944     for(pc = pb->pcHead; pc; pc = pc->next) 
1945       if(compareLabel(pc,pcop_label))
1946         return pc;
1947     
1948   }
1949
1950   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
1951   return NULL;
1952 }
1953
1954 /*-----------------------------------------------------------------*/
1955 /* findNextInstruction - given a pCode, find the next instruction  */
1956 /*                       in the linked list                        */
1957 /*-----------------------------------------------------------------*/
1958 pCode * findNextInstruction(pCode *pc)
1959 {
1960
1961   while(pc) {
1962     if((pc->type == PC_OPCODE) || (pc->type == PC_WILD))
1963       return pc;
1964
1965     pc = pc->next;
1966   }
1967
1968   fprintf(stderr,"Couldn't find instruction\n");
1969   return NULL;
1970 }
1971
1972 /*-----------------------------------------------------------------*/
1973 /* findFunctionEnd - given a pCode find the end of the function    */
1974 /*                   that contains it     t                        */
1975 /*-----------------------------------------------------------------*/
1976 pCode * findFunctionEnd(pCode *pc)
1977 {
1978
1979   while(pc) {
1980     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
1981       return pc;
1982
1983     pc = pc->next;
1984   }
1985
1986   fprintf(stderr,"Couldn't find function end\n");
1987   return NULL;
1988 }
1989
1990 #if 0
1991 /*-----------------------------------------------------------------*/
1992 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
1993 /*                instruction with which it is associated.         */
1994 /*-----------------------------------------------------------------*/
1995 static void AnalyzeLabel(pCode *pc)
1996 {
1997
1998   pCodeUnlink(pc);
1999
2000 }
2001 #endif
2002
2003 static void AnalyzeGOTO(pCode *pc)
2004 {
2005
2006   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
2007
2008 }
2009
2010 static void AnalyzeSKIP(pCode *pc)
2011 {
2012
2013   pBranchLink(pc,findNextInstruction(pc->next));
2014   pBranchLink(pc,findNextInstruction(pc->next->next));
2015
2016 }
2017
2018 static void AnalyzeRETURN(pCode *pc)
2019 {
2020
2021   //  branch_link(pc,findFunctionEnd(pc->next));
2022
2023 }
2024
2025
2026 void AnalyzepBlock(pBlock *pb)
2027 {
2028   pCode *pc;
2029
2030   if(!pb)
2031     return;
2032
2033   /* Find all of the registers used in this pBlock */
2034   for(pc = pb->pcHead; pc; pc = pc->next) {
2035     if(pc->type == PC_OPCODE) {
2036       if(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_TEMP) {
2037
2038         /* Loop through all of the registers declared so far in
2039            this block and see if we find this new there */
2040
2041         regs *r = setFirstItem(pb->registers);
2042
2043         while(r) {
2044           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
2045             PCOR(PCI(pc)->pcop)->r = r;
2046             break;
2047           }
2048           r = setNextItem(pb->registers);
2049         }
2050
2051         if(!r) {
2052           /* register wasn't found */
2053           r = Safe_calloc(1, sizeof(regs));
2054           memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
2055           addSet(&pb->registers, r);
2056           PCOR(PCI(pc)->pcop)->r = r;
2057           fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
2058         } else 
2059           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
2060       }
2061     }
2062   }
2063 }
2064
2065 int OptimizepBlock(pBlock *pb)
2066 {
2067   pCode *pc;
2068   int matches =0;
2069
2070   if(!pb || !peepOptimizing)
2071     return 0;
2072
2073   fprintf(stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb));
2074   for(pc = pb->pcHead; pc; pc = pc->next)
2075     matches += pCodePeepMatchRule(pc);
2076
2077   return matches;
2078
2079 }
2080
2081 /*-----------------------------------------------------------------*/
2082 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2083 /*-----------------------------------------------------------------*/
2084 pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
2085 {
2086   pCode *pc;
2087
2088   for(pc = pcs; pc; pc = pc->next) {
2089
2090     if((pc->type == PC_OPCODE) && 
2091        (PCI(pc)->pcop) && 
2092        (PCI(pc)->pcop->type == PO_LABEL) &&
2093        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
2094       return pc;
2095   }
2096  
2097
2098   return NULL;
2099 }
2100
2101 /*-----------------------------------------------------------------*/
2102 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2103 /*                            pCode chain if they're not used.     */
2104 /*-----------------------------------------------------------------*/
2105 void pBlockRemoveUnusedLabels(pBlock *pb)
2106 {
2107   pCode *pc; pCodeLabel *pcl;
2108
2109   if(!pb)
2110     return;
2111
2112   for(pc = pb->pcHead; pc; pc = pc->next) {
2113
2114     if(pc->type == PC_LABEL)
2115       pcl = PCL(pc);
2116     else if (pc->label)
2117       pcl = PCL(pc->label->pc);
2118     else continue;
2119
2120       /* This pCode is a label, so search the pBlock to see if anyone
2121        * refers to it */
2122
2123     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))) {
2124       /* Couldn't find an instruction that refers to this label
2125        * So, unlink the pCode label from it's pCode chain
2126        * and destroy the label */
2127
2128       fprintf(stderr," !!! REMOVED A LABEL !!! key = %d\n", pcl->key);
2129
2130       if(pc->type == PC_LABEL) {
2131         //unlinkPC(pc);
2132         pCodeLabelDestruct(pc);
2133       } else {
2134         unlinkpCodeFromBranch(pc->label, pc);
2135         if(pc->label->next == NULL && pc->label->pc == NULL) {
2136           free(pc->label);
2137         }
2138       }
2139
2140     }
2141   }
2142
2143 }
2144
2145
2146 /*-----------------------------------------------------------------*/
2147 /* pBlockMergeLabels - remove the pCode labels from the pCode      */
2148 /*                     chain and put them into pBranches that are  */
2149 /*                     associated with the appropriate pCode       */
2150 /*                     instructions.                               */
2151 /*-----------------------------------------------------------------*/
2152 void pBlockMergeLabels(pBlock *pb)
2153 {
2154   pBranch *pbr;
2155   pCode *pc, *pcnext=NULL;
2156
2157   if(!pb)
2158     return;
2159
2160   /* First, Try to remove any unused labels */
2161   //pBlockRemoveUnusedLabels(pb);
2162
2163   /* Now loop through the pBlock and merge the labels with the opcodes */
2164
2165   for(pc = pb->pcHead; pc; pc = pc->next) {
2166
2167     if(pc->type == PC_LABEL) {
2168       fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
2169       if( !(pcnext = findNextInstruction(pc)) ) 
2170         return;  // Couldn't find an instruction associated with this label
2171
2172       // Unlink the pCode label from it's pCode chain
2173       unlinkPC(pc);
2174
2175       fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
2176       // And link it into the instruction's pBranch labels. (Note, since
2177       // it's possible to have multiple labels associated with one instruction
2178       // we must provide a means to accomodate the additional labels. Thus
2179       // the labels are placed into the singly-linked list "label" as 
2180       // opposed to being a single member of the pCodeInstruction.)
2181
2182       _ALLOC(pbr,sizeof(pBranch));
2183       pbr->pc = pc;
2184       pbr->next = NULL;
2185
2186       pcnext->label = pBranchAppend(pcnext->label,pbr);
2187       if(pcnext->prev) 
2188         pc = pcnext->prev;
2189       else
2190         pc = pcnext;
2191     }
2192
2193   }
2194   pBlockRemoveUnusedLabels(pb);
2195
2196 }
2197
2198 /*-----------------------------------------------------------------*/
2199 /*-----------------------------------------------------------------*/
2200 void OptimizepCode(char dbName)
2201 {
2202 #define MAX_PASSES 4
2203
2204   int matches = 0;
2205   int passes = 0;
2206   pBlock *pb;
2207
2208   if(!the_pFile)
2209     return;
2210
2211   fprintf(stderr," Optimizing pCode\n");
2212
2213   do {
2214     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2215       if('*' == dbName || getpBlock_dbName(pb) == dbName)
2216         matches += OptimizepBlock(pb);
2217     }
2218   }
2219   while(matches && ++passes < MAX_PASSES);
2220
2221 }
2222
2223 /*-----------------------------------------------------------------*/
2224 /* AnalyzepCode - parse the pCode that has been generated and form */
2225 /*                all of the logical connections.                  */
2226 /*                                                                 */
2227 /* Essentially what's done here is that the pCode flow is          */
2228 /* determined.                                                     */
2229 /*-----------------------------------------------------------------*/
2230
2231 void AnalyzepCode(char dbName)
2232 {
2233   pBlock *pb;
2234   pCode *pc;
2235   pBranch *pbr;
2236
2237   if(!the_pFile)
2238     return;
2239
2240   fprintf(stderr," Analyzing pCode");
2241
2242   /* First, merge the labels with the instructions */
2243   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2244     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2245
2246       fprintf(stderr," analyze and merging block %c\n",dbName);
2247       pBlockMergeLabels(pb);
2248       AnalyzepBlock(pb);
2249     }
2250   }
2251
2252   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2253     if('*' == dbName || getpBlock_dbName(pb) == dbName)
2254       OptimizepBlock(pb);
2255   }
2256
2257   /* Now build the call tree.
2258      First we examine all of the pCodes for functions.
2259      Keep in mind that the function boundaries coincide
2260      with pBlock boundaries. 
2261
2262      The algorithm goes something like this:
2263      We have two nested loops. The outer loop iterates
2264      through all of the pBlocks/functions. The inner
2265      loop iterates through all of the pCodes for
2266      a given pBlock. When we begin iterating through
2267      a pBlock, the variable pc_fstart, pCode of the start
2268      of a function, is cleared. We then search for pCodes
2269      of type PC_FUNCTION. When one is encountered, we
2270      initialize pc_fstart to this and at the same time
2271      associate a new pBranch object that signifies a 
2272      branch entry. If a return is found, then this signifies
2273      a function exit point. We'll link the pCodes of these
2274      returns to the matching pc_fstart.
2275
2276      When we're done, a doubly linked list of pBranches
2277      will exist. The head of this list is stored in
2278      `the_pFile', which is the meta structure for all
2279      of the pCode. Look at the printCallTree function
2280      on how the pBranches are linked together.
2281
2282    */
2283   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2284     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2285       pCode *pc_fstart=NULL;
2286       for(pc = pb->pcHead; pc; pc = pc->next) {
2287         if(pc->type == PC_FUNCTION) {
2288           if (PCF(pc)->fname) {
2289             // I'm not liking this....
2290             // Found the beginning of a function.
2291             _ALLOC(pbr,sizeof(pBranch));
2292             pbr->pc = pc_fstart = pc;
2293             pbr->next = NULL;
2294
2295             the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
2296
2297             // Here's a better way of doing the same:
2298             addSet(&pb->function_entries, pc);
2299
2300           } else {
2301             // Found an exit point in a function, e.g. return
2302             // (Note, there may be more than one return per function)
2303             if(pc_fstart)
2304               pBranchLink(pc_fstart, pc);
2305
2306             addSet(&pb->function_exits, pc);
2307           }
2308         } else  if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2309           addSet(&pb->function_calls,pc);
2310         }
2311       }
2312     }
2313   }
2314 }
2315
2316 /*-----------------------------------------------------------------*/
2317 /* ispCodeFunction - returns true if *pc is the pCode of a         */
2318 /*                   function                                      */
2319 /*-----------------------------------------------------------------*/
2320 bool ispCodeFunction(pCode *pc)
2321 {
2322
2323   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
2324     return 1;
2325
2326   return 0;
2327 }
2328
2329 /*-----------------------------------------------------------------*/
2330 /* findFunction - Search for a function by name (given the name)   */
2331 /*                in the set of all functions that are in a pBlock */
2332 /* (note - I expect this to change because I'm planning to limit   */
2333 /*  pBlock's to just one function declaration                      */
2334 /*-----------------------------------------------------------------*/
2335 pCode *findFunction(char *fname)
2336 {
2337   pBlock *pb;
2338   pCode *pc;
2339   if(!fname)
2340     return NULL;
2341
2342   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2343
2344     pc = setFirstItem(pb->function_entries);
2345     while(pc) {
2346     
2347       if((pc->type == PC_FUNCTION) &&
2348          (PCF(pc)->fname) && 
2349          (strcmp(fname, PCF(pc)->fname)==0))
2350         return pc;
2351
2352       pc = setNextItem(pb->function_entries);
2353
2354     }
2355
2356   }
2357   return NULL;
2358 }
2359
2360 void MarkUsedRegisters(set *regset)
2361 {
2362
2363   regs *r1,*r2;
2364
2365   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
2366     r2 = pic14_regWithIdx(r1->rIdx);
2367     r2->isFree = 0;
2368     r2->wasUsed = 1;
2369   }
2370 }
2371
2372 void pBlockStats(FILE *of, pBlock *pb)
2373 {
2374
2375   pCode *pc;
2376   regs  *r;
2377
2378   fprintf(of,"***\n  pBlock Stats\n***\n");
2379
2380   // for now just print the first element of each set
2381   pc = setFirstItem(pb->function_entries);
2382   if(pc) {
2383     fprintf(of,"entry\n");
2384     pc->print(of,pc);
2385   }
2386   pc = setFirstItem(pb->function_exits);
2387   if(pc) {
2388     fprintf(of,"has an exit\n");
2389     pc->print(of,pc);
2390   }
2391
2392   pc = setFirstItem(pb->function_calls);
2393   if(pc) {
2394     fprintf(of,"functions called\n");
2395
2396     while(pc) {
2397       pc->print(of,pc);
2398       pc = setNextItem(pb->function_calls);
2399     }
2400   }
2401
2402   r = setFirstItem(pb->registers);
2403   if(r) {
2404     int n = elementsInSet(pb->registers);
2405
2406     fprintf(of,"%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
2407
2408     while (r) {
2409       fprintf(of,"   %s\n",r->name);
2410       r = setNextItem(pb->registers);
2411     }
2412   }
2413 }
2414
2415 /*-----------------------------------------------------------------*/
2416 /*-----------------------------------------------------------------*/
2417 void sequencepCode(void)
2418 {
2419   pBlock *pb;
2420   pCode *pc;
2421
2422
2423   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2424
2425     pb->seq = GpCodeSequenceNumber+1;
2426
2427     for( pc = pb->pcHead; pc; pc = pc->next)
2428       pc->seq = ++GpCodeSequenceNumber;
2429   }
2430
2431 }
2432
2433 /*-----------------------------------------------------------------*/
2434 /*-----------------------------------------------------------------*/
2435 set *register_usage(pBlock *pb)
2436 {
2437   pCode *pc,*pcn;
2438   set *registers=NULL;
2439   set *registersInCallPath = NULL;
2440
2441   /* check recursion */
2442
2443   pc = setFirstItem(pb->function_entries);
2444
2445   if(!pc)
2446     return registers;
2447
2448   pb->visited = 1;
2449
2450   if(pc->type != PC_FUNCTION)
2451     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
2452
2453   pc = setFirstItem(pb->function_calls);
2454   for( ; pc; pc = setNextItem(pb->function_calls)) {
2455
2456     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2457       char *dest = get_op(PCI(pc));
2458
2459       pcn = findFunction(dest);
2460       if(pcn) 
2461         registersInCallPath = register_usage(pcn->pb);
2462     } else
2463       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2464
2465   }
2466
2467
2468   pBlockStats(stderr,pb);  // debug
2469   if(registersInCallPath) {
2470     /* registers were used in the functions this pBlock has called */
2471     /* so now, we need to see if these collide with the ones we are */
2472     /* using here */
2473
2474     regs *r1,*r2, *newreg;
2475
2476     fprintf(stderr,"comparing registers\n");
2477
2478     r1 = setFirstItem(registersInCallPath);
2479     while(r1) {
2480
2481       r2 = setFirstItem(pb->registers);
2482
2483       while(r2) {
2484
2485         if(r2->rIdx == r1->rIdx) {
2486           newreg = pic14_findFreeReg();
2487
2488
2489           if(!newreg) {
2490             fprintf(stderr,"Bummer, no more registers.\n");
2491             exit(1);
2492           }
2493
2494           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2495                   r1->rIdx, newreg->rIdx);
2496           r2->rIdx = newreg->rIdx;
2497           //if(r2->name) free(r2->name);
2498           r2->name = Safe_strdup(newreg->name);
2499           newreg->isFree = 0;
2500           newreg->wasUsed = 1;
2501         }
2502         r2 = setNextItem(pb->registers);
2503       }
2504
2505       r1 = setNextItem(registersInCallPath);
2506     }
2507
2508     /* Collisions have been resolved. Now free the registers in the call path */
2509     r1 = setFirstItem(registersInCallPath);
2510     while(r1) {
2511       newreg = pic14_regWithIdx(r1->rIdx);
2512       newreg->isFree = 1;
2513       r1 = setNextItem(registersInCallPath);
2514     }
2515
2516   } else
2517     MarkUsedRegisters(pb->registers);
2518
2519   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2520
2521   if(registers) 
2522     fprintf(stderr,"returning regs\n");
2523   else
2524     fprintf(stderr,"not returning regs\n");
2525
2526   fprintf(stderr,"pBlock after register optim.\n");
2527   pBlockStats(stderr,pb);  // debug
2528
2529
2530   return registers;
2531 }
2532
2533 /*-----------------------------------------------------------------*/
2534 /* printCallTree - writes the call tree to a file                  */
2535 /*                                                                 */
2536 /*-----------------------------------------------------------------*/
2537 void pct2(FILE *of,pBlock *pb,int indent)
2538 {
2539   pCode *pc,*pcn;
2540   int i;
2541   //  set *registersInCallPath = NULL;
2542
2543   if(!of)
2544     return;// registers;
2545
2546   if(indent > 10)
2547     return; // registers;   //recursion ?
2548
2549   pc = setFirstItem(pb->function_entries);
2550
2551   if(!pc)
2552     return;
2553
2554   pb->visited = 0;
2555
2556   for(i=0;i<indent;i++)   // Indentation
2557     fputc(' ',of);
2558
2559   if(pc->type == PC_FUNCTION)
2560     fprintf(of,"%s\n",PCF(pc)->fname);
2561   else
2562     return;  // ???
2563
2564
2565   pc = setFirstItem(pb->function_calls);
2566   for( ; pc; pc = setNextItem(pb->function_calls)) {
2567
2568     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2569       char *dest = get_op(PCI(pc));
2570
2571       pcn = findFunction(dest);
2572       if(pcn) 
2573         pct2(of,pcn->pb,indent+1);
2574     } else
2575       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2576
2577   }
2578
2579
2580 }
2581
2582 #if 0
2583   fprintf(stderr,"pBlock before register optim.\n");
2584   pBlockStats(stderr,pb);  // debug
2585
2586   if(registersInCallPath) {
2587     /* registers were used in the functions this pBlock has called */
2588     /* so now, we need to see if these collide with the ones we are using here */
2589
2590     regs *r1,*r2, *newreg;
2591
2592     fprintf(stderr,"comparing registers\n");
2593
2594     r1 = setFirstItem(registersInCallPath);
2595     while(r1) {
2596
2597       r2 = setFirstItem(pb->registers);
2598
2599       while(r2) {
2600
2601         if(r2->rIdx == r1->rIdx) {
2602           newreg = pic14_findFreeReg();
2603
2604
2605           if(!newreg) {
2606             fprintf(stderr,"Bummer, no more registers.\n");
2607             exit(1);
2608           }
2609
2610           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2611                   r1->rIdx, newreg->rIdx);
2612           r2->rIdx = newreg->rIdx;
2613           //if(r2->name) free(r2->name);
2614           r2->name = Safe_strdup(newreg->name);
2615           newreg->isFree = 0;
2616           newreg->wasUsed = 1;
2617         }
2618         r2 = setNextItem(pb->registers);
2619       }
2620
2621       r1 = setNextItem(registersInCallPath);
2622     }
2623
2624     /* Collisions have been resolved. Now free the registers in the call path */
2625     r1 = setFirstItem(registersInCallPath);
2626     while(r1) {
2627       newreg = pic14_regWithIdx(r1->rIdx);
2628       newreg->isFree = 1;
2629       r1 = setNextItem(registersInCallPath);
2630     }
2631
2632   } else
2633     MarkUsedRegisters(pb->registers);
2634
2635   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2636
2637   if(registers) 
2638     fprintf(stderr,"returning regs\n");
2639   else
2640     fprintf(stderr,"not returning regs\n");
2641
2642   fprintf(stderr,"pBlock after register optim.\n");
2643   pBlockStats(stderr,pb);  // debug
2644
2645
2646   return registers;
2647
2648 #endif
2649
2650
2651 /*-----------------------------------------------------------------*/
2652 /* printCallTree - writes the call tree to a file                  */
2653 /*                                                                 */
2654 /*-----------------------------------------------------------------*/
2655
2656 void printCallTree(FILE *of)
2657 {
2658   pBranch *pbr;
2659   pBlock  *pb;
2660   pCode   *pc;
2661
2662   if(!the_pFile)
2663     return;
2664
2665   if(!of)
2666     of = stderr;
2667
2668   fprintf(of, "\npBlock statistics\n");
2669   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
2670     pBlockStats(stderr,pb);
2671
2672
2673
2674   fprintf(of,"Call Tree\n");
2675   pbr = the_pFile->functions;
2676   while(pbr) {
2677     if(pbr->pc) {
2678       pc = pbr->pc;
2679       if(!ispCodeFunction(pc))
2680         fprintf(of,"bug in call tree");
2681
2682
2683       fprintf(of,"Function: %s\n", PCF(pc)->fname);
2684
2685       while(pc->next && !ispCodeFunction(pc->next)) {
2686         pc = pc->next;
2687         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
2688           fprintf(of,"\t%s\n",get_op(PCI(pc)));
2689       }
2690     }
2691
2692     pbr = pbr->next;
2693   }
2694
2695
2696   /* Re-allocate the registers so that there are no collisions
2697    * between local variables when one function call another */
2698
2699   pic14_deallocateAllRegs();
2700
2701   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2702     if(!pb->visited)
2703       register_usage(pb);
2704   }
2705
2706   fprintf(of,"\n**************\n\na better call tree\n");
2707   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2708     if(pb->visited)
2709       pct2(of,pb,0);
2710   }
2711
2712   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2713     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
2714   }
2715 }