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