*** empty log message ***
[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       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
2111         if(PCOR(PCI(pc)->pcop)->r) {
2112           pic14_allocWithIdx (PCOR(PCI(pc)->pcop)->r->rIdx);
2113           fprintf(stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx);
2114         } else {
2115           if(PCI(pc)->pcop->name)
2116             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
2117           else
2118             fprintf(stderr,"ERROR: NULL register\n");
2119         }
2120       }
2121     }
2122
2123
2124   }
2125 }
2126
2127 /*-----------------------------------------------------------------*/
2128 /*-----------------------------------------------------------------*/
2129 int OptimizepBlock(pBlock *pb)
2130 {
2131   pCode *pc;
2132   int matches =0;
2133
2134   if(!pb || !peepOptimizing)
2135     return 0;
2136
2137   fprintf(stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb));
2138   for(pc = pb->pcHead; pc; pc = pc->next)
2139     matches += pCodePeepMatchRule(pc);
2140
2141   return matches;
2142
2143 }
2144
2145 /*-----------------------------------------------------------------*/
2146 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2147 /*-----------------------------------------------------------------*/
2148 pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
2149 {
2150   pCode *pc;
2151
2152   for(pc = pcs; pc; pc = pc->next) {
2153
2154     if((pc->type == PC_OPCODE) && 
2155        (PCI(pc)->pcop) && 
2156        (PCI(pc)->pcop->type == PO_LABEL) &&
2157        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
2158       return pc;
2159   }
2160  
2161
2162   return NULL;
2163 }
2164
2165 /*-----------------------------------------------------------------*/
2166 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2167 /*                            pCode chain if they're not used.     */
2168 /*-----------------------------------------------------------------*/
2169 void pBlockRemoveUnusedLabels(pBlock *pb)
2170 {
2171   pCode *pc; pCodeLabel *pcl;
2172
2173   if(!pb)
2174     return;
2175
2176   for(pc = pb->pcHead; pc; pc = pc->next) {
2177
2178     if(pc->type == PC_LABEL)
2179       pcl = PCL(pc);
2180     else if (pc->label)
2181       pcl = PCL(pc->label->pc);
2182     else continue;
2183
2184       /* This pCode is a label, so search the pBlock to see if anyone
2185        * refers to it */
2186
2187     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))) {
2188       /* Couldn't find an instruction that refers to this label
2189        * So, unlink the pCode label from it's pCode chain
2190        * and destroy the label */
2191
2192       fprintf(stderr," !!! REMOVED A LABEL !!! key = %d\n", pcl->key);
2193
2194       if(pc->type == PC_LABEL) {
2195         unlinkPC(pc);
2196         pCodeLabelDestruct(pc);
2197       } else {
2198         unlinkpCodeFromBranch(pc, PCODE(pcl));
2199         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
2200           free(pc->label);
2201         }*/
2202       }
2203
2204     }
2205   }
2206
2207 }
2208
2209
2210 /*-----------------------------------------------------------------*/
2211 /* pBlockMergeLabels - remove the pCode labels from the pCode      */
2212 /*                     chain and put them into pBranches that are  */
2213 /*                     associated with the appropriate pCode       */
2214 /*                     instructions.                               */
2215 /*-----------------------------------------------------------------*/
2216 void pBlockMergeLabels(pBlock *pb)
2217 {
2218   pBranch *pbr;
2219   pCode *pc, *pcnext=NULL;
2220
2221   if(!pb)
2222     return;
2223
2224   /* First, Try to remove any unused labels */
2225   //pBlockRemoveUnusedLabels(pb);
2226
2227   /* Now loop through the pBlock and merge the labels with the opcodes */
2228
2229   for(pc = pb->pcHead; pc; pc = pc->next) {
2230
2231     if(pc->type == PC_LABEL) {
2232       fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
2233       if( !(pcnext = findNextInstruction(pc)) ) 
2234         return;  // Couldn't find an instruction associated with this label
2235
2236       // Unlink the pCode label from it's pCode chain
2237       unlinkPC(pc);
2238
2239       fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
2240       // And link it into the instruction's pBranch labels. (Note, since
2241       // it's possible to have multiple labels associated with one instruction
2242       // we must provide a means to accomodate the additional labels. Thus
2243       // the labels are placed into the singly-linked list "label" as 
2244       // opposed to being a single member of the pCodeInstruction.)
2245
2246       _ALLOC(pbr,sizeof(pBranch));
2247       pbr->pc = pc;
2248       pbr->next = NULL;
2249
2250       pcnext->label = pBranchAppend(pcnext->label,pbr);
2251       if(pcnext->prev) 
2252         pc = pcnext->prev;
2253       else
2254         pc = pcnext;
2255     }
2256
2257   }
2258   pBlockRemoveUnusedLabels(pb);
2259
2260 }
2261
2262 /*-----------------------------------------------------------------*/
2263 /*-----------------------------------------------------------------*/
2264 void OptimizepCode(char dbName)
2265 {
2266 #define MAX_PASSES 4
2267
2268   int matches = 0;
2269   int passes = 0;
2270   pBlock *pb;
2271
2272   if(!the_pFile)
2273     return;
2274
2275   fprintf(stderr," Optimizing pCode\n");
2276
2277   do {
2278     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2279       if('*' == dbName || getpBlock_dbName(pb) == dbName)
2280         matches += OptimizepBlock(pb);
2281     }
2282   }
2283   while(matches && ++passes < MAX_PASSES);
2284
2285 }
2286
2287 /*-----------------------------------------------------------------*/
2288 /* AnalyzepCode - parse the pCode that has been generated and form */
2289 /*                all of the logical connections.                  */
2290 /*                                                                 */
2291 /* Essentially what's done here is that the pCode flow is          */
2292 /* determined.                                                     */
2293 /*-----------------------------------------------------------------*/
2294
2295 void AnalyzepCode(char dbName)
2296 {
2297   pBlock *pb;
2298   pCode *pc;
2299   pBranch *pbr;
2300
2301   int i,changes;
2302
2303   if(!the_pFile)
2304     return;
2305
2306   fprintf(stderr," Analyzing pCode");
2307
2308   changes = 0;
2309   i = 0;
2310   do {
2311     /* First, merge the labels with the instructions */
2312     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2313       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2314
2315         fprintf(stderr," analyze and merging block %c\n",dbName);
2316         pBlockMergeLabels(pb);
2317         AnalyzepBlock(pb);
2318       }
2319     }
2320
2321     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2322       if('*' == dbName || getpBlock_dbName(pb) == dbName)
2323         changes += OptimizepBlock(pb);
2324     }
2325       
2326   } while(changes && (i++ < MAX_PASSES));
2327
2328   /* Now build the call tree.
2329      First we examine all of the pCodes for functions.
2330      Keep in mind that the function boundaries coincide
2331      with pBlock boundaries. 
2332
2333      The algorithm goes something like this:
2334      We have two nested loops. The outer loop iterates
2335      through all of the pBlocks/functions. The inner
2336      loop iterates through all of the pCodes for
2337      a given pBlock. When we begin iterating through
2338      a pBlock, the variable pc_fstart, pCode of the start
2339      of a function, is cleared. We then search for pCodes
2340      of type PC_FUNCTION. When one is encountered, we
2341      initialize pc_fstart to this and at the same time
2342      associate a new pBranch object that signifies a 
2343      branch entry. If a return is found, then this signifies
2344      a function exit point. We'll link the pCodes of these
2345      returns to the matching pc_fstart.
2346
2347      When we're done, a doubly linked list of pBranches
2348      will exist. The head of this list is stored in
2349      `the_pFile', which is the meta structure for all
2350      of the pCode. Look at the printCallTree function
2351      on how the pBranches are linked together.
2352
2353    */
2354   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2355     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2356       pCode *pc_fstart=NULL;
2357       for(pc = pb->pcHead; pc; pc = pc->next) {
2358         if(pc->type == PC_FUNCTION) {
2359           if (PCF(pc)->fname) {
2360             // I'm not liking this....
2361             // Found the beginning of a function.
2362             _ALLOC(pbr,sizeof(pBranch));
2363             pbr->pc = pc_fstart = pc;
2364             pbr->next = NULL;
2365
2366             the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
2367
2368             // Here's a better way of doing the same:
2369             addSet(&pb->function_entries, pc);
2370
2371           } else {
2372             // Found an exit point in a function, e.g. return
2373             // (Note, there may be more than one return per function)
2374             if(pc_fstart)
2375               pBranchLink(pc_fstart, pc);
2376
2377             addSet(&pb->function_exits, pc);
2378           }
2379         } else  if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2380           addSet(&pb->function_calls,pc);
2381         }
2382       }
2383     }
2384   }
2385 }
2386
2387 /*-----------------------------------------------------------------*/
2388 /* ispCodeFunction - returns true if *pc is the pCode of a         */
2389 /*                   function                                      */
2390 /*-----------------------------------------------------------------*/
2391 bool ispCodeFunction(pCode *pc)
2392 {
2393
2394   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
2395     return 1;
2396
2397   return 0;
2398 }
2399
2400 /*-----------------------------------------------------------------*/
2401 /* findFunction - Search for a function by name (given the name)   */
2402 /*                in the set of all functions that are in a pBlock */
2403 /* (note - I expect this to change because I'm planning to limit   */
2404 /*  pBlock's to just one function declaration                      */
2405 /*-----------------------------------------------------------------*/
2406 pCode *findFunction(char *fname)
2407 {
2408   pBlock *pb;
2409   pCode *pc;
2410   if(!fname)
2411     return NULL;
2412
2413   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2414
2415     pc = setFirstItem(pb->function_entries);
2416     while(pc) {
2417     
2418       if((pc->type == PC_FUNCTION) &&
2419          (PCF(pc)->fname) && 
2420          (strcmp(fname, PCF(pc)->fname)==0))
2421         return pc;
2422
2423       pc = setNextItem(pb->function_entries);
2424
2425     }
2426
2427   }
2428   return NULL;
2429 }
2430
2431 void MarkUsedRegisters(set *regset)
2432 {
2433
2434   regs *r1,*r2;
2435
2436   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
2437     r2 = pic14_regWithIdx(r1->rIdx);
2438     r2->isFree = 0;
2439     r2->wasUsed = 1;
2440   }
2441 }
2442
2443 void pBlockStats(FILE *of, pBlock *pb)
2444 {
2445
2446   pCode *pc;
2447   regs  *r;
2448
2449   fprintf(of,";***\n;  pBlock Stats\n;***\n");
2450
2451   // for now just print the first element of each set
2452   pc = setFirstItem(pb->function_entries);
2453   if(pc) {
2454     fprintf(of,";entry:  ");
2455     pc->print(of,pc);
2456   }
2457   pc = setFirstItem(pb->function_exits);
2458   if(pc) {
2459     fprintf(of,";has an exit\n");
2460     //pc->print(of,pc);
2461   }
2462
2463   pc = setFirstItem(pb->function_calls);
2464   if(pc) {
2465     fprintf(of,";functions called:\n");
2466
2467     while(pc) {
2468       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2469         fprintf(of,";   %s\n",get_op(PCI(pc)));
2470       }
2471       pc = setNextItem(pb->function_calls);
2472     }
2473   }
2474
2475   r = setFirstItem(pb->registers);
2476   if(r) {
2477     int n = elementsInSet(pb->registers);
2478
2479     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
2480
2481     while (r) {
2482       fprintf(of,";   %s\n",r->name);
2483       r = setNextItem(pb->registers);
2484     }
2485   }
2486 }
2487
2488 /*-----------------------------------------------------------------*/
2489 /*-----------------------------------------------------------------*/
2490 void sequencepCode(void)
2491 {
2492   pBlock *pb;
2493   pCode *pc;
2494
2495
2496   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2497
2498     pb->seq = GpCodeSequenceNumber+1;
2499
2500     for( pc = pb->pcHead; pc; pc = pc->next)
2501       pc->seq = ++GpCodeSequenceNumber;
2502   }
2503
2504 }
2505
2506 /*-----------------------------------------------------------------*/
2507 /*-----------------------------------------------------------------*/
2508 set *register_usage(pBlock *pb)
2509 {
2510   pCode *pc,*pcn;
2511   set *registers=NULL;
2512   set *registersInCallPath = NULL;
2513
2514   /* check recursion */
2515
2516   pc = setFirstItem(pb->function_entries);
2517
2518   if(!pc)
2519     return registers;
2520
2521   pb->visited = 1;
2522
2523   if(pc->type != PC_FUNCTION)
2524     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
2525
2526   pc = setFirstItem(pb->function_calls);
2527   for( ; pc; pc = setNextItem(pb->function_calls)) {
2528
2529     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2530       char *dest = get_op(PCI(pc));
2531
2532       pcn = findFunction(dest);
2533       if(pcn) 
2534         registersInCallPath = register_usage(pcn->pb);
2535     } else
2536       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2537
2538   }
2539
2540
2541   pBlockStats(stderr,pb);  // debug
2542
2543   // Mark the registers in this block as used.
2544
2545   MarkUsedRegisters(pb->registers);
2546   if(registersInCallPath) {
2547     /* registers were used in the functions this pBlock has called */
2548     /* so now, we need to see if these collide with the ones we are */
2549     /* using here */
2550
2551     regs *r1,*r2, *newreg;
2552
2553     fprintf(stderr,"comparing registers\n");
2554
2555     r1 = setFirstItem(registersInCallPath);
2556     while(r1) {
2557
2558       r2 = setFirstItem(pb->registers);
2559
2560       while(r2 && (r1->type != REG_STK)) {
2561
2562         if(r2->rIdx == r1->rIdx) {
2563           newreg = pic14_findFreeReg(REG_GPR);
2564
2565
2566           if(!newreg) {
2567             fprintf(stderr,"Bummer, no more registers.\n");
2568             exit(1);
2569           }
2570
2571           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2572                   r1->rIdx, newreg->rIdx);
2573           r2->rIdx = newreg->rIdx;
2574           //if(r2->name) free(r2->name);
2575           if(newreg->name)
2576             r2->name = Safe_strdup(newreg->name);
2577           else
2578             r2->name = NULL;
2579           newreg->isFree = 0;
2580           newreg->wasUsed = 1;
2581         }
2582         r2 = setNextItem(pb->registers);
2583       }
2584
2585       r1 = setNextItem(registersInCallPath);
2586     }
2587
2588     /* Collisions have been resolved. Now free the registers in the call path */
2589     r1 = setFirstItem(registersInCallPath);
2590     while(r1) {
2591       if(r1->type != REG_STK) {
2592         newreg = pic14_regWithIdx(r1->rIdx);
2593         newreg->isFree = 1;
2594       }
2595       r1 = setNextItem(registersInCallPath);
2596     }
2597
2598   }// else
2599   //    MarkUsedRegisters(pb->registers);
2600
2601   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2602
2603   if(registers) 
2604     fprintf(stderr,"returning regs\n");
2605   else
2606     fprintf(stderr,"not returning regs\n");
2607
2608   fprintf(stderr,"pBlock after register optim.\n");
2609   pBlockStats(stderr,pb);  // debug
2610
2611
2612   return registers;
2613 }
2614
2615 /*-----------------------------------------------------------------*/
2616 /* printCallTree - writes the call tree to a file                  */
2617 /*                                                                 */
2618 /*-----------------------------------------------------------------*/
2619 void pct2(FILE *of,pBlock *pb,int indent)
2620 {
2621   pCode *pc,*pcn;
2622   int i;
2623   //  set *registersInCallPath = NULL;
2624
2625   if(!of)
2626     return;// registers;
2627
2628   if(indent > 10)
2629     return; // registers;   //recursion ?
2630
2631   pc = setFirstItem(pb->function_entries);
2632
2633   if(!pc)
2634     return;
2635
2636   pb->visited = 0;
2637
2638   for(i=0;i<indent;i++)   // Indentation
2639     fputc(' ',of);
2640
2641   if(pc->type == PC_FUNCTION)
2642     fprintf(of,"%s\n",PCF(pc)->fname);
2643   else
2644     return;  // ???
2645
2646
2647   pc = setFirstItem(pb->function_calls);
2648   for( ; pc; pc = setNextItem(pb->function_calls)) {
2649
2650     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2651       char *dest = get_op(PCI(pc));
2652
2653       pcn = findFunction(dest);
2654       if(pcn) 
2655         pct2(of,pcn->pb,indent+1);
2656     } else
2657       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2658
2659   }
2660
2661
2662 }
2663
2664 #if 0
2665   fprintf(stderr,"pBlock before register optim.\n");
2666   pBlockStats(stderr,pb);  // debug
2667
2668   if(registersInCallPath) {
2669     /* registers were used in the functions this pBlock has called */
2670     /* so now, we need to see if these collide with the ones we are using here */
2671
2672     regs *r1,*r2, *newreg;
2673
2674     fprintf(stderr,"comparing registers\n");
2675
2676     r1 = setFirstItem(registersInCallPath);
2677     while(r1) {
2678
2679       r2 = setFirstItem(pb->registers);
2680
2681       while(r2) {
2682
2683         if(r2->rIdx == r1->rIdx) {
2684           newreg = pic14_findFreeReg();
2685
2686
2687           if(!newreg) {
2688             fprintf(stderr,"Bummer, no more registers.\n");
2689             exit(1);
2690           }
2691
2692           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2693                   r1->rIdx, newreg->rIdx);
2694           r2->rIdx = newreg->rIdx;
2695           //if(r2->name) free(r2->name);
2696           if(newreg->name)
2697             r2->name = Safe_strdup(newreg->name);
2698           else
2699             r2->name = NULL;
2700           newreg->isFree = 0;
2701           newreg->wasUsed = 1;
2702         }
2703         r2 = setNextItem(pb->registers);
2704       }
2705
2706       r1 = setNextItem(registersInCallPath);
2707     }
2708
2709     /* Collisions have been resolved. Now free the registers in the call path */
2710     r1 = setFirstItem(registersInCallPath);
2711     while(r1) {
2712       newreg = pic14_regWithIdx(r1->rIdx);
2713       newreg->isFree = 1;
2714       r1 = setNextItem(registersInCallPath);
2715     }
2716
2717   } else
2718     MarkUsedRegisters(pb->registers);
2719
2720   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2721
2722   if(registers) 
2723     fprintf(stderr,"returning regs\n");
2724   else
2725     fprintf(stderr,"not returning regs\n");
2726
2727   fprintf(stderr,"pBlock after register optim.\n");
2728   pBlockStats(stderr,pb);  // debug
2729
2730
2731   return registers;
2732
2733 #endif
2734
2735
2736 /*-----------------------------------------------------------------*/
2737 /* printCallTree - writes the call tree to a file                  */
2738 /*                                                                 */
2739 /*-----------------------------------------------------------------*/
2740
2741 void printCallTree(FILE *of)
2742 {
2743   pBranch *pbr;
2744   pBlock  *pb;
2745   pCode   *pc;
2746
2747   if(!the_pFile)
2748     return;
2749
2750   if(!of)
2751     of = stderr;
2752
2753   fprintf(of, "\npBlock statistics\n");
2754   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
2755     pBlockStats(stderr,pb);
2756
2757
2758
2759   fprintf(of,"Call Tree\n");
2760   pbr = the_pFile->functions;
2761   while(pbr) {
2762     if(pbr->pc) {
2763       pc = pbr->pc;
2764       if(!ispCodeFunction(pc))
2765         fprintf(of,"bug in call tree");
2766
2767
2768       fprintf(of,"Function: %s\n", PCF(pc)->fname);
2769
2770       while(pc->next && !ispCodeFunction(pc->next)) {
2771         pc = pc->next;
2772         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
2773           fprintf(of,"\t%s\n",get_op(PCI(pc)));
2774       }
2775     }
2776
2777     pbr = pbr->next;
2778   }
2779
2780
2781   /* Re-allocate the registers so that there are no collisions
2782    * between local variables when one function call another */
2783
2784   pic14_deallocateAllRegs();
2785
2786   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2787     if(!pb->visited)
2788       register_usage(pb);
2789   }
2790
2791   fprintf(of,"\n**************\n\na better call tree\n");
2792   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2793     if(pb->visited)
2794       pct2(of,pb,0);
2795   }
2796
2797   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2798     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
2799   }
2800 }