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 char *Safe_strdup(char *str);
44 int getpCode(char *mnem,int dest);
45 void pBlockMergeLabels(pBlock *pb);
46 char *pCode2str(char *str, int size, pCode *pc);
48 extern pCodeInstruction *pic14Mnemonics[];
51 /****************************************************************/
53 * rootRules - defined in SDCCpeep.c
54 * This is a pointer to the (parsed) peephole rules that are
55 * defined in peep.def.
58 //extern peepRule *rootRules;
63 /****************************************************************/
64 /****************************************************************/
72 typedef struct pCodePeepSnippets
79 /****************************************************************/
83 /****************************************************************/
85 static pCodePeepSnippets *peepSnippets=NULL;
87 /****************************************************************/
91 /****************************************************************/
93 static pCodePeep *curPeep=NULL;
95 /****************************************************************/
99 /****************************************************************/
101 static pBlock *curBlock=NULL;
104 /****************************************************************/
106 /* max wild cards in a peep rule */
108 /****************************************************************/
110 static int sMaxWildVar = 0;
111 static int sMaxWildMnem = 0;
114 typedef struct pCodeToken
116 int tt; // token type;
125 pCodeToken tokArr[50];
142 typedef struct parsedPattern {
143 struct pcPattern *pcp;
147 #define MAX_PARSEDPATARR 50
148 parsedPattern parsedPatArr[MAX_PARSEDPATARR];
149 unsigned int parsedPatIdx=0;
162 static char pcpat_label[] = {PCT_PERCENT, PCT_NUMBER, PCT_COLON, 0};
163 static char pcpat_number[] = {PCT_NUMBER, 0};
164 static char pcpat_string[] = {PCT_STRING, 0};
165 static char pcpat_wildString[] = {PCT_PERCENT, PCT_STRING, 0};
166 static char pcpat_wildVar[] = {PCT_PERCENT, PCT_NUMBER, 0};
167 static char pcpat_comma[] = {PCT_COMMA, 0};
168 static char pcpat_comment[] = {PCT_COMMENT, 0};
171 typedef struct pcPattern {
172 char pt; // Pattern type
173 char *tokens; // list of tokens that describe the pattern
174 void * (*f) (void *);
177 pcPattern pcpArr[] = {
178 {PCP_LABEL, pcpat_label, NULL},
179 {PCP_WILDSTR, pcpat_wildString, NULL},
180 {PCP_STR, pcpat_string, NULL},
181 {PCP_WILDVAR, pcpat_wildVar, NULL},
182 {PCP_COMMA, pcpat_comma, NULL},
183 {PCP_COMMENT, pcpat_comment, NULL},
184 {PCP_NUMBER, pcpat_number, NULL}
187 #define PCPATTERNS (sizeof(pcpArr)/sizeof(pcPattern))
189 // Assembly Line Token
202 static char alt_comment[] = { PCP_COMMENT, 0};
203 static char alt_label[] = { PCP_LABEL, 0};
204 static char alt_mnem0[] = { PCP_STR, 0};
205 static char alt_mnem0a[] = { PCP_WILDVAR, 0};
206 static char alt_mnem1[] = { PCP_STR, PCP_STR, 0};
207 static char alt_mnem1a[] = { PCP_STR, PCP_WILDVAR, 0};
208 static char alt_mnem1b[] = { PCP_STR, PCP_NUMBER, 0};
209 static char alt_mnem2[] = { PCP_STR, PCP_STR, PCP_COMMA, PCP_STR, 0};
210 static char alt_mnem2a[] = { PCP_STR, PCP_WILDVAR, PCP_COMMA, PCP_STR, 0};
212 static void * cvt_altpat_label(void *pp);
213 static void * cvt_altpat_comment(void *pp);
214 static void * cvt_altpat_mnem0(void *pp);
215 static void * cvt_altpat_mnem0a(void *pp);
216 static void * cvt_altpat_mnem1(void *pp);
217 static void * cvt_altpat_mnem1a(void *pp);
218 static void * cvt_altpat_mnem1b(void *pp);
219 static void * cvt_altpat_mnem2(void *pp);
220 static void * cvt_altpat_mnem2a(void *pp);
222 pcPattern altArr[] = {
223 {ALT_LABEL, alt_label, cvt_altpat_label},
224 {ALT_COMMENT, alt_comment,cvt_altpat_comment},
225 {ALT_MNEM2A, alt_mnem2a, cvt_altpat_mnem2a},
226 {ALT_MNEM2, alt_mnem2, cvt_altpat_mnem2},
227 {ALT_MNEM1B, alt_mnem1b, cvt_altpat_mnem1b},
228 {ALT_MNEM1A, alt_mnem1a, cvt_altpat_mnem1a},
229 {ALT_MNEM1, alt_mnem1, cvt_altpat_mnem1},
230 {ALT_MNEM0A, alt_mnem0a, cvt_altpat_mnem0a},
231 {ALT_MNEM0, alt_mnem0, cvt_altpat_mnem0},
235 #define ALTPATTERNS (sizeof(altArr)/sizeof(pcPattern))
237 // forward declarations
238 static void * DLL_append(_DLL *list, _DLL *next);
240 /*-----------------------------------------------------------------*/
241 /* cvt_extract_destination - helper function extracts the register */
242 /* destination from a parsedPattern. */
244 /*-----------------------------------------------------------------*/
245 static int cvt_extract_destination(parsedPattern *pp)
248 if(pp->pct[0].tt == PCT_STRING) {
250 // just check first letter for now
252 if(toupper(*pp->pct[0].tok.s) == 'F')
255 } else if (pp->pct[0].tt == PCT_NUMBER) {
265 /*-----------------------------------------------------------------*/
266 /* pCodeOp *cvt_extract_status(char *reg, char *bit) */
267 /* if *reg is the "status" register and *bit is one of the */
268 /* status bits, then this function will create a new pCode op */
269 /* containing the status register. */
270 /*-----------------------------------------------------------------*/
272 static pCodeOp *cvt_extract_status(char *reg, char *bit)
276 if(STRCASECMP(reg, pc_status.pcop.name))
283 if(toupper(*bit) == 'C')
284 return PCOP(popCopyGPR2Bit(&pc_status,PIC_C_BIT));
285 if(toupper(*bit) == 'Z')
286 return PCOP(popCopyGPR2Bit(&pc_status,PIC_Z_BIT));
290 if(len ==2 && toupper(bit[0]) == 'D' && toupper(bit[1]) == 'C')
291 return PCOP(popCopyGPR2Bit(&pc_status,PIC_DC_BIT));
297 /*-----------------------------------------------------------------*/
298 /* cvt_altpat_label - convert assembly line type to a pCode label */
299 /* INPUT: pointer to the parsedPattern */
303 /* label pattern => '%' number ':' */
304 /* at this point, we wish to extract only the 'number' */
306 /*-----------------------------------------------------------------*/
307 static void * cvt_altpat_label(void *pp)
309 parsedPattern *p = pp;
311 fprintf(stderr,"altpat_label with ID = %d\n",p->pct[1].tok.n);
312 return newpCodeLabel(-p->pct[1].tok.n);
316 /*-----------------------------------------------------------------*/
317 /* cvt_altpat_comment - convert assembly line type to a comment */
318 /* INPUT: pointer to the parsedPattern */
320 /* pp[0] - comment */
323 /*-----------------------------------------------------------------*/
324 static void * cvt_altpat_comment(void *pp)
326 parsedPattern *p = pp;
328 fprintf(stderr,"altpat_comment = %s\n",p->pct[0].tok.s);
329 return newpCodeCharP(p->pct[0].tok.s);
333 /*-----------------------------------------------------------------*/
334 /*-----------------------------------------------------------------*/
335 static void * cvt_altpat_mnem0(void *pp)
337 parsedPattern *p = pp;
340 pCodeInstruction *pci=NULL;
342 fprintf(stderr,"altpat_mnem0 %s\n", p->pct[0].tok.s);
344 opcode = getpCode(p->pct[0].tok.s,0);
346 fprintf(stderr, "Bad mnemonic\n");
350 pci = PCI(newpCode(opcode, NULL));
353 fprintf(stderr,"couldn't find mnemonic\n");
359 /*-----------------------------------------------------------------*/
360 /* cvt_altpat_mem0a - convert assembly line type to a wild pCode */
363 /* pp[0] - wild var */
365 /*-----------------------------------------------------------------*/
366 static void * cvt_altpat_mnem0a(void *pp)
368 parsedPattern *p = pp;
370 fprintf(stderr,"altpat_mnem0a wild mnem # %d\n", p[0].pct[1].tok.n);
372 /* Save the index of the maximum wildcard mnemonic */
374 if(p[0].pct[1].tok.n > sMaxWildVar)
375 sMaxWildMnem = p[0].pct[1].tok.n;
377 return newpCodeWild(p[0].pct[1].tok.n,NULL,NULL);
381 /*-----------------------------------------------------------------*/
382 /* cvt_altpat_mem1 - convert assembly line type to a pCode */
383 /* instruction with 1 operand. */
386 /* pp[1] - Operand */
388 /*-----------------------------------------------------------------*/
389 static void * cvt_altpat_mnem1(void *pp)
392 parsedPattern *p = pp;
395 pCodeInstruction *pci=NULL;
398 fprintf(stderr,"altpat_mnem1 %s var %s\n", p->pct[0].tok.s,p[1].pct[0].tok.s);
400 opcode = getpCode(p->pct[0].tok.s,0);
402 fprintf(stderr, "Bad mnemonic\n");
406 if(pic14Mnemonics[opcode]->bit_inst)
407 pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_BIT);
409 pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER);
412 pci = PCI(newpCode(opcode, pcosubtype));
415 fprintf(stderr,"couldn't find mnemonic\n");
421 /*-----------------------------------------------------------------*/
422 /* cvt_altpat_mem1a - convert assembly line type to a pCode */
423 /* instruction with 1 wild operand. */
426 /* pp[1] - wild var */
428 /*-----------------------------------------------------------------*/
429 static void * cvt_altpat_mnem1a(void *pp)
431 parsedPattern *p = pp;
434 pCodeInstruction *pci=NULL;
437 fprintf(stderr,"altpat_mnem1a %s var %d\n", p->pct[0].tok.s,p[1].pct[1].tok.n);
439 opcode = getpCode(p->pct[0].tok.s,0);
441 fprintf(stderr, "Bad mnemonic\n");
445 if(pic14Mnemonics[opcode]->bit_inst)
446 pcosubtype = newpCodeOpBit(NULL,-1,0);
448 pcosubtype = newpCodeOp(NULL,PO_GPR_REGISTER);
451 pci = PCI(newpCode(opcode,
452 newpCodeOpWild(p[1].pct[1].tok.n, curPeep, pcosubtype)));
454 /* Save the index of the maximum wildcard variable */
455 if(p[1].pct[1].tok.n > sMaxWildVar)
456 sMaxWildVar = p[1].pct[1].tok.n;
459 fprintf(stderr,"couldn't find mnemonic\n");
465 /*-----------------------------------------------------------------*/
466 /*-----------------------------------------------------------------*/
467 static void * cvt_altpat_mnem1b(void *pp)
469 parsedPattern *p = pp;
472 pCodeInstruction *pci=NULL;
474 fprintf(stderr,"altpat_mnem1b %s var %d\n", p->pct[0].tok.s,p[1].pct[0].tok.n);
476 opcode = getpCode(p->pct[0].tok.s,0);
478 fprintf(stderr, "Bad mnemonic\n");
482 pci = PCI(newpCode(opcode, newpCodeOpLit(p[1].pct[0].tok.n) ));
485 fprintf(stderr,"couldn't find mnemonic\n");
491 /*-----------------------------------------------------------------*/
492 /*-----------------------------------------------------------------*/
493 static void * cvt_altpat_mnem2(void *pp)
495 parsedPattern *p = pp;
499 pCodeInstruction *pci=NULL;
502 dest = cvt_extract_destination(&p[3]);
504 fprintf(stderr,"altpat_mnem2 %s var %s destination %s(%d)\n",
511 opcode = getpCode(p->pct[0].tok.s,dest);
513 fprintf(stderr, "Bad mnemonic\n");
517 if(pic14Mnemonics[opcode]->bit_inst) {
518 pcosubtype = cvt_extract_status(p[1].pct[0].tok.s, p[3].pct[0].tok.s);
519 if(pcosubtype == NULL) {
520 fprintf(stderr, "bad operand?\n");
525 pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER);
528 pci = PCI(newpCode(opcode,pcosubtype));
531 fprintf(stderr,"couldn't find mnemonic\n");
537 /*-----------------------------------------------------------------*/
538 /* cvt_altpat_mem2a - convert assembly line type to a pCode */
539 /* instruction with 1 wild operand and a */
540 /* destination operand (e.g. w or f) */
543 /* pp[1] - wild var */
545 /* pp[3] - destination */
547 /*-----------------------------------------------------------------*/
548 static void * cvt_altpat_mnem2a(void *pp)
550 parsedPattern *p = pp;
554 pCodeInstruction *pci=NULL;
557 dest = cvt_extract_destination(&p[3]);
559 fprintf(stderr,"altpat_mnem2a %s var %d destination %s(%d)\n",
566 opcode = getpCode(p->pct[0].tok.s,dest);
568 fprintf(stderr, "Bad mnemonic\n");
572 if(pic14Mnemonics[opcode]->bit_inst)
573 pcosubtype = newpCodeOp(NULL,PO_BIT);
575 pcosubtype = newpCodeOp(NULL,PO_GPR_REGISTER);
578 pci = PCI(newpCode(opcode,
579 newpCodeOpWild(p[1].pct[1].tok.n, curPeep, pcosubtype)));
581 /* Save the index of the maximum wildcard variable */
582 if(p[1].pct[1].tok.n > sMaxWildVar)
583 sMaxWildVar = p[1].pct[1].tok.n;
586 fprintf(stderr,"couldn't find mnemonic\n");
592 /*-----------------------------------------------------------------*/
593 /* tokenizeLineNode - Convert a string (of char's) that was parsed */
594 /* by SDCCpeeph.c into a string of tokens. */
597 /* The tokenizer is of the classic type. When an item is encounterd*/
598 /* it is converted into a token. The token is a structure that */
599 /* encodes the item's type and it's value (when appropriate). */
601 /* Accepted token types: */
602 /* SPACE NUMBER STRING % : , ; */
606 /*-----------------------------------------------------------------*/
609 static void tokenizeLineNode(char *ln)
612 tokIdx = 0; // Starting off at the beginning
613 tokArr[0].tt = PCT_NULL; // and assume invalid character for first token.
621 // add a SPACE token and eat the extra spaces.
622 tokArr[tokIdx++].tt = PCT_SPACE;
623 while (isspace (*ln))
630 tokArr[tokIdx].tt = PCT_NUMBER;
631 tokArr[tokIdx++].tok.n = strtol(ln, &ln, 0);
639 tokArr[tokIdx++].tt = PCT_PERCENT;
642 tokArr[tokIdx++].tt = PCT_COLON;
645 tokArr[tokIdx].tok.s = Safe_strdup(ln);
646 tokArr[tokIdx++].tt = PCT_COMMENT;
647 tokArr[tokIdx].tt = PCT_NULL;
650 tokArr[tokIdx++].tt = PCT_COMMA;
659 while( (isalpha(*ln) || isdigit(*ln)) && i<49)
665 tokArr[tokIdx].tok.s = Safe_strdup(buffer);
666 tokArr[tokIdx++].tt = PCT_STRING;
671 /* Advance to next character in input string .
672 * Note, if none of the tests passed above, then
673 * we effectively ignore the `bad' character.
674 * Since the line has already been parsed by SDCCpeeph,
675 * chance are that there are no invalid characters... */
681 tokArr[tokIdx].tt = 0;
685 /*-----------------------------------------------------------------*/
686 /*-----------------------------------------------------------------*/
690 void dump1Token(pCodeTokens tt)
695 fprintf(stderr, " space ");
698 fprintf(stderr, " pct ");
702 fprintf(stderr, " col ");
706 fprintf(stderr, " comma , ");
709 fprintf(stderr, " comment ");
710 //fprintf(stderr,"%s",tokArr[i].tok.s);
713 fprintf(stderr, " str ");
714 //fprintf(stderr,"%s",tokArr[i].tok.s);
717 fprintf(stderr, " num ");
718 //fprintf(stderr,"%d",tokArr[i].tok.n);
721 fprintf(stderr, " null ");
727 /*-----------------------------------------------------------------*/
728 /*-----------------------------------------------------------------*/
730 int pcComparePattern(pCodeToken *pct, char *pat, int max_tokens)
734 if(!pct || !pat || !*pat)
737 //fprintf(stderr,"comparing against:\n");
739 while(i < max_tokens) {
742 //fprintf(stderr,"matched\n");
746 //dump1Token(*pat); fprintf(stderr,"\n");
760 /*-----------------------------------------------------------------*/
761 /*-----------------------------------------------------------------*/
763 int altComparePattern( char *pct, parsedPattern *pat, int max_tokens)
767 if(!pct || !pat || !*pct)
771 while(i < max_tokens) {
774 //fprintf(stderr,"matched\n");
778 //dump1Token(*pat); fprintf(stderr,"\n");
780 if( !pat || !pat->pcp )
783 if (pat->pcp->pt != *pct)
786 //fprintf(stderr," pct=%d\n",*pct);
795 /*-----------------------------------------------------------------*/
796 /*-----------------------------------------------------------------*/
798 int advTokIdx(int *v, int amt)
801 if((unsigned) (*v + amt) > tokIdx)
809 /*-----------------------------------------------------------------*/
810 /* parseTokens - convert the tokens corresponding to a single line */
811 /* of a peep hole assembly into a pCode object. */
816 /* This is a simple parser that looks for strings of the type */
817 /* allowed in the peep hole definition file. Essentially the format*/
818 /* is the same as a line of assembly: */
820 /* label: mnemonic op1, op2, op3 ; comment */
822 /* Some of these items aren't present. It's the job of the parser */
823 /* to determine which are and convert those into the appropriate */
825 /*-----------------------------------------------------------------*/
827 void parseTokens(void)
835 for(i=0; i<=tokIdx; i++)
836 dump1Token(tokArr[i].tt);
848 char * cPmnem = NULL; // Pointer to non-wild mnemonic (if any)
849 char * cP1stop = NULL;
850 char * cP2ndop = NULL;
852 //pCodeOp *pcl = NULL; // Storage for a label
853 //pCodeOp *pco1 = NULL; // 1st operand
854 //pCodeOp *pco2 = NULL; // 2nd operand
855 //pCode *pc = NULL; // Mnemonic
866 ParseStates state = PS_START;
873 if( ((tokArr[ltokIdx].tt == PCT_SPACE) )
874 && (advTokIdx(<okIdx, 1)) ) // eat space
878 j = pcComparePattern(&tokArr[ltokIdx], pcpArr[lpcpIdx].tokens, tokIdx +1);
881 switch(pcpArr[lpcpIdx].pt) {
883 if(state == PS_START){
884 fprintf(stderr," label\n");
885 state = PS_HAVE_LABEL;
887 fprintf(stderr," bad state (%d) for label\n",state);
891 fprintf(stderr," %s is",tokArr[ltokIdx].tok.s);
895 fprintf(stderr," mnem\n");
896 cPmnem = tokArr[ltokIdx].tok.s;
897 state = PS_HAVE_MNEM;
900 fprintf(stderr," 1st operand\n");
901 cP1stop = tokArr[ltokIdx].tok.s;
902 //pco1 = newpCodeOp(NULL,PO_GPR_REGISTER);
903 state = PS_HAVE_1OPERAND;
905 case PS_HAVE_1OPERAND:
906 fprintf(stderr," error expecting comma\n");
909 fprintf(stderr," 2 operands\n");
910 cP2ndop = tokArr[ltokIdx].tok.s;
912 case PS_HAVE_2OPERANDS:
921 fprintf(stderr," wild mnem\n");
922 state = PS_HAVE_MNEM;
925 fprintf(stderr," 1st operand is wild\n");
926 state = PS_HAVE_1OPERAND;
928 case PS_HAVE_1OPERAND:
929 fprintf(stderr," error expecting comma\n");
932 fprintf(stderr," 2nd operand is wild\n");
934 case PS_HAVE_2OPERANDS:
943 fprintf(stderr," ERROR number\n");
946 fprintf(stderr," 1st operand is a number\n");
947 state = PS_HAVE_1OPERAND;
949 case PS_HAVE_1OPERAND:
950 fprintf(stderr," error expecting comma\n");
953 fprintf(stderr," 2nd operand is a number\n");
955 case PS_HAVE_2OPERANDS:
963 if(state == PS_HAVE_1OPERAND){
964 fprintf(stderr," got a comma\n");
965 state = PS_HAVE_COMMA;
967 fprintf(stderr," unexpected comma\n");
971 parsedPatArr[lparsedPatIdx].pcp = &pcpArr[lpcpIdx];
972 parsedPatArr[lparsedPatIdx].pct = &tokArr[ltokIdx];
975 //dump1Token(tokArr[ltokIdx].tt);
977 if(advTokIdx(<okIdx, strlen(pcpArr[lpcpIdx].tokens) ) ) {
978 fprintf(stderr," reached end \n");
985 } while ((++lpcpIdx < PCPATTERNS) && !matching);
989 parsedPatArr[lparsedPatIdx].pcp = NULL;
990 parsedPatArr[lparsedPatIdx].pct = NULL;
996 if( (c=altComparePattern( altArr[k].tokens, &parsedPatArr[j],10) ) ) {
999 pc = altArr[k].f(&parsedPatArr[j]);
1001 pc->print(stderr,pc);
1002 //if(pc && pc->destruct) pc->destruct(pc); dumps core?
1004 addpCode2pBlock(curBlock, pc);
1010 while(j<=lparsedPatIdx && k<ALTPATTERNS);
1013 fprintf(stderr,"\nConverting parsed line to pCode:\n\n");
1017 if(parsedPatArr[j].pcp && parsedPatArr[j].pcp->f )
1018 parsedPatArr[j].pcp->f(&parsedPatArr[j]);
1019 fprintf(stderr," %d",parsedPatArr[j].pcp->pt);
1022 while(j<lparsedPatIdx);
1024 fprintf(stderr,"\n");
1031 /*-----------------------------------------------------------------*/
1033 /*-----------------------------------------------------------------*/
1034 void peepRuleBlock2pCodeBlock( lineNode *ln)
1040 for( ; ln; ln = ln->next) {
1042 fprintf(stderr,"%s\n",ln->line);
1044 tokenizeLineNode(ln->line);
1050 /*-----------------------------------------------------------------*/
1051 /* peepRuleCondition */
1052 /*-----------------------------------------------------------------*/
1053 static void peepRuleCondition(char *cond)
1058 fprintf(stderr,"\nCondition: %s\n",cond);
1060 /* brute force compares for now */
1062 if(STRCASECMP(cond, "NZ") == 0) {
1063 fprintf(stderr,"found NZ\n");
1064 curPeep->postFalseCond = PCC_Z;
1069 /*-----------------------------------------------------------------*/
1070 /* peepRules2pCode - parse the "parsed" peep hole rules to generate*/
1073 /* SDCCpeeph parses the peep rules file and extracts variables, */
1074 /* removes white space, and checks the syntax. This function */
1075 /* extends that processing to produce pCode objects. You can kind */
1076 /* think of this function as an "assembler", though instead of */
1077 /* taking raw text to produce machine code, it produces pCode. */
1079 /*-----------------------------------------------------------------*/
1081 void peepRules2pCode(peepRule *rules)
1085 pCodePeepSnippets *pcps;
1087 /* The rules are in a linked-list. Each rule has two portions */
1088 /* There's the `target' and there's the `replace'. The target */
1089 /* is compared against the SDCC generated code and if it */
1090 /* matches, it gets replaced by the `replace' block of code. */
1092 /* Here we loop through each rule and convert the target's and*/
1093 /* replace's into pCode target and replace blocks */
1095 for (pr = rules; pr; pr = pr->next) {
1097 fprintf(stderr,"\nRule:\n\n");
1099 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1100 curPeep = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
1102 curPeep->vars = NULL;
1103 curPeep->wildpCodes = NULL; curPeep->wildpCodeOps = NULL;
1104 curPeep->postFalseCond = PCC_NONE;
1105 curPeep->postTrueCond = PCC_NONE;
1107 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1109 curPeep->target = curBlock = newpCodeChain(NULL, 'W', NULL);
1113 /* Convert the target block */
1114 peepRuleBlock2pCodeBlock(pr->match);
1116 fprintf(stderr,"finished target, here it is in pcode form:\n");
1117 printpBlock(stderr, curBlock);
1119 fprintf(stderr,"target with labels merged:\n");
1120 pBlockMergeLabels(curBlock);
1121 printpBlock(stderr, curBlock);
1123 fprintf(stderr,"\nReplaced by:\n");
1126 curPeep->replace = curBlock = newpCodeChain(NULL, 'W', NULL);
1128 /* Convert the replace block */
1129 peepRuleBlock2pCodeBlock(pr->replace);
1131 fprintf(stderr,"finished replace block, here it is in pcode form:\n");
1132 printpBlock(stderr, curBlock);
1134 fprintf(stderr,"replace with labels merged:\n");
1135 pBlockMergeLabels(curBlock);
1136 printpBlock(stderr, curBlock);
1138 peepRuleCondition(pr->cond);
1140 /* The rule has been converted to pCode. Now allocate
1141 * space for the wildcards */
1144 curPeep->nvars = sMaxWildVar;
1145 curPeep->vars = Safe_calloc(sMaxWildVar, sizeof(char *));
1147 curPeep->nops = sMaxWildVar;
1148 curPeep->wildpCodeOps = Safe_calloc(sMaxWildVar, sizeof(pCodeOp *));
1150 curPeep->nwildpCodes = ++sMaxWildMnem;
1151 curPeep->wildpCodes = Safe_calloc(sMaxWildMnem, sizeof(char *));
1154 //return; // debug ... don't want to go through all the rules yet
1159 void printpCodeString(FILE *of, pCode *pc, int max)
1163 while(pc && (i++<max)) {
1169 /*-----------------------------------------------------------------*/
1170 /* _DLL * DLL_append */
1172 /* Append a _DLL object to the end of a _DLL (doubly linked list) */
1173 /* If The list to which we want to append is non-existant then one */
1174 /* is created. Other wise, the end of the list is sought out and */
1175 /* a new DLL object is appended to it. In either case, the void */
1176 /* *data is added to the newly created DLL object. */
1177 /*-----------------------------------------------------------------*/
1179 static void * DLL_append(_DLL *list, _DLL *next)
1184 /* If there's no list, then create one: */
1186 next->next = next->prev = NULL;
1191 /* Search for the end of the list. */
1196 /* Now append the new DLL object */
1207 /*-----------------------------------------------------------------
1209 pCode peephole optimization
1212 The pCode "peep hole" optimization is not too unlike the peep hole
1213 optimization in SDCCpeeph.c. The major difference is that here we
1214 use pCode's whereas there we use ASCII strings. The advantage with
1215 pCode's is that we can ascertain flow information in the instructions
1219 <FIX ME> - elaborate...
1221 -----------------------------------------------------------------*/
1224 /*-----------------------------------------------------------------*/
1226 /*-----------------------------------------------------------------*/
1227 int pCodePeepCompare(pCode *pc, pCodePeep *pcp)
1229 pCode *pcfrom,*pcto;
1232 for( pcto=pcp->target; pcto; pcto=pcto->next) {
1234 pcfrom = findNextInstruction(pcfrom);
1237 (PCI(pcfrom)->op == PCI(pcto)->op ||
1238 PCI(pcto)->op == POC_WILD))
1245 /*-----------------------------------------------------------------*/
1247 /*-----------------------------------------------------------------*/
1248 void pCodePeepSearch(pCodePeep *snippet)
1256 /* compare the chain to the pCode that we've
1257 got so far. If a match is found, then replace
1260 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1261 for(pc = pb->pcHead; pc; pc = pc->next) {
1262 pCodePeepCompare(pc,snippet);
1270 pBlock *pBlockAppend(pBlock *pb1, pBlock *pb2)
1287 void pCodePeepInit(void)
1293 pCodePeepSnippets *pcps;
1295 /* Declare a peep code snippet */
1296 /* <FIXME> do I really need a separate struct just to DLL the snippets? */
1297 /* e.g. I could put the DLL into the pCodePeep structure */
1311 false condition - PCC_Z (Z bit is not used as input to subsequent code)
1312 true condition - none
1314 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1315 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
1316 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1319 pb = newpCodeChain(NULL, 'W', newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1320 addpCode2pBlock( pb, newpCode(POC_MOVFW, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1324 pcp->replace = newpCodeChain(NULL, 'W',newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
1326 /* Allocate space to store pointers to the wildcard variables */
1328 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
1329 pcp->nwildpCodes = 0;
1330 pcp->wildpCodes = NULL;
1332 pcp->postFalseCond = PCC_Z;
1333 pcp->postTrueCond = PCC_NONE;
1335 fprintf(stderr,"Peep rule\nTarget:\n");
1336 printpCodeString(stderr,pcp->target->pcHead, 10);
1337 fprintf(stderr,"Replaced with:\n");
1338 printpCodeString(stderr,pcp->replace->pcHead, 10);
1340 /* Now for another peep example */
1341 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1342 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
1343 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1359 The %3 and %4 are wild opcodes. Since the opcodes
1360 are stored in a different array than the wild operands,
1361 they can have the same indices and not conflict. So
1362 below, the %3 is really a %0, %4 is a %1.
1369 // Create a new wild operand subtyped as a bit
1370 pcwb = newpCodeOpWild(0,pcp,newpCodeOpBit(NULL,-1,0));
1373 pb = newpCodeChain(NULL, 'W',newpCode(POC_BTFSC,pcwb));
1375 pcl = newpCodeOpLabel(-1);
1376 pcw = newpCodeOpWild(1, pcp, pcl);
1377 addpCode2pBlock( pb, newpCode(POC_GOTO, pcw));
1378 addpCode2pBlock( pb, newpCodeWild(0,NULL,NULL));
1379 addpCode2pBlock( pb, newpCodeWild(1,NULL,pcw));
1384 pb = newpCodeChain(NULL, 'W',newpCode(POC_BTFSS, pcwb));
1385 addpCode2pBlock( pb, newpCodeWild(0,NULL,NULL));
1386 addpCode2pBlock( pb, newpCodeWild(1,NULL,pcw));
1390 /* Allocate space to store pointers to the wildcard variables */
1392 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
1393 pcp->nwildpCodes = 2;
1394 pcp->wildpCodes = Safe_calloc(pcp->nwildpCodes, sizeof(pCode *));
1396 pcp->postFalseCond = PCC_NONE;
1397 pcp->postTrueCond = PCC_NONE;
1411 /* Now for another peep example */
1412 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
1413 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
1414 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
1419 pcw = newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER));
1421 pb = newpCodeChain(NULL, 'W', newpCode(POC_MOVWF, pcw));
1422 addpCode2pBlock( pb, newpCode(POC_MOVWF, pcw));
1426 pb = newpCodeChain(NULL, 'W',newpCode(POC_MOVWF, pcw));
1430 /* Allocate space to store pointers to the wildcard variables */
1432 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
1433 pcp->nwildpCodes = 0;
1434 pcp->wildpCodes = NULL;
1436 pcp->postFalseCond = PCC_NONE;
1437 pcp->postTrueCond = PCC_NONE;
1445 /*-----------------------------------------------------------------*/
1446 /* pCodeSearchCondition - Search a pCode chain for a 'condition' */
1448 /* return conditions */
1449 /* 1 - The Condition was found for a pCode's input */
1450 /* 0 - No matching condition was found for the whole chain */
1451 /* -1 - The Condition was found for a pCode's output */
1453 /*-----------------------------------------------------------------*/
1454 int pCodeSearchCondition(pCode *pc, unsigned int cond)
1459 /* If we reach a function end (presumably an end since we most
1460 probably began the search in the middle of a function), then
1461 the condition was not found. */
1462 if(pc->type == PC_FUNCTION)
1465 if(pc->type == PC_OPCODE) {
1466 if(PCI(pc)->inCond & cond)
1468 if(PCI(pc)->outCond & cond)
1477 /*-----------------------------------------------------------------*/
1478 /* pCodePeepMatchLine - Compare source and destination pCodes to */
1479 /* see they're the same. */
1481 /* In this context, "source" refers to the coded generated by gen.c*/
1482 /* and "destination" refers to a pcode in a peep rule. If the dest-*/
1483 /* ination has no wild cards, then MatchLine will compare the two */
1484 /* pcodes (src and dest) for a one-to-one match. If the destination*/
1485 /* has wildcards, then those get expanded. When a wild card is */
1486 /* encountered for the first time it autmatically is considered a */
1487 /* match and the object that matches it is referenced in the */
1488 /* variables or opcodes array (depending on the type of match). */
1492 /* *peepBlock - A pointer to the peepBlock that contains the */
1493 /* entire rule to which the destination pcode belongs*/
1494 /* *pcs - a pointer to the source pcode */
1495 /* *pcd - a pointer to the destination pcode */
1498 /* 1 - pcodes match */
1499 /* 0 - pcodes don't match */
1502 /*-----------------------------------------------------------------*/
1504 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd)
1506 int index; // index into wild card arrays
1508 if(pcs->type == pcd->type) {
1510 if(pcs->type == PC_OPCODE) {
1512 /* If the opcodes don't match then the line doesn't match */
1513 if(PCI(pcs)->op != PCI(pcd)->op)
1516 fprintf(stderr,"%s comparing\n",__FUNCTION__);
1517 pcs->print(stderr,pcs);
1518 pcd->print(stderr,pcd);
1520 /* Compare the operands */
1521 if(PCI(pcd)->pcop) {
1522 if (PCI(pcd)->pcop->type == PO_WILD) {
1523 index = PCOW(PCI(pcd)->pcop)->id;
1525 fprintf(stderr,"destination is wild\n");
1526 #ifdef DEBUG_PCODEPEEP
1527 if (index > peepBlock->nops) {
1528 fprintf(stderr,"%s - variables exceeded\n",__FUNCTION__);
1532 PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
1533 if(!peepBlock->wildpCodeOps[index]) {
1534 peepBlock->wildpCodeOps[index] = PCI(pcs)->pcop;
1536 //if(PCI(pcs)->pcop->type == PO_GPR_TEMP)
1542 if(PCI(pcs)->pcop->type == PO_GPR_TEMP)
1543 n = PCOR(PCI(pcs)->pcop)->r->name;
1545 n = PCI(pcs)->pcop->name;
1547 if(peepBlock->vars[index])
1548 return (strcmp(peepBlock->vars[index],n) == 0);
1550 fprintf(stderr,"first time for a variable: %d, %s\n",index,n);
1551 peepBlock->vars[index] = n; //PCI(pcs)->pcop->name;
1556 /* FIXME - need an else to check the case when the destination
1557 * isn't a wild card */
1559 /* The pcd has no operand. Lines match if pcs has no operand either*/
1560 return (PCI(pcs)->pcop == NULL);
1565 if((pcd->type == PC_WILD) && (pcs->type == PC_OPCODE)) {
1569 index = PCW(pcd)->id;
1571 fprintf(stderr,"%s comparing wild cards\n",__FUNCTION__);
1572 pcs->print(stderr,pcs);
1573 pcd->print(stderr,pcd);
1575 peepBlock->wildpCodes[PCW(pcd)->id] = pcs;
1577 /* Check for a label associated with this wild pCode */
1578 // If the wild card has a label, make sure the source code does too.
1585 pcl = pcd->label->pc;
1586 //labindex = PCOW(pcl)->id;
1587 labindex = -PCL(pcl)->key;
1588 fprintf(stderr,"label id = %d (labindex = %d)\n",PCL(pcl)->key,labindex);
1589 if(peepBlock->vars[labindex] == NULL) {
1590 // First time to encounter this label
1591 peepBlock->vars[labindex] = PCL(pcs->label->pc)->label;
1592 fprintf(stderr,"first time for a label: %d %s\n",labindex, peepBlock->vars[labindex]);
1594 if(strcmp(peepBlock->vars[labindex],PCL(pcs->label->pc)->label) != 0) {
1595 fprintf(stderr,"labels don't match\n");
1598 fprintf(stderr,"matched a label\n");
1601 fprintf(stderr,"wild card doesn't have a label\n");
1603 if(PCW(pcd)->operand) {
1604 PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
1605 if(peepBlock->vars[index]) {
1606 int i = (strcmp(peepBlock->vars[index],PCI(pcs)->pcop->name) == 0);
1608 fprintf(stderr," (matched)\n");
1610 fprintf(stderr," (no match: wild card operand mismatch\n");
1611 fprintf(stderr," peepblock= %s, pcodeop= %s\n",
1612 peepBlock->vars[index],
1613 PCI(pcs)->pcop->name);
1617 peepBlock->vars[index] = PCI(pcs)->pcop->name;
1622 pcs = findNextInstruction(pcs->next);
1624 fprintf(stderr," (next to match)\n");
1625 pcs->print(stderr,pcs);
1626 } else if(pcd->next) {
1627 /* oops, we ran out of code, but there's more to the rule */
1631 return 1; /* wild card matches */
1637 /*-----------------------------------------------------------------*/
1638 /*-----------------------------------------------------------------*/
1639 void pCodePeepClrVars(pCodePeep *pcp)
1646 for(i=0;i<pcp->nvars; i++) {
1647 pcp->vars[i] = NULL;
1648 pcp->wildpCodeOps[i] = NULL;
1652 /*-----------------------------------------------------------------*/
1653 /* pCodeInsertAfter - splice in the pCode chain starting with pc2 */
1654 /* into the pCode chain containing pc1 */
1655 /*-----------------------------------------------------------------*/
1656 void pCodeInsertAfter(pCode *pc1, pCode *pc2)
1662 pc2->next = pc1->next;
1664 pc1->next->prev = pc2;
1672 /*-----------------------------------------------------------------*/
1673 /* pCodeOpCopy - copy a pcode operator */
1674 /*-----------------------------------------------------------------*/
1675 static pCodeOp *pCodeOpCopy(pCodeOp *pcop)
1677 pCodeOp *pcopnew=NULL;
1682 switch(pcop->type) {
1685 fprintf(stderr,"pCodeOpCopy bit\n");
1686 pcopnew = Safe_calloc(1,sizeof(pCodeOpBit) );
1687 PCOB(pcopnew)->bit = PCOB(pcop)->bit;
1688 PCOB(pcopnew)->inBitSpace = PCOB(pcop)->inBitSpace;
1693 /* Here we expand the wild card into the appropriate type: */
1694 /* By recursively calling pCodeOpCopy */
1695 fprintf(stderr,"pCodeOpCopy wild\n");
1696 if(PCOW(pcop)->matched)
1697 pcopnew = pCodeOpCopy(PCOW(pcop)->matched);
1700 pcopnew = pCodeOpCopy(PCOW(pcop)->subtype);
1701 pcopnew->name = Safe_strdup(PCOW(pcop)->pcp->vars[PCOW(pcop)->id]);
1702 fprintf(stderr,"copied a wild op named %s\n",pcopnew->name);
1709 fprintf(stderr,"pCodeOpCopy label\n");
1710 pcopnew = Safe_calloc(1,sizeof(pCodeOpLabel) );
1711 PCOLAB(pcopnew)->key = PCOLAB(pcop)->key;
1716 fprintf(stderr,"pCodeOpCopy lit\n");
1717 pcopnew = Safe_calloc(1,sizeof(pCodeOpLit) );
1718 PCOL(pcopnew)->lit = PCOL(pcop)->lit;
1721 case PO_GPR_REGISTER:
1724 fprintf(stderr,"pCodeOpCopy GPR register\n");
1725 pcopnew = Safe_calloc(1,sizeof(pCodeOpReg) );
1726 PCOR(pcopnew)->r = PCOR(pcop)->r;
1727 PCOR(pcopnew)->rIdx = PCOR(pcop)->rIdx;
1728 fprintf(stderr," register index %d\n", PCOR(pcop)->r->rIdx);
1732 fprintf(stderr,"pCodeOpCopy PO_DIR\n");
1733 case PO_SFR_REGISTER:
1743 fprintf(stderr,"pCodeOpCopy register type %d\n", pcop->type);
1744 pcopnew = Safe_calloc(1,sizeof(pCodeOp) );
1748 pcopnew->type = pcop->type;
1749 pcopnew->name = Safe_strdup(pcop->name);
1755 /*-----------------------------------------------------------------*/
1756 /* pCodeCopy - copy a pcode */
1757 /*-----------------------------------------------------------------*/
1758 static pCode *pCodeCopy(pCode *pc)
1763 pcnew = newpCode(pc->type,pc->pcop);
1766 /*-----------------------------------------------------------------*/
1767 /*-----------------------------------------------------------------*/
1768 void pCodeDeleteChain(pCode *f,pCode *t)
1774 fprintf(stderr,"delete pCode:\n");
1777 //f->delete(f); this dumps core...
1784 /*-----------------------------------------------------------------*/
1785 /*-----------------------------------------------------------------*/
1786 int pCodePeepMatchRule(pCode *pc)
1788 pCodePeep *peepBlock;
1793 peeprules = (_DLL *)peepSnippets;
1796 peepBlock = ((pCodePeepSnippets*)peeprules)->peep;
1797 if(!peepBlock || !peepBlock->target || !peepBlock->target->pcHead)
1800 pCodePeepClrVars(peepBlock);
1803 pct = peepBlock->target->pcHead;
1805 while(pct && pcin) {
1807 if(! (matched = pCodePeepMatchLine(peepBlock, pcin,pct)))
1810 pcin = findNextInstruction(pcin->next);
1813 fprintf(stderr," matched\n");
1815 fprintf(stderr," end of code\n");
1817 fprintf(stderr," end of rule\n");
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
1830 fprintf(stderr," matched rule so far, now checking conditions\n");
1831 if (pcin && peepBlock->postFalseCond &&
1832 (pCodeSearchCondition(pcin,peepBlock->postFalseCond) > 0) )
1842 /* We matched a rule! Now we have to go through and remove the
1843 inefficient code with the optimized version */
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);
1850 fprintf(stderr,"last thing matched\n");
1851 pcin->print(stderr,pcin);
1854 /* Unlink the original code */
1856 pcprev->next = pcin;
1858 pcin->prev = pc->prev;
1862 /* Converted the deleted pCodes into comments */
1869 while(pc && pc!=pcin) {
1870 pCode2str(&buf[2], 254, pc);
1871 pCodeInsertAfter(pcprev, newpCodeCharP(buf));
1872 pcprev = pcprev->next;
1878 pCodeDeleteChain(pc,pcin);
1880 /* Generate the replacement code */
1882 pcr = peepBlock->replace->pcHead; // This is the replacement code
1885 /* If the replace pcode is an instruction with an operand, */
1886 /* then duplicate the operand (and expand wild cards in the process). */
1887 if(pcr->type == PC_OPCODE) {
1888 if(PCI(pcr)->pcop) {
1889 /* The replacing instruction has an operand.
1891 if(PCI(pcr)->pcop->type == PO_WILD) {
1892 int index = PCOW(PCI(pcr)->pcop)->id;
1893 fprintf(stderr,"copying wildopcode\n");
1894 if(peepBlock->wildpCodeOps[index])
1895 pcop = pCodeOpCopy(peepBlock->wildpCodeOps[index]);
1897 fprintf(stderr,"error, wildopcode in replace but not source?\n");
1899 pcop = pCodeOpCopy(PCI(pcr)->pcop);
1901 fprintf(stderr,"inserting pCode\n");
1902 pCodeInsertAfter(pc, newpCode(PCI(pcr)->op,pcop));
1903 } else if (pcr->type == PC_WILD) {
1904 pCodeInsertAfter(pc,peepBlock->wildpCodes[PCW(pcr)->id]);
1905 } else if (pcr->type == PC_COMMENT) {
1906 pCodeInsertAfter(pc, newpCodeCharP( ((pCodeComment *)(pcr))->comment));
1912 pc->print(stderr,pc);
1919 peeprules = peeprules->next;
1935 /*******************/
1936 pCode *parseLineNode(char *ln)
1938 char buffer[50], *s;
1939 int state=0; //0 label, 1 mnemonic, 2 operand, 3 operand, 4 comment
1942 // pCodeLabel *pcl = NULL;
1952 /* skip white space */
1953 while (isspace (*ln))
1958 case 0: // look for a label
1959 case 1: // look for mnemonic
1970 var = strtol(ln, &ln, 10);
1972 // valid wild card label
1973 fprintf(stderr, " wildcard label: %d\n",var);
1976 fprintf(stderr, " wild opcode: %d\n",var), state++;
1980 // Extract the label/mnemonic from the line
1983 while(*ln && !(isspace(*ln) || *ln == ':'))
1988 fprintf(stderr," regular label: %s\n",buffer), ln++;
1990 fprintf(stderr," regular mnem: %s\n",buffer), state++;