1 /*-------------------------------------------------------------------------
3 pcode.h - 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 -------------------------------------------------------------------------*/
23 #include "common.h" // Include everything in the SDCC src directory
29 // Eventually this will go into device dependent files:
30 pCodeOp pc_status = {PO_STATUS, "STATUS"};
31 pCodeOp pc_indf = {PO_INDF, "INDF"};
32 pCodeOp pc_fsr = {PO_FSR, "FSR"};
34 //static char *PIC_mnemonics[] = {
35 static char *scpADDLW = "ADDLW";
36 static char *scpADDWF = "ADDWF";
37 static char *scpANDLW = "ANDLW";
38 static char *scpANDWF = "ANDWF";
39 static char *scpBCF = "BCF";
40 static char *scpBSF = "BSF";
41 static char *scpBTFSC = "BTFSC";
42 static char *scpBTFSS = "BTFSS";
43 static char *scpCALL = "CALL";
44 static char *scpCOMF = "COMF";
45 static char *scpCLRF = "CLRF";
46 static char *scpCLRW = "CLRW";
47 static char *scpDECF = "DECF";
48 static char *scpDECFSZ = "DECFSZ";
49 static char *scpGOTO = "GOTO";
50 static char *scpINCF = "INCF";
51 static char *scpINCFSZ = "INCFSZ";
52 static char *scpIORLW = "IORLW";
53 static char *scpIORWF = "IORWF";
54 static char *scpMOVF = "MOVF";
55 static char *scpMOVLW = "MOVLW";
56 static char *scpMOVWF = "MOVWF";
57 static char *scpNEGF = "NEGF";
58 static char *scpRETLW = "RETLW";
59 static char *scpRETURN = "RETURN";
60 static char *scpSUBLW = "SUBLW";
61 static char *scpSUBWF = "SUBWF";
62 static char *scpTRIS = "TRIS";
63 static char *scpXORLW = "XORLW";
64 static char *scpXORWF = "XORWF";
67 static pFile *the_pFile = NULL;
68 static int peepOptimizing = 0;
69 static int GpCodeSequenceNumber = 1;
71 /****************************************************************/
72 /****************************************************************/
80 typedef struct pCodePeepSnippets
87 static pCodePeepSnippets *peepSnippets=NULL;
89 /****************************************************************/
90 /* Forward declarations */
91 /****************************************************************/
93 static void unlink(pCode *pc);
94 static void genericAnalyze(pCode *pc);
95 static void AnalyzeGOTO(pCode *pc);
96 static void AnalyzeSKIP(pCode *pc);
97 static void AnalyzeRETURN(pCode *pc);
99 static void genericDestruct(pCode *pc);
100 static void genericPrint(FILE *of,pCode *pc);
102 static void pCodePrintLabel(FILE *of, pCode *pc);
103 static void pCodePrintFunction(FILE *of, pCode *pc);
104 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
105 static char *get_op( pCodeInstruction *pcc);
106 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
107 int pCodePeepMatchRule(pCode *pc);
110 char *Safe_strdup(char *str)
119 fprintf(stderr, "out of memory %s,%d\n",__FUNCTION__,__LINE__);
127 char getpBlock_dbName(pBlock *pb)
133 return pb->cmemmap->dbName;
137 /*-----------------------------------------------------------------*/
138 /* movepBlock2Head - given the dbname of a pBlock, move all */
139 /* instances to the front of the doubly linked */
140 /* list of pBlocks */
141 /*-----------------------------------------------------------------*/
143 void movepBlock2Head(char dbName)
147 pb = the_pFile->pbHead;
151 if(getpBlock_dbName(pb) == dbName) {
152 pBlock *pbn = pb->next;
153 pb->next = the_pFile->pbHead;
154 the_pFile->pbHead->prev = pb;
155 the_pFile->pbHead = pb;
158 pb->prev->next = pbn;
160 // If the pBlock that we just moved was the last
161 // one in the link of all of the pBlocks, then we
162 // need to point the tail to the block just before
164 // Note: if pb->next is NULL, then pb must have
165 // been the last pBlock in the chain.
168 pbn->prev = pb->prev;
170 the_pFile->pbTail = pb->prev;
181 void copypCode(FILE *of, char dbName)
185 if(!of || !the_pFile)
188 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
189 if(getpBlock_dbName(pb) == dbName)
194 void pcode_test(void)
197 printf("pcode is alive!\n");
205 /* create the file name */
206 strcpy(buffer,srcFileName);
209 if( !(pFile = fopen(buffer, "w" ))) {
210 werror(E_FILE_OPEN_ERR,buffer);
214 fprintf(pFile,"pcode dump\n\n");
216 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
217 fprintf(pFile,"\n\tNew pBlock\n\n");
219 fprintf(pFile,"%s",pb->cmemmap->sname);
221 fprintf(pFile,"internal pblock");
223 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
224 printpBlock(pFile,pb);
229 /*-----------------------------------------------------------------*/
230 /* newpCode - create and return a newly initialized pCode */
232 /* fixme - rename this */
234 /* The purpose of this routine is to create a new Instruction */
235 /* pCode. This is called by gen.c while the assembly code is being */
239 /* PIC_OPCODE op - the assembly instruction we wish to create. */
240 /* (note that the op is analogous to but not the */
241 /* same thing as the opcode of the instruction.) */
242 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
245 /* a pointer to the new malloc'd pCode is returned. */
249 /*-----------------------------------------------------------------*/
250 pCode *newpCode (PIC_OPCODE op, pCodeOp *pcop)
252 pCodeInstruction *pci ;
255 pci = Safe_calloc(1, sizeof(pCodeInstruction));
257 pci->pc.analyze = genericAnalyze; // pointers to the generic functions, it
258 pci->pc.destruct = genericDestruct; // doesn't hurt to think about C++ virtual
259 pci->pc.print = genericPrint; // functions here.
260 pci->pc.type = PC_OPCODE; //
261 pci->op = op; // the "opcode" for the instruction.
262 pci->pc.prev = pci->pc.next = NULL; // The pCode gets linked in later
263 pci->pcop = pcop; // The operand of the instruction
264 pci->dest = 0; // e.g. W or F
265 pci->bit_inst = 0; // e.g. btfxx instructions
266 pci->num_ops = 2; // Most instructions have two ops...
267 pci->inCond = pci->outCond = PCC_NONE; /* input/output conditions. This is used during
268 * optimization to ascertain instruction dependencies.
269 * For example, if an instruction affects the Z bit,
270 * then the output condition for this instruction
271 * is "z bit is affected". The "conditions" are bit
272 * constants defined in pcode.h. */
273 pci->pc.from = pci->pc.to = NULL; // Flow linkages are defined later
274 pci->pc.label = NULL; // Labels get merged into instructions here.
275 pci->pc.pb = NULL; // The pBlock to which this instruction belongs
277 if(pcop && pcop->name)
278 printf("newpCode operand name %s\n",pcop->name);
280 // The most pic dependent portion of the pCode logic:
285 pci->outCond = PCC_W | PCC_Z;
286 pci->mnemonic = scpANDLW;
291 pci->inCond = PCC_W | PCC_REGISTER;
292 pci->outCond = PCC_REGISTER | PCC_Z;
293 pci->mnemonic = scpANDWF;
296 pci->inCond = PCC_W | PCC_REGISTER;
297 pci->outCond = PCC_W | PCC_Z;
298 pci->mnemonic = scpANDWF;
303 pci->outCond = PCC_W | PCC_Z | PCC_C | PCC_DC;
304 pci->mnemonic = scpADDLW;
309 pci->inCond = PCC_W | PCC_REGISTER;
310 pci->outCond = PCC_REGISTER | PCC_Z | PCC_C | PCC_DC;
311 pci->mnemonic = scpADDWF;
314 pci->inCond = PCC_W | PCC_REGISTER;
315 pci->outCond = PCC_W | PCC_Z | PCC_C | PCC_DC;
316 pci->mnemonic = scpADDWF;
321 pci->mnemonic = scpBCF;
325 pci->mnemonic = scpBSF;
329 pci->mnemonic = scpBTFSC;
330 pci->pc.analyze = AnalyzeSKIP;
334 pci->mnemonic = scpBTFSS;
335 pci->pc.analyze = AnalyzeSKIP;
339 pci->mnemonic = scpCALL;
342 pci->mnemonic = scpCOMF;
346 pci->mnemonic = scpCLRF;
350 pci->mnemonic = scpCLRW;
355 pci->mnemonic = scpDECF;
360 pci->mnemonic = scpDECFSZ;
361 pci->pc.analyze = AnalyzeSKIP;
365 pci->mnemonic = scpGOTO;
366 pci->pc.analyze = AnalyzeGOTO;
371 pci->mnemonic = scpINCF;
376 pci->mnemonic = scpINCFSZ;
377 pci->pc.analyze = AnalyzeSKIP;
381 pci->mnemonic = scpIORLW;
386 pci->mnemonic = scpIORWF;
391 pci->mnemonic = scpMOVF;
395 pci->mnemonic = scpMOVLW;
399 pci->mnemonic = scpMOVWF;
402 pci->mnemonic = scpNEGF;
406 pci->mnemonic = scpRETLW;
407 pci->pc.analyze = AnalyzeRETURN;
411 pci->mnemonic = scpRETURN;
412 pci->pc.analyze = AnalyzeRETURN;
415 pci->mnemonic = scpSUBLW;
421 pci->mnemonic = scpSUBWF;
424 pci->mnemonic = scpTRIS;
428 pci->mnemonic = scpXORLW;
433 pci->mnemonic = scpXORWF;
437 pci->pc.print = genericPrint;
443 /*-----------------------------------------------------------------*/
444 /* newpCodeWild - create a "wild" as in wild card pCode */
446 /* Wild pcodes are used during the peep hole optimizer to serve */
447 /* as place holders for any instruction. When a snippet of code is */
448 /* compared to a peep hole rule, the wild card opcode will match */
449 /* any instruction. However, the optional operand and label are */
450 /* additional qualifiers that must also be matched before the */
451 /* line (of assembly code) is declared matched. Note that the */
452 /* operand may be wild too. */
454 /*-----------------------------------------------------------------*/
456 pCode *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
461 pcw = Safe_calloc(1,sizeof(pCodeWild));
463 pcw->pc.type = PC_WILD;
464 pcw->pc.prev = pcw->pc.next = NULL;
465 pcw->pc.from = pcw->pc.to = pcw->pc.label = NULL;
468 pcw->pc.analyze = genericAnalyze;
469 pcw->pc.destruct = genericDestruct;
470 pcw->pc.print = genericPrint;
473 pcw->operand = optional_operand;
474 pcw->label = optional_label;
476 return ( (pCode *)pcw);
480 /*-----------------------------------------------------------------*/
481 /* newPcodeCharP - create a new pCode from a char string */
482 /*-----------------------------------------------------------------*/
484 pCode *newpCodeCharP(char *cP)
489 pcc = Safe_calloc(1,sizeof(pCodeComment));
491 pcc->pc.type = PC_COMMENT;
492 pcc->pc.prev = pcc->pc.next = NULL;
493 pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
496 pcc->pc.analyze = genericAnalyze;
497 pcc->pc.destruct = genericDestruct;
498 pcc->pc.print = genericPrint;
500 pcc->comment = Safe_strdup(cP);
502 return ( (pCode *)pcc);
506 /*-----------------------------------------------------------------*/
507 /* newpCodeGLabel - create a new global label */
508 /*-----------------------------------------------------------------*/
511 pCode *newpCodeFunction(char *mod,char *f)
515 _ALLOC(pcf,sizeof(pCodeFunction));
517 pcf->pc.type = PC_FUNCTION;
518 pcf->pc.prev = pcf->pc.next = NULL;
519 pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
522 pcf->pc.analyze = genericAnalyze;
523 pcf->pc.destruct = genericDestruct;
524 pcf->pc.print = pCodePrintFunction;
527 _ALLOC_ATOMIC(pcf->modname,strlen(mod)+1);
528 strcpy(pcf->modname,mod);
533 _ALLOC_ATOMIC(pcf->fname,strlen(f)+1);
534 strcpy(pcf->fname,f);
538 return ( (pCode *)pcf);
543 pCode *newpCodeLabel(int key)
549 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
551 pcl->pc.type = PC_LABEL;
552 pcl->pc.prev = pcl->pc.next = NULL;
553 pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
556 pcl->pc.analyze = genericAnalyze;
557 pcl->pc.destruct = genericDestruct;
558 pcl->pc.print = pCodePrintLabel;
563 sprintf(s,"_%05d_DS_",key);
564 pcl->label = Safe_strdup(s);
568 return ( (pCode *)pcl);
571 pCode *newpCodeLabelStr(char *str)
573 pCode *pc = newpCodeLabel(-1);
575 PCL(pc)->label = Safe_strdup(str);
580 /*-----------------------------------------------------------------*/
581 /* newpBlock - create and return a pointer to a new pBlock */
582 /*-----------------------------------------------------------------*/
583 pBlock *newpBlock(void)
588 _ALLOC(PpB,sizeof(pBlock));
589 PpB->next = PpB->prev = NULL;
591 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
592 PpB->registers = NULL;
599 /*-----------------------------------------------------------------*/
600 /* newpCodeChain - create a new chain of pCodes */
601 /*-----------------------------------------------------------------*
603 * This function will create a new pBlock and the pointer to the
604 * pCode that is passed in will be the first pCode in the block.
605 *-----------------------------------------------------------------*/
608 pBlock *newpCodeChain(memmap *cm,char c, pCode *pc)
611 pBlock *pB = newpBlock();
613 pB->pcHead = pB->pcTail = pc;
620 /*-----------------------------------------------------------------*/
621 /*-----------------------------------------------------------------*/
623 pCodeOp *newpCodeOp(char *name, PIC_OPTYPE type)
627 pcop = Safe_calloc(1,sizeof(pCodeOp) );
629 pcop->name = Safe_strdup(name);
634 /*-----------------------------------------------------------------*/
635 /* newpCodeOpLabel - Create a new label given the key */
636 /* Note, a negative key means that the label is part of wild card */
637 /* (and hence a wild card label) used in the pCodePeep */
638 /* optimizations). */
639 /*-----------------------------------------------------------------*/
641 pCodeOp *newpCodeOpLabel(int key)
646 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
647 pcop->type = PO_LABEL;
650 sprintf(s,"_%05d_DS_",key);
651 pcop->name = Safe_strdup(s);
655 ((pCodeOpLabel *)pcop)->key = key;
660 pCodeOp *newpCodeOpLit(int lit)
666 _ALLOC(pcop,sizeof(pCodeOpLit) );
667 pcop->type = PO_LITERAL;
668 sprintf(s,"0x%02x",lit);
669 _ALLOC_ATOMIC(pcop->name,strlen(s)+1);
670 strcpy(pcop->name,s);
671 ((pCodeOpLit *)pcop)->lit = lit;
676 pCodeOp *newpCodeOpWild(int id, pCodePeep *pcp, pCodeOp *subtype)
682 if(!pcp || !subtype) {
683 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
687 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
688 pcop->type = PO_WILD;
689 sprintf(s,"%%%d",id);
690 pcop->name = Safe_strdup(s);
693 PCOW(pcop)->pcp = pcp;
694 PCOW(pcop)->subtype = subtype;
695 PCOW(pcop)->matched = NULL;
700 pCodeOp *newpCodeOpBit(char *s, int bit)
704 _ALLOC(pcop,sizeof(pCodeOpBit) );
706 pcop->name = Safe_strdup(s);
707 PCOB(pcop)->bit = bit;
709 PCOB(pcop)->inBitSpace = 1;
711 PCOB(pcop)->inBitSpace = 0;
716 /*-----------------------------------------------------------------*/
717 /* addpCode2pBlock - place the pCode into the pBlock linked list */
718 /*-----------------------------------------------------------------*/
719 void addpCode2pBlock(pBlock *pb, pCode *pc)
722 pb->pcTail->next = pc;
723 pc->prev = pb->pcTail;
729 /*-----------------------------------------------------------------*/
730 /* addpBlock - place a pBlock into the pFile */
731 /*-----------------------------------------------------------------*/
732 void addpBlock(pBlock *pb)
736 /* First time called, we'll pass through here. */
737 _ALLOC(the_pFile,sizeof(the_pFile));
738 the_pFile->pbHead = the_pFile->pbTail = pb;
739 the_pFile->functions = NULL;
743 the_pFile->pbTail->next = pb;
744 pb->prev = the_pFile->pbTail;
746 the_pFile->pbTail = pb;
749 void printpCodeString(FILE *of, pCode *pc, int max)
753 while(pc && (i++<max)) {
758 /*-----------------------------------------------------------------*/
759 /* printpCode - write the contents of a pCode to a file */
760 /*-----------------------------------------------------------------*/
761 void printpCode(FILE *of, pCode *pc)
772 fprintf(of,"warning - unable to print pCode\n");
775 /*-----------------------------------------------------------------*/
776 /* printpBlock - write the contents of a pBlock to a file */
777 /*-----------------------------------------------------------------*/
778 void printpBlock(FILE *of, pBlock *pb)
788 for(pc = pb->pcHead; pc; pc = pc->next)
793 /*-----------------------------------------------------------------*/
795 /* pCode processing */
799 /*-----------------------------------------------------------------*/
801 static void unlink(pCode *pc)
803 if(pc && pc->prev && pc->next) {
805 pc->prev->next = pc->next;
806 pc->next->prev = pc->prev;
809 static void genericDestruct(pCode *pc)
813 fprintf(stderr,"warning, calling default pCode destructor\n");
818 void pBlockRegs(FILE *of, pBlock *pb)
823 r = setFirstItem(pb->registers);
825 fprintf(of," %s\n",r->name);
826 r = setNextItem(pb->registers);
831 static char *get_op( pCodeInstruction *pcc)
833 if(pcc && pcc->pcop) {
837 if(pcc->pcop->type == PO_GPR_TEMP) {
839 r = pic14_regWithIdx(PCOR(pcc->pcop)->r->rIdx);
840 //pcc->pcop->name = Safe_strdup(r->name);
841 //sprintf(buffer, "R0X%x",PCOR(pcc->pcop)->rIdx);
842 //pcc->pcop->name = Safe_strdup(PCOR(pcc->pcop)->r->name);
843 fprintf(stderr,"getop: getting %s\nfrom:\n",r->name); //pcc->pcop->name);
844 pBlockRegs(stderr,pcc->pc.pb);
849 return pcc->pcop->name;
855 /*-----------------------------------------------------------------*/
856 /*-----------------------------------------------------------------*/
857 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
860 fprintf(of,"pcodeopprint\n");
863 /*-----------------------------------------------------------------*/
864 /* genericPrint - the contents of a pCode to a file */
865 /*-----------------------------------------------------------------*/
866 static void genericPrint(FILE *of, pCode *pc)
874 fprintf(of,";%s\n", ((pCodeComment *)pc)->comment);
878 // If the opcode has a label, print that first
880 pBranch *pbl = pc->label;
882 if(pbl->pc->type == PC_LABEL)
883 pCodePrintLabel(of, pbl->pc);
888 fprintf(of, "\t%s\t", PCI(pc)->mnemonic);
889 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
891 if(PCI(pc)->bit_inst) {
892 if(PCI(pc)->pcop->type == PO_BIT) {
893 if( (((pCodeOpBit *)(PCI(pc)->pcop))->inBitSpace) )
894 fprintf(of,"(%s >> 3), (%s & 7)",
895 PCI(pc)->pcop->name ,
896 PCI(pc)->pcop->name );
898 fprintf(of,"%s,%d", get_op(PCI(pc)), (((pCodeOpBit *)(PCI(pc)->pcop))->bit ));
900 fprintf(of,"%s,0 ; ?bug", get_op(PCI(pc)));
901 //PCI(pc)->pcop->t.bit );
904 if(PCI(pc)->pcop->type == PO_BIT) {
905 if( PCI(pc)->num_ops == 2)
906 fprintf(of,"(%s >> 3),%c",get_op(PCI(pc)),((PCI(pc)->dest) ? 'F':'W'));
908 fprintf(of,"(1 << (%s & 7))",get_op(PCI(pc)));
911 if( PCI(pc)->num_ops == 2)
912 fprintf(of,"(%s >> 3),%c",PCI(pc)->pcop->name,((PCI(pc)->dest) ? 'F':'W'));
914 fprintf(of,"(1 << (%s & 7))",PCI(pc)->pcop->name);
917 fprintf(of,"%s",get_op(PCI(pc)));
919 if( PCI(pc)->num_ops == 2)
920 fprintf(of,",%c", ( (PCI(pc)->dest) ? 'F':'W'));
926 pBranch *dpb = pc->to; // debug
928 switch ( dpb->pc->type) {
930 fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic);
933 fprintf(of, "\t;label %d", PCL(dpb->pc)->key);
936 fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]"));
950 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
951 if(PCW(pc)->operand) {
952 fprintf(of,";\toperand ");
953 pCodeOpPrint(of,PCW(pc)->operand );
959 fprintf(of,"unknown pCode type %d\n",pc->type);
964 /*-----------------------------------------------------------------*/
965 /* pCodePrintFunction - prints function begin/end */
966 /*-----------------------------------------------------------------*/
968 static void pCodePrintFunction(FILE *of, pCode *pc)
974 if( ((pCodeFunction *)pc)->modname)
975 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
978 pBranch *exits = pc->to;
980 fprintf(of,"%s\t;Function start\n",PCF(pc)->fname);
986 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
990 pc->from->pc->type == PC_FUNCTION &&
991 PCF(pc->from->pc)->fname)
992 fprintf(of,"; exit point of %s\n",PCF(pc->from->pc)->fname);
994 fprintf(of,"; exit point [can't find entry point]\n");
997 /*-----------------------------------------------------------------*/
998 /* pCodePrintLabel - prints label */
999 /*-----------------------------------------------------------------*/
1001 static void pCodePrintLabel(FILE *of, pCode *pc)
1008 fprintf(of,"%s\n",PCL(pc)->label);
1009 else if (PCL(pc)->key >=0)
1010 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
1012 fprintf(of,";wild card label\n");
1016 /*-----------------------------------------------------------------*/
1017 /* _DLL * DLL_append */
1019 /* Append a _DLL object to the end of a _DLL (doubly linked list) */
1020 /* If The list to which we want to append is non-existant then one */
1021 /* is created. Other wise, the end of the list is sought out and */
1022 /* a new DLL object is appended to it. In either case, the void */
1023 /* *data is added to the newly created DLL object. */
1024 /*-----------------------------------------------------------------*/
1026 static void * DLL_append(_DLL *list, _DLL *next)
1031 /* If there's no list, then create one: */
1033 next->next = next->prev = NULL;
1038 /* Search for the end of the list. */
1043 /* Now append the new DLL object */
1052 /*-----------------------------------------------------------------*/
1054 static pBranch * pBranchAppend(pBranch *h, pBranch *n)
1070 /*-----------------------------------------------------------------*/
1071 /* pBranchLink - given two pcodes, this function will link them */
1072 /* together through their pBranches */
1073 /*-----------------------------------------------------------------*/
1074 static void pBranchLink(pCode *f, pCode *t)
1078 // Declare a new branch object for the 'from' pCode.
1080 _ALLOC(b,sizeof(pBranch));
1081 b->pc = t; // The link to the 'to' pCode.
1084 f->to = pBranchAppend(f->to,b);
1086 // Now do the same for the 'to' pCode.
1088 _ALLOC(b,sizeof(pBranch));
1092 t->from = pBranchAppend(t->from,b);
1097 /*-----------------------------------------------------------------*/
1098 /* pBranchFind - find the pBranch in a pBranch chain that contains */
1100 /*-----------------------------------------------------------------*/
1101 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
1114 /*-----------------------------------------------------------------*/
1115 /* pCodeUnlink - Unlink the given pCode from its pCode chain. */
1116 /*-----------------------------------------------------------------*/
1117 static void pCodeUnlink(pCode *pc)
1122 if(!pc->prev || !pc->next) {
1123 fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
1127 /* first remove the pCode from the chain */
1128 pc->prev->next = pc->next;
1129 pc->next->prev = pc->prev;
1131 /* Now for the hard part... */
1133 /* Remove the branches */
1137 pc1 = pb1->pc; /* Get the pCode that branches to the
1138 * one we're unlinking */
1140 /* search for the link back to this pCode (the one we're
1142 if(pb2 = pBranchFind(pc1->to,pc)) {
1143 pb2->pc = pc->to->pc; // make the replacement
1145 /* if the pCode we're unlinking contains multiple 'to'
1146 * branches (e.g. this a skip instruction) then we need
1147 * to copy these extra branches to the chain. */
1149 pBranchAppend(pb2, pc->to->next);
1158 /*-----------------------------------------------------------------*/
1159 /*-----------------------------------------------------------------*/
1160 static void genericAnalyze(pCode *pc)
1170 // Go through the pCodes that are in pCode chain and link
1171 // them together through the pBranches. Note, the pCodes
1172 // are linked together as a contiguous stream like the
1173 // assembly source code lines. The linking here mimics this
1174 // except that comments are not linked in.
1176 pCode *npc = pc->next;
1178 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
1179 pBranchLink(pc,npc);
1188 /*-----------------------------------------------------------------*/
1189 /* findLabel - Search the pCode for a particular label */
1190 /*-----------------------------------------------------------------*/
1191 pCode * findLabel(pCodeOpLabel *pcop_label)
1200 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1201 for(pc = pb->pcHead; pc; pc = pc->next) {
1202 if(pc->type == PC_LABEL) {
1203 if( ((pCodeLabel *)pc)->key == pcop_label->key)
1206 if(pc->type == PC_OPCODE) {
1209 if(pbr->pc->type == PC_LABEL) {
1210 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
1220 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
1224 /*-----------------------------------------------------------------*/
1225 /* findNextInstruction - given a pCode, find the next instruction */
1226 /* in the linked list */
1227 /*-----------------------------------------------------------------*/
1228 pCode * findNextInstruction(pCode *pc)
1232 if(pc->type == PC_OPCODE)
1238 fprintf(stderr,"Couldn't find instruction\n");
1242 /*-----------------------------------------------------------------*/
1243 /* findFunctionEnd - given a pCode find the end of the function */
1244 /* that contains it t */
1245 /*-----------------------------------------------------------------*/
1246 pCode * findFunctionEnd(pCode *pc)
1250 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
1256 fprintf(stderr,"Couldn't find function end\n");
1261 /*-----------------------------------------------------------------*/
1262 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
1263 /* instruction with which it is associated. */
1264 /*-----------------------------------------------------------------*/
1265 static void AnalyzeLabel(pCode *pc)
1273 static void AnalyzeGOTO(pCode *pc)
1276 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
1280 static void AnalyzeSKIP(pCode *pc)
1283 pBranchLink(pc,findNextInstruction(pc->next));
1284 pBranchLink(pc,findNextInstruction(pc->next->next));
1288 static void AnalyzeRETURN(pCode *pc)
1291 // branch_link(pc,findFunctionEnd(pc->next));
1296 void AnalyzepBlock(pBlock *pb)
1303 /* Find all of the registers used in this pBlock */
1304 for(pc = pb->pcHead; pc; pc = pc->next) {
1305 if(pc->type == PC_OPCODE) {
1306 if(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_TEMP) {
1308 /* Loop through all of the registers declared so far in
1309 this block and see if we find this new there */
1311 regs *r = setFirstItem(pb->registers);
1314 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
1315 PCOR(PCI(pc)->pcop)->r = r;
1318 r = setNextItem(pb->registers);
1322 /* register wasn't found */
1323 r = Safe_calloc(1, sizeof(regs));
1324 memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
1325 addSet(&pb->registers, r);
1326 PCOR(PCI(pc)->pcop)->r = r;
1327 fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
1329 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
1335 int OptimizepBlock(pBlock *pb)
1340 if(!pb || !peepOptimizing)
1343 fprintf(stderr," Optimizing pBlock\n");
1345 for(pc = pb->pcHead; pc; pc = pc->next)
1346 matches += pCodePeepMatchRule(pc);
1351 /*-----------------------------------------------------------------*/
1352 /* pBlockMergeLabels - remove the pCode labels from the pCode */
1353 /* chain and put them into pBranches that are */
1354 /* associated with the appropriate pCode */
1356 /*-----------------------------------------------------------------*/
1357 void pBlockMergeLabels(pBlock *pb)
1360 pCode *pc, *pcnext=NULL;
1365 for(pc = pb->pcHead; pc; pc = pc->next) {
1367 if(pc->type == PC_LABEL) {
1368 if( !(pcnext = findNextInstruction(pc)) )
1369 return; // Couldn't find an instruction associated with this label
1371 // Unlink the pCode label from it's pCode chain
1373 pc->prev->next = pc->next;
1375 pc->next->prev = pc->prev;
1377 // And link it into the instruction's pBranch labels. (Note, since
1378 // it's possible to have multiple labels associated with one instruction
1379 // we must provide a means to accomodate the additional labels. Thus
1380 // the labels are placed into the singly-linked list "label" as
1381 // opposed to being a single member of the pCodeInstruction.)
1383 _ALLOC(pbr,sizeof(pBranch));
1387 pcnext->label = pBranchAppend(pcnext->label,pbr);
1394 /*-----------------------------------------------------------------*/
1395 /*-----------------------------------------------------------------*/
1396 void OptimizepCode(char dbName)
1398 #define MAX_PASSES 4
1407 fprintf(stderr," Optimizing pCode\n");
1410 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1411 if('*' == dbName || getpBlock_dbName(pb) == dbName)
1412 matches += OptimizepBlock(pb);
1415 while(matches && ++passes < MAX_PASSES);
1419 /*-----------------------------------------------------------------*/
1420 /* AnalyzepCode - parse the pCode that has been generated and form */
1421 /* all of the logical connections. */
1423 /* Essentially what's done here is that the pCode flow is */
1425 /*-----------------------------------------------------------------*/
1427 void AnalyzepCode(char dbName)
1436 fprintf(stderr," Analyzing pCode");
1438 /* First, merge the labels with the instructions */
1439 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1440 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
1441 pBlockMergeLabels(pb);
1446 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1447 if('*' == dbName || getpBlock_dbName(pb) == dbName)
1451 /* Now build the call tree.
1452 First we examine all of the pCodes for functions.
1453 Keep in mind that the function boundaries coincide
1454 with pBlock boundaries.
1456 The algorithm goes something like this:
1457 We have two nested loops. The outer loop iterates
1458 through all of the pBlocks/functions. The inner
1459 loop iterates through all of the pCodes for
1460 a given pBlock. When we begin iterating through
1461 a pBlock, the variable pc_fstart, pCode of the start
1462 of a function, is cleared. We then search for pCodes
1463 of type PC_FUNCTION. When one is encountered, we
1464 initialize pc_fstart to this and at the same time
1465 associate a new pBranch object that signifies a
1466 branch entry. If a return is found, then this signifies
1467 a function exit point. We'll link the pCodes of these
1468 returns to the matching pc_fstart.
1470 When we're done, a doubly linked list of pBranches
1471 will exist. The head of this list is stored in
1472 `the_pFile', which is the meta structure for all
1473 of the pCode. Look at the printCallTree function
1474 on how the pBranches are linked together.
1477 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1478 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
1479 pCode *pc_fstart=NULL;
1480 for(pc = pb->pcHead; pc; pc = pc->next) {
1481 if(pc->type == PC_FUNCTION) {
1482 if (PCF(pc)->fname) {
1483 // I'm not liking this....
1484 // Found the beginning of a function.
1485 _ALLOC(pbr,sizeof(pBranch));
1486 pbr->pc = pc_fstart = pc;
1489 the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
1491 // Here's a better way of doing the same:
1492 addSet(&pb->function_entries, pc);
1495 // Found an exit point in a function, e.g. return
1496 // (Note, there may be more than one return per function)
1498 pBranchLink(pc_fstart, pc);
1500 addSet(&pb->function_exits, pc);
1502 } else if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
1503 addSet(&pb->function_calls,pc);
1510 /*-----------------------------------------------------------------*/
1511 /* ispCodeFunction - returns true if *pc is the pCode of a */
1513 /*-----------------------------------------------------------------*/
1514 bool ispCodeFunction(pCode *pc)
1517 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
1523 /*-----------------------------------------------------------------*/
1524 /* findFunction - Search for a function by name (given the name) */
1525 /* in the set of all functions that are in a pBlock */
1526 /* (note - I expect this to change because I'm planning to limit */
1527 /* pBlock's to just one function declaration */
1528 /*-----------------------------------------------------------------*/
1529 pCode *findFunction(char *fname)
1536 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1538 pc = setFirstItem(pb->function_entries);
1541 if((pc->type == PC_FUNCTION) &&
1543 (strcmp(fname, PCF(pc)->fname)==0))
1546 pc = setNextItem(pb->function_entries);
1554 void MarkUsedRegisters(set *regset)
1559 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
1560 r2 = pic14_regWithIdx(r1->rIdx);
1566 void pBlockStats(FILE *of, pBlock *pb)
1572 fprintf(of,"***\n pBlock Stats\n***\n");
1574 // for now just print the first element of each set
1575 pc = setFirstItem(pb->function_entries);
1577 fprintf(of,"entry\n");
1580 pc = setFirstItem(pb->function_exits);
1582 fprintf(of,"has an exit\n");
1586 pc = setFirstItem(pb->function_calls);
1588 fprintf(of,"functions called\n");
1592 pc = setNextItem(pb->function_calls);
1596 r = setFirstItem(pb->registers);
1598 int n = elementsInSet(pb->registers);
1600 fprintf(of,"%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
1603 fprintf(of," %s\n",r->name);
1604 r = setNextItem(pb->registers);
1609 /*-----------------------------------------------------------------*/
1610 /*-----------------------------------------------------------------*/
1611 void sequencepCode(void)
1617 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1619 pb->seq = GpCodeSequenceNumber+1;
1621 for( pc = pb->pcHead; pc; pc = pc->next)
1622 pc->seq = ++GpCodeSequenceNumber;
1627 /*-----------------------------------------------------------------*/
1628 /*-----------------------------------------------------------------*/
1629 set *register_usage(pBlock *pb)
1632 set *registers=NULL;
1633 set *registersInCallPath = NULL;
1635 /* check recursion */
1637 pc = setFirstItem(pb->function_entries);
1644 if(pc->type != PC_FUNCTION)
1645 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
1647 pc = setFirstItem(pb->function_calls);
1648 for( ; pc; pc = setNextItem(pb->function_calls)) {
1650 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
1651 char *dest = get_op(PCI(pc));
1653 pcn = findFunction(dest);
1655 registersInCallPath = register_usage(pcn->pb);
1657 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
1662 pBlockStats(stderr,pb); // debug
1663 if(registersInCallPath) {
1664 /* registers were used in the functions this pBlock has called */
1665 /* so now, we need to see if these collide with the ones we are */
1668 regs *r1,*r2, *newreg;
1670 fprintf(stderr,"comparing registers\n");
1672 r1 = setFirstItem(registersInCallPath);
1675 r2 = setFirstItem(pb->registers);
1679 if(r2->rIdx == r1->rIdx) {
1680 newreg = pic14_findFreeReg();
1684 fprintf(stderr,"Bummer, no more registers.\n");
1688 fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
1689 r1->rIdx, newreg->rIdx);
1690 r2->rIdx = newreg->rIdx;
1691 //if(r2->name) free(r2->name);
1692 r2->name = Safe_strdup(newreg->name);
1694 newreg->wasUsed = 1;
1696 r2 = setNextItem(pb->registers);
1699 r1 = setNextItem(registersInCallPath);
1702 /* Collisions have been resolved. Now free the registers in the call path */
1703 r1 = setFirstItem(registersInCallPath);
1705 newreg = pic14_regWithIdx(r1->rIdx);
1707 r1 = setNextItem(registersInCallPath);
1711 MarkUsedRegisters(pb->registers);
1713 registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
1716 fprintf(stderr,"returning regs\n");
1718 fprintf(stderr,"not returning regs\n");
1720 fprintf(stderr,"pBlock after register optim.\n");
1721 pBlockStats(stderr,pb); // debug
1727 /*-----------------------------------------------------------------*/
1728 /* printCallTree - writes the call tree to a file */
1730 /*-----------------------------------------------------------------*/
1731 void pct2(FILE *of,pBlock *pb,int indent)
1735 // set *registersInCallPath = NULL;
1738 return;// registers;
1741 return; // registers; //recursion ?
1743 pc = setFirstItem(pb->function_entries);
1750 for(i=0;i<indent;i++) // Indentation
1753 if(pc->type == PC_FUNCTION)
1754 fprintf(of,"%s\n",PCF(pc)->fname);
1759 pc = setFirstItem(pb->function_calls);
1760 for( ; pc; pc = setNextItem(pb->function_calls)) {
1762 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
1763 char *dest = get_op(PCI(pc));
1765 pcn = findFunction(dest);
1767 pct2(of,pcn->pb,indent+1);
1769 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
1777 fprintf(stderr,"pBlock before register optim.\n");
1778 pBlockStats(stderr,pb); // debug
1780 if(registersInCallPath) {
1781 /* registers were used in the functions this pBlock has called */
1782 /* so now, we need to see if these collide with the ones we are using here */
1784 regs *r1,*r2, *newreg;
1786 fprintf(stderr,"comparing registers\n");
1788 r1 = setFirstItem(registersInCallPath);
1791 r2 = setFirstItem(pb->registers);
1795 if(r2->rIdx == r1->rIdx) {
1796 newreg = pic14_findFreeReg();
1800 fprintf(stderr,"Bummer, no more registers.\n");
1804 fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
1805 r1->rIdx, newreg->rIdx);
1806 r2->rIdx = newreg->rIdx;
1807 //if(r2->name) free(r2->name);
1808 r2->name = Safe_strdup(newreg->name);
1810 newreg->wasUsed = 1;
1812 r2 = setNextItem(pb->registers);
1815 r1 = setNextItem(registersInCallPath);
1818 /* Collisions have been resolved. Now free the registers in the call path */
1819 r1 = setFirstItem(registersInCallPath);
1821 newreg = pic14_regWithIdx(r1->rIdx);
1823 r1 = setNextItem(registersInCallPath);
1827 MarkUsedRegisters(pb->registers);
1829 registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
1832 fprintf(stderr,"returning regs\n");
1834 fprintf(stderr,"not returning regs\n");
1836 fprintf(stderr,"pBlock after register optim.\n");
1837 pBlockStats(stderr,pb); // debug
1845 /*-----------------------------------------------------------------*/
1846 /* printCallTree - writes the call tree to a file */
1848 /*-----------------------------------------------------------------*/
1850 void printCallTree(FILE *of)
1862 fprintf(of, "\npBlock statistics\n");
1863 for(pb = the_pFile->pbHead; pb; pb = pb->next )
1864 pBlockStats(stderr,pb);
1868 fprintf(of,"Call Tree\n");
1869 pbr = the_pFile->functions;
1873 if(!ispCodeFunction(pc))
1874 fprintf(of,"bug in call tree");
1877 fprintf(of,"Function: %s\n", PCF(pc)->fname);
1879 while(pc->next && !ispCodeFunction(pc->next)) {
1881 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
1882 fprintf(of,"\t%s\n",get_op(PCI(pc)));
1890 /* Re-allocate the registers so that there are no collisions
1891 * between local variables when one function call another */
1893 pic14_deallocateAllRegs();
1895 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1900 fprintf(of,"\n**************\n\na better call tree\n");
1901 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1906 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1907 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
1910 /*-----------------------------------------------------------------
1912 pCode peephole optimization
1915 The pCode "peep hole" optimization is not too unlike the peep hole
1916 optimization in SDCCpeeph.c. The major difference is that here we
1917 use pCode's whereas there we use ASCII strings. The advantage with
1918 pCode's is that we can ascertain flow information in the instructions
1922 <FIX ME> - elaborate...
1924 -----------------------------------------------------------------*/
1927 /*-----------------------------------------------------------------*/
1929 /*-----------------------------------------------------------------*/
1930 int pCodePeepCompare(pCode *pc, pCodePeep *pcp)
1932 pCode *pcfrom,*pcto;
1935 for( pcto=pcp->target; pcto; pcto=pcto->next) {
1937 pcfrom = findNextInstruction(pcfrom);
1940 (PCI(pcfrom)->op == PCI(pcto)->op ||
1941 PCI(pcto)->op == POC_WILD))
1948 /*-----------------------------------------------------------------*/
1950 /*-----------------------------------------------------------------*/
1951 void pCodePeepSearch(pCodePeep *snippet)
1959 /* compare the chain to the pCode that we've
1960 got so far. If a match is found, then replace
1963 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1964 for(pc = pb->pcHead; pc; pc = pc->next) {
1965 pCodePeepCompare(pc,snippet);
1973 pBlock *pBlockAppend(pBlock *pb1, pBlock *pb2)
1990 void pCodePeepInit(void)
1995 pCodePeepSnippets *pcps;
1997 /* Declare a peep code snippet */
1998 /* <FIXME> do I really need a separate struct just to DLL the snippets? */
1999 /* e.g. I could put the DLL into the pCodePeep structure */
2000 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
2001 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
2002 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
2005 pb = newpCodeChain(NULL, 'W', newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
2006 addpCode2pBlock( pb, newpCode(POC_MOVFW, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
2010 pcp->replace = newpCodeChain(NULL, 'W',newpCode(POC_MOVWF, newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER))) );
2012 /* Allocate space to store pointers to the wildcard variables */
2014 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
2015 pcp->nwildpCodes = 0;
2016 pcp->wildpCodes = NULL;
2018 pcp->postFalseCond = PCC_Z;
2019 pcp->postTrueCond = PCC_NONE;
2021 fprintf(stderr,"Peep rule\nTarget:\n");
2022 printpCodeString(stderr,pcp->target->pcHead, 10);
2023 fprintf(stderr,"Replaced with:\n");
2024 printpCodeString(stderr,pcp->replace->pcHead, 10);
2026 /* Now for another peep example */
2027 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
2028 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
2029 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
2036 pcwb = newpCodeOpWild(0,pcp,newpCodeOpBit(NULL,-1));
2037 pb = newpCodeChain(NULL, 'W',newpCode(POC_BTFSC,pcwb));
2039 pcl = newpCodeOpLabel(-1);
2040 pcw = newpCodeOpWild(1, pcp, pcl);
2041 addpCode2pBlock( pb, newpCode(POC_GOTO, pcw));
2042 addpCode2pBlock( pb, newpCodeWild(0,NULL,NULL));
2043 addpCode2pBlock( pb, newpCodeWild(1,NULL,pcw));
2048 pb = newpCodeChain(NULL, 'W',newpCode(POC_BTFSS, pcwb));
2049 addpCode2pBlock( pb, newpCodeWild(0,NULL,NULL));
2050 addpCode2pBlock( pb, newpCodeWild(1,NULL,pcw));
2054 /* Allocate space to store pointers to the wildcard variables */
2056 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
2057 pcp->nwildpCodes = 2;
2058 pcp->wildpCodes = Safe_calloc(pcp->nwildpCodes, sizeof(pCode *));
2060 pcp->postFalseCond = PCC_NONE;
2061 pcp->postTrueCond = PCC_NONE;
2075 /* Now for another peep example */
2076 pcps = Safe_calloc(1,sizeof(pCodePeepSnippets));
2077 pcp = pcps->peep = Safe_calloc(1,sizeof(pCodePeep));
2078 peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps);
2083 pcw = newpCodeOpWild(0,pcp,newpCodeOp(NULL,PO_GPR_REGISTER));
2085 pb = newpCodeChain(NULL, 'W', newpCode(POC_MOVWF, pcw));
2086 addpCode2pBlock( pb, newpCode(POC_MOVWF, pcw));
2090 pb = newpCodeChain(NULL, 'W',newpCode(POC_MOVWF, pcw));
2094 /* Allocate space to store pointers to the wildcard variables */
2096 pcp->vars = Safe_calloc(pcp->nvars, sizeof(char *));
2097 pcp->nwildpCodes = 0;
2098 pcp->wildpCodes = NULL;
2100 pcp->postFalseCond = PCC_NONE;
2101 pcp->postTrueCond = PCC_NONE;
2109 /*-----------------------------------------------------------------*/
2110 /* pCodeSearchCondition - Search a pCode chain for a 'condition' */
2112 /* return conditions */
2113 /* 1 - The Condition was found for a pCode's input */
2114 /* 0 - No matching condition was found for the whole chain */
2115 /* -1 - The Condition was found for a pCode's output */
2117 /*-----------------------------------------------------------------*/
2118 int pCodeSearchCondition(pCode *pc, unsigned int cond)
2123 /* If we reach a function end (presumably an end since we most
2124 probably began the search in the middle of a function), then
2125 the condition was not found. */
2126 if(pc->type == PC_FUNCTION)
2129 if(pc->type == PC_OPCODE) {
2130 if(PCI(pc)->inCond & cond)
2132 if(PCI(pc)->outCond & cond)
2141 /*-----------------------------------------------------------------*/
2142 /* pCodePeepMatchLine - Compare source and destination pCodes to */
2143 /* see they're the same. */
2144 /*-----------------------------------------------------------------*/
2145 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd)
2147 int index; // index into wild card arrays
2149 if(pcs->type == pcd->type) {
2151 if(pcs->type == PC_OPCODE) {
2153 /* If the opcodes don't match then the line doesn't match */
2154 if(PCI(pcs)->op != PCI(pcd)->op)
2157 fprintf(stderr,"%s comparing\n",__FUNCTION__);
2158 pcs->print(stderr,pcs);
2159 pcd->print(stderr,pcd);
2161 /* Compare the operands */
2162 if(PCI(pcd)->pcop) {
2163 if (PCI(pcd)->pcop->type == PO_WILD) {
2164 index = PCOW(PCI(pcd)->pcop)->id;
2166 fprintf(stderr,"destination is wild\n");
2167 #ifdef DEBUG_PCODEPEEP
2168 if (index > peepBlock->nvars) {
2169 fprintf(stderr,"%s - variables exceeded\n",__FUNCTION__);
2173 PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
2177 if(PCI(pcs)->pcop->type == PO_GPR_TEMP)
2178 n = PCOR(PCI(pcs)->pcop)->r->name;
2180 n = PCI(pcs)->pcop->name;
2182 if(peepBlock->vars[index])
2183 return (strcmp(peepBlock->vars[index],n) == 0);
2185 peepBlock->vars[index] = n; //PCI(pcs)->pcop->name;
2191 /* The pcd has no operand. Lines match if pcs has no operand either*/
2192 return (PCI(pcs)->pcop == NULL);
2197 if((pcd->type == PC_WILD) && (pcs->type == PC_OPCODE)) {
2201 index = PCW(pcd)->id;
2203 fprintf(stderr,"%s comparing wild cards\n",__FUNCTION__);
2204 pcs->print(stderr,pcs);
2205 pcd->print(stderr,pcd);
2207 peepBlock->wildpCodes[PCW(pcd)->id] = pcs;
2209 /* Check for a label associated with this wild pCode */
2210 // If the wild card has a label, make sure the source code does too.
2211 if(PCW(pcd)->label) {
2215 labindex = PCOW(PCW(pcd)->label)->id;
2216 if(peepBlock->vars[labindex] == NULL) {
2217 // First time to encounter this label
2218 peepBlock->vars[labindex] = PCL(pcs->label->pc)->label;
2219 fprintf(stderr,"first time for a label\n");
2221 if(strcmp(peepBlock->vars[labindex],PCL(pcs->label->pc)->label) != 0) {
2222 fprintf(stderr,"labels don't match\n");
2225 fprintf(stderr,"matched a label\n");
2230 if(PCW(pcd)->operand) {
2231 PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
2232 if(peepBlock->vars[index]) {
2233 int i = (strcmp(peepBlock->vars[index],PCI(pcs)->pcop->name) == 0);
2235 fprintf(stderr," (matched)\n");
2237 fprintf(stderr," (no match: wild card operand mismatch\n");
2238 fprintf(stderr," peepblock= %s, pcodeop= %s\n",
2239 peepBlock->vars[index],
2240 PCI(pcs)->pcop->name);
2244 peepBlock->vars[index] = PCI(pcs)->pcop->name;
2249 pcs = findNextInstruction(pcs->next);
2251 fprintf(stderr," (next to match)\n");
2252 pcs->print(stderr,pcs);
2255 return 1; /* wild card matches */
2261 /*-----------------------------------------------------------------*/
2262 /*-----------------------------------------------------------------*/
2263 void pCodePeepClrVars(pCodePeep *pcp)
2268 for(i=0;i<pcp->nvars; i++)
2269 pcp->vars[i] = NULL;
2273 /*-----------------------------------------------------------------*/
2274 /*-----------------------------------------------------------------*/
2275 void pCodeInsertAfter(pCode *pc1, pCode *pc2)
2281 pc2->next = pc1->next;
2283 pc1->next->prev = pc2;
2290 /*-----------------------------------------------------------------*/
2291 /* pCodeOpCopy - copy a pcode operator */
2292 /*-----------------------------------------------------------------*/
2293 static pCodeOp *pCodeOpCopy(pCodeOp *pcop)
2295 pCodeOp *pcopnew=NULL;
2300 switch(pcop->type) {
2303 pcopnew = Safe_calloc(1,sizeof(pCodeOpBit) );
2304 PCOB(pcopnew)->bit = PCOB(pcop)->bit;
2305 PCOB(pcopnew)->inBitSpace = PCOB(pcop)->inBitSpace;
2310 /* Here we expand the wild card into the appropriate type: */
2311 /* By recursively calling pCodeOpCopy */
2312 if(PCOW(pcop)->matched)
2313 pcopnew = pCodeOpCopy(PCOW(pcop)->matched);
2316 pcopnew = pCodeOpCopy(PCOW(pcop)->subtype);
2317 pcopnew->name = Safe_strdup(PCOW(pcop)->pcp->vars[PCOW(pcop)->id]);
2318 fprintf(stderr,"copied a wild op named %s\n",pcopnew->name);
2325 pcopnew = Safe_calloc(1,sizeof(pCodeOpLabel) );
2326 PCOLAB(pcopnew)->key = PCOLAB(pcop)->key;
2331 pcopnew = Safe_calloc(1,sizeof(pCodeOpLit) );
2332 PCOL(pcopnew)->lit = PCOL(pcop)->lit;
2335 case PO_GPR_REGISTER:
2337 case PO_SFR_REGISTER:
2346 pcopnew = Safe_calloc(1,sizeof(pCodeOp) );
2350 pcopnew->type = pcop->type;
2351 pcopnew->name = Safe_strdup(pcop->name);
2357 /*-----------------------------------------------------------------*/
2358 /* pCodeCopy - copy a pcode */
2359 /*-----------------------------------------------------------------*/
2360 static pCode *pCodeCopy(pCode *pc)
2365 pcnew = newpCode(pc->type,pc->pcop);
2368 /*-----------------------------------------------------------------*/
2369 /*-----------------------------------------------------------------*/
2370 void pCodeDeleteChain(pCode *f,pCode *t)
2375 fprintf(stderr,"delete pCode:\n");
2383 /*-----------------------------------------------------------------*/
2384 /*-----------------------------------------------------------------*/
2385 int pCodePeepMatchRule(pCode *pc)
2387 pCodePeep *peepBlock;
2392 peeprules = (_DLL *)peepSnippets;
2395 peepBlock = ((pCodePeepSnippets*)peeprules)->peep;
2396 pCodePeepClrVars(peepBlock);
2399 pct = peepBlock->target->pcHead;
2401 while(pct && pcin) {
2403 if(! (matched = pCodePeepMatchLine(peepBlock, pcin,pct)))
2406 pcin = findNextInstruction(pcin->next);
2409 fprintf(stderr," matched\n");
2411 fprintf(stderr," end of code\n");
2413 fprintf(stderr," end of rule\n");
2416 if(matched && pcin) {
2418 /* So far we matched the rule up to the point of the conditions .
2419 * In other words, all of the opcodes match. Now we need to see
2420 * if the post conditions are satisfied.
2421 * First we check the 'postFalseCond'. This means that we check
2422 * to see if any of the subsequent pCode's in the pCode chain
2423 * following the point just past where we have matched depend on
2424 * the `postFalseCond' as input then we abort the match
2426 fprintf(stderr," matched rule so far, now checking conditions\n");
2427 if (peepBlock->postFalseCond &&
2428 (pCodeSearchCondition(pcin,peepBlock->postFalseCond) > 0) )
2432 if(matched && pcin) {
2438 /* We matched a rule! Now we have to go through and remove the
2439 inefficient code with the optimized version */
2441 fprintf(stderr, "Found a pcode peep match:\nRule:\n");
2442 printpCodeString(stderr,peepBlock->target->pcHead,10);
2443 fprintf(stderr,"first thing matched\n");
2444 pc->print(stderr,pc);
2445 fprintf(stderr,"last thing matched\n");
2446 pcin->print(stderr,pcin);
2448 /* Unlink the original code */
2450 pcprev->next = pcin;
2451 pcin->prev = pc->prev;
2452 pCodeDeleteChain(pc,pcin);
2454 /* Generate the replacement code */
2456 pcr = peepBlock->replace->pcHead; // This is the replacement code
2459 /* If the replace pcode is an instruction with an operand, */
2460 /* then duplicate the operand (and expand wild cards in the process). */
2461 if(pcr->type == PC_OPCODE) {
2463 pcop = pCodeOpCopy(PCI(pcr)->pcop);
2465 pCodeInsertAfter(pc, newpCode(PCI(pcr)->op,pcop));
2466 } else if (pcr->type == PC_WILD) {
2467 pCodeInsertAfter(pc,peepBlock->wildpCodes[PCW(pcr)->id]);
2472 pc->print(stderr,pc);
2479 peeprules = peeprules->next;