1 /*-------------------------------------------------------------------------
3 pcodepeep.c - post code generation
4 Written By - Scott Dattalo scott@dattalo.com
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
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.
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 -------------------------------------------------------------------------*/
24 #include "common.h" // Include everything in the SDCC src directory
31 #if defined(__BORLANDC__) || defined(_MSC_VER)
32 #define STRCASECMP stricmp
34 #define STRCASECMP strcasecmp
37 pCodeOp *popCopyGPR2Bit(pCodeOpReg *pc, int bitval);
40 pCodeOp *newpCodeOpWild(int id, pCodePeep *pcp, pCodeOp *subtype);
41 pCode *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label);
42 pCode * findNextInstruction(pCode *pc);
43 int getpCode(char *mnem,int dest);
44 void pBlockMergeLabels(pBlock *pb);
45 char *pCode2str(char *str, int size, pCode *pc);
47 extern pCodeInstruction *pic14Mnemonics[];
50 /****************************************************************/
52 * rootRules - defined in SDCCpeep.c
53 * This is a pointer to the (parsed) peephole rules that are
54 * defined in peep.def.
57 //extern peepRule *rootRules;
62 /****************************************************************/
63 /****************************************************************/
71 typedef struct pCodePeepSnippets
78 /****************************************************************/
82 /****************************************************************/
84 static pCodePeepSnippets *peepSnippets=NULL;
86 /****************************************************************/
90 /****************************************************************/
92 static pCodePeep *curPeep=NULL;
94 /****************************************************************/
98 /****************************************************************/
100 static pBlock *curBlock=NULL;
103 /****************************************************************/
105 /* max wild cards in a peep rule */
107 /****************************************************************/
109 static int sMaxWildVar = 0;
110 static int sMaxWildMnem = 0;
113 typedef struct pCodeToken
115 int tt; // token type;
124 pCodeToken tokArr[50];
141 typedef struct parsedPattern {
142 struct pcPattern *pcp;
146 #define MAX_PARSEDPATARR 50
147 parsedPattern parsedPatArr[MAX_PARSEDPATARR];
148 unsigned int parsedPatIdx=0;
161 static char pcpat_label[] = {PCT_PERCENT, PCT_NUMBER, PCT_COLON, 0};
162 static char pcpat_number[] = {PCT_NUMBER, 0};
163 static char pcpat_string[] = {PCT_STRING, 0};
164 static char pcpat_wildString[] = {PCT_PERCENT, PCT_STRING, 0};
165 static char pcpat_wildVar[] = {PCT_PERCENT, PCT_NUMBER, 0};
166 static char pcpat_comma[] = {PCT_COMMA, 0};
167 static char pcpat_comment[] = {PCT_COMMENT, 0};
170 typedef struct pcPattern {
171 char pt; // Pattern type
172 char *tokens; // list of tokens that describe the pattern
173 void * (*f) (void *);
176 pcPattern pcpArr[] = {
177 {PCP_LABEL, pcpat_label, NULL},
178 {PCP_WILDSTR, pcpat_wildString, NULL},
179 {PCP_STR, pcpat_string, NULL},
180 {PCP_WILDVAR, pcpat_wildVar, NULL},
181 {PCP_COMMA, pcpat_comma, NULL},
182 {PCP_COMMENT, pcpat_comment, NULL},
183 {PCP_NUMBER, pcpat_number, NULL}
186 #define PCPATTERNS (sizeof(pcpArr)/sizeof(pcPattern))
188 // Assembly Line Token
201 static char alt_comment[] = { PCP_COMMENT, 0};
202 static char alt_label[] = { PCP_LABEL, 0};
203 static char alt_mnem0[] = { PCP_STR, 0};
204 static char alt_mnem0a[] = { PCP_WILDVAR, 0};
205 static char alt_mnem1[] = { PCP_STR, PCP_STR, 0};
206 static char alt_mnem1a[] = { PCP_STR, PCP_WILDVAR, 0};
207 static char alt_mnem1b[] = { PCP_STR, PCP_NUMBER, 0};
208 static char alt_mnem2[] = { PCP_STR, PCP_STR, PCP_COMMA, PCP_STR, 0};
209 static char alt_mnem2a[] = { PCP_STR, PCP_WILDVAR, PCP_COMMA, PCP_STR, 0};
211 static void * cvt_altpat_label(void *pp);
212 static void * cvt_altpat_comment(void *pp);
213 static void * cvt_altpat_mnem0(void *pp);
214 static void * cvt_altpat_mnem0a(void *pp);
215 static void * cvt_altpat_mnem1(void *pp);
216 static void * cvt_altpat_mnem1a(void *pp);
217 static void * cvt_altpat_mnem1b(void *pp);
218 static void * cvt_altpat_mnem2(void *pp);
219 static void * cvt_altpat_mnem2a(void *pp);
221 pcPattern altArr[] = {
222 {ALT_LABEL, alt_label, cvt_altpat_label},
223 {ALT_COMMENT, alt_comment,cvt_altpat_comment},
224 {ALT_MNEM2A, alt_mnem2a, cvt_altpat_mnem2a},
225 {ALT_MNEM2, alt_mnem2, cvt_altpat_mnem2},
226 {ALT_MNEM1B, alt_mnem1b, cvt_altpat_mnem1b},
227 {ALT_MNEM1A, alt_mnem1a, cvt_altpat_mnem1a},
228 {ALT_MNEM1, alt_mnem1, cvt_altpat_mnem1},
229 {ALT_MNEM0A, alt_mnem0a, cvt_altpat_mnem0a},
230 {ALT_MNEM0, alt_mnem0, cvt_altpat_mnem0},
234 #define ALTPATTERNS (sizeof(altArr)/sizeof(pcPattern))
236 // forward declarations
237 static void * DLL_append(_DLL *list, _DLL *next);
239 /*-----------------------------------------------------------------*/
240 /* cvt_extract_destination - helper function extracts the register */
241 /* destination from a parsedPattern. */
243 /*-----------------------------------------------------------------*/
244 static int cvt_extract_destination(parsedPattern *pp)
247 if(pp->pct[0].tt == PCT_STRING) {
249 // just check first letter for now
251 if(toupper(*pp->pct[0].tok.s) == 'F')
254 } else if (pp->pct[0].tt == PCT_NUMBER) {
264 /*-----------------------------------------------------------------*/
265 /* pCodeOp *cvt_extract_status(char *reg, char *bit) */
266 /* if *reg is the "status" register and *bit is one of the */
267 /* status bits, then this function will create a new pCode op */
268 /* containing the status register. */
269 /*-----------------------------------------------------------------*/
271 static pCodeOp *cvt_extract_status(char *reg, char *bit)
275 if(STRCASECMP(reg, pc_status.pcop.name))
282 if(toupper(*bit) == 'C')
283 return PCOP(popCopyGPR2Bit(&pc_status,PIC_C_BIT));
284 if(toupper(*bit) == 'Z')
285 return PCOP(popCopyGPR2Bit(&pc_status,PIC_Z_BIT));
289 if(len ==2 && toupper(bit[0]) == 'D' && toupper(bit[1]) == 'C')
290 return PCOP(popCopyGPR2Bit(&pc_status,PIC_DC_BIT));
296 /*-----------------------------------------------------------------*/
297 /* cvt_altpat_label - convert assembly line type to a pCode label */
298 /* INPUT: pointer to the parsedPattern */
302 /* label pattern => '%' number ':' */
303 /* at this point, we wish to extract only the 'number' */
305 /*-----------------------------------------------------------------*/
306 static void * cvt_altpat_label(void *pp)
308 parsedPattern *p = pp;
310 fprintf(stderr,"altpat_label with ID = %d\n",p->pct[1].tok.n);
311 return newpCodeLabel(-p->pct[1].tok.n);
315 /*-----------------------------------------------------------------*/
316 /* cvt_altpat_comment - convert assembly line type to a comment */
317 /* INPUT: pointer to the parsedPattern */
319 /* pp[0] - comment */
322 /*-----------------------------------------------------------------*/
323 static void * cvt_altpat_comment(void *pp)
325 parsedPattern *p = pp;
327 fprintf(stderr,"altpat_comment = %s\n",p->pct[0].tok.s);
328 return newpCodeCharP(p->pct[0].tok.s);
332 /*-----------------------------------------------------------------*/
333 /*-----------------------------------------------------------------*/
334 static void * cvt_altpat_mnem0(void *pp)
336 parsedPattern *p = pp;
339 pCodeInstruction *pci=NULL;
341 fprintf(stderr,"altpat_mnem0 %s\n", p->pct[0].tok.s);
343 opcode = getpCode(p->pct[0].tok.s,0);
345 fprintf(stderr, "Bad mnemonic\n");
349 pci = PCI(newpCode(opcode, NULL));
352 fprintf(stderr,"couldn't find mnemonic\n");
358 /*-----------------------------------------------------------------*/
359 /* cvt_altpat_mem0a - convert assembly line type to a wild pCode */
362 /* pp[0] - wild var */
364 /*-----------------------------------------------------------------*/
365 static void * cvt_altpat_mnem0a(void *pp)
367 parsedPattern *p = pp;
369 fprintf(stderr,"altpat_mnem0a wild mnem # %d\n", p[0].pct[1].tok.n);
371 /* Save the index of the maximum wildcard mnemonic */
373 if(p[0].pct[1].tok.n > sMaxWildVar)
374 sMaxWildMnem = p[0].pct[1].tok.n;
376 return newpCodeWild(p[0].pct[1].tok.n,NULL,NULL);
380 /*-----------------------------------------------------------------*/
381 /* cvt_altpat_mem1 - convert assembly line type to a pCode */
382 /* instruction with 1 operand. */
385 /* pp[1] - Operand */
387 /*-----------------------------------------------------------------*/
388 static void * cvt_altpat_mnem1(void *pp)
391 parsedPattern *p = pp;
394 pCodeInstruction *pci=NULL;
397 fprintf(stderr,"altpat_mnem1 %s var %s\n", p->pct[0].tok.s,p[1].pct[0].tok.s);
399 opcode = getpCode(p->pct[0].tok.s,0);
401 fprintf(stderr, "Bad mnemonic\n");
405 if(pic14Mnemonics[opcode]->bit_inst)
406 pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_BIT);
408 pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER);
411 pci = PCI(newpCode(opcode, pcosubtype));
414 fprintf(stderr,"couldn't find mnemonic\n");
420 /*-----------------------------------------------------------------*/
421 /* cvt_altpat_mem1a - convert assembly line type to a pCode */
422 /* instruction with 1 wild operand. */
425 /* pp[1] - wild var */
427 /*-----------------------------------------------------------------*/
428 static void * cvt_altpat_mnem1a(void *pp)
430 parsedPattern *p = pp;
433 pCodeInstruction *pci=NULL;
436 fprintf(stderr,"altpat_mnem1a %s var %d\n", p->pct[0].tok.s,p[1].pct[1].tok.n);
438 opcode = getpCode(p->pct[0].tok.s,0);
440 fprintf(stderr, "Bad mnemonic\n");
444 if(pic14Mnemonics[opcode]->bit_inst)
445 pcosubtype = newpCodeOpBit(NULL,-1,0);
447 pcosubtype = newpCodeOp(NULL,PO_GPR_REGISTER);
450 pci = PCI(newpCode(opcode,
451 newpCodeOpWild(p[1].pct[1].tok.n, curPeep, pcosubtype)));
453 /* Save the index of the maximum wildcard variable */
454 if(p[1].pct[1].tok.n > sMaxWildVar)
455 sMaxWildVar = p[1].pct[1].tok.n;
458 fprintf(stderr,"couldn't find mnemonic\n");
464 /*-----------------------------------------------------------------*/
465 /*-----------------------------------------------------------------*/
466 static void * cvt_altpat_mnem1b(void *pp)
468 parsedPattern *p = pp;
471 pCodeInstruction *pci=NULL;
473 fprintf(stderr,"altpat_mnem1b %s var %d\n", p->pct[0].tok.s,p[1].pct[0].tok.n);
475 opcode = getpCode(p->pct[0].tok.s,0);
477 fprintf(stderr, "Bad mnemonic\n");
481 pci = PCI(newpCode(opcode, newpCodeOpLit(p[1].pct[0].tok.n) ));
484 fprintf(stderr,"couldn't find mnemonic\n");
490 /*-----------------------------------------------------------------*/
491 /*-----------------------------------------------------------------*/
492 static void * cvt_altpat_mnem2(void *pp)
494 parsedPattern *p = pp;
498 pCodeInstruction *pci=NULL;
501 dest = cvt_extract_destination(&p[3]);
503 fprintf(stderr,"altpat_mnem2 %s var %s destination %s(%d)\n",
510 opcode = getpCode(p->pct[0].tok.s,dest);
512 fprintf(stderr, "Bad mnemonic\n");
516 if(pic14Mnemonics[opcode]->bit_inst) {
517 pcosubtype = cvt_extract_status(p[1].pct[0].tok.s, p[3].pct[0].tok.s);
518 if(pcosubtype == NULL) {
519 fprintf(stderr, "bad operand?\n");
524 pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER);
527 pci = PCI(newpCode(opcode,pcosubtype));
530 fprintf(stderr,"couldn't find mnemonic\n");
536 /*-----------------------------------------------------------------*/
537 /* cvt_altpat_mem2a - convert assembly line type to a pCode */
538 /* instruction with 1 wild operand and a */
539 /* destination operand (e.g. w or f) */
542 /* pp[1] - wild var */
544 /* pp[3] - destination */
546 /*-----------------------------------------------------------------*/
547 static void * cvt_altpat_mnem2a(void *pp)
549 parsedPattern *p = pp;
553 pCodeInstruction *pci=NULL;
556 dest = cvt_extract_destination(&p[3]);
558 fprintf(stderr,"altpat_mnem2a %s var %d destination %s(%d)\n",
565 opcode = getpCode(p->pct[0].tok.s,dest);
567 fprintf(stderr, "Bad mnemonic\n");
571 if(pic14Mnemonics[opcode]->bit_inst)
572 pcosubtype = newpCodeOp(NULL,PO_BIT);
574 pcosubtype = newpCodeOp(NULL,PO_GPR_REGISTER);
577 pci = PCI(newpCode(opcode,
578 newpCodeOpWild(p[1].pct[1].tok.n, curPeep, pcosubtype)));
580 /* Save the index of the maximum wildcard variable */
581 if(p[1].pct[1].tok.n > sMaxWildVar)
582 sMaxWildVar = p[1].pct[1].tok.n;
585 fprintf(stderr,"couldn't find mnemonic\n");
591 /*-----------------------------------------------------------------*/
592 /* tokenizeLineNode - Convert a string (of char's) that was parsed */
593 /* by SDCCpeeph.c into a string of tokens. */
596 /* The tokenizer is of the classic type. When an item is encounterd*/
597 /* it is converted into a token. The token is a structure that */
598 /* encodes the item's type and it's value (when appropriate). */
600 /* Accepted token types: */
601 /* SPACE NUMBER STRING % : , ; */
605 /*-----------------------------------------------------------------*/
608 static void tokenizeLineNode(char *ln)
611 tokIdx = 0; // Starting off at the beginning
612 tokArr[0].tt = PCT_NULL; // and assume invalid character for first token.
620 // add a SPACE token and eat the extra spaces.
621 tokArr[tokIdx++].tt = PCT_SPACE;
622 while (isspace (*ln))
629 tokArr[tokIdx].tt = PCT_NUMBER;
630 tokArr[tokIdx++].tok.n = strtol(ln, &ln, 0);
638 tokArr[tokIdx++].tt = PCT_PERCENT;
641 tokArr[tokIdx++].tt = PCT_COLON;
644 tokArr[tokIdx].tok.s = Safe_strdup(ln);
645 tokArr[tokIdx++].tt = PCT_COMMENT;
646 tokArr[tokIdx].tt = PCT_NULL;
649 tokArr[tokIdx++].tt = PCT_COMMA;
658 while( (isalpha(*ln) || isdigit(*ln)) && i<49)
664 tokArr[tokIdx].tok.s = Safe_strdup(buffer);
665 tokArr[tokIdx++].tt = PCT_STRING;
670 /* Advance to next character in input string .
671 * Note, if none of the tests passed above, then
672 * we effectively ignore the `bad' character.
673 * Since the line has already been parsed by SDCCpeeph,
674 * chance are that there are no invalid characters... */
680 tokArr[tokIdx].tt = 0;
684 /*-----------------------------------------------------------------*/
685 /*-----------------------------------------------------------------*/
689 void dump1Token(pCodeTokens tt)
694 fprintf(stderr, " space ");
697 fprintf(stderr, " pct ");
701 fprintf(stderr, " col ");
705 fprintf(stderr, " comma , ");
708 fprintf(stderr, " comment ");
709 //fprintf(stderr,"%s",tokArr[i].tok.s);
712 fprintf(stderr, " str ");
713 //fprintf(stderr,"%s",tokArr[i].tok.s);
716 fprintf(stderr, " num ");
717 //fprintf(stderr,"%d",tokArr[i].tok.n);
720 fprintf(stderr, " null ");
726 /*-----------------------------------------------------------------*/
727 /*-----------------------------------------------------------------*/
729 int pcComparePattern(pCodeToken *pct, char *pat, int max_tokens)
733 if(!pct || !pat || !*pat)
736 //fprintf(stderr,"comparing against:\n");
738 while(i < max_tokens) {
741 //fprintf(stderr,"matched\n");
745 //dump1Token(*pat); fprintf(stderr,"\n");
759 /*-----------------------------------------------------------------*/
760 /*-----------------------------------------------------------------*/
762 int altComparePattern( char *pct, parsedPattern *pat, int max_tokens)
766 if(!pct || !pat || !*pct)
770 while(i < max_tokens) {
773 //fprintf(stderr,"matched\n");
777 //dump1Token(*pat); fprintf(stderr,"\n");
779 if( !pat || !pat->pcp )
782 if (pat->pcp->pt != *pct)
785 //fprintf(stderr," pct=%d\n",*pct);
794 /*-----------------------------------------------------------------*/
795 /*-----------------------------------------------------------------*/
797 int advTokIdx(int *v, int amt)
800 if((unsigned) (*v + amt) > tokIdx)
808 /*-----------------------------------------------------------------*/
809 /* parseTokens - convert the tokens corresponding to a single line */
810 /* of a peep hole assembly into a pCode object. */
815 /* This is a simple parser that looks for strings of the type */
816 /* allowed in the peep hole definition file. Essentially the format*/
817 /* is the same as a line of assembly: */
819 /* label: mnemonic op1, op2, op3 ; comment */
821 /* Some of these items aren't present. It's the job of the parser */
822 /* to determine which are and convert those into the appropriate */
824 /*-----------------------------------------------------------------*/
826 void parseTokens(void)
834 for(i=0; i<=tokIdx; i++)
835 dump1Token(tokArr[i].tt);
847 char * cPmnem = NULL; // Pointer to non-wild mnemonic (if any)
848 char * cP1stop = NULL;
849 char * cP2ndop = NULL;
851 //pCodeOp *pcl = NULL; // Storage for a label
852 //pCodeOp *pco1 = NULL; // 1st operand
853 //pCodeOp *pco2 = NULL; // 2nd operand
854 //pCode *pc = NULL; // Mnemonic
865 ParseStates state = PS_START;
872 if( ((tokArr[ltokIdx].tt == PCT_SPACE) )
873 && (advTokIdx(<okIdx, 1)) ) // eat space
877 j = pcComparePattern(&tokArr[ltokIdx], pcpArr[lpcpIdx].tokens, tokIdx +1);
880 switch(pcpArr[lpcpIdx].pt) {
882 if(state == PS_START){
883 fprintf(stderr," label\n");
884 state = PS_HAVE_LABEL;
886 fprintf(stderr," bad state (%d) for label\n",state);
890 fprintf(stderr," %s is",tokArr[ltokIdx].tok.s);
894 fprintf(stderr," mnem\n");
895 cPmnem = tokArr[ltokIdx].tok.s;
896 state = PS_HAVE_MNEM;
899 fprintf(stderr," 1st operand\n");
900 cP1stop = tokArr[ltokIdx].tok.s;
901 //pco1 = newpCodeOp(NULL,PO_GPR_REGISTER);
902 state = PS_HAVE_1OPERAND;
904 case PS_HAVE_1OPERAND:
905 fprintf(stderr," error expecting comma\n");
908 fprintf(stderr," 2 operands\n");
909 cP2ndop = tokArr[ltokIdx].tok.s;
911 case PS_HAVE_2OPERANDS:
920 fprintf(stderr," wild mnem\n");
921 state = PS_HAVE_MNEM;
924 fprintf(stderr," 1st operand is wild\n");
925 state = PS_HAVE_1OPERAND;
927 case PS_HAVE_1OPERAND:
928 fprintf(stderr," error expecting comma\n");
931 fprintf(stderr," 2nd operand is wild\n");
933 case PS_HAVE_2OPERANDS:
942 fprintf(stderr," ERROR number\n");
945 fprintf(stderr," 1st operand is a number\n");
946 state = PS_HAVE_1OPERAND;
948 case PS_HAVE_1OPERAND:
949 fprintf(stderr," error expecting comma\n");
952 fprintf(stderr," 2nd operand is a number\n");
954 case PS_HAVE_2OPERANDS:
962 if(state == PS_HAVE_1OPERAND){
963 fprintf(stderr," got a comma\n");
964 state = PS_HAVE_COMMA;
966 fprintf(stderr," unexpected comma\n");
970 parsedPatArr[lparsedPatIdx].pcp = &pcpArr[lpcpIdx];
971 parsedPatArr[lparsedPatIdx].pct = &tokArr[ltokIdx];
974 //dump1Token(tokArr[ltokIdx].tt);
976 if(advTokIdx(<okIdx, strlen(pcpArr[lpcpIdx].tokens) ) ) {
977 fprintf(stderr," reached end \n");
984 } while ((++lpcpIdx < PCPATTERNS) && !matching);
988 parsedPatArr[lparsedPatIdx].pcp = NULL;
989 parsedPatArr[lparsedPatIdx].pct = NULL;
995 if( (c=altComparePattern( altArr[k].tokens, &parsedPatArr[j],10) ) ) {
998 pc = altArr[k].f(&parsedPatArr[j]);
1000 pc->print(stderr,pc);
1001 //if(pc && pc->destruct) pc->destruct(pc); dumps core?
1003 addpCode2pBlock(curBlock, pc);
1009 while(j<=lparsedPatIdx && k<ALTPATTERNS);
1012 fprintf(stderr,"\nConverting parsed line to pCode:\n\n");
1016 if(parsedPatArr[j].pcp && parsedPatArr[j].pcp->f )
1017 parsedPatArr[j].pcp->f(&parsedPatArr[j]);
1018 fprintf(stderr," %d",parsedPatArr[j].pcp->pt);
1021 while(j<lparsedPatIdx);
1023 fprintf(stderr,"\n");
1030 /*-----------------------------------------------------------------*/
1032 /*-----------------------------------------------------------------*/
1033 void peepRuleBlock2pCodeBlock( lineNode *ln)
1039 for( ; ln; ln = ln->next) {
1041 fprintf(stderr,"%s\n",ln->line);
1043 tokenizeLineNode(ln->line);
1049 /*-----------------------------------------------------------------*/
1050 /* peepRuleCondition */
1051 /*-----------------------------------------------------------------*/
1052 static void peepRuleCondition(char *cond)
1057 fprintf(stderr,"\nCondition: %s\n",cond);
1059 /* brute force compares for now */
1061 if(STRCASECMP(cond, "NZ") == 0) {
1062 fprintf(stderr,"found NZ\n");
1063 curPeep->postFalseCond = PCC_Z;
1068 /*-----------------------------------------------------------------*/
1069 /* peepRules2pCode - parse the "parsed" peep hole rules to generate*/
1072 /* SDCCpeeph parses the peep rules file and extracts variables, */
1073 /* removes white space, and checks the syntax. This function */
1074 /* extends that processing to produce pCode objects. You can kind */
1075 /* think of this function as an "assembler", though instead of */
1076 /* taking raw text to produce machine code, it produces pCode. */
1078 /*-----------------------------------------------------------------*/
1080 void peepRules2pCode(peepRule *rules)
1084 pCodePeepSnippets *pcps;
1086 /* The rules are in a linked-list. Each rule has two portions */
1087 /* There's the `target' and there's the `replace'. The target */
1088 /* is compared against the SDCC generated code and if it */
1089 /* matches, it gets replaced by the `replace' block of code. */
1091 /* Here we loop through each rule and convert the target's and*/
1092 /* replace's into pCode target and replace blocks */
1094 for (pr = rules; pr; pr = pr->next) {
1096 fprintf(stderr,"\nRule:\n\n");
1098 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1099 curPeep = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
1101 curPeep->vars = NULL;
1102 curPeep->wildpCodes = NULL; curPeep->wildpCodeOps = NULL;
1103 curPeep->postFalseCond = PCC_NONE;
1104 curPeep->postTrueCond = PCC_NONE;
1106 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1108 curPeep->target = curBlock = newpCodeChain(NULL, 'W', NULL);
1112 /* Convert the target block */
1113 peepRuleBlock2pCodeBlock(pr->match);
1115 fprintf(stderr,"finished target, here it is in pcode form:\n");
1116 printpBlock(stderr, curBlock);
1118 fprintf(stderr,"target with labels merged:\n");
1119 pBlockMergeLabels(curBlock);
1120 printpBlock(stderr, curBlock);
1122 fprintf(stderr,"\nReplaced by:\n");
1125 curPeep->replace = curBlock = newpCodeChain(NULL, 'W', NULL);
1127 /* Convert the replace block */
1128 peepRuleBlock2pCodeBlock(pr->replace);
1130 fprintf(stderr,"finished replace block, here it is in pcode form:\n");
1131 printpBlock(stderr, curBlock);
1133 fprintf(stderr,"replace with labels merged:\n");
1134 pBlockMergeLabels(curBlock);
1135 printpBlock(stderr, curBlock);
1137 peepRuleCondition(pr->cond);
1139 /* The rule has been converted to pCode. Now allocate
1140 * space for the wildcards */
1143 curPeep->nvars = sMaxWildVar;
1144 curPeep->vars = Safe_calloc(sMaxWildVar, sizeof(char *));
1146 curPeep->nops = sMaxWildVar;
1147 curPeep->wildpCodeOps = Safe_calloc(sMaxWildVar, sizeof(pCodeOp *));
1149 curPeep->nwildpCodes = ++sMaxWildMnem;
1150 curPeep->wildpCodes = Safe_calloc(sMaxWildMnem, sizeof(char *));
1153 //return; // debug ... don't want to go through all the rules yet
1158 void printpCodeString(FILE *of, pCode *pc, int max)
1162 while(pc && (i++<max)) {
1168 /*-----------------------------------------------------------------*/
1169 /* _DLL * DLL_append */
1171 /* Append a _DLL object to the end of a _DLL (doubly linked list) */
1172 /* If The list to which we want to append is non-existant then one */
1173 /* is created. Other wise, the end of the list is sought out and */
1174 /* a new DLL object is appended to it. In either case, the void */
1175 /* *data is added to the newly created DLL object. */
1176 /*-----------------------------------------------------------------*/
1178 static void * DLL_append(_DLL *list, _DLL *next)
1183 /* If there's no list, then create one: */
1185 next->next = next->prev = NULL;
1190 /* Search for the end of the list. */
1195 /* Now append the new DLL object */
1206 /*-----------------------------------------------------------------
1208 pCode peephole optimization
1211 The pCode "peep hole" optimization is not too unlike the peep hole
1212 optimization in SDCCpeeph.c. The major difference is that here we
1213 use pCode's whereas there we use ASCII strings. The advantage with
1214 pCode's is that we can ascertain flow information in the instructions
1218 <FIX ME> - elaborate...
1220 -----------------------------------------------------------------*/
1223 /*-----------------------------------------------------------------*/
1225 /*-----------------------------------------------------------------*/
1226 int pCodePeepCompare(pCode *pc, pCodePeep *pcp)
1228 pCode *pcfrom,*pcto;
1231 for( pcto=pcp->target; pcto; pcto=pcto->next) {
1233 pcfrom = findNextInstruction(pcfrom);
1236 (PCI(pcfrom)->op == PCI(pcto)->op ||
1237 PCI(pcto)->op == POC_WILD))
1244 /*-----------------------------------------------------------------*/
1246 /*-----------------------------------------------------------------*/
1247 void pCodePeepSearch(pCodePeep *snippet)
1255 /* compare the chain to the pCode that we've
1256 got so far. If a match is found, then replace
1259 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1260 for(pc = pb->pcHead; pc; pc = pc->next) {
1261 pCodePeepCompare(pc,snippet);
1269 pBlock *pBlockAppend(pBlock *pb1, pBlock *pb2)
1286 void pCodePeepInit(void)
1292 pCodePeepSnippets *pcps;
1294 /* Declare a peep code snippet */
1295 /* <FIXME> do I really need a separate struct just to DLL the snippets? */
1296 /* e.g. I could put the DLL into the pCodePeep structure */
1310 false condition - PCC_Z (Z bit is not used as input to subsequent code)
1311 true condition - none
1313 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1314 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
1315 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1318 pb = newpCodeChain(NULL, 'W', newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1319 addpCode2pBlock( pb, newpCode(POC_MOVFW, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1323 pcp->replace = newpCodeChain(NULL, 'W',newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1325 /* Allocate space to store pointers to the wildcard variables */
1327 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
1328 pcp->nwildpCodes = 0;
1329 pcp->wildpCodes = NULL;
1331 pcp->postFalseCond = PCC_Z;
1332 pcp->postTrueCond = PCC_NONE;
1334 fprintf(stderr,"Peep rule\nTarget:\n");
1335 printpCodeString(stderr,pcp->target->pcHead, 10);
1336 fprintf(stderr,"Replaced with:\n");
1337 printpCodeString(stderr,pcp->replace->pcHead, 10);
1339 /* Now for another peep example */
1340 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1341 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
1342 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1358 The %3 and %4 are wild opcodes. Since the opcodes
1359 are stored in a different array than the wild operands,
1360 they can have the same indices and not conflict. So
1361 below, the %3 is really a %0, %4 is a %1.
1368 // Create a new wild operand subtyped as a bit
1369 pcwb = newpCodeOpWild(0,pcp,newpCodeOpBit(NULL,-1,0));
1372 pb = newpCodeChain(NULL, 'W',newpCode(POC_BTFSC,pcwb));
1374 pcl = newpCodeOpLabel(-1);
1375 pcw = newpCodeOpWild(1, pcp, pcl);
1376 addpCode2pBlock( pb, newpCode(POC_GOTO, pcw));
1377 addpCode2pBlock( pb, newpCodeWild(0,NULL,NULL));
1378 addpCode2pBlock( pb, newpCodeWild(1,NULL,pcw));
1383 pb = newpCodeChain(NULL, 'W',newpCode(POC_BTFSS, pcwb));
1384 addpCode2pBlock( pb, newpCodeWild(0,NULL,NULL));
1385 addpCode2pBlock( pb, newpCodeWild(1,NULL,pcw));
1389 /* Allocate space to store pointers to the wildcard variables */
1391 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
1392 pcp->nwildpCodes = 2;
1393 pcp->wildpCodes = Safe_calloc(pcp->nwildpCodes, sizeof(pCode *));
1395 pcp->postFalseCond = PCC_NONE;
1396 pcp->postTrueCond = PCC_NONE;
1410 /* Now for another peep example */
1411 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1412 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
1413 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1418 pcw = newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER));
1420 pb = newpCodeChain(NULL, 'W', newpCode(POC_MOVWF, pcw));
1421 addpCode2pBlock( pb, newpCode(POC_MOVWF, pcw));
1425 pb = newpCodeChain(NULL, 'W',newpCode(POC_MOVWF, pcw));
1429 /* Allocate space to store pointers to the wildcard variables */
1431 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
1432 pcp->nwildpCodes = 0;
1433 pcp->wildpCodes = NULL;
1435 pcp->postFalseCond = PCC_NONE;
1436 pcp->postTrueCond = PCC_NONE;
1444 /*-----------------------------------------------------------------*/
1445 /* pCodeSearchCondition - Search a pCode chain for a 'condition' */
1447 /* return conditions */
1448 /* 1 - The Condition was found for a pCode's input */
1449 /* 0 - No matching condition was found for the whole chain */
1450 /* -1 - The Condition was found for a pCode's output */
1452 /*-----------------------------------------------------------------*/
1453 int pCodeSearchCondition(pCode *pc, unsigned int cond)
1458 /* If we reach a function end (presumably an end since we most
1459 probably began the search in the middle of a function), then
1460 the condition was not found. */
1461 if(pc->type == PC_FUNCTION)
1464 if(pc->type == PC_OPCODE) {
1465 if(PCI(pc)->inCond & cond)
1467 if(PCI(pc)->outCond & cond)
1477 int pCodePeepMatchLabels(pCodePeep *peepBlock, pCode *pcs, pCode *pcd)
1481 /* Check for a label associated with this wild pCode */
1482 // If the wild card has a label, make sure the source code does too.
1489 pcl = pcd->label->pc;
1490 //labindex = PCOW(pcl)->id;
1491 labindex = -PCL(pcl)->key;
1492 fprintf(stderr,"label id = %d (labindex = %d)\n",PCL(pcl)->key,labindex);
1493 if(peepBlock->vars[labindex] == NULL) {
1494 // First time to encounter this label
1495 peepBlock->vars[labindex] = PCL(pcs->label->pc)->label;
1496 fprintf(stderr,"first time for a label: %d %s\n",labindex, peepBlock->vars[labindex]);
1498 if(strcmp(peepBlock->vars[labindex],PCL(pcs->label->pc)->label) != 0) {
1499 fprintf(stderr,"labels don't match\n");
1502 fprintf(stderr,"matched a label\n");
1505 fprintf(stderr,"destination doesn't have a label\n");
1515 /*-----------------------------------------------------------------*/
1516 /* pCodePeepMatchLine - Compare source and destination pCodes to */
1517 /* see they're the same. */
1519 /* In this context, "source" refers to the coded generated by gen.c*/
1520 /* and "destination" refers to a pcode in a peep rule. If the dest-*/
1521 /* ination has no wild cards, then MatchLine will compare the two */
1522 /* pcodes (src and dest) for a one-to-one match. If the destination*/
1523 /* has wildcards, then those get expanded. When a wild card is */
1524 /* encountered for the first time it autmatically is considered a */
1525 /* match and the object that matches it is referenced in the */
1526 /* variables or opcodes array (depending on the type of match). */
1530 /* *peepBlock - A pointer to the peepBlock that contains the */
1531 /* entire rule to which the destination pcode belongs*/
1532 /* *pcs - a pointer to the source pcode */
1533 /* *pcd - a pointer to the destination pcode */
1536 /* 1 - pcodes match */
1537 /* 0 - pcodes don't match */
1540 /*-----------------------------------------------------------------*/
1542 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd)
1544 int index; // index into wild card arrays
1546 if(pcs->type == pcd->type) {
1548 if(pcs->type == PC_OPCODE) {
1550 /* If the opcodes don't match then the line doesn't match */
1551 if(PCI(pcs)->op != PCI(pcd)->op)
1554 fprintf(stderr,"%s comparing\n",__FUNCTION__);
1555 pcs->print(stderr,pcs);
1556 pcd->print(stderr,pcd);
1558 if(!pCodePeepMatchLabels(peepBlock, pcs, pcd))
1561 /* Compare the operands */
1562 if(PCI(pcd)->pcop) {
1563 if (PCI(pcd)->pcop->type == PO_WILD) {
1564 index = PCOW(PCI(pcd)->pcop)->id;
1566 fprintf(stderr,"destination is wild\n");
1567 #ifdef DEBUG_PCODEPEEP
1568 if (index > peepBlock->nops) {
1569 fprintf(stderr,"%s - variables exceeded\n",__FUNCTION__);
1573 PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
1574 if(!peepBlock->wildpCodeOps[index]) {
1575 peepBlock->wildpCodeOps[index] = PCI(pcs)->pcop;
1577 //if(PCI(pcs)->pcop->type == PO_GPR_TEMP)
1583 switch(PCI(pcs)->pcop->type) {
1586 n = PCOR(PCI(pcs)->pcop)->r->name;
1589 n = PCI(pcs)->pcop->name;
1592 if(peepBlock->vars[index])
1593 return (strcmp(peepBlock->vars[index],n) == 0);
1595 fprintf(stderr,"first time for a variable: %d, %s\n",index,n);
1596 peepBlock->vars[index] = n; //PCI(pcs)->pcop->name;
1601 /* FIXME - need an else to check the case when the destination
1602 * isn't a wild card */
1604 /* The pcd has no operand. Lines match if pcs has no operand either*/
1605 return (PCI(pcs)->pcop == NULL);
1610 if((pcd->type == PC_WILD) && (pcs->type == PC_OPCODE)) {
1613 index = PCW(pcd)->id;
1615 fprintf(stderr,"%s comparing wild cards\n",__FUNCTION__);
1616 pcs->print(stderr,pcs);
1617 pcd->print(stderr,pcd);
1619 peepBlock->wildpCodes[PCW(pcd)->id] = pcs;
1621 if(!pCodePeepMatchLabels(peepBlock, pcs, pcd))
1624 if(PCW(pcd)->operand) {
1625 PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
1626 if(peepBlock->vars[index]) {
1627 int i = (strcmp(peepBlock->vars[index],PCI(pcs)->pcop->name) == 0);
1629 fprintf(stderr," (matched)\n");
1631 fprintf(stderr," (no match: wild card operand mismatch\n");
1632 fprintf(stderr," peepblock= %s, pcodeop= %s\n",
1633 peepBlock->vars[index],
1634 PCI(pcs)->pcop->name);
1638 peepBlock->vars[index] = PCI(pcs)->pcop->name;
1643 pcs = findNextInstruction(pcs->next);
1645 fprintf(stderr," (next to match)\n");
1646 pcs->print(stderr,pcs);
1647 } else if(pcd->next) {
1648 /* oops, we ran out of code, but there's more to the rule */
1652 return 1; /* wild card matches */
1658 /*-----------------------------------------------------------------*/
1659 /*-----------------------------------------------------------------*/
1660 void pCodePeepClrVars(pCodePeep *pcp)
1667 for(i=0;i<pcp->nvars; i++) {
1668 pcp->vars[i] = NULL;
1669 pcp->wildpCodeOps[i] = NULL;
1673 /*-----------------------------------------------------------------*/
1674 /* pCodeInsertAfter - splice in the pCode chain starting with pc2 */
1675 /* into the pCode chain containing pc1 */
1676 /*-----------------------------------------------------------------*/
1677 void pCodeInsertAfter(pCode *pc1, pCode *pc2)
1683 pc2->next = pc1->next;
1685 pc1->next->prev = pc2;
1693 /*-----------------------------------------------------------------*/
1694 /* pCodeOpCopy - copy a pcode operator */
1695 /*-----------------------------------------------------------------*/
1696 static pCodeOp *pCodeOpCopy(pCodeOp *pcop)
1698 pCodeOp *pcopnew=NULL;
1703 switch(pcop->type) {
1706 fprintf(stderr,"pCodeOpCopy bit\n");
1707 pcopnew = Safe_calloc(1,sizeof(pCodeOpBit) );
1708 PCOB(pcopnew)->bit = PCOB(pcop)->bit;
1709 PCOB(pcopnew)->inBitSpace = PCOB(pcop)->inBitSpace;
1714 /* Here we expand the wild card into the appropriate type: */
1715 /* By recursively calling pCodeOpCopy */
1716 fprintf(stderr,"pCodeOpCopy wild\n");
1717 if(PCOW(pcop)->matched)
1718 pcopnew = pCodeOpCopy(PCOW(pcop)->matched);
1721 pcopnew = pCodeOpCopy(PCOW(pcop)->subtype);
1722 pcopnew->name = Safe_strdup(PCOW(pcop)->pcp->vars[PCOW(pcop)->id]);
1723 fprintf(stderr,"copied a wild op named %s\n",pcopnew->name);
1730 fprintf(stderr,"pCodeOpCopy label\n");
1731 pcopnew = Safe_calloc(1,sizeof(pCodeOpLabel) );
1732 PCOLAB(pcopnew)->key = PCOLAB(pcop)->key;
1737 fprintf(stderr,"pCodeOpCopy lit\n");
1738 pcopnew = Safe_calloc(1,sizeof(pCodeOpLit) );
1739 PCOL(pcopnew)->lit = PCOL(pcop)->lit;
1742 case PO_GPR_REGISTER:
1745 fprintf(stderr,"pCodeOpCopy GPR register\n");
1746 pcopnew = Safe_calloc(1,sizeof(pCodeOpReg) );
1747 PCOR(pcopnew)->r = PCOR(pcop)->r;
1748 PCOR(pcopnew)->rIdx = PCOR(pcop)->rIdx;
1749 fprintf(stderr," register index %d\n", PCOR(pcop)->r->rIdx);
1753 fprintf(stderr,"pCodeOpCopy PO_DIR\n");
1754 case PO_SFR_REGISTER:
1764 fprintf(stderr,"pCodeOpCopy register type %d\n", pcop->type);
1765 pcopnew = Safe_calloc(1,sizeof(pCodeOp) );
1769 pcopnew->type = pcop->type;
1771 pcopnew->name = Safe_strdup(pcop->name);
1773 pcopnew->name = NULL;
1779 /*-----------------------------------------------------------------*/
1780 /* pCodeCopy - copy a pcode */
1781 /*-----------------------------------------------------------------*/
1782 static pCode *pCodeCopy(pCode *pc)
1787 pcnew = newpCode(pc->type,pc->pcop);
1790 /*-----------------------------------------------------------------*/
1791 /*-----------------------------------------------------------------*/
1792 void pCodeDeleteChain(pCode *f,pCode *t)
1798 fprintf(stderr,"delete pCode:\n");
1801 //f->delete(f); this dumps core...
1808 /*-----------------------------------------------------------------*/
1809 /*-----------------------------------------------------------------*/
1810 int pCodePeepMatchRule(pCode *pc)
1812 pCodePeep *peepBlock;
1817 peeprules = (_DLL *)peepSnippets;
1820 peepBlock = ((pCodePeepSnippets*)peeprules)->peep;
1821 if(!peepBlock || !peepBlock->target || !peepBlock->target->pcHead)
1824 pCodePeepClrVars(peepBlock);
1827 pct = peepBlock->target->pcHead;
1829 while(pct && pcin) {
1831 if(! (matched = pCodePeepMatchLine(peepBlock, pcin,pct)))
1834 pcin = findNextInstruction(pcin->next);
1837 fprintf(stderr," matched\n");
1839 fprintf(stderr," end of code\n");
1841 fprintf(stderr," end of rule\n");
1846 /* So far we matched the rule up to the point of the conditions .
1847 * In other words, all of the opcodes match. Now we need to see
1848 * if the post conditions are satisfied.
1849 * First we check the 'postFalseCond'. This means that we check
1850 * to see if any of the subsequent pCode's in the pCode chain
1851 * following the point just past where we have matched depend on
1852 * the `postFalseCond' as input then we abort the match
1854 fprintf(stderr," matched rule so far, now checking conditions\n");
1855 if (pcin && peepBlock->postFalseCond &&
1856 (pCodeSearchCondition(pcin,peepBlock->postFalseCond) > 0) )
1866 /* We matched a rule! Now we have to go through and remove the
1867 inefficient code with the optimized version */
1869 fprintf(stderr, "Found a pcode peep match:\nRule:\n");
1870 printpCodeString(stderr,peepBlock->target->pcHead,10);
1871 fprintf(stderr,"first thing matched\n");
1872 pc->print(stderr,pc);
1874 fprintf(stderr,"last thing matched\n");
1875 pcin->print(stderr,pcin);
1878 /* Unlink the original code */
1880 pcprev->next = pcin;
1882 pcin->prev = pc->prev;
1886 /* Converted the deleted pCodes into comments */
1893 while(pc && pc!=pcin) {
1894 pCode2str(&buf[2], 254, pc);
1895 pCodeInsertAfter(pcprev, newpCodeCharP(buf));
1896 pcprev = pcprev->next;
1902 pCodeDeleteChain(pc,pcin);
1904 /* Generate the replacement code */
1906 pcr = peepBlock->replace->pcHead; // This is the replacement code
1909 /* If the replace pcode is an instruction with an operand, */
1910 /* then duplicate the operand (and expand wild cards in the process). */
1911 if(pcr->type == PC_OPCODE) {
1912 if(PCI(pcr)->pcop) {
1913 /* The replacing instruction has an operand.
1915 if(PCI(pcr)->pcop->type == PO_WILD) {
1916 int index = PCOW(PCI(pcr)->pcop)->id;
1917 fprintf(stderr,"copying wildopcode\n");
1918 if(peepBlock->wildpCodeOps[index])
1919 pcop = pCodeOpCopy(peepBlock->wildpCodeOps[index]);
1921 fprintf(stderr,"error, wildopcode in replace but not source?\n");
1923 pcop = pCodeOpCopy(PCI(pcr)->pcop);
1925 fprintf(stderr,"inserting pCode\n");
1926 pCodeInsertAfter(pc, newpCode(PCI(pcr)->op,pcop));
1927 } else if (pcr->type == PC_WILD) {
1928 pCodeInsertAfter(pc,peepBlock->wildpCodes[PCW(pcr)->id]);
1929 } else if (pcr->type == PC_COMMENT) {
1930 pCodeInsertAfter(pc, newpCodeCharP( ((pCodeComment *)(pcr))->comment));
1936 pc->print(stderr,pc);
1943 peeprules = peeprules->next;
1959 /*******************/
1960 pCode *parseLineNode(char *ln)
1962 char buffer[50], *s;
1963 int state=0; //0 label, 1 mnemonic, 2 operand, 3 operand, 4 comment
1966 // pCodeLabel *pcl = NULL;
1976 /* skip white space */
1977 while (isspace (*ln))
1982 case 0: // look for a label
1983 case 1: // look for mnemonic
1994 var = strtol(ln, &ln, 10);
1996 // valid wild card label
1997 fprintf(stderr, " wildcard label: %d\n",var);
2000 fprintf(stderr, " wild opcode: %d\n",var), state++;
2004 // Extract the label/mnemonic from the line
2007 while(*ln && !(isspace(*ln) || *ln == ':'))
2012 fprintf(stderr," regular label: %s\n",buffer), ln++;
2014 fprintf(stderr," regular mnem: %s\n",buffer), state++;