Parse peephole snippets to generate pCode
[fw/sdcc] / src / pic / pcodepeep.c
1 /*-------------------------------------------------------------------------
2
3    pcodepeep.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 #include <stdlib.h>
23
24 #include "common.h"   // Include everything in the SDCC src directory
25 #include "newalloc.h"
26
27
28 #include "pcode.h"
29 #include "ralloc.h"
30
31
32 pCodeOp *newpCodeOpWild(int id, pCodePeep *pcp, pCodeOp *subtype);
33 pCode *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label);
34 pCode * findNextInstruction(pCode *pc);
35 char *Safe_strdup(char *str);
36
37
38 /****************************************************************/
39 /*
40  * rootRules - defined in SDCCpeep.c
41  *  This is a pointer to the (parsed) peephole rules that are
42  * defined in peep.def.
43  */
44
45 //extern peepRule *rootRules;
46
47
48
49
50 /****************************************************************/
51 /****************************************************************/
52 typedef struct _DLL {
53   struct _DLL *prev;
54   struct _DLL *next;
55   //  void *data;
56 } _DLL;
57
58
59 typedef struct pCodePeepSnippets
60 {
61   _DLL dll;
62   pCodePeep *peep;
63 } pCodePeepSnippets;
64
65
66 static pCodePeepSnippets  *peepSnippets=NULL;
67
68 typedef struct pCodeToken 
69 {
70   int tt;  // token type;
71   union {
72     char c;  // character
73     int  n;  // number
74     char *s; // string
75   } tok;
76
77 } pCodeToken;
78
79 pCodeToken tokArr[50];
80 unsigned   tokIdx=0;
81
82
83 typedef enum  {
84   PCT_SPACE,
85   PCT_PERCENT,
86   PCT_COLON,
87   PCT_COMMA,
88   PCT_COMMENT,
89   PCT_STRING,
90   PCT_NUMBER
91
92 } pCodeTokens;
93
94
95 typedef struct parsedPattern {
96   struct pcPattern *pcp;
97   pCodeToken *pct;
98 } parsedPattern;
99
100 #define MAX_PARSEDPATARR 50
101 parsedPattern parsedPatArr[MAX_PARSEDPATARR];
102 unsigned int parsedPatIdx=0;
103
104
105 typedef enum {
106   PCP_LABEL,
107   PCP_STR,
108   PCP_WILDVAR,
109   PCP_WILDSTR,
110   PCP_COMMA
111 } pCodePatterns;
112
113 static char pcpat_label[]      = {PCT_PERCENT, PCT_NUMBER, PCT_COLON, 0};
114 static char pcpat_string[]     = {PCT_STRING, 0};
115 static char pcpat_wildString[] = {PCT_PERCENT, PCT_STRING, 0};
116 static char pcpat_wildVar[]    = {PCT_PERCENT, PCT_NUMBER, 0};
117 static char pcpat_comma[]      = {PCT_COMMA, 0};
118
119
120 typedef struct pcPattern {
121   int pt;                 // Pattern type
122   char *tokens;           // list of tokens that describe the pattern
123   void * (*f) (void *);
124 } pcPattern;
125
126 pcPattern pcpArr[] = {
127   {PCP_LABEL,     pcpat_label,      NULL},
128   {PCP_WILDSTR,   pcpat_wildString, NULL},
129   {PCP_STR,       pcpat_string,     NULL},
130   {PCP_WILDVAR,   pcpat_wildVar,    NULL},
131   {PCP_COMMA,     pcpat_comma,      NULL}
132 };
133
134 #define PCPATTERNS (sizeof(pcpArr)/sizeof(pcPattern))
135
136 // Assembly Line Token
137 typedef enum {
138   ALT_LABEL,
139   ALT_MNEM0,
140   ALT_MNEM1,
141   ALT_MNEM2
142 } altPatterns;
143
144 static char alt_label[]     = { PCP_LABEL, 0};
145 static char alt_mnem0[]     = { PCP_STR, 0};
146 static char alt_mnem1[]     = { PCP_STR, PCP_STR, 0};
147 static char alt_mnem2[]     = { PCP_STR, PCP_STR, PCP_COMMA, PCP_STR, 0};
148
149 static void * cvt_altpat_label(void *pp);
150
151 pcPattern altArr[] = {
152   {ALT_LABEL,        alt_label,  cvt_altpat_label},
153   {ALT_MNEM2,        alt_mnem2,  NULL},
154
155 };
156 /*-----------------------------------------------------------------*/
157 /*-----------------------------------------------------------------*/
158 static void * cvt_altpat_label(void *pp)
159 {
160   fprintf(stderr,"altpat_label\n");
161   return NULL;
162 }
163
164 #if 0
165 /*-----------------------------------------------------------------*/
166 /*-----------------------------------------------------------------*/
167 static pCode * cvt_pcpat_wildMnem(parsedPattern *pp)
168 {
169   fprintf(stderr,"pcpat_wildMnem\n");
170   return NULL;
171 }
172 /*-----------------------------------------------------------------*/
173 /*-----------------------------------------------------------------*/
174 static pCode * cvt_pcpat_Mnem(parsedPattern *pp)
175 {
176   fprintf(stderr,"pcpat_Mnem\n");
177   return NULL;
178 }
179 /*-----------------------------------------------------------------*/
180 /*-----------------------------------------------------------------*/
181 static pCode * cvt_pcpat_wildVar(parsedPattern *pp)
182 {
183   fprintf(stderr,"pcpat_wildVar\n");
184   return NULL;
185 }
186 /*-----------------------------------------------------------------*/
187 /*-----------------------------------------------------------------*/
188 static pCode * cvt_pcpat_var(parsedPattern *pp)
189 {
190   fprintf(stderr,"pcpat_var\n");
191   return NULL;
192 }
193 #endif
194
195
196
197
198
199 /*-----------------------------------------------------------------*/
200 /*-----------------------------------------------------------------*/
201
202
203 static void parseLineNode(char *ln)
204 {
205
206   tokIdx = 0;
207
208   if(!ln || !*ln)
209     return;
210
211   while(*ln) {
212
213     if(isspace(*ln)) {
214       tokArr[tokIdx++].tt = PCT_SPACE;
215       while (isspace (*ln))
216         ln++;
217       continue;
218     }
219
220     if(isdigit(*ln)) {
221
222       tokArr[tokIdx].tt = PCT_NUMBER;
223       tokArr[tokIdx++].tok.n = strtol(ln, &ln, 10);
224
225       continue;
226
227     }
228
229     switch(*ln) {
230     case '%':
231       tokArr[tokIdx++].tt = PCT_PERCENT;
232       break;
233     case ':':
234       tokArr[tokIdx++].tt = PCT_COLON;
235       break;
236     case ';':
237       tokArr[tokIdx].tok.s = Safe_strdup(ln);
238       tokArr[tokIdx++].tt = PCT_COMMENT;
239       return;
240     case ',':
241       tokArr[tokIdx++].tt = PCT_COMMA;
242       break;
243
244
245     default:
246       if(isalpha(*ln)) {
247         char buffer[50];
248         int i=0;
249
250         while( (isalpha(*ln)  ||  isdigit(*ln)) && i<49)
251           buffer[i++] = *ln++;
252
253         ln--;
254         buffer[i] = 0;
255
256         tokArr[tokIdx].tok.s = Safe_strdup(buffer);
257         //fprintf(stderr," string %s",tokArr[tokIdx].tok.s);
258
259         tokArr[tokIdx++].tt = PCT_STRING;
260
261       }
262     }
263     ln++;
264   }
265 }
266
267
268
269
270 void dump1Token(pCodeTokens tt)
271 {
272
273   switch(tt) {
274   case PCT_SPACE:
275     fprintf(stderr, " space ");
276     break;
277   case PCT_PERCENT:
278     fprintf(stderr, " pct ");
279     fputc('%', stderr);
280     break;
281   case PCT_COLON:
282     fprintf(stderr, " col ");
283     fputc(':',stderr);
284     break;
285   case PCT_COMMA:
286     fprintf(stderr, " com ");
287     fputc(',',stderr);
288     break;
289   case PCT_COMMENT:
290   case PCT_STRING:
291     fprintf(stderr, " str ");
292     //fprintf(stderr,"%s",tokArr[i].tok.s);
293     break;
294   case PCT_NUMBER:
295     fprintf(stderr, " num ");
296     //fprintf(stderr,"%d",tokArr[i].tok.n);
297
298
299   }
300 }
301
302
303 int pcComparePattern(pCodeToken *pct, char *pat, int max_tokens)
304 {
305   int i=0;
306
307   if(!pct || !pat || !*pat)
308     return 0;
309
310   //fprintf(stderr,"comparing against:\n");
311
312   while(i < max_tokens) {
313
314     if(*pat == 0){
315       //fprintf(stderr,"matched\n");
316       return (i+1);
317     }
318
319     //dump1Token(*pat); fprintf(stderr,"\n");
320
321     if(pct->tt != *pat) 
322       return 0;
323
324
325     pct++;
326     pat++;
327   }
328
329   return 0;
330
331 }
332
333 int advTokIdx(int *v, int amt)
334 {
335
336   if(*v + amt > tokIdx)
337     return 1;
338
339   *v += amt;
340   return 0;
341
342 }
343
344 void dumpTokens(void)
345 {
346   int i;
347
348   if(!tokIdx)
349     return;
350
351   for(i=0; i<=tokIdx; i++)
352     dump1Token(tokArr[i].tt);
353
354
355   fputc('\n',stderr);
356
357   {
358     int lparsedPatIdx=0;
359     int lpcpIdx;
360     int ltokIdx =0;
361     int matching = 0;
362     int j;
363
364     pCodeOp *pcl   = NULL;       // Storage for a label
365     pCodeOp *pco1  = NULL;       // 1st operand
366     pCodeOp *pco2  = NULL;       // 2nd operand
367     pCode   *pc    = NULL;       // Mnemonic
368
369     typedef enum {
370       PS_START,
371       PS_HAVE_LABEL,
372       PS_HAVE_MNEM,
373       PS_HAVE_1OPERAND,
374       PS_HAVE_COMMA,
375       PS_HAVE_2OPERANDS
376     } ParseStates;
377
378     ParseStates state = PS_START;
379
380     do {
381
382       lpcpIdx=0;
383       matching = 0;
384       //fprintf(stderr,"ltokIdx = %d\n",ltokIdx);
385
386       if(  ((tokArr[ltokIdx].tt == PCT_SPACE) )//|| (tokArr[ltokIdx].tt == PCT_COMMA))
387            && (advTokIdx(&ltokIdx, 1)) ) // eat space
388         break;
389
390       do {
391         j = pcComparePattern(&tokArr[ltokIdx], pcpArr[lpcpIdx].tokens, tokIdx +1);
392         if( j ) {
393           //fprintf(stderr,"found token pattern match\n");
394           switch(pcpArr[lpcpIdx].pt) {
395           case  PCP_LABEL:
396             if(state == PS_START){
397               fprintf(stderr,"  label\n");
398               state = PS_HAVE_LABEL;
399             } else 
400               fprintf(stderr,"  bad state (%d) for label\n",state);
401             break;
402
403           case  PCP_STR:
404             switch(state) {
405             case PS_START:
406             case PS_HAVE_LABEL:
407               fprintf(stderr,"  mnem\n");
408               state = PS_HAVE_MNEM;
409               break;
410             case PS_HAVE_MNEM:
411               fprintf(stderr,"  1st operand\n");
412               pco1 = newpCodeOp(NULL,PO_GPR_REGISTER);
413               state = PS_HAVE_1OPERAND;
414               break;
415             case PS_HAVE_1OPERAND:
416               fprintf(stderr,"  error expecting comma\n");
417               break;
418             case PS_HAVE_COMMA:
419               fprintf(stderr,"  2 operands\n");
420               break;
421             }
422             break;
423
424           case  PCP_WILDVAR:
425             switch(state) {
426             case PS_START:
427             case PS_HAVE_LABEL:
428               fprintf(stderr,"  wild mnem\n");
429               state = PS_HAVE_MNEM;
430               break;
431             case PS_HAVE_MNEM:
432               fprintf(stderr,"  1st operand is wild\n");
433               state = PS_HAVE_1OPERAND;
434               break;
435             case PS_HAVE_1OPERAND:
436               fprintf(stderr,"  error expecting comma\n");
437               break;
438             case PS_HAVE_COMMA:
439               fprintf(stderr,"  2nd operand is wild\n");
440               break;
441             }
442             break;
443
444           case  PCP_WILDSTR:
445             break;
446           case  PCP_COMMA:
447             if(state == PS_HAVE_1OPERAND){
448               fprintf(stderr,"  got a comma\n");
449               state = PS_HAVE_COMMA;
450             } else
451               fprintf(stderr,"  unexpected comma\n");
452           }
453
454           matching = 1;
455           parsedPatArr[lparsedPatIdx].pcp = &pcpArr[lpcpIdx];
456           parsedPatArr[lparsedPatIdx].pct = &tokArr[ltokIdx];
457           lparsedPatIdx++;
458
459           //dump1Token(tokArr[ltokIdx].tt);
460
461           if(advTokIdx(&ltokIdx, strlen(pcpArr[lpcpIdx].tokens) ) ) {
462             fprintf(stderr," reached end \n");
463             matching = 0;
464             //return;
465           }
466         }
467
468
469       } while ((++lpcpIdx < PCPATTERNS) && !matching);
470
471     } while (matching);
472
473     fprintf(stderr,"\nConverting parsed line to pCode:\n\n");
474
475     j = 0;
476     do {
477       if(parsedPatArr[j].pcp && parsedPatArr[j].pcp->f )
478         parsedPatArr[j].pcp->f(&parsedPatArr[j]);
479       j++;
480     }
481     while(j<lparsedPatIdx);
482
483     fprintf(stderr,"\n");
484
485   }
486   return;
487   /*now decode */
488 #if 0
489   i=0;
490
491   if(pcComparePattern(&tokArr[0], pcpat_label, tokIdx +1)) {
492     fprintf(stderr,"has a wild label\n");
493     if(advTokIdx(&i, sizeof(pcpat_label) -1))
494       return;
495   }
496
497   if( (tokArr[i].tt == PCT_SPACE) && (advTokIdx(&i, 1)) ) // eat space
498     return;
499
500   if(pcComparePattern(&tokArr[i], pcpat_wildMnem, tokIdx +1 -i)) {
501     fprintf(stderr,"has a wild mnemonic\n");
502     if(advTokIdx(&i, sizeof(pcpat_wildMnem) -1))
503       return;
504   } else if(pcComparePattern(&tokArr[i], pcpat_Mnem, tokIdx +1 -i)) {
505     fprintf(stderr,"has a mnemonic\n");
506     if(advTokIdx(&i, sizeof(pcpat_Mnem) -1))
507      return;
508   } else
509     return;  // doesn't matter what follows
510
511   if( (tokArr[i].tt == PCT_SPACE) && (advTokIdx(&i, 1)) ) // eat space
512     return;
513
514   fprintf(stderr,"checking variable; next token  ");
515   dump1Token(tokArr[i].tt);
516   fprintf(stderr,"\n");
517
518   if(pcComparePattern(&tokArr[i], pcpat_wildVar, tokIdx +1 -i)) {
519     fprintf(stderr,"has a wild var\n");
520     if(advTokIdx(&i, sizeof(pcpat_wildVar) -1))
521       return;
522   } else if(pcComparePattern(&tokArr[i], pcpat_Var, tokIdx +1 -i)) {
523     fprintf(stderr,"has a var\n");
524     if(advTokIdx(&i, sizeof(pcpat_Var) -1))
525       return;
526   } else
527     return;
528
529   if(  ((tokArr[i].tt == PCT_SPACE) || (tokArr[i].tt == PCT_COMMA))
530        && (advTokIdx(&i, 1)) ) // eat space
531     return;
532
533   if(pcComparePattern(&tokArr[i], pcpat_wildVar, tokIdx +10 -i)) {
534     fprintf(stderr,"has a wild var\n");
535     if(advTokIdx(&i, sizeof(pcpat_wildVar) -1))
536       return;
537   } else if(pcComparePattern(&tokArr[i], pcpat_Var, tokIdx +10 -i)) {
538     fprintf(stderr,"has a var\n");
539     if(advTokIdx(&i, sizeof(pcpat_Var) -1))
540       return;
541   } else if(tokArr[i].tt == PCT_NUMBER) {
542     fprintf(stderr,"has a number\n");
543     if (advTokIdx(&i, 1))
544       return;
545   } else
546     return;
547 #endif
548
549 }
550
551 void  peepRules2pCode(peepRule *rules)
552 {
553   peepRule *pr;
554   lineNode *ln;
555
556   for (pr = rules; pr; pr = pr->next) {
557     fprintf(stderr,"\nRule:\n\n");
558     for(ln = pr->match; ln; ln = ln->next) {
559       fprintf(stderr,"%s\n",ln->line);
560       //parseLineNode(ln->line);
561       parseLineNode(ln->line);
562       dumpTokens();
563
564     }
565
566     fprintf(stderr,"\nReplaced by:\n");
567     for(ln = pr->replace; ln; ln = ln->next)
568       fprintf(stderr,"%s\n",ln->line);
569
570     if(pr->cond)
571       fprintf(stderr,"\nCondition:  %s\n",pr->cond);
572
573   }
574
575 }
576
577 void printpCodeString(FILE *of, pCode *pc, int max)
578 {
579   int i=0;
580
581   while(pc && (i++<max)) {
582     pc->print(of,pc);
583     pc = pc->next;
584   }
585 }
586
587 /*-----------------------------------------------------------------*/
588 /* _DLL * DLL_append                                               */
589 /*                                                                 */ 
590 /*  Append a _DLL object to the end of a _DLL (doubly linked list) */ 
591 /* If The list to which we want to append is non-existant then one */ 
592 /* is created. Other wise, the end of the list is sought out and   */ 
593 /* a new DLL object is appended to it. In either case, the void    */
594 /* *data is added to the newly created DLL object.                 */
595 /*-----------------------------------------------------------------*/
596
597 static void * DLL_append(_DLL *list, _DLL *next)
598 {
599   _DLL *b;
600
601
602   /* If there's no list, then create one: */
603   if(!list) {
604     next->next = next->prev = NULL;
605     return next;
606   }
607
608
609   /* Search for the end of the list. */
610   b = list;
611   while(b->next)
612     b = b->next;
613
614   /* Now append the new DLL object */
615   b->next = next;
616   b->next->prev = b;
617   b = b->next; 
618   b->next = NULL;
619
620   return list;
621   
622 }  
623
624
625 /*-----------------------------------------------------------------
626
627   pCode peephole optimization
628
629
630   The pCode "peep hole" optimization is not too unlike the peep hole
631   optimization in SDCCpeeph.c. The major difference is that here we
632   use pCode's whereas there we use ASCII strings. The advantage with
633   pCode's is that we can ascertain flow information in the instructions
634   being optimized.
635
636
637 <FIX ME> - elaborate...
638
639   -----------------------------------------------------------------*/
640
641 #if 0
642 /*-----------------------------------------------------------------*/
643 /* pCodePeep */
644 /*-----------------------------------------------------------------*/
645 int pCodePeepCompare(pCode *pc, pCodePeep *pcp)
646 {
647   pCode *pcfrom,*pcto;
648
649   pcfrom = pc;
650   for( pcto=pcp->target; pcto; pcto=pcto->next) {
651
652     pcfrom = findNextInstruction(pcfrom);
653
654     if( pcfrom &&  
655         (PCI(pcfrom)->op == PCI(pcto)->op || 
656          PCI(pcto)->op == POC_WILD))
657       continue;
658     return 0;
659   }
660   return 0;
661 }
662
663 /*-----------------------------------------------------------------*/
664 /* pCodePeep */
665 /*-----------------------------------------------------------------*/
666 void pCodePeepSearch(pCodePeep *snippet)
667 {
668   pBlock *pb;
669   pCode *pc;
670
671   if(!the_pFile)
672     return;
673
674   /* compare the chain to the pCode that we've 
675      got so far. If a match is found, then replace
676      the pCode chain.
677   */
678   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
679     for(pc = pb->pcHead; pc; pc = pc->next) {
680       pCodePeepCompare(pc,snippet);
681     }
682   }
683
684 }
685 #endif
686
687 #if 0
688 pBlock *pBlockAppend(pBlock *pb1, pBlock *pb2)
689 {
690   pBlock *pb;
691
692   if(!pb1->tail)
693     return pb2;
694
695   pb = pb1->tail;
696
697   pb2->head = pb1;
698   pb2->tail = NULL;
699   pb1->tail = pb2;
700
701 }
702
703 #endif
704
705 void pCodePeepInit(void)
706 {
707   pBlock *pb;
708   //  pCode *pc;
709   pCodePeep *pcp;
710   pCodePeepSnippets *pcps;
711
712   /* Declare a peep code snippet */
713   /* <FIXME> do I really need a separate struct just to DLL the snippets? */
714   /* e.g. I could put the DLL into the pCodePeep structure */
715   pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
716   pcp = pcps->peep  = Safe_calloc(1,sizeof(pCodePeep));
717   peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
718
719
720   pb = newpCodeChain(NULL, 'W', newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
721   addpCode2pBlock( pb,     newpCode(POC_MOVFW, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
722
723   pcp->target = pb;
724
725   pcp->replace = newpCodeChain(NULL, 'W',newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
726
727   /* Allocate space to store pointers to the wildcard variables */
728   pcp->nvars = 1;
729   pcp->vars  = Safe_calloc(pcp->nvars, sizeof(char *));
730   pcp->nwildpCodes = 0;
731   pcp->wildpCodes  = NULL;
732
733   pcp->postFalseCond = PCC_Z;
734   pcp->postTrueCond  = PCC_NONE;
735
736   fprintf(stderr,"Peep rule\nTarget:\n");
737   printpCodeString(stderr,pcp->target->pcHead, 10);
738   fprintf(stderr,"Replaced with:\n");
739   printpCodeString(stderr,pcp->replace->pcHead, 10);
740
741   /* Now for another peep example */
742   pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
743   pcp = pcps->peep  = Safe_calloc(1,sizeof(pCodePeep));
744   peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
745
746   {
747     /*
748       target:
749
750           btfsc  %0
751            goto  %1
752           %3
753       %1: %4
754
755       replace:
756           btfss  %0
757       %1:  %4
758           %3
759
760           The %3 and %4 are wild opcodes. Since the opcodes
761           are stored in a different array than the wild operands,
762           they can have the same indices and not conflict. So
763           below, the %3 is really a %0, %4 is a %1.
764
765      */
766     pCodeOp *pcl;
767     pCodeOp *pcw;
768     pCodeOp *pcwb;
769
770     // Create a new wild operand subtyped as a bit
771     pcwb =  newpCodeOpWild(0,pcp,newpCodeOpBit(NULL,-1));
772
773     // Create a 
774     pb = newpCodeChain(NULL, 'W',newpCode(POC_BTFSC,pcwb));
775
776     pcl = newpCodeOpLabel(-1);
777     pcw = newpCodeOpWild(1, pcp, pcl);
778     addpCode2pBlock( pb,     newpCode(POC_GOTO,  pcw));
779     addpCode2pBlock( pb,     newpCodeWild(0,NULL,NULL));
780     addpCode2pBlock( pb,     newpCodeWild(1,NULL,pcw));
781
782
783     pcp->target = pb;
784
785     pb = newpCodeChain(NULL, 'W',newpCode(POC_BTFSS, pcwb));
786     addpCode2pBlock( pb,     newpCodeWild(0,NULL,NULL));
787     addpCode2pBlock( pb,     newpCodeWild(1,NULL,pcw));
788
789     pcp->replace = pb;
790
791     /* Allocate space to store pointers to the wildcard variables */
792     pcp->nvars = 2;
793     pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
794     pcp->nwildpCodes = 2;
795     pcp->wildpCodes = Safe_calloc(pcp->nwildpCodes, sizeof(pCode *));
796
797     pcp->postFalseCond = PCC_NONE;
798     pcp->postTrueCond  = PCC_NONE;
799   }
800
801
802
803
804
805
806
807
808
809
810   //-------------
811
812   /* Now for another peep example */
813   pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
814   pcp = pcps->peep  = Safe_calloc(1,sizeof(pCodePeep));
815   peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
816
817   {
818     pCodeOp *pcw;
819
820     pcw = newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER));
821
822     pb = newpCodeChain(NULL, 'W', newpCode(POC_MOVWF, pcw));
823     addpCode2pBlock( pb,     newpCode(POC_MOVWF, pcw));
824
825     pcp->target = pb;
826
827     pb = newpCodeChain(NULL, 'W',newpCode(POC_MOVWF, pcw));
828
829     pcp->replace = pb;
830
831     /* Allocate space to store pointers to the wildcard variables */
832     pcp->nvars = 1;
833     pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
834     pcp->nwildpCodes = 0;
835     pcp->wildpCodes = NULL;
836
837     pcp->postFalseCond = PCC_NONE;
838     pcp->postTrueCond  = PCC_NONE;
839   }
840
841
842
843
844 }
845
846 /*-----------------------------------------------------------------*/
847 /* pCodeSearchCondition - Search a pCode chain for a 'condition'   */
848 /*                                                                 */
849 /* return conditions                                               */
850 /*  1 - The Condition was found for a pCode's input                */
851 /*  0 - No matching condition was found for the whole chain        */
852 /* -1 - The Condition was found for a pCode's output               */
853 /*                                                                 */
854 /*-----------------------------------------------------------------*/
855 int pCodeSearchCondition(pCode *pc, unsigned int cond)
856 {
857
858   while(pc) {
859
860     /* If we reach a function end (presumably an end since we most
861        probably began the search in the middle of a function), then
862        the condition was not found. */
863     if(pc->type == PC_FUNCTION)
864       return 0;
865
866     if(pc->type == PC_OPCODE) {
867       if(PCI(pc)->inCond & cond)
868         return 1;
869       if(PCI(pc)->outCond & cond)
870         return -1;
871     }
872
873     pc = pc->next;
874   }
875
876   return 0;
877 }
878 /*-----------------------------------------------------------------*/
879 /* pCodePeepMatchLine - Compare source and destination pCodes to   */
880 /*                      see they're the same.                      */
881 /*-----------------------------------------------------------------*/
882 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd)
883 {
884   int index;   // index into wild card arrays
885
886   if(pcs->type == pcd->type) {
887
888     if(pcs->type == PC_OPCODE) {
889
890       /* If the opcodes don't match then the line doesn't match */
891       if(PCI(pcs)->op != PCI(pcd)->op)
892         return 0;
893
894       fprintf(stderr,"%s comparing\n",__FUNCTION__);
895       pcs->print(stderr,pcs);
896       pcd->print(stderr,pcd);
897
898       /* Compare the operands */
899       if(PCI(pcd)->pcop) {
900         if (PCI(pcd)->pcop->type == PO_WILD) {
901           index = PCOW(PCI(pcd)->pcop)->id;
902
903           fprintf(stderr,"destination is wild\n");
904 #ifdef DEBUG_PCODEPEEP
905           if (index > peepBlock->nvars) {
906             fprintf(stderr,"%s - variables exceeded\n",__FUNCTION__);
907             exit(1);
908           }
909 #endif
910           PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
911           {
912             char *n;
913
914             if(PCI(pcs)->pcop->type == PO_GPR_TEMP)
915               n = PCOR(PCI(pcs)->pcop)->r->name;
916             else
917               n = PCI(pcs)->pcop->name;
918
919             if(peepBlock->vars[index])
920               return  (strcmp(peepBlock->vars[index],n) == 0);
921             else {
922               peepBlock->vars[index] = n; //PCI(pcs)->pcop->name;
923               return 1;
924             }
925           }
926         }
927       } else
928         /* The pcd has no operand. Lines match if pcs has no operand either*/
929         return (PCI(pcs)->pcop == NULL);
930     }
931   }
932
933
934   if((pcd->type == PC_WILD) && (pcs->type == PC_OPCODE)) {
935
936     int labindex;
937
938     index = PCW(pcd)->id;
939
940     fprintf(stderr,"%s comparing wild cards\n",__FUNCTION__);
941     pcs->print(stderr,pcs);
942     pcd->print(stderr,pcd);
943
944     peepBlock->wildpCodes[PCW(pcd)->id] = pcs;
945
946     /* Check for a label associated with this wild pCode */
947     // If the wild card has a label, make sure the source code does too.
948     if(PCW(pcd)->label) {
949       if(!pcs->label)
950         return 0;
951
952       labindex = PCOW(PCW(pcd)->label)->id;
953       if(peepBlock->vars[labindex] == NULL) {
954         // First time to encounter this label
955         peepBlock->vars[labindex] = PCL(pcs->label->pc)->label;
956         fprintf(stderr,"first time for a label\n");
957       } else {
958         if(strcmp(peepBlock->vars[labindex],PCL(pcs->label->pc)->label) != 0) {
959           fprintf(stderr,"labels don't match\n");
960           return 0;
961         }
962         fprintf(stderr,"matched a label\n");
963       }
964
965     }
966
967     if(PCW(pcd)->operand) {
968       PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
969       if(peepBlock->vars[index]) {
970         int i = (strcmp(peepBlock->vars[index],PCI(pcs)->pcop->name) == 0);
971         if(i)
972           fprintf(stderr," (matched)\n");
973         else {
974           fprintf(stderr," (no match: wild card operand mismatch\n");
975           fprintf(stderr,"  peepblock= %s,  pcodeop= %s\n",
976                   peepBlock->vars[index],
977                   PCI(pcs)->pcop->name);
978         }
979         return i;
980       } else {
981         peepBlock->vars[index] = PCI(pcs)->pcop->name;
982         return 1;
983       }
984     }
985
986     pcs = findNextInstruction(pcs->next); 
987     if(pcs) {
988       fprintf(stderr," (next to match)\n");
989       pcs->print(stderr,pcs);
990     }
991
992     return 1; /*  wild card matches */
993   }
994
995   return 0;
996 }
997
998 /*-----------------------------------------------------------------*/
999 /*-----------------------------------------------------------------*/
1000 void pCodePeepClrVars(pCodePeep *pcp)
1001 {
1002
1003   int i;
1004
1005   for(i=0;i<pcp->nvars; i++)
1006     pcp->vars[i] = NULL;
1007
1008 }
1009
1010 /*-----------------------------------------------------------------*/
1011 /*-----------------------------------------------------------------*/
1012 void pCodeInsertAfter(pCode *pc1, pCode *pc2)
1013 {
1014
1015   if(!pc1 || !pc2)
1016     return;
1017
1018   pc2->next = pc1->next;
1019   if(pc1->next)
1020     pc1->next->prev = pc2;
1021
1022   pc2->prev = pc1;
1023   pc1->next = pc2;
1024
1025 }
1026
1027 /*-----------------------------------------------------------------*/
1028 /* pCodeOpCopy - copy a pcode operator                             */
1029 /*-----------------------------------------------------------------*/
1030 static pCodeOp *pCodeOpCopy(pCodeOp *pcop)
1031 {
1032   pCodeOp *pcopnew=NULL;
1033
1034   if(!pcop)
1035     return NULL;
1036
1037   switch(pcop->type) { 
1038   case PO_CRY:
1039   case PO_BIT:
1040     pcopnew = Safe_calloc(1,sizeof(pCodeOpBit) );
1041     PCOB(pcopnew)->bit = PCOB(pcop)->bit;
1042     PCOB(pcopnew)->inBitSpace = PCOB(pcop)->inBitSpace;
1043
1044     break;
1045
1046   case PO_WILD:
1047     /* Here we expand the wild card into the appropriate type: */
1048     /* By recursively calling pCodeOpCopy */
1049     if(PCOW(pcop)->matched)
1050       pcopnew = pCodeOpCopy(PCOW(pcop)->matched);
1051     else {
1052       // Probably a label
1053       pcopnew = pCodeOpCopy(PCOW(pcop)->subtype);
1054       pcopnew->name = Safe_strdup(PCOW(pcop)->pcp->vars[PCOW(pcop)->id]);
1055       fprintf(stderr,"copied a wild op named %s\n",pcopnew->name);
1056     }
1057
1058     return pcopnew;
1059     break;
1060
1061   case PO_LABEL:
1062     pcopnew = Safe_calloc(1,sizeof(pCodeOpLabel) );
1063     PCOLAB(pcopnew)->key =  PCOLAB(pcop)->key;
1064     break;
1065
1066   case PO_LITERAL:
1067   case PO_IMMEDIATE:
1068     pcopnew = Safe_calloc(1,sizeof(pCodeOpLit) );
1069     PCOL(pcopnew)->lit = PCOL(pcop)->lit;
1070     break;
1071
1072   case PO_GPR_REGISTER:
1073   case PO_GPR_TEMP:
1074   case PO_SFR_REGISTER:
1075   case PO_DIR:
1076   case PO_STR:
1077   case PO_NONE:
1078   case PO_W:
1079   case PO_STATUS:
1080   case PO_FSR:
1081   case PO_INDF:
1082
1083     pcopnew = Safe_calloc(1,sizeof(pCodeOp) );
1084
1085   }
1086
1087   pcopnew->type = pcop->type;
1088   pcopnew->name = Safe_strdup(pcop->name);
1089
1090   return pcopnew;
1091 }
1092
1093 #if 0
1094 /*-----------------------------------------------------------------*/
1095 /* pCodeCopy - copy a pcode                                        */
1096 /*-----------------------------------------------------------------*/
1097 static pCode *pCodeCopy(pCode *pc)
1098 {
1099
1100   pCode *pcnew;
1101
1102   pcnew = newpCode(pc->type,pc->pcop);
1103 }
1104 #endif
1105 /*-----------------------------------------------------------------*/
1106 /*-----------------------------------------------------------------*/
1107 void pCodeDeleteChain(pCode *f,pCode *t)
1108 {
1109   pCode *pc;
1110
1111   while(f && f!=t) {
1112     fprintf(stderr,"delete pCode:\n");
1113     pc = f->next;
1114     f->print(stderr,f);
1115     //f->delete(f);
1116     f = pc;
1117   }
1118
1119 }
1120 /*-----------------------------------------------------------------*/
1121 /*-----------------------------------------------------------------*/
1122 int pCodePeepMatchRule(pCode *pc)
1123 {
1124   pCodePeep *peepBlock;
1125   pCode *pct, *pcin;
1126   _DLL *peeprules;
1127   int matched;
1128
1129   peeprules = (_DLL *)peepSnippets;
1130
1131   while(peeprules) {
1132     peepBlock = ((pCodePeepSnippets*)peeprules)->peep;
1133     pCodePeepClrVars(peepBlock);
1134
1135     pcin = pc;
1136     pct = peepBlock->target->pcHead;
1137     matched = 0;
1138     while(pct && pcin) {
1139
1140       if(! (matched = pCodePeepMatchLine(peepBlock, pcin,pct)))
1141         break;
1142
1143       pcin = findNextInstruction(pcin->next);
1144       pct = pct->next;
1145       //debug:
1146       fprintf(stderr,"    matched\n");
1147       if(!pcin)
1148         fprintf(stderr," end of code\n");
1149       if(!pct)
1150         fprintf(stderr," end of rule\n");
1151     }
1152
1153     if(matched && pcin) {
1154
1155       /* So far we matched the rule up to the point of the conditions .
1156        * In other words, all of the opcodes match. Now we need to see
1157        * if the post conditions are satisfied.
1158        * First we check the 'postFalseCond'. This means that we check
1159        * to see if any of the subsequent pCode's in the pCode chain 
1160        * following the point just past where we have matched depend on
1161        * the `postFalseCond' as input then we abort the match
1162        */
1163       fprintf(stderr,"    matched rule so far, now checking conditions\n");
1164       if (peepBlock->postFalseCond && 
1165           (pCodeSearchCondition(pcin,peepBlock->postFalseCond) > 0) )
1166         matched = 0;
1167     }
1168
1169     if(matched && pcin) {
1170
1171       pCode *pcprev;
1172       pCode *pcr;
1173
1174
1175       /* We matched a rule! Now we have to go through and remove the
1176          inefficient code with the optimized version */
1177
1178       fprintf(stderr, "Found a pcode peep match:\nRule:\n");
1179       printpCodeString(stderr,peepBlock->target->pcHead,10);
1180       fprintf(stderr,"first thing matched\n");
1181       pc->print(stderr,pc);
1182       fprintf(stderr,"last thing matched\n");
1183       pcin->print(stderr,pcin);
1184
1185       /* Unlink the original code */
1186       pcprev = pc->prev;
1187       pcprev->next = pcin;
1188       pcin->prev = pc->prev;
1189       pCodeDeleteChain(pc,pcin);
1190
1191       /* Generate the replacement code */
1192       pc = pcprev;
1193       pcr = peepBlock->replace->pcHead;  // This is the replacement code
1194       while (pcr) {
1195         pCodeOp *pcop=NULL;
1196         /* If the replace pcode is an instruction with an operand, */
1197         /* then duplicate the operand (and expand wild cards in the process). */
1198         if(pcr->type == PC_OPCODE) {
1199           if(PCI(pcr)->pcop)
1200             pcop = pCodeOpCopy(PCI(pcr)->pcop);
1201           fprintf(stderr,"inserting pCode\n");
1202           pCodeInsertAfter(pc, newpCode(PCI(pcr)->op,pcop));
1203         } else if (pcr->type == PC_WILD) {
1204           pCodeInsertAfter(pc,peepBlock->wildpCodes[PCW(pcr)->id]);
1205         }
1206
1207
1208         pc = pc->next;
1209         pc->print(stderr,pc);
1210         pcr = pcr->next;
1211       }
1212
1213       return 1;
1214     }
1215
1216     peeprules = peeprules->next;
1217   }
1218
1219   return 0;
1220 }
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231 #if 0
1232 /*******************/
1233 pCode *parseLineNode(char *ln)
1234 {
1235   char buffer[50], *s;
1236   int state=0;          //0 label, 1 mnemonic, 2 operand, 3 operand, 4 comment
1237   int var;
1238   pCode *pc = NULL;
1239   //  pCodeLabel *pcl = NULL;
1240
1241   if(!ln || !*ln)
1242     return pc;
1243
1244   s = buffer;
1245   *s = 0;
1246
1247   while(*ln) {
1248
1249     /* skip white space */
1250     while (isspace (*ln))
1251       ln++;
1252
1253     switch(state) {
1254
1255     case 0:   // look for a label
1256     case 1:   // look for mnemonic
1257
1258       if(*ln == '%') {
1259
1260         // Wild
1261
1262         ln++;
1263         if(!isdigit(*ln) )
1264           break;
1265           //goto next_state;
1266
1267         var = strtol(ln, &ln, 10);
1268         if(*ln  == ':') {
1269           // valid wild card label
1270           fprintf(stderr, " wildcard label: %d\n",var);
1271           ln++;
1272         } else
1273           fprintf(stderr, " wild opcode: %d\n",var), state++;
1274
1275       } else {
1276         // not wild
1277         // Extract the label/mnemonic from the line
1278
1279         s = buffer;
1280         while(*ln && !(isspace(*ln) || *ln == ':'))
1281           *s++ = *ln++;
1282
1283         *s = 0;
1284         if(*ln == ':')
1285           fprintf(stderr," regular label: %s\n",buffer), ln++;
1286         else
1287           fprintf(stderr," regular mnem: %s\n",buffer), state++;
1288       }
1289       state++;
1290       break;
1291
1292     default:
1293       ln++;
1294
1295     }
1296   }
1297
1298   return pc;
1299   
1300 }
1301 #endif