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