PIC port pcode. Added pcode peephole feature.
[fw/sdcc] / src / pic / pcode.c
1 /*-------------------------------------------------------------------------
2
3    pcode.h - 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 #include "pcode.h"
27
28 // Eventually this will go into device dependent files:
29 pCodeOp pc_status    = {PO_STATUS,  "STATUS"};
30 pCodeOp pc_indf      = {PO_INDF,    "INDF"};
31 pCodeOp pc_fsr       = {PO_FSR,     "FSR"};
32
33 //static char *PIC_mnemonics[] = {
34 static char *scpADDLW = "ADDLW";
35 static char *scpADDWF = "ADDWF";
36 static char *scpANDLW = "ANDLW";
37 static char *scpANDWF = "ANDWF";
38 static char *scpBCF = "BCF";
39 static char *scpBSF = "BSF";
40 static char *scpBTFSC = "BTFSC";
41 static char *scpBTFSS = "BTFSS";
42 static char *scpCALL = "CALL";
43 static char *scpCOMF = "COMF";
44 static char *scpCLRF = "CLRF";
45 static char *scpCLRW = "CLRW";
46 static char *scpDECF = "DECF";
47 static char *scpDECFSZ = "DECFSZ";
48 static char *scpGOTO = "GOTO";
49 static char *scpINCF = "INCF";
50 static char *scpINCFSZ = "INCFSZ";
51 static char *scpIORLW = "IORLW";
52 static char *scpIORWF = "IORWF";
53 static char *scpMOVF = "MOVF";
54 static char *scpMOVLW = "MOVLW";
55 static char *scpMOVWF = "MOVWF";
56 static char *scpNEGF = "NEGF";
57 static char *scpRETLW = "RETLW";
58 static char *scpRETURN = "RETURN";
59 static char *scpSUBLW = "SUBLW";
60 static char *scpSUBWF = "SUBWF";
61 static char *scpTRIS = "TRIS";
62 static char *scpXORLW = "XORLW";
63 static char *scpXORWF = "XORWF";
64
65
66 static pFile *the_pFile = NULL;
67 static int peepOptimizing = 1;
68
69 /****************************************************************/
70 /****************************************************************/
71 typedef struct _DLL {
72   struct _DLL *prev;
73   struct _DLL *next;
74   //  void *data;
75 } _DLL;
76
77
78 typedef struct pCodePeepSnippets
79 {
80   _DLL dll;
81   pCodePeep *peep;
82 } pCodePeepSnippets;
83
84
85 static pCodePeepSnippets  *peepSnippets=NULL;
86
87 /****************************************************************/
88 /*                      Forward declarations                    */
89 /****************************************************************/
90
91 static void unlink(pCode *pc);
92 static void genericAnalyze(pCode *pc);
93 static void AnalyzeGOTO(pCode *pc);
94 static void AnalyzeSKIP(pCode *pc);
95 static void AnalyzeRETURN(pCode *pc);
96
97 static void genericDestruct(pCode *pc);
98 static void genericPrint(FILE *of,pCode *pc);
99
100 static void pCodePrintLabel(FILE *of, pCode *pc);
101 static void pCodePrintFunction(FILE *of, pCode *pc);
102 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
103 static char *get_op( pCodeInstruction *pcc);
104 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
105 int pCodePeepMatchRule(pCode *pc);
106
107
108 char *Safe_strdup(char *str)
109 {
110   char *copy;
111
112   if(!str)
113     return NULL;
114
115   copy = strdup(str);
116   if(!copy) {
117     fprintf(stderr, "out of memory %s,%d\n",__FUNCTION__,__LINE__);
118     exit(1);
119   }
120
121   return copy;
122     
123 }
124
125 void copypCode(FILE *of, char dbName)
126 {
127   pBlock *pb;
128
129   if(!of || !the_pFile)
130     return;
131
132   fprintf(of,";dumping pcode to a file");
133
134   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
135     if(pb->cmemmap->dbName == dbName)
136       printpBlock(of,pb);
137   }
138
139 }
140 void pcode_test(void)
141 {
142
143   printf("pcode is alive!\n");
144
145   if(the_pFile) {
146
147     pBlock *pb;
148     FILE *pFile;
149     char buffer[100];
150
151     /* create the file name */
152     strcpy(buffer,srcFileName);
153     strcat(buffer,".p");
154
155     if( !(pFile = fopen(buffer, "w" ))) {
156       werror(E_FILE_OPEN_ERR,buffer);
157       exit(1);
158     }
159
160     fprintf(pFile,"pcode dump\n\n");
161
162     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
163       fprintf(pFile,"\n\tNew pBlock\n\n");
164       fprintf(pFile,"%s, dbName =%c\n",pb->cmemmap->sname,pb->cmemmap->dbName);
165       printpBlock(pFile,pb);
166     }
167   }
168 }
169
170 /*-----------------------------------------------------------------*/
171 /* newpCode - create and return a newly initialized pCode          */
172 /*-----------------------------------------------------------------*/
173 pCode *newpCode (PIC_OPCODE op, pCodeOp *pcop)
174 {
175   pCodeInstruction *pci ;
176     
177
178   pci = Safe_calloc(1, sizeof(pCodeInstruction));
179   pci->pc.analyze = genericAnalyze;
180   pci->pc.destruct = genericDestruct;
181   pci->pc.type = PC_OPCODE;
182   pci->op = op;
183   pci->pc.prev = pci->pc.next = NULL;
184   pci->pcop = pcop;
185   pci->dest = 0;
186   pci->bit_inst = 0;
187   pci->num_ops = 2;
188   pci->inCond = pci->outCond = PCC_NONE;
189   pci->pc.print = genericPrint;
190   pci->pc.from = pci->pc.to = pci->pc.label = NULL;
191
192   if(pcop && pcop->name)
193     printf("newpCode  operand name %s\n",pcop->name);
194
195   switch(op) { 
196
197   case POC_ANDLW:
198     pci->inCond   = PCC_W;
199     pci->outCond  = PCC_W | PCC_Z;
200     pci->mnemonic = scpANDLW;
201     pci->num_ops  = 1;
202     break;
203   case POC_ANDWF:
204     pci->dest = 1;
205     pci->inCond   = PCC_W | PCC_REGISTER;
206     pci->outCond  = PCC_REGISTER | PCC_Z;
207     pci->mnemonic = scpANDWF;
208     break;
209   case POC_ANDFW:
210     pci->inCond   = PCC_W | PCC_REGISTER;
211     pci->outCond  = PCC_W | PCC_Z;
212     pci->mnemonic = scpANDWF;
213     break;
214
215   case POC_ADDLW:
216     pci->inCond   = PCC_W;
217     pci->outCond  = PCC_W | PCC_Z | PCC_C | PCC_DC;
218     pci->mnemonic = scpADDLW;
219     pci->num_ops = 1;
220     break;
221   case POC_ADDWF:
222     pci->dest     = 1;
223     pci->inCond   = PCC_W | PCC_REGISTER;
224     pci->outCond  = PCC_REGISTER | PCC_Z | PCC_C | PCC_DC;
225     pci->mnemonic = scpADDWF;
226     break;
227   case POC_ADDFW:
228     pci->inCond   = PCC_W | PCC_REGISTER;
229     pci->outCond  = PCC_W | PCC_Z | PCC_C | PCC_DC;
230     pci->mnemonic = scpADDWF;
231     break;
232
233   case POC_BCF:
234     pci->bit_inst = 1;
235     pci->mnemonic = scpBCF;
236     break;
237   case POC_BSF:
238     pci->bit_inst = 1;
239     pci->mnemonic = scpBSF;
240     break;
241   case POC_BTFSC:
242     pci->bit_inst = 1;
243     pci->mnemonic = scpBTFSC;
244     pci->pc.analyze = AnalyzeSKIP;
245     break;
246   case POC_BTFSS:
247     pci->bit_inst = 1;
248     pci->mnemonic = scpBTFSS;
249     pci->pc.analyze = AnalyzeSKIP;
250     break;
251   case POC_CALL:
252     pci->num_ops = 1;
253     pci->mnemonic = scpCALL;
254     break;
255   case POC_COMF:
256     pci->mnemonic = scpCOMF;
257     break;
258   case POC_CLRF:
259     pci->num_ops = 1;
260     pci->mnemonic = scpCLRF;
261     break;
262   case POC_CLRW:
263     pci->num_ops = 0;
264     pci->mnemonic = scpCLRW;
265     break;
266   case POC_DECF:
267     pci->dest = 1;
268   case POC_DECFW:
269     pci->mnemonic = scpDECF;
270     break;
271   case POC_DECFSZ:
272     pci->dest = 1;
273   case POC_DECFSZW:
274     pci->mnemonic = scpDECFSZ;
275     pci->pc.analyze = AnalyzeSKIP;
276     break;
277   case POC_GOTO:
278     pci->num_ops = 1;
279     pci->mnemonic = scpGOTO;
280     pci->pc.analyze = AnalyzeGOTO;
281     break;
282   case POC_INCF:
283     pci->dest = 1;
284   case POC_INCFW:
285     pci->mnemonic = scpINCF;
286     break;
287   case POC_INCFSZ:
288     pci->dest = 1;
289   case POC_INCFSZW:
290     pci->mnemonic = scpINCFSZ;
291     pci->pc.analyze = AnalyzeSKIP;
292     break;
293   case POC_IORLW:
294     pci->num_ops = 1;
295     pci->mnemonic = scpIORLW;
296     break;
297   case POC_IORWF:
298     pci->dest = 1;
299   case POC_IORFW:
300     pci->mnemonic = scpIORWF;
301     break;
302   case POC_MOVF:
303     pci->dest = 1;
304   case POC_MOVFW:
305     pci->mnemonic = scpMOVF;
306     break;
307   case POC_MOVLW:
308     pci->num_ops = 1;
309     pci->mnemonic = scpMOVLW;
310     break;
311   case POC_MOVWF:
312     pci->num_ops = 1;
313     pci->mnemonic = scpMOVWF;
314     break;
315   case POC_NEGF:
316     pci->mnemonic = scpNEGF;
317     break;
318   case POC_RETLW:
319     pci->num_ops = 1;
320     pci->mnemonic = scpRETLW;
321     pci->pc.analyze = AnalyzeRETURN;
322     break;
323   case POC_RETURN:
324     pci->num_ops = 0;
325     pci->mnemonic = scpRETURN;
326     pci->pc.analyze = AnalyzeRETURN;
327     break;
328   case POC_SUBLW:
329     pci->mnemonic = scpSUBLW;
330     pci->num_ops = 1;
331     break;
332   case POC_SUBWF:
333     pci->dest = 1;
334   case POC_SUBFW:
335     pci->mnemonic = scpSUBWF;
336     break;
337   case POC_TRIS:
338     pci->mnemonic = scpTRIS;
339     break;
340   case POC_XORLW:
341     pci->num_ops = 1;
342     pci->mnemonic = scpXORLW;
343     break;
344   case POC_XORWF:
345     pci->dest = 1;
346   case POC_XORFW:
347     pci->mnemonic = scpXORWF;
348     break;
349
350   default:
351     pci->pc.print = genericPrint;
352   }
353    
354   return (pCode *)pci;
355 }       
356
357 pCode *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
358 {
359
360   pCodeWild *pcw;
361     
362   pcw = Safe_calloc(1,sizeof(pCodeWild));
363
364   pcw->pc.type = PC_WILD;
365   pcw->pc.prev = pcw->pc.next = NULL;
366   pcw->pc.from = pcw->pc.to = pcw->pc.label = NULL;
367
368   pcw->pc.analyze = genericAnalyze;
369   pcw->pc.destruct = genericDestruct;
370   pcw->pc.print = genericPrint;
371
372   pcw->id = pCodeID;
373   pcw->operand = optional_operand;
374   pcw->label   = optional_label;
375
376   return ( (pCode *)pcw);
377   
378 }
379
380 /*-----------------------------------------------------------------*/
381 /* newPcodeCharP - create a new pCode from a char string           */
382 /*-----------------------------------------------------------------*/
383
384 pCode *newpCodeCharP(char *cP)
385 {
386
387   pCodeComment *pcc ;
388     
389   pcc = Safe_calloc(1,sizeof(pCodeComment));
390
391   pcc->pc.type = PC_COMMENT;
392   pcc->pc.prev = pcc->pc.next = NULL;
393   pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
394
395   pcc->pc.analyze = genericAnalyze;
396   pcc->pc.destruct = genericDestruct;
397   pcc->pc.print = genericPrint;
398
399   pcc->comment = Safe_strdup(cP);
400
401   return ( (pCode *)pcc);
402
403 }
404
405 /*-----------------------------------------------------------------*/
406 /* newpCodeGLabel - create a new global label                      */
407 /*-----------------------------------------------------------------*/
408
409
410 pCode *newpCodeFunction(char *mod,char *f)
411 {
412   pCodeFunction *pcf;
413
414   _ALLOC(pcf,sizeof(pCodeFunction));
415
416   pcf->pc.type = PC_FUNCTION;
417   pcf->pc.prev = pcf->pc.next = NULL;
418   pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
419
420   pcf->pc.analyze = genericAnalyze;
421   pcf->pc.destruct = genericDestruct;
422   pcf->pc.print = pCodePrintFunction;
423
424   if(mod) {
425     _ALLOC_ATOMIC(pcf->modname,strlen(mod)+1);
426     strcpy(pcf->modname,mod);
427   } else
428     pcf->modname = NULL;
429
430   if(f) {
431     _ALLOC_ATOMIC(pcf->fname,strlen(f)+1);
432     strcpy(pcf->fname,f);
433   } else
434     pcf->fname = NULL;
435
436   return ( (pCode *)pcf);
437
438 }
439
440
441 pCode *newpCodeLabel(int key)
442 {
443
444   char *s = buffer;
445   pCodeLabel *pcl;
446     
447   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
448
449   pcl->pc.type = PC_LABEL;
450   pcl->pc.prev = pcl->pc.next = NULL;
451   pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
452
453   pcl->pc.analyze = genericAnalyze;
454   pcl->pc.destruct = genericDestruct;
455   pcl->pc.print = pCodePrintLabel;
456
457   pcl->key = key;
458
459   if(key>0) {
460     sprintf(s,"_%05d_DS_",key);
461     pcl->label = Safe_strdup(s);
462   } else
463     pcl->label = NULL;
464
465   return ( (pCode *)pcl);
466
467 }
468
469 /*-----------------------------------------------------------------*/
470 /* newpBlock - create and return a pointer to a new pBlock         */
471 /*-----------------------------------------------------------------*/
472 pBlock *newpBlock(void)
473 {
474
475   pBlock *PpB;
476
477   _ALLOC(PpB,sizeof(pBlock));
478   PpB->next = PpB->prev = NULL;
479
480   return PpB;
481
482 }
483
484 /*-----------------------------------------------------------------*/
485 /* newpCodeChain - create a new chain of pCodes                    */
486 /*-----------------------------------------------------------------*
487  *
488  *  This function will create a new pBlock and the pointer to the
489  *  pCode that is passed in will be the first pCode in the block.
490  *-----------------------------------------------------------------*/
491
492
493 pBlock *newpCodeChain(memmap *cm,pCode *pc)
494 {
495
496   pBlock *pB = newpBlock();
497
498   pB->pcHead = pB->pcTail = pc;
499   pB->cmemmap = cm;
500
501   return pB;
502 }
503
504 /*-----------------------------------------------------------------*/
505 /*-----------------------------------------------------------------*/
506
507 pCodeOp *newpCodeOp(char *name, PIC_OPTYPE type)
508 {
509   pCodeOp *pcop;
510
511   pcop = Safe_calloc(1,sizeof(pCodeOp) );
512   pcop->type = type;
513   pcop->name = Safe_strdup(name);   
514
515   return pcop;
516 }
517
518 /*-----------------------------------------------------------------*/
519 /* newpCodeOpLabel - Create a new label given the key              */
520 /*  Note, a negative key means that the label is part of wild card */
521 /*  (and hence a wild card label) used in the pCodePeep            */
522 /*   optimizations).                                               */
523 /*-----------------------------------------------------------------*/
524
525 pCodeOp *newpCodeOpLabel(int key)
526 {
527   char *s = buffer;
528   pCodeOp *pcop;
529
530   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
531   pcop->type = PO_LABEL;
532
533   if(key>0) {
534     sprintf(s,"_%05d_DS_",key);
535     pcop->name = Safe_strdup(s);
536   } else
537     pcop->name = NULL;
538
539   ((pCodeOpLabel *)pcop)->key = key;
540
541   return pcop;
542 }
543
544 pCodeOp *newpCodeOpLit(int lit)
545 {
546   char *s = buffer;
547   pCodeOp *pcop;
548
549
550   _ALLOC(pcop,sizeof(pCodeOpLit) );
551   pcop->type = PO_LITERAL;
552   sprintf(s,"0x%02x",lit);
553   _ALLOC_ATOMIC(pcop->name,strlen(s)+1);
554   strcpy(pcop->name,s);
555   ((pCodeOpLit *)pcop)->lit = lit;
556
557   return pcop;
558 }
559
560 pCodeOp *newpCodeOpWild(int id, pCodePeep *pcp, pCodeOp *subtype)
561 {
562   char *s = buffer;
563   pCodeOp *pcop;
564
565
566   if(!pcp || !subtype) {
567     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
568     exit(1);
569   }
570
571   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
572   pcop->type = PO_WILD;
573   sprintf(s,"%%%d",id);
574   pcop->name = Safe_strdup(s);
575
576   PCOW(pcop)->id = id;
577   PCOW(pcop)->pcp = pcp;
578   PCOW(pcop)->subtype = subtype;
579
580   return pcop;
581 }
582
583 pCodeOp *newpCodeOpBit(char *s, int bit)
584 {
585   pCodeOp *pcop;
586
587   _ALLOC(pcop,sizeof(pCodeOpBit) );
588   pcop->type = PO_BIT;
589   pcop->name = Safe_strdup(s);   
590   PCOB(pcop)->bit = bit;
591   PCOB(pcop)->inBitSpace = 1;
592
593   return pcop;
594 }
595
596 /*-----------------------------------------------------------------*/
597 /* addpCode2pBlock - place the pCode into the pBlock linked list   */
598 /*-----------------------------------------------------------------*/
599 void addpCode2pBlock(pBlock *pb, pCode *pc)
600 {
601
602   pb->pcTail->next = pc;
603   pc->prev = pb->pcTail;
604   pc->next = NULL;
605   pb->pcTail = pc;
606 }
607
608 /*-----------------------------------------------------------------*/
609 /* addpBlock - place a pBlock into the pFile                       */
610 /*-----------------------------------------------------------------*/
611 void addpBlock(pBlock *pb)
612 {
613
614   if(!the_pFile) {
615     /* First time called, we'll pass through here. */
616     _ALLOC(the_pFile,sizeof(the_pFile));
617     the_pFile->pbHead = the_pFile->pbTail = pb;
618     the_pFile->functions = NULL;
619     return;
620   }
621
622   the_pFile->pbTail->next = pb;
623   pb->prev = the_pFile->pbTail;
624   pb->next = NULL;
625   the_pFile->pbTail = pb;
626 }
627
628 void printpCodeString(FILE *of, pCode *pc, int max)
629 {
630   int i=0;
631
632   while(pc && (i++<max)) {
633     pc->print(of,pc);
634     pc = pc->next;
635   }
636 }
637 /*-----------------------------------------------------------------*/
638 /* printpCode - write the contents of a pCode to a file            */
639 /*-----------------------------------------------------------------*/
640 void printpCode(FILE *of, pCode *pc)
641 {
642
643   if(!pc || !of)
644     return;
645
646   if(pc->print) {
647     pc->print(of,pc);
648     return;
649   }
650
651   fprintf(of,"warning - unable to print pCode\n");
652 }
653
654 /*-----------------------------------------------------------------*/
655 /* printpBlock - write the contents of a pBlock to a file          */
656 /*-----------------------------------------------------------------*/
657 void printpBlock(FILE *of, pBlock *pb)
658 {
659   pCode *pc;
660
661   if(!pb)
662     return;
663
664   if(!of)
665     of = stderr;
666
667   for(pc = pb->pcHead; pc; pc = pc->next)
668     printpCode(of,pc);
669
670 }
671
672 /*-----------------------------------------------------------------*/
673 /*                                                                 */
674 /*       pCode processing                                          */
675 /*                                                                 */
676 /*    The stuff that follows is very PIC specific!                 */
677 /*                                                                 */
678 /*                                                                 */
679 /*                                                                 */
680 /*                                                                 */
681 /*-----------------------------------------------------------------*/
682
683 static void unlink(pCode *pc)
684 {
685   if(pc  && pc->prev && pc->next) {
686
687     pc->prev->next = pc->next;
688     pc->next->prev = pc->prev;
689   }
690 }
691 static void genericDestruct(pCode *pc)
692 {
693   unlink(pc);
694
695   fprintf(stderr,"warning, calling default pCode destructor\n");
696   free(pc);
697 }
698
699 static char *get_op( pCodeInstruction *pcc)
700 {
701   if(pcc && pcc->pcop && pcc->pcop->name)
702     return pcc->pcop->name;
703   return "NO operand";
704 }
705
706 /*-----------------------------------------------------------------*/
707 /*-----------------------------------------------------------------*/
708 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
709 {
710
711   fprintf(of,"pcodeopprint\n");
712 }
713
714 /*-----------------------------------------------------------------*/
715 /* genericPrint - the contents of a pCode to a file                */
716 /*-----------------------------------------------------------------*/
717 static void genericPrint(FILE *of, pCode *pc)
718 {
719
720   if(!pc || !of)
721     return;
722
723   switch(pc->type) {
724   case PC_COMMENT:
725     fprintf(of,";%s\n", ((pCodeComment *)pc)->comment);
726     break;
727
728   case PC_OPCODE:
729     // If the opcode has a label, print that first
730     {
731       pBranch *pbl = pc->label;
732       while(pbl) {
733         if(pbl->pc->type == PC_LABEL)
734           pCodePrintLabel(of, pbl->pc);
735         pbl = pbl->next;
736       }
737     }
738
739     fprintf(of, "\t%s\t", PCI(pc)->mnemonic);
740     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
741
742       if(PCI(pc)->bit_inst) {
743         if(PCI(pc)->pcop->type == PO_BIT) {
744           if( (((pCodeOpBit *)(PCI(pc)->pcop))->inBitSpace) )
745             fprintf(of,"(%s >> 3), (%s & 7)", 
746                     PCI(pc)->pcop->name ,
747                     PCI(pc)->pcop->name );
748           else
749             fprintf(of,"%s,%d", get_op(PCI(pc)), (((pCodeOpBit *)(PCI(pc)->pcop))->bit ));
750         } else
751           fprintf(of,"%s,0 ; ?bug", get_op(PCI(pc)));
752         //PCI(pc)->pcop->t.bit );
753       } else {
754
755         if(PCI(pc)->pcop->type == PO_BIT) {
756           if( PCI(pc)->num_ops == 2)
757             fprintf(of,"(%s >> 3),%c",PCI(pc)->pcop->name,((PCI(pc)->dest) ? 'F':'W'));
758           else
759             fprintf(of,"(1 << (%s & 7))",PCI(pc)->pcop->name);
760         }else {
761           fprintf(of,"%s",get_op(PCI(pc)));
762
763           if( PCI(pc)->num_ops == 2)
764             fprintf(of,",%c", ( (PCI(pc)->dest) ? 'F':'W'));
765         }
766       }
767     }
768
769     {
770       pBranch *dpb = pc->to;   // debug
771       while(dpb) {
772         switch ( dpb->pc->type) {
773         case PC_OPCODE:
774           fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic);
775           break;
776         case PC_LABEL:
777           fprintf(of, "\t;label %d", PCL(dpb->pc)->key);
778           break;
779         case PC_FUNCTION:
780           fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]"));
781           break;
782         case PC_COMMENT:
783         case PC_WILD:
784           break;
785         }
786         dpb = dpb->next;
787       }
788       fprintf(of,"\n");
789     }
790
791     break;
792
793   case PC_WILD:
794     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
795     if(PCW(pc)->operand) {
796       fprintf(of,";\toperand  ");
797       pCodeOpPrint(of,PCW(pc)->operand );
798     }
799     break;
800
801   case PC_LABEL:
802   default:
803     fprintf(of,"unknown pCode type %d\n",pc->type);
804   }
805
806 }
807
808 /*-----------------------------------------------------------------*/
809 /* pCodePrintFunction - prints function begin/end                  */
810 /*-----------------------------------------------------------------*/
811
812 static void pCodePrintFunction(FILE *of, pCode *pc)
813 {
814
815   if(!pc || !of)
816     return;
817
818   if( ((pCodeFunction *)pc)->modname) 
819     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
820
821   if(PCF(pc)->fname) {
822     pBranch *exits = pc->to;
823     int i=0;
824     fprintf(of,"%s\t;Function start\n",PCF(pc)->fname);
825     while(exits) {
826       i++;
827       exits = exits->next;
828     }
829     if(i) i--;
830     fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
831     
832   }else {
833     if(pc->from && 
834        pc->from->pc->type == PC_FUNCTION &&
835        PCF(pc->from->pc)->fname) 
836       fprintf(of,"; exit point of %s\n",PCF(pc->from->pc)->fname);
837     else
838       fprintf(of,"; exit point [can't find entry point]\n");
839   }
840 }
841 /*-----------------------------------------------------------------*/
842 /* pCodePrintLabel - prints label                                  */
843 /*-----------------------------------------------------------------*/
844
845 static void pCodePrintLabel(FILE *of, pCode *pc)
846 {
847
848   if(!pc || !of)
849     return;
850
851   if(PCL(pc)->label) 
852     fprintf(of,"%s\n",PCL(pc)->label);
853   else if (PCL(pc)->key >=0) 
854     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
855   else
856     fprintf(of,";wild card label\n");
857
858 }
859
860 /*-----------------------------------------------------------------*/
861 /* _DLL * DLL_append                                               */
862 /*                                                                 */ 
863 /*  Append a _DLL object to the end of a _DLL (doubly linked list) */ 
864 /* If The list to which we want to append is non-existant then one */ 
865 /* is created. Other wise, the end of the list is sought out and   */ 
866 /* a new DLL object is appended to it. In either case, the void    */
867 /* *data is added to the newly created DLL object.                 */
868 /*-----------------------------------------------------------------*/
869
870 static void * DLL_append(_DLL *list, _DLL *next)
871 {
872   _DLL *b;
873
874
875   /* If there's no list, then create one: */
876   if(!list) {
877     next->next = next->prev = NULL;
878     return next;
879   }
880
881
882   /* Search for the end of the list. */
883   b = list;
884   while(b->next)
885     b = b->next;
886
887   /* Now append the new DLL object */
888   b->next = next;
889   b->next->prev = b;
890   b = b->next; 
891   b->next = NULL;
892
893   return list;
894   
895 }  
896 /*-----------------------------------------------------------------*/
897
898 static pBranch * pBranchAppend(pBranch *h, pBranch *n)
899 {
900   pBranch *b;
901
902   if(!h)
903     return n;
904
905   b = h;
906   while(b->next)
907     b = b->next;
908
909   b->next = n;
910
911   return h;
912   
913 }  
914 /*-----------------------------------------------------------------*/
915 /* pBranchLink - given two pcodes, this function will link them    */
916 /*               together through their pBranches                  */
917 /*-----------------------------------------------------------------*/
918 static void pBranchLink(pCode *f, pCode *t)
919 {
920   pBranch *b;
921
922   // Declare a new branch object for the 'from' pCode.
923
924   _ALLOC(b,sizeof(pBranch));
925   b->pc = t;                    // The link to the 'to' pCode.
926   b->next = NULL;
927
928   f->to = pBranchAppend(f->to,b);
929
930   // Now do the same for the 'to' pCode.
931
932   _ALLOC(b,sizeof(pBranch));
933   b->pc = f;
934   b->next = NULL;
935
936   t->from = pBranchAppend(t->from,b);
937   
938 }
939
940 #if 0
941 /*-----------------------------------------------------------------*/
942 /* pBranchFind - find the pBranch in a pBranch chain that contains */
943 /*               a pCode                                           */
944 /*-----------------------------------------------------------------*/
945 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
946 {
947   while(pb) {
948
949     if(pb->pc == pc)
950       return pb;
951
952     pb = pb->next;
953   }
954
955   return NULL;
956 }
957
958 /*-----------------------------------------------------------------*/
959 /* pCodeUnlink - Unlink the given pCode from its pCode chain.      */
960 /*-----------------------------------------------------------------*/
961 static void pCodeUnlink(pCode *pc)
962 {
963   pBranch *pb1,*pb2;
964   pCode *pc1;
965
966   if(!pc->prev || !pc->next) {
967     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
968     exit(1);
969   }
970
971   /* first remove the pCode from the chain */
972   pc->prev->next = pc->next;
973   pc->next->prev = pc->prev;
974
975   /* Now for the hard part... */
976
977   /* Remove the branches */
978
979   pb1 = pc->from;
980   while(pb1) {
981     pc1 = pb1->pc;    /* Get the pCode that branches to the
982                        * one we're unlinking */
983
984     /* search for the link back to this pCode (the one we're
985      * unlinking) */
986     if(pb2 = pBranchFind(pc1->to,pc)) {
987       pb2->pc = pc->to->pc;  // make the replacement
988
989       /* if the pCode we're unlinking contains multiple 'to'
990        * branches (e.g. this a skip instruction) then we need
991        * to copy these extra branches to the chain. */
992       if(pc->to->next)
993         pBranchAppend(pb2, pc->to->next);
994     }
995     
996     pb1 = pb1->next;
997   }
998
999
1000 }
1001 #endif
1002 /*-----------------------------------------------------------------*/
1003 /*-----------------------------------------------------------------*/
1004 static void genericAnalyze(pCode *pc)
1005 {
1006   switch(pc->type) {
1007   case PC_WILD:
1008   case PC_COMMENT:
1009     return;
1010   case PC_LABEL:
1011   case PC_FUNCTION:
1012   case PC_OPCODE:
1013     {
1014       // Go through the pCodes that are in pCode chain and link
1015       // them together through the pBranches. Note, the pCodes
1016       // are linked together as a contiguous stream like the 
1017       // assembly source code lines. The linking here mimics this
1018       // except that comments are not linked in.
1019       // 
1020       pCode *npc = pc->next;
1021       while(npc) {
1022         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
1023           pBranchLink(pc,npc);
1024           return;
1025         } else
1026           npc = npc->next;
1027       }
1028     }
1029   }
1030 }
1031
1032 /*-----------------------------------------------------------------*/
1033 /* findLabel - Search the pCode for a particular label             */
1034 /*-----------------------------------------------------------------*/
1035 pCode * findLabel(pCodeOpLabel *pcop_label)
1036 {
1037   pBlock *pb;
1038   pCode  *pc;
1039   pBranch *pbr;
1040
1041   if(!the_pFile)
1042     return NULL;
1043
1044   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1045     for(pc = pb->pcHead; pc; pc = pc->next) {
1046       if(pc->type == PC_LABEL) {
1047         if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
1048           return pc;
1049       }
1050       if(pc->type == PC_OPCODE) {
1051         pbr = pc->label;
1052         while(pbr) {
1053           if(pbr->pc->type == PC_LABEL) {
1054             if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
1055               return pc;
1056           }
1057           pbr = pbr->next;
1058         }
1059       }
1060
1061     }
1062   }
1063
1064   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
1065   return NULL;
1066 }
1067
1068 /*-----------------------------------------------------------------*/
1069 /* findNextInstruction - given a pCode, find the next instruction  */
1070 /*                       in the linked list                        */
1071 /*-----------------------------------------------------------------*/
1072 pCode * findNextInstruction(pCode *pc)
1073 {
1074
1075   while(pc) {
1076     if(pc->type == PC_OPCODE)
1077       return pc;
1078
1079     pc = pc->next;
1080   }
1081
1082   fprintf(stderr,"Couldn't find instruction\n");
1083   return NULL;
1084 }
1085
1086 /*-----------------------------------------------------------------*/
1087 /* findFunctionEnd - given a pCode find the end of the function    */
1088 /*                   that contains it     t                        */
1089 /*-----------------------------------------------------------------*/
1090 pCode * findFunctionEnd(pCode *pc)
1091 {
1092
1093   while(pc) {
1094     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
1095       return pc;
1096
1097     pc = pc->next;
1098   }
1099
1100   fprintf(stderr,"Couldn't find function end\n");
1101   return NULL;
1102 }
1103
1104 #if 0
1105 /*-----------------------------------------------------------------*/
1106 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
1107 /*                instruction with which it is associated.         */
1108 /*-----------------------------------------------------------------*/
1109 static void AnalyzeLabel(pCode *pc)
1110 {
1111
1112   pCodeUnlink(pc);
1113
1114 }
1115 #endif
1116
1117 static void AnalyzeGOTO(pCode *pc)
1118 {
1119
1120   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
1121
1122 }
1123
1124 static void AnalyzeSKIP(pCode *pc)
1125 {
1126
1127   pBranchLink(pc,findNextInstruction(pc->next));
1128   pBranchLink(pc,findNextInstruction(pc->next->next));
1129
1130 }
1131
1132 static void AnalyzeRETURN(pCode *pc)
1133 {
1134
1135   //  branch_link(pc,findFunctionEnd(pc->next));
1136
1137 }
1138
1139
1140 void AnalyzepBlock(pBlock *pb)
1141 {
1142   pCode *pc;
1143
1144   if(!pb)
1145     return;
1146
1147   for(pc = pb->pcHead; pc; pc = pc->next)
1148     pc->analyze(pc);
1149
1150 }
1151
1152 int OptimizepBlock(pBlock *pb)
1153 {
1154   pCode *pc;
1155   int matches =0;
1156
1157   if(!pb || !peepOptimizing)
1158     return 0;
1159
1160   fprintf(stderr," Optimizing pBlock\n");
1161
1162   for(pc = pb->pcHead; pc; pc = pc->next)
1163     matches += pCodePeepMatchRule(pc);
1164
1165   return matches;
1166
1167 }
1168 /*-----------------------------------------------------------------*/
1169 /* pBlockMergeLabels - remove the pCode labels from the pCode      */
1170 /*                     chain and put them into pBranches that are  */
1171 /*                     associated with the appropriate pCode       */
1172 /*                     instructions.                               */
1173 /*-----------------------------------------------------------------*/
1174 void pBlockMergeLabels(pBlock *pb)
1175 {
1176   pBranch *pbr;
1177   pCode *pc, *pcnext=NULL;
1178
1179   if(!pb)
1180     return;
1181
1182   for(pc = pb->pcHead; pc; pc = pc->next) {
1183
1184     if(pc->type == PC_LABEL) {
1185       if( !(pcnext = findNextInstruction(pc)) ) 
1186         return;  // Couldn't find an instruction associated with this label
1187
1188       // Unlink the pCode label from it's pCode chain
1189       if(pc->prev) 
1190         pc->prev->next = pc->next;
1191       if(pc->next)
1192         pc->next->prev = pc->prev;
1193
1194       // And link it into the instruction's pBranch labels. (Note, since
1195       // it's possible to have multiple labels associated with one instruction
1196       // we must provide a means to accomodate the additional labels. Thus
1197       // the labels are placed into the singly-linked list "label" as 
1198       // opposed to being a single member of the pCodeInstruction.)
1199
1200       _ALLOC(pbr,sizeof(pBranch));
1201       pbr->pc = pc;
1202       pbr->next = NULL;
1203
1204       pcnext->label = pBranchAppend(pcnext->label,pbr);
1205     }
1206
1207   }
1208
1209 }
1210
1211 /*-----------------------------------------------------------------*/
1212 /*-----------------------------------------------------------------*/
1213 void OptimizepCode(char dbName)
1214 {
1215 #define MAX_PASSES 4
1216
1217   int matches = 0;
1218   int passes = 0;
1219   pBlock *pb;
1220
1221   if(!the_pFile)
1222     return;
1223
1224   fprintf(stderr," Optimizing pCode\n");
1225
1226   do {
1227     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1228       if(pb->cmemmap->dbName == dbName)
1229         matches += OptimizepBlock(pb);
1230     }
1231   }
1232   while(matches && ++passes < MAX_PASSES);
1233
1234 }
1235
1236 /*-----------------------------------------------------------------*/
1237 /* AnalyzepCode - parse the pCode that has been generated and form */
1238 /*                all of the logical connections.                  */
1239 /*                                                                 */
1240 /* Essentially what's done here is that the pCode flow is          */
1241 /* determined.                                                     */
1242 /*-----------------------------------------------------------------*/
1243
1244 void AnalyzepCode(char dbName)
1245 {
1246   pBlock *pb;
1247   pCode *pc;
1248   pBranch *pbr;
1249
1250   if(!the_pFile)
1251     return;
1252
1253   fprintf(stderr," Analyzing pCode");
1254
1255   /* First, merge the labels with the instructions */
1256   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1257     if(pb->cmemmap->dbName == dbName)
1258       pBlockMergeLabels(pb);
1259   }
1260
1261   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1262     if(pb->cmemmap->dbName == dbName)
1263       OptimizepBlock(pb);
1264   }
1265
1266   /* Now build the call tree.
1267      First we examine all of the pCodes for functions.
1268      
1269    */
1270   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1271     if(pb->cmemmap->dbName == dbName) {
1272       pCode *pc_fstart=NULL;
1273       for(pc = pb->pcHead; pc; pc = pc->next) {
1274         if(pc->type == PC_FUNCTION) {
1275           if (PCF(pc)->fname) {
1276             // Found the beginning of a function.
1277             _ALLOC(pbr,sizeof(pBranch));
1278             pbr->pc = pc_fstart = pc;
1279             pbr->next = NULL;
1280
1281             the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
1282           } else {
1283             // Found an exit point in a function, e.g. return
1284             // (Note, there may be more than one return per function)
1285             if(pc_fstart)
1286               pBranchLink(pc_fstart, pc);
1287           }
1288         }
1289       }
1290     }
1291   }
1292 }
1293
1294 /*-----------------------------------------------------------------*/
1295 /* ispCodeFunction - returns true if *pc is the pCode of a         */
1296 /*                   function                                      */
1297 /*-----------------------------------------------------------------*/
1298 bool ispCodeFunction(pCode *pc)
1299 {
1300
1301   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
1302     return 1;
1303
1304   return 0;
1305 }
1306
1307 void printCallTree(FILE *of)
1308 {
1309   pBranch *pbr;
1310
1311   if(!the_pFile)
1312     return;
1313
1314   if(!of)
1315     of = stderr;
1316
1317   pbr = the_pFile->functions;
1318
1319   fprintf(of,"Call Tree\n");
1320   while(pbr) {
1321     if(pbr->pc) {
1322       pCode *pc = pbr->pc;
1323       if(!ispCodeFunction(pc))
1324         fprintf(of,"bug in call tree");
1325
1326
1327       fprintf(of,"Function: %s\n", PCF(pc)->fname);
1328
1329       while(pc->next && !ispCodeFunction(pc->next)) {
1330         pc = pc->next;
1331         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
1332           fprintf(of,"\t%s\n",get_op(PCI(pc)));
1333       }
1334     }
1335
1336     pbr = pbr->next;
1337   }
1338 }
1339 /*-----------------------------------------------------------------
1340
1341   pCode peephole optimization
1342
1343
1344   The pCode "peep hole" optimization is not too unlike the peep hole
1345   optimization in SDCCpeeph.c. The major difference is that here we
1346   use pCode's whereas there we use ASCII strings. The advantage with
1347   pCode's is that we can ascertain flow information in the instructions
1348   being optimized.
1349
1350
1351 <FIX ME> - elaborate...
1352
1353   -----------------------------------------------------------------*/
1354
1355 #if 0
1356 /*-----------------------------------------------------------------*/
1357 /* pCodePeep */
1358 /*-----------------------------------------------------------------*/
1359 int pCodePeepCompare(pCode *pc, pCodePeep *pcp)
1360 {
1361   pCode *pcfrom,*pcto;
1362
1363   pcfrom = pc;
1364   for( pcto=pcp->target; pcto; pcto=pcto->next) {
1365
1366     pcfrom = findNextInstruction(pcfrom);
1367
1368     if( pcfrom &&  
1369         (PCI(pcfrom)->op == PCI(pcto)->op || 
1370          PCI(pcto)->op == POC_WILD))
1371       continue;
1372     return 0;
1373   }
1374   return 0;
1375 }
1376
1377 /*-----------------------------------------------------------------*/
1378 /* pCodePeep */
1379 /*-----------------------------------------------------------------*/
1380 void pCodePeepSearch(pCodePeep *snippet)
1381 {
1382   pBlock *pb;
1383   pCode *pc;
1384
1385   if(!the_pFile)
1386     return;
1387
1388   /* compare the chain to the pCode that we've 
1389      got so far. If a match is found, then replace
1390      the pCode chain.
1391   */
1392   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1393     for(pc = pb->pcHead; pc; pc = pc->next) {
1394       pCodePeepCompare(pc,snippet);
1395     }
1396   }
1397
1398 }
1399 #endif
1400
1401 #if 0
1402 pBlock *pBlockAppend(pBlock *pb1, pBlock *pb2)
1403 {
1404   pBlock *pb;
1405
1406   if(!pb1->tail)
1407     return pb2;
1408
1409   pb = pb1->tail;
1410
1411   pb2->head = pb1;
1412   pb2->tail = NULL;
1413   pb1->tail = pb2;
1414
1415 }
1416
1417 #endif
1418
1419 void pCodePeepInit(void)
1420 {
1421   pBlock *pb;
1422   //  pCode *pc;
1423   pCodePeep *pcp;
1424   pCodePeepSnippets *pcps;
1425
1426   /* Declare a peep code snippet */
1427   /* <FIXME> do I really need a separate struct just to DLL the snippets? */
1428   /* e.g. I could put the DLL into the pCodePeep structure */
1429   pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1430   pcp = pcps->peep  = Safe_calloc(1,sizeof(pCodePeep));
1431   peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1432
1433
1434   pb = newpCodeChain(NULL, newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1435   addpCode2pBlock( pb,     newpCode(POC_MOVFW, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1436
1437   pcp->target = pb;
1438
1439   pcp->replace = newpCodeChain(NULL, newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1440
1441   /* Allocate space to store pointers to the wildcard variables */
1442   pcp->nvars = 1;
1443   pcp->vars  = Safe_calloc(pcp->nvars, sizeof(char *));
1444   pcp->nwildpCodes = 0;
1445   pcp->wildpCodes  = NULL;
1446
1447   pcp->postFalseCond = PCC_Z;
1448   pcp->postTrueCond  = PCC_NONE;
1449
1450   fprintf(stderr,"Peep rule\nTarget:\n");
1451   printpCodeString(stderr,pcp->target->pcHead, 10);
1452   fprintf(stderr,"Replaced with:\n");
1453   printpCodeString(stderr,pcp->replace->pcHead, 10);
1454
1455   /* Now for another peep example */
1456   pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1457   pcp = pcps->peep  = Safe_calloc(1,sizeof(pCodePeep));
1458   peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1459
1460   {
1461     pCodeOp *pcl;
1462     pCodeOp *pcw;
1463
1464     pb = newpCodeChain(NULL, newpCode(POC_BTFSC, newpCodeOpWild(0,pcp,newpCodeOpBit(NULL,-1))) );
1465
1466     pcl = newpCodeOpLabel(-1);
1467     pcw = newpCodeOpWild(1, pcp, pcl);
1468     addpCode2pBlock( pb,     newpCode(POC_GOTO,  pcw));
1469     addpCode2pBlock( pb,     newpCodeWild(0,NULL,NULL));
1470     addpCode2pBlock( pb,     newpCodeWild(1,NULL,pcw));
1471
1472
1473     pcp->target = pb;
1474
1475     pb = newpCodeChain(NULL, newpCode(POC_BTFSS, newpCodeOpWild(0,pcp,newpCodeOpBit(NULL,-1))) );
1476     addpCode2pBlock( pb,     newpCodeWild(0,NULL,NULL));
1477     addpCode2pBlock( pb,     newpCodeWild(1,NULL,pcw));
1478
1479     pcp->replace = pb;
1480
1481     /* Allocate space to store pointers to the wildcard variables */
1482     pcp->nvars = 2;
1483     pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
1484     pcp->nwildpCodes = 2;
1485     pcp->wildpCodes = Safe_calloc(pcp->nwildpCodes, sizeof(pCode *));
1486
1487     pcp->postFalseCond = PCC_NONE;
1488     pcp->postTrueCond  = PCC_NONE;
1489   }
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500   //-------------
1501
1502   /* Now for another peep example */
1503   pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1504   pcp = pcps->peep  = Safe_calloc(1,sizeof(pCodePeep));
1505   peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1506
1507   {
1508     pCodeOp *pcw;
1509
1510     pcw = newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER));
1511
1512     pb = newpCodeChain(NULL, newpCode(POC_MOVWF, pcw));
1513     addpCode2pBlock( pb,     newpCode(POC_MOVWF, pcw));
1514
1515     pcp->target = pb;
1516
1517     pb = newpCodeChain(NULL, newpCode(POC_MOVWF, pcw));
1518
1519     pcp->replace = pb;
1520
1521     /* Allocate space to store pointers to the wildcard variables */
1522     pcp->nvars = 1;
1523     pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
1524     pcp->nwildpCodes = 0;
1525     pcp->wildpCodes = NULL;
1526
1527     pcp->postFalseCond = PCC_NONE;
1528     pcp->postTrueCond  = PCC_NONE;
1529   }
1530
1531
1532
1533
1534 }
1535
1536 /*-----------------------------------------------------------------*/
1537 /* pCodeSearchCondition - Search a pCode chain for a 'condition'   */
1538 /*                                                                 */
1539 /* return conditions                                               */
1540 /*  1 - The Condition was found for a pCode's input                */
1541 /*  0 - No matching condition was found for the whole chain        */
1542 /* -1 - The Condition was found for a pCode's output               */
1543 /*                                                                 */
1544 /*-----------------------------------------------------------------*/
1545 int pCodeSearchCondition(pCode *pc, unsigned int cond)
1546 {
1547
1548   while(pc) {
1549
1550     /* If we reach a function end (presumably an end since we most
1551        probably began the search in the middle of a function), then
1552        the condition was not found. */
1553     if(pc->type == PC_FUNCTION)
1554       return 0;
1555
1556     if(pc->type == PC_OPCODE) {
1557       if(PCI(pc)->inCond & cond)
1558         return 1;
1559       if(PCI(pc)->outCond & cond)
1560         return -1;
1561     }
1562
1563     pc = pc->next;
1564   }
1565
1566   return 0;
1567 }
1568 /*-----------------------------------------------------------------*/
1569 /* pCodePeepMatchLine - Compare source and destination pCodes to   */
1570 /*                      see they're the same.                      */
1571 /*-----------------------------------------------------------------*/
1572 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd)
1573 {
1574   int index;   // index into wild card arrays
1575
1576   if(pcs->type == pcd->type) {
1577
1578     if(pcs->type == PC_OPCODE) {
1579
1580       /* If the opcodes don't match then the line doesn't match */
1581       if(PCI(pcs)->op != PCI(pcd)->op)
1582         return 0;
1583
1584       fprintf(stderr,"%s comparing\n",__FUNCTION__);
1585       pcs->print(stderr,pcs);
1586       pcd->print(stderr,pcd);
1587
1588       /* Compare the operands */
1589       if(PCI(pcd)->pcop) {
1590         if (PCI(pcd)->pcop->type == PO_WILD) {
1591           index = PCOW(PCI(pcd)->pcop)->id;
1592
1593 #ifdef DEBUG_PCODEPEEP
1594           if (index > peepBlock->nvars) {
1595             fprintf(stderr,"%s - variables exceeded\n",__FUNCTION__);
1596             exit(1);
1597           }
1598 #endif
1599           if(peepBlock->vars[index])
1600             return (strcmp(peepBlock->vars[index],PCI(pcs)->pcop->name) == 0);
1601           else {
1602             peepBlock->vars[index] = PCI(pcs)->pcop->name;
1603             return 1;
1604           }
1605         }
1606       } else
1607         /* The pcd has no operand. Lines match if pcs has no operand either*/
1608         return (PCI(pcs)->pcop == NULL);
1609     }
1610   }
1611
1612
1613   if((pcd->type == PC_WILD) && (pcs->type == PC_OPCODE)) {
1614
1615     int labindex;
1616
1617     index = PCW(pcd)->id;
1618
1619     fprintf(stderr,"%s comparing wild cards\n",__FUNCTION__);
1620     pcs->print(stderr,pcs);
1621     pcd->print(stderr,pcd);
1622
1623     peepBlock->wildpCodes[PCW(pcd)->id] = pcs;
1624
1625     /* Check for a label associated with this wild pCode */
1626     // If the wild card has a label, make sure the source code does too.
1627     if(PCW(pcd)->label) {
1628       if(!pcs->label)
1629         return 0;
1630
1631       labindex = PCOW(PCW(pcd)->label)->id;
1632       if(peepBlock->vars[labindex] == NULL) {
1633         // First time to encounter this label
1634         peepBlock->vars[labindex] = PCL(pcs->label->pc)->label;
1635         fprintf(stderr,"first time for a label\n");
1636       } else {
1637         if(strcmp(peepBlock->vars[labindex],PCL(pcs->label->pc)->label) != 0) {
1638           fprintf(stderr,"labels don't match\n");
1639           return 0;
1640         }
1641         fprintf(stderr,"matched a label\n");
1642       }
1643
1644     }
1645
1646     if(PCW(pcd)->operand) {
1647       if(peepBlock->vars[index]) {
1648         int i = (strcmp(peepBlock->vars[index],PCI(pcs)->pcop->name) == 0);
1649         if(i)
1650           fprintf(stderr," (matched)\n");
1651         else {
1652           fprintf(stderr," (no match: wild card operand mismatch\n");
1653           fprintf(stderr,"  peepblock= %s,  pcodeop= %s\n",
1654                   peepBlock->vars[index],
1655                   PCI(pcs)->pcop->name);
1656         }
1657         return i;
1658       } else {
1659         peepBlock->vars[index] = PCI(pcs)->pcop->name;
1660         return 1;
1661       }
1662     }
1663
1664     pcs = findNextInstruction(pcs->next);
1665     fprintf(stderr," (next to match)\n");
1666     pcs->print(stderr,pcs);
1667     return 1; /*  wild card matches */
1668   }
1669
1670   return 0;
1671 }
1672
1673 /*-----------------------------------------------------------------*/
1674 /*-----------------------------------------------------------------*/
1675 void pCodePeepClrVars(pCodePeep *pcp)
1676 {
1677
1678   int i;
1679
1680   for(i=0;i<pcp->nvars; i++)
1681     pcp->vars[i] = NULL;
1682
1683 }
1684
1685 /*-----------------------------------------------------------------*/
1686 /*-----------------------------------------------------------------*/
1687 void pCodeInsertAfter(pCode *pc1, pCode *pc2)
1688 {
1689
1690   if(!pc1 || !pc2)
1691     return;
1692
1693   pc2->next = pc1->next;
1694   if(pc1->next)
1695     pc1->next->prev = pc2;
1696
1697   pc2->prev = pc1;
1698   pc1->next = pc2;
1699
1700 }
1701
1702 /*-----------------------------------------------------------------*/
1703 /* pCodeOpCopy - copy a pcode operator                             */
1704 /*-----------------------------------------------------------------*/
1705 static pCodeOp *pCodeOpCopy(pCodeOp *pcop)
1706 {
1707   pCodeOp *pcopnew=NULL;
1708
1709   if(!pcop)
1710     return NULL;
1711
1712   switch(pcop->type) { 
1713   case PO_CRY:
1714   case PO_BIT:
1715     pcopnew = Safe_calloc(1,sizeof(pCodeOpBit) );
1716     PCOB(pcopnew)->bit = PCOB(pcop)->bit;
1717     PCOB(pcopnew)->inBitSpace = PCOB(pcop)->inBitSpace;
1718
1719     break;
1720
1721   case PO_WILD:
1722     /* Here we expand the wild card into the appropriate type: */
1723     /* By recursively calling pCodeOpCopy */
1724     pcopnew = pCodeOpCopy(PCOW(pcop)->subtype);
1725     pcopnew->name = Safe_strdup(PCOW(pcop)->pcp->vars[PCOW(pcop)->id]);
1726     return pcopnew;
1727     break;
1728
1729   case PO_LABEL:
1730     pcopnew = Safe_calloc(1,sizeof(pCodeOpLabel) );
1731     PCOLAB(pcopnew)->key =  PCOLAB(pcop)->key;
1732     break;
1733
1734   case PO_LITERAL:
1735   case PO_IMMEDIATE:
1736     pcopnew = Safe_calloc(1,sizeof(pCodeOpLit) );
1737     PCOL(pcopnew)->lit = PCOL(pcop)->lit;
1738     break;
1739
1740   case PO_GPR_REGISTER:
1741   case PO_SFR_REGISTER:
1742   case PO_DIR:
1743   case PO_STR:
1744   case PO_NONE:
1745   case PO_W:
1746   case PO_STATUS:
1747   case PO_FSR:
1748   case PO_INDF:
1749
1750     pcopnew = Safe_calloc(1,sizeof(pCodeOp) );
1751
1752   }
1753
1754   pcopnew->type = pcop->type;
1755   pcopnew->name = Safe_strdup(pcop->name);
1756
1757   return pcopnew;
1758 }
1759
1760 #if 0
1761 /*-----------------------------------------------------------------*/
1762 /* pCodeCopy - copy a pcode                                        */
1763 /*-----------------------------------------------------------------*/
1764 static pCode *pCodeCopy(pCode *pc)
1765 {
1766
1767   pCode *pcnew;
1768
1769   pcnew = newpCode(pc->type,pc->pcop);
1770 }
1771 #endif
1772 /*-----------------------------------------------------------------*/
1773 /*-----------------------------------------------------------------*/
1774 void pCodeDeleteChain(pCode *f,pCode *t)
1775 {
1776   pCode *pc;
1777
1778   while(f && f!=t) {
1779     fprintf(stderr,"delete pCode:\n");
1780     pc = f->next;
1781     f->print(stderr,f);
1782     //f->delete(f);
1783     f = pc;
1784   }
1785
1786 }
1787 /*-----------------------------------------------------------------*/
1788 /*-----------------------------------------------------------------*/
1789 int pCodePeepMatchRule(pCode *pc)
1790 {
1791   pCodePeep *peepBlock;
1792   pCode *pct, *pcin;
1793   _DLL *peeprules;
1794   int matched;
1795
1796   peeprules = (_DLL *)peepSnippets;
1797
1798   while(peeprules) {
1799     peepBlock = ((pCodePeepSnippets*)peeprules)->peep;
1800     pCodePeepClrVars(peepBlock);
1801
1802     pcin = pc;
1803     pct = peepBlock->target->pcHead;
1804     matched = 0;
1805     while(pct && pcin) {
1806
1807       if(! (matched = pCodePeepMatchLine(peepBlock, pcin,pct)))
1808         break;
1809
1810       pcin = findNextInstruction(pcin->next);
1811       pct = pct->next;
1812       //debug:
1813       fprintf(stderr,"    matched\n");
1814       if(!pcin)
1815         fprintf(stderr," end of code\n");
1816       if(!pct)
1817         fprintf(stderr," end of rule\n");
1818     }
1819
1820     if(matched) {
1821
1822       /* So far we matched the rule up to the point of the conditions .
1823        * In other words, all of the opcodes match. Now we need to see
1824        * if the post conditions are satisfied.
1825        * First we check the 'postFalseCond'. This means that we check
1826        * to see if any of the subsequent pCode's in the pCode chain 
1827        * following the point just past where we have matched depend on
1828        * the `postFalseCond' as input then we abort the match
1829        */
1830       fprintf(stderr,"    matched rule so far, now checking conditions\n");
1831       if (peepBlock->postFalseCond && 
1832           (pCodeSearchCondition(pcin,peepBlock->postFalseCond) > 0) )
1833         matched = 0;
1834     }
1835
1836     if(matched) {
1837
1838       pCode *pcprev;
1839       pCode *pcr;
1840
1841
1842       /* We matched a rule! Now we have to go through and remove the
1843          inefficient code with the optimized version */
1844
1845       fprintf(stderr, "Found a pcode peep match:\nRule:\n");
1846       printpCodeString(stderr,peepBlock->target->pcHead,10);
1847       fprintf(stderr,"first thing matched\n");
1848       pc->print(stderr,pc);
1849       fprintf(stderr,"last thing matched\n");
1850       pcin->print(stderr,pcin);
1851
1852
1853       /* Unlink the original code */
1854       pcprev = pc->prev;
1855       pcprev->next = pcin;
1856       pcin->prev = pc->prev;
1857       pCodeDeleteChain(pc,pcin);
1858
1859       /* Generate the replacement code */
1860       pc = pcprev;
1861       pcr = peepBlock->replace->pcHead;  // This is the replacement code
1862       while (pcr) {
1863         pCodeOp *pcop=NULL;
1864         /* If the replace pcode is an instruction with an operand, */
1865         /* then duplicate the operand (and expand wild cards in the process. */
1866         if(pcr->type == PC_OPCODE) {
1867           if(PCI(pcr)->pcop)
1868             pcop = pCodeOpCopy(PCI(pcr)->pcop);
1869
1870           pCodeInsertAfter(pc, newpCode(PCI(pcr)->op,pcop));
1871         } else if (pcr->type == PC_WILD) {
1872           pCodeInsertAfter(pc,peepBlock->wildpCodes[PCW(pcr)->id]);
1873         }
1874
1875         pc = pc->next;
1876         pcr = pcr->next;
1877       }
1878
1879       return 1;
1880     }
1881
1882     peeprules = peeprules->next;
1883   }
1884
1885   return 0;
1886 }