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