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);
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));
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. */
1480 /*-----------------------------------------------------------------*/
1481 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd)
1483 int index; // index into wild card arrays
1485 if(pcs->type == pcd->type) {
1487 if(pcs->type == PC_OPCODE) {
1489 /* If the opcodes don't match then the line doesn't match */
1490 if(PCI(pcs)->op != PCI(pcd)->op)
1493 fprintf(stderr,"%s comparing\n",__FUNCTION__);
1494 pcs->print(stderr,pcs);
1495 pcd->print(stderr,pcd);
1497 /* Compare the operands */
1498 if(PCI(pcd)->pcop) {
1499 if (PCI(pcd)->pcop->type == PO_WILD) {
1500 index = PCOW(PCI(pcd)->pcop)->id;
1502 fprintf(stderr,"destination is wild\n");
1503 #ifdef DEBUG_PCODEPEEP
1504 if (index > peepBlock->nops) {
1505 fprintf(stderr,"%s - variables exceeded\n",__FUNCTION__);
1509 PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
1510 if(!peepBlock->wildpCodeOps[index]) {
1511 peepBlock->wildpCodeOps[index] = PCI(pcs)->pcop;
1513 //if(PCI(pcs)->pcop->type == PO_GPR_TEMP)
1519 if(PCI(pcs)->pcop->type == PO_GPR_TEMP)
1520 n = PCOR(PCI(pcs)->pcop)->r->name;
1522 n = PCI(pcs)->pcop->name;
1524 if(peepBlock->vars[index])
1525 return (strcmp(peepBlock->vars[index],n) == 0);
1527 peepBlock->vars[index] = n; //PCI(pcs)->pcop->name;
1533 /* The pcd has no operand. Lines match if pcs has no operand either*/
1534 return (PCI(pcs)->pcop == NULL);
1539 if((pcd->type == PC_WILD) && (pcs->type == PC_OPCODE)) {
1543 index = PCW(pcd)->id;
1545 fprintf(stderr,"%s comparing wild cards\n",__FUNCTION__);
1546 pcs->print(stderr,pcs);
1547 pcd->print(stderr,pcd);
1549 peepBlock->wildpCodes[PCW(pcd)->id] = pcs;
1551 /* Check for a label associated with this wild pCode */
1552 // If the wild card has a label, make sure the source code does too.
1559 pcl = pcd->label->pc;
1561 labindex = PCOW(pcl)->id;
1562 if(peepBlock->vars[labindex] == NULL) {
1563 // First time to encounter this label
1564 peepBlock->vars[labindex] = PCL(pcs->label->pc)->label;
1565 fprintf(stderr,"first time for a label\n");
1567 if(strcmp(peepBlock->vars[labindex],PCL(pcs->label->pc)->label) != 0) {
1568 fprintf(stderr,"labels don't match\n");
1571 fprintf(stderr,"matched a label\n");
1574 fprintf(stderr,"wild card doesn't have a label\n");
1576 if(PCW(pcd)->operand) {
1577 PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
1578 if(peepBlock->vars[index]) {
1579 int i = (strcmp(peepBlock->vars[index],PCI(pcs)->pcop->name) == 0);
1581 fprintf(stderr," (matched)\n");
1583 fprintf(stderr," (no match: wild card operand mismatch\n");
1584 fprintf(stderr," peepblock= %s, pcodeop= %s\n",
1585 peepBlock->vars[index],
1586 PCI(pcs)->pcop->name);
1590 peepBlock->vars[index] = PCI(pcs)->pcop->name;
1595 pcs = findNextInstruction(pcs->next);
1597 fprintf(stderr," (next to match)\n");
1598 pcs->print(stderr,pcs);
1601 return 1; /* wild card matches */
1607 /*-----------------------------------------------------------------*/
1608 /*-----------------------------------------------------------------*/
1609 void pCodePeepClrVars(pCodePeep *pcp)
1616 for(i=0;i<pcp->nvars; i++) {
1617 pcp->vars[i] = NULL;
1618 pcp->wildpCodeOps[i] = NULL;
1622 /*-----------------------------------------------------------------*/
1623 /* pCodeInsertAfter - splice in the pCode chain starting with pc2 */
1624 /* into the pCode chain containing pc1 */
1625 /*-----------------------------------------------------------------*/
1626 void pCodeInsertAfter(pCode *pc1, pCode *pc2)
1632 pc2->next = pc1->next;
1634 pc1->next->prev = pc2;
1642 /*-----------------------------------------------------------------*/
1643 /* pCodeOpCopy - copy a pcode operator */
1644 /*-----------------------------------------------------------------*/
1645 static pCodeOp *pCodeOpCopy(pCodeOp *pcop)
1647 pCodeOp *pcopnew=NULL;
1652 switch(pcop->type) {
1655 fprintf(stderr,"pCodeOpCopy bit\n");
1656 pcopnew = Safe_calloc(1,sizeof(pCodeOpBit) );
1657 PCOB(pcopnew)->bit = PCOB(pcop)->bit;
1658 PCOB(pcopnew)->inBitSpace = PCOB(pcop)->inBitSpace;
1663 /* Here we expand the wild card into the appropriate type: */
1664 /* By recursively calling pCodeOpCopy */
1665 fprintf(stderr,"pCodeOpCopy wild\n");
1666 if(PCOW(pcop)->matched)
1667 pcopnew = pCodeOpCopy(PCOW(pcop)->matched);
1670 pcopnew = pCodeOpCopy(PCOW(pcop)->subtype);
1671 pcopnew->name = Safe_strdup(PCOW(pcop)->pcp->vars[PCOW(pcop)->id]);
1672 fprintf(stderr,"copied a wild op named %s\n",pcopnew->name);
1679 fprintf(stderr,"pCodeOpCopy label\n");
1680 pcopnew = Safe_calloc(1,sizeof(pCodeOpLabel) );
1681 PCOLAB(pcopnew)->key = PCOLAB(pcop)->key;
1686 fprintf(stderr,"pCodeOpCopy lit\n");
1687 pcopnew = Safe_calloc(1,sizeof(pCodeOpLit) );
1688 PCOL(pcopnew)->lit = PCOL(pcop)->lit;
1691 case PO_GPR_REGISTER:
1693 fprintf(stderr,"pCodeOpCopy GPR register\n");
1694 pcopnew = Safe_calloc(1,sizeof(pCodeOpReg) );
1695 PCOR(pcopnew)->r = PCOR(pcop)->r;
1696 PCOR(pcopnew)->rIdx = PCOR(pcop)->rIdx;
1697 fprintf(stderr," register index %d\n", PCOR(pcop)->r->rIdx);
1701 fprintf(stderr,"pCodeOpCopy PO_DIR\n");
1702 case PO_SFR_REGISTER:
1710 fprintf(stderr,"pCodeOpCopy register type %d\n", pcop->type);
1711 pcopnew = Safe_calloc(1,sizeof(pCodeOp) );
1715 pcopnew->type = pcop->type;
1716 pcopnew->name = Safe_strdup(pcop->name);
1722 /*-----------------------------------------------------------------*/
1723 /* pCodeCopy - copy a pcode */
1724 /*-----------------------------------------------------------------*/
1725 static pCode *pCodeCopy(pCode *pc)
1730 pcnew = newpCode(pc->type,pc->pcop);
1733 /*-----------------------------------------------------------------*/
1734 /*-----------------------------------------------------------------*/
1735 void pCodeDeleteChain(pCode *f,pCode *t)
1741 fprintf(stderr,"delete pCode:\n");
1744 //f->delete(f); this dumps core...
1751 /*-----------------------------------------------------------------*/
1752 /*-----------------------------------------------------------------*/
1753 int pCodePeepMatchRule(pCode *pc)
1755 pCodePeep *peepBlock;
1760 peeprules = (_DLL *)peepSnippets;
1763 peepBlock = ((pCodePeepSnippets*)peeprules)->peep;
1764 if(!peepBlock || !peepBlock->target || !peepBlock->target->pcHead)
1767 pCodePeepClrVars(peepBlock);
1770 pct = peepBlock->target->pcHead;
1772 while(pct && pcin) {
1774 if(! (matched = pCodePeepMatchLine(peepBlock, pcin,pct)))
1777 pcin = findNextInstruction(pcin->next);
1780 fprintf(stderr," matched\n");
1782 fprintf(stderr," end of code\n");
1784 fprintf(stderr," end of rule\n");
1787 if(matched && pcin) {
1789 /* So far we matched the rule up to the point of the conditions .
1790 * In other words, all of the opcodes match. Now we need to see
1791 * if the post conditions are satisfied.
1792 * First we check the 'postFalseCond'. This means that we check
1793 * to see if any of the subsequent pCode's in the pCode chain
1794 * following the point just past where we have matched depend on
1795 * the `postFalseCond' as input then we abort the match
1797 fprintf(stderr," matched rule so far, now checking conditions\n");
1798 if (peepBlock->postFalseCond &&
1799 (pCodeSearchCondition(pcin,peepBlock->postFalseCond) > 0) )
1803 if(matched && pcin) {
1809 /* We matched a rule! Now we have to go through and remove the
1810 inefficient code with the optimized version */
1812 fprintf(stderr, "Found a pcode peep match:\nRule:\n");
1813 printpCodeString(stderr,peepBlock->target->pcHead,10);
1814 fprintf(stderr,"first thing matched\n");
1815 pc->print(stderr,pc);
1816 fprintf(stderr,"last thing matched\n");
1817 pcin->print(stderr,pcin);
1819 /* Unlink the original code */
1821 pcprev->next = pcin;
1822 pcin->prev = pc->prev;
1826 /* Converted the deleted pCodes into comments */
1833 while(pc && pc!=pcin) {
1834 pCode2str(&buf[2], 254, pc);
1835 pCodeInsertAfter(pcprev, newpCodeCharP(buf));
1836 pcprev = pcprev->next;
1841 pCodeDeleteChain(pc,pcin);
1843 /* Generate the replacement code */
1845 pcr = peepBlock->replace->pcHead; // This is the replacement code
1848 /* If the replace pcode is an instruction with an operand, */
1849 /* then duplicate the operand (and expand wild cards in the process). */
1850 if(pcr->type == PC_OPCODE) {
1851 if(PCI(pcr)->pcop) {
1852 /* The replacing instruction has an operand.
1854 if(PCI(pcr)->pcop->type == PO_WILD) {
1855 int index = PCOW(PCI(pcr)->pcop)->id;
1856 fprintf(stderr,"copying wildopcode\n");
1857 if(peepBlock->wildpCodeOps[index])
1858 pcop = pCodeOpCopy(peepBlock->wildpCodeOps[index]);
1860 fprintf(stderr,"error, wildopcode in replace but not source?\n");
1862 pcop = pCodeOpCopy(PCI(pcr)->pcop);
1864 fprintf(stderr,"inserting pCode\n");
1865 pCodeInsertAfter(pc, newpCode(PCI(pcr)->op,pcop));
1866 } else if (pcr->type == PC_WILD) {
1867 pCodeInsertAfter(pc,peepBlock->wildpCodes[PCW(pcr)->id]);
1868 } else if (pcr->type == PC_COMMENT) {
1869 pCodeInsertAfter(pc, newpCodeCharP( ((pCodeComment *)(pcr))->comment));
1874 pc->print(stderr,pc);
1881 peeprules = peeprules->next;
1897 /*******************/
1898 pCode *parseLineNode(char *ln)
1900 char buffer[50], *s;
1901 int state=0; //0 label, 1 mnemonic, 2 operand, 3 operand, 4 comment
1904 // pCodeLabel *pcl = NULL;
1914 /* skip white space */
1915 while (isspace (*ln))
1920 case 0: // look for a label
1921 case 1: // look for mnemonic
1932 var = strtol(ln, &ln, 10);
1934 // valid wild card label
1935 fprintf(stderr, " wildcard label: %d\n",var);
1938 fprintf(stderr, " wild opcode: %d\n",var), state++;
1942 // Extract the label/mnemonic from the line
1945 while(*ln && !(isspace(*ln) || *ln == ':'))
1950 fprintf(stderr," regular label: %s\n",buffer), ln++;
1952 fprintf(stderr," regular mnem: %s\n",buffer), state++;