1 /*-------------------------------------------------------------------------
2 SDCCpeeph.c - The peep hole optimizer: for interpreting the
5 Copyright (C) 1999, Sandeep Dutta . sandeep.dutta@usa.net
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 -------------------------------------------------------------------------*/
23 #include "dbuf_string.h"
25 #define ISCHARDIGIT(c) isdigit((unsigned char)c)
26 #define ISCHARSPACE(c) isspace((unsigned char)c)
27 #define ISCHARALNUM(c) isalnum((unsigned char)c)
29 #define ISINST(l, i) (!STRNCASECMP((l), (i), sizeof(i) - 1) && (!(l)[sizeof(i) - 1] || isspace((unsigned char)((l)[sizeof(i) - 1]))))
31 static peepRule
*rootRules
= NULL
;
32 static peepRule
*currRule
= NULL
;
36 hTab
*labelHash
= NULL
;
44 static int hashSymbolName (const char *name
);
45 static void buildLabelRefCountHash (lineNode
* head
);
46 static void bindVar (int key
, char **s
, hTab
** vtab
);
48 static bool matchLine (char *, const char *, hTab
**);
50 #define FBYNAME(x) static int x (hTab *vars, lineNode *currPl, lineNode *endPl, \
51 lineNode *head, char *cmdLine)
53 #if !OPT_DISABLE_PIC14
54 void peepRules2pCode(peepRule
*);
57 #if !OPT_DISABLE_PIC16
58 void pic16_peepRules2pCode(peepRule
*);
61 /*-----------------------------------------------------------------*/
62 /* getPatternVar - finds a pattern variable */
63 /*-----------------------------------------------------------------*/
66 getPatternVar (hTab
*vars
, char **cmdLine
)
71 if (!cmdLine
|| !*cmdLine
|| !**cmdLine
)
72 return NULL
; /* no parameters given */
74 while (**cmdLine
&& ISCHARSPACE(**cmdLine
))
75 (*cmdLine
)++; /* skip whitespace */
80 if (!ISCHARDIGIT (**cmdLine
))
82 varNumber
= strtol (*cmdLine
, &digitend
, 10);
84 return hTabItemWithKey (vars
, varNumber
);
88 "*** internal error: peephole restriction malformed: %s\n", *cmdLine
);
92 /*-----------------------------------------------------------------*/
93 /* interpreteLine - interpret general ASxxxx syntax */
94 /* Returns distance */
95 /* Can recurse to interpret some simple macros */
96 /*-----------------------------------------------------------------*/
99 interpretLine (lineNode
**pl
, char *buff
, bool back
)
107 // handle general ASxxxx syntax
108 // this can be a lot bigger than 4B due to macros
109 if(ISINST((*pl
)->line
, ".db") || ISINST((*pl
)->line
, ".byte") || ISINST((*pl
)->line
, ".fcb"))
112 for(i
= 1, j
= 0; (*pl
)->line
[j
]; i
+= (*pl
)->line
[j
] == ',', j
++);
115 else if(ISINST((*pl
)->line
, ".dw") || ISINST((*pl
)->line
, ".word") || ISINST((*pl
)->line
, ".fdb"))
118 for(i
= 1, j
= 0; (*pl
)->line
[j
]; i
+= (*pl
)->line
[j
] == ',', j
++);
121 else if(ISINST((*pl
)->line
, ".3byte") || ISINST((*pl
)->line
, ".triple"))
124 for(i
= 1, j
= 0; (*pl
)->line
[j
]; i
+= (*pl
)->line
[j
] == ',', j
++);
127 else if(ISINST((*pl
)->line
, ".4byte") || ISINST((*pl
)->line
, ".quad"))
130 for(i
= 1, j
= 0; (*pl
)->line
[j
]; i
+= (*pl
)->line
[j
] == ',', j
++);
133 else if(ISINST((*pl
)->line
, ".str") || ISINST((*pl
)->line
, ".ascii") || ISINST((*pl
)->line
, ".fcc")
134 || ISINST((*pl
)->line
, ".strz") || ISINST((*pl
)->line
, ".asciz")
135 || ISINST((*pl
)->line
, ".strs") || ISINST((*pl
)->line
, ".ascis"))
139 for (value
= (*pl
)->line
; *value
&& !isspace (*value
); ++value
);
141 for (; *value
&& isspace (*value
); ++value
);
142 // just part of the syntax
145 // delimiter can be freely chosen
146 char delimiter
= *(value
++);
147 for (;*value
&& *value
!= delimiter
; ++value
, ++dist
);
148 // \0 terminated string
149 if (ISINST((*pl
)->line
, ".strz") || ISINST((*pl
)->line
, ".asciz"))
151 // it doesn't end with delimiter
152 if (*value
!= delimiter
)
154 werrorfl("delimitererror", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
158 else if(!back
&& ISINST((*pl
)->line
, ".rept"))
160 // we can ignore the label for now
161 // rept doesn't allow duplicate labels
162 const char *op1start
;
166 for (op1start
= (*pl
)->line
; *op1start
&& !isspace (*op1start
); ++op1start
);
168 for (; *op1start
&& isspace (*op1start
); ++op1start
);
169 times
= atoi(op1start
);
170 // 0 times is probably an error with atoi
173 werrorfl("atoierror", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
177 while((*pl
) && !ISINST((*pl
)->line
, ".endm"))
179 dist
+= interpretLine(pl
, buff
, back
);
184 // we reached the end, not .endm
189 else if(back
&& ISINST((*pl
)->line
, ".endm"))
191 // parse rept backwards
192 const char *op1start
;
196 while((*pl
) && !ISINST((*pl
)->line
, ".rept"))
198 dist
+= interpretLine(pl
, buff
, back
);
203 // we reached the end, not .rept
207 for (op1start
= (*pl
)->line
; *op1start
&& !isspace (*op1start
); ++op1start
);
209 for (; *op1start
&& isspace (*op1start
); ++op1start
);
210 times
= atoi(op1start
);
211 // 0 times is probably an error with atoi
214 werrorfl("atoierror", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
219 else if (ISINST((*pl
)->line
, ".incbin"))
221 // .incbin /string/ [,offset [,count]]
222 // if count is given, we can work with it
223 const char *op1start
= (*pl
)->line
;
226 while (*op1start
&& *(op1start
++) != ',');
229 werrorfl("unsupported", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
233 while (*op1start
&& *(op1start
++) != ',');
236 werrorfl("unsupported", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
240 for (; *op1start
&& isspace (*op1start
); ++op1start
);
243 werrorfl("unsupported", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
246 count
= atoi(op1start
);
247 // probably an error with atoi
250 werrorfl("atoierror", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
255 else if (ISINST((*pl
)->line
, ".odd") || ISINST((*pl
)->line
, ".even"))
257 // 0 or 1, assume worst
260 else if(ISINST((*pl
)->line
, ".bndry") || ISINST((*pl
)->line
, ".ds") || ISINST((*pl
)->line
, ".rmb")
261 || ISINST((*pl
)->line
, ".rs") || ISINST((*pl
)->line
, ".blkb") || ISINST((*pl
)->line
, ".blkw")
262 || ISINST((*pl
)->line
, ".blk3") || ISINST((*pl
)->line
, ".blk4"))
264 const char *op1start
;
268 for (op1start
= (*pl
)->line
; *op1start
&& !isspace (*op1start
); ++op1start
);
270 for (; *op1start
&& isspace (*op1start
); ++op1start
);
271 offset
= atoi(op1start
);
272 // 0 times is probably an error with atoi
275 werrorfl("atoierror", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
278 if (ISINST((*pl
)->line
, ".blkw"))
280 if (ISINST((*pl
)->line
, ".blk3"))
282 if (ISINST((*pl
)->line
, ".blk4"))
284 // bndry: assume the worst
287 else if ( ISINST((*pl
)->line
, ".iift") || ISINST((*pl
)->line
, ".iiff") || ISINST((*pl
)->line
, ".iiftf")
288 || ISINST((*pl
)->line
, ".iifne") || ISINST((*pl
)->line
, ".iifeq") || ISINST((*pl
)->line
, ".iifgt")
289 || ISINST((*pl
)->line
, ".iiflt") || ISINST((*pl
)->line
, ".iifge") || ISINST((*pl
)->line
, ".iifle")
290 || ISINST((*pl
)->line
, ".iifdef") || ISINST((*pl
)->line
, ".iifndef") || ISINST((*pl
)->line
, ".iifb")
291 || ISINST((*pl
)->line
, ".iifnb") || ISINST((*pl
)->line
, ".iifidn") || ISINST((*pl
)->line
, ".iifdif")
292 || ISINST((*pl
)->line
, ".iif"))
294 // the line ends with real operations and directives
295 werrorfl("unsupported", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
298 else if (ISINST((*pl
)->line
, ".msg") || ISINST((*pl
)->line
, ".error") || ISINST((*pl
)->line
, ".assume")
299 || ISINST((*pl
)->line
, ".radix") || ISINST((*pl
)->line
, ".local") || ISINST((*pl
)->line
, ".globl")
300 || ISINST((*pl
)->line
, ".equ") || ISINST((*pl
)->line
, ".gblequ") || ISINST((*pl
)->line
, ".lclequ")
301 || ISINST((*pl
)->line
, ".if") || ISINST((*pl
)->line
, ".else") || ISINST((*pl
)->line
, ".endif")
302 || ISINST((*pl
)->line
, ".ift") || ISINST((*pl
)->line
, ".iff") || ISINST((*pl
)->line
, ".iftf")
303 || ISINST((*pl
)->line
, ".ifne") || ISINST((*pl
)->line
, ".ifeq") || ISINST((*pl
)->line
, ".ifgt")
304 || ISINST((*pl
)->line
, ".iflt") || ISINST((*pl
)->line
, ".ifge") || ISINST((*pl
)->line
, ".ifle")
305 || ISINST((*pl
)->line
, ".ifdef") || ISINST((*pl
)->line
, ".ifndef") || ISINST((*pl
)->line
, ".ifb")
306 || ISINST((*pl
)->line
, ".ifnb") || ISINST((*pl
)->line
, ".ifidn") || ISINST((*pl
)->line
, ".ifdif")
307 || ISINST((*pl
)->line
, ".define") || ISINST((*pl
)->line
, ".undefine"))
309 // ignore these, makes it longer at worst
312 else if (ISINST((*pl
)->line
, ".macro") || ISINST((*pl
)->line
, ".irp") || ISINST((*pl
)->line
, ".irpc")
313 || ISINST((*pl
)->line
, ".include") || ISINST((*pl
)->line
, ".rept") || ISINST((*pl
)->line
, ".endm"))
315 // catch some unsupported long or complex directives
316 werrorfl("unsupported", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, (*pl
)->line
);
319 // get port specific size
322 const char *op1start
;
324 for (op1start
= (*pl
)->line
; *op1start
&& !isspace (*op1start
); ++op1start
);
326 for (; *op1start
&& isspace (*op1start
); ++op1start
);
327 // catch "sym1 .equ expr" "sym1 = expr" "sym1 =: expr" etc
328 // ".equ sym1 expr" got already handled
329 if (ISINST(op1start
, ".equ") || ISINST(op1start
, ".gblequ") || ISINST(op1start
, ".lclequ")
335 else if (port
->peep
.getSize
)
337 dist
+= port
->peep
.getSize((*pl
));
339 fprintf(stderr
, "Line: %s, dist: %i, total: %i\n", pl
->line
, port
->peep
.getSize(pl
), dist
);
344 // could be a macro call
352 /*-----------------------------------------------------------------*/
353 /* pcDistance - finds a label backward or forward */
354 /*-----------------------------------------------------------------*/
357 pcDistance (lineNode
*cpos
, char *lbl
, bool back
)
360 char buff
[MAX_PATTERN_LEN
];
363 SNPRINTF (buff
, sizeof(buff
) - 1, "%s:", lbl
);
366 dist
+= interpretLine(&pl
, buff
, back
);
367 // interpretLine changes pl
371 if (strncmp (pl
->line
, buff
, strlen (buff
)) == 0)
381 /*-----------------------------------------------------------------*/
382 /* flat24bitMode - will check to see if we are in flat24 mode */
383 /*-----------------------------------------------------------------*/
384 FBYNAME (flat24bitMode
)
386 return (options
.model
== MODEL_FLAT24
);
389 /*-----------------------------------------------------------------*/
390 /* xramMovcOption - check if using movc to read xram */
391 /*-----------------------------------------------------------------*/
392 FBYNAME (xramMovcOption
)
394 return (options
.xram_movc
&& (strcmp(port
->target
,"mcs51") == 0));
397 /*-----------------------------------------------------------------*/
398 /* useAcallAjmp - Enable replacement of lcall/ljmp with acall/ajmp */
399 /*-----------------------------------------------------------------*/
400 FBYNAME (useAcallAjmp
)
402 return (options
.acall_ajmp
&& (strcmp(port
->target
,"mcs51") == 0));
405 /*-----------------------------------------------------------------*/
406 /* labelInRange - will check to see if label is within range */
407 /*-----------------------------------------------------------------*/
408 FBYNAME (labelInRange
)
411 char *lbl
= getPatternVar (vars
, &cmdLine
);
416 "*** internal error: labelInRange peephole restriction"
417 " malformed: %s\n", cmdLine
);
419 /* If no parameters given, assume that %5 pattern variable
420 has the label name for backward compatibility */
421 lbl
= hTabItemWithKey (vars
, 5);
429 /* Don't optimize jumps in a jump table; a more generic test */
430 if (currPl
->ic
&& currPl
->ic
->op
== JUMPTABLE
)
433 /* if the previous two instructions are "ljmp"s then don't
434 do it since it can be part of a jump table */
435 if (currPl
->prev
&& currPl
->prev
->prev
&&
436 strstr (currPl
->prev
->line
, "ljmp") &&
437 strstr (currPl
->prev
->prev
->line
, "ljmp"))
440 /* Calculate the label distance. For mcs51 the jump can be
441 -127 to + 127 bytes, for Z80 -126 to +129 bytes.*/
442 dist
= (pcDistance (currPl
, lbl
, TRUE
) +
443 pcDistance (currPl
, lbl
, FALSE
));
445 /* Use 125 for now. Could be made more exact using port and
446 exact jump location instead of currPl. */
447 if (!dist
|| dist
> 127)
450 lbl
= getPatternVar (vars
, &cmdLine
);
457 /*-----------------------------------------------------------------*/
458 /* labelJTInRange - will check to see if label %5 and up are */
460 /* Specifically meant to optimize long (3-byte) jumps to short */
461 /* (2-byte) jumps in jumptables */
462 /*-----------------------------------------------------------------*/
463 FBYNAME (labelJTInRange
)
468 /* Only optimize within a jump table */
469 if (currPl
->ic
&& currPl
->ic
->op
!= JUMPTABLE
)
472 count
= elementsInSet( IC_JTLABELS (currPl
->ic
) );
474 /* check all labels (this is needed if the case statements are unsorted) */
475 for (i
=0; i
<count
; i
++)
477 /* assumes that the %5 pattern variable has the first ljmp label */
478 lbl
= hTabItemWithKey (vars
, 5+i
);
482 dist
= (pcDistance (currPl
, lbl
, TRUE
) +
483 pcDistance (currPl
, lbl
, FALSE
));
485 /* three terms used to calculate allowable distance */
486 /* Could be made more exact and port-specific. */
488 dist
> 127+ /* range of sjmp */
489 (3+3*i
)+ /* offset between this jump and currPl,
490 should use pcDistance instead? */
491 (count
-i
-1) /* if peephole applies distance is shortened */
498 /*-----------------------------------------------------------------*/
499 /* optimizeReturn - is it allowed to optimize RET instructions */
500 /*-----------------------------------------------------------------*/
501 FBYNAME (optimizeReturn
)
503 return (options
.peepReturn
>= 0);
506 /*-----------------------------------------------------------------*/
507 /* labelIsReturnOnly - Check if label is followed by ret */
508 /*-----------------------------------------------------------------*/
509 FBYNAME (labelIsReturnOnly
)
511 /* assumes that %5 pattern variable has the label name */
512 const char *label
, *p
;
517 /* Don't optimize jumps in a jump table; a more generic test */
518 if (currPl
->ic
&& currPl
->ic
->op
== JUMPTABLE
)
521 if (!(label
= getPatternVar (vars
, &cmdLine
)))
524 "*** internal error: labelIsReturnOnly peephole restriction"
525 " malformed: %s\n", cmdLine
);
527 /* If no parameters given, assume that %5 pattern variable
528 has the label name for backward compatibility */
529 label
= hTabItemWithKey (vars
, 5);
536 for(pl
= currPl
; pl
; pl
= pl
->next
)
538 if (pl
->line
&& !pl
->isDebug
&& !pl
->isComment
&& pl
->isLabel
)
540 if (strncmp(pl
->line
, label
, len
) == 0)
541 break; /* Found Label */
542 if (strlen(pl
->line
) != 7 || !ISCHARDIGIT(*(pl
->line
)) ||
543 !ISCHARDIGIT(*(pl
->line
+1)) || !ISCHARDIGIT(*(pl
->line
+2)) ||
544 !ISCHARDIGIT(*(pl
->line
+3)) || !ISCHARDIGIT(*(pl
->line
+4)) ||
545 *(pl
->line
+5) != '$')
547 return FALSE
; /* non-local label encountered */
552 return FALSE
; /* did not find the label */
554 while (pl
&& (pl
->isDebug
|| pl
->isComment
|| pl
->isLabel
))
556 if (!pl
|| !pl
->line
|| pl
->isDebug
)
557 return FALSE
; /* next line not valid */
558 for (p
= pl
->line
; *p
&& ISCHARSPACE(*p
); p
++)
562 if (TARGET_HC08_LIKE
|| TARGET_MOS6502_LIKE
)
565 if (strncmp(p
, retInst
,strlen(retInst
)) != 0)
569 while(*p
&& ISCHARSPACE(*p
))
578 /*-----------------------------------------------------------------*/
579 /* labelIsUncondJump - Check if label %5 is followed by an */
580 /* unconditional jump and put the destination of that jump in %6 */
581 /*-----------------------------------------------------------------*/
582 FBYNAME (labelIsUncondJump
)
584 /* assumes that %5 pattern variable has the label name */
590 char * jpInst
= NULL
;
591 char * jpInst2
= NULL
;
593 label
= hTabItemWithKey (vars
, 5);
598 for (pl
= currPl
; pl
; pl
= pl
->prev
)
600 if (pl
->line
&& !pl
->isDebug
&& !pl
->isComment
&& pl
->isLabel
)
602 if (strncmp(pl
->line
, label
, len
) == 0 && pl
->line
[len
] == ':')
605 break; /* Found Label */
607 if (strlen(pl
->line
) != 7 || !ISCHARDIGIT(*(pl
->line
)) ||
608 !ISCHARDIGIT(*(pl
->line
+1)) || !ISCHARDIGIT(*(pl
->line
+2)) ||
609 !ISCHARDIGIT(*(pl
->line
+3)) || !ISCHARDIGIT(*(pl
->line
+4)) ||
610 *(pl
->line
+5) != '$')
612 break; /* non-local label encountered */
619 for (pl
= currPl
; pl
; pl
= pl
->next
)
621 if (pl
->line
&& !pl
->isDebug
&& !pl
->isComment
&& pl
->isLabel
)
623 if (strncmp(pl
->line
, label
, len
) == 0 && pl
->line
[len
] == ':')
626 break; /* Found Label */
628 if (strlen(pl
->line
) != 7 || !ISCHARDIGIT(*(pl
->line
)) ||
629 !ISCHARDIGIT(*(pl
->line
+1)) || !ISCHARDIGIT(*(pl
->line
+2)) ||
630 !ISCHARDIGIT(*(pl
->line
+3)) || !ISCHARDIGIT(*(pl
->line
+4)) ||
631 *(pl
->line
+5) != '$')
633 return FALSE
; /* non-local label encountered */
640 return FALSE
; /* did not find the label */
642 while (pl
&& (pl
->isDebug
|| pl
->isComment
))
644 if (!pl
|| !pl
->line
)
645 return FALSE
; /* next line not valid */
647 while (*p
&& ISCHARSPACE(*p
))
650 if (TARGET_MCS51_LIKE
)
655 else if (TARGET_HC08_LIKE
|| TARGET_MOS6502_LIKE
)
660 else if (TARGET_Z80_LIKE
|| TARGET_IS_F8
)
665 else if (TARGET_IS_STM8
)
667 jpInst
= (options
.model
== MODEL_LARGE
? "jpf" : "jp");
670 else if (TARGET_PDK_LIKE
)
674 len
= strlen(jpInst
);
675 if (strncmp(p
, jpInst
, len
))
677 len
= jpInst2
? strlen(jpInst2
) : 0;
678 if(!jpInst2
|| strncmp(p
, jpInst2
, len
))
679 return FALSE
; /* next line is no jump */
683 while (*p
&& ISCHARSPACE(*p
))
687 while (*q
&& *q
!=';')
689 while (q
>p
&& ISCHARSPACE(*q
))
693 return false; /* no destination? */
697 while (q
>p
&& *q
!=',')
700 return false; /* conditional jump */
703 if (TARGET_IS_F8
&& p
[0] == '#')
706 /* now put the destination in %6 */
707 bindVar (6, &p
, &vars
);
712 /*-----------------------------------------------------------------*/
713 /* okToRemoveSLOC - Check if label %1 is a SLOC and not other */
714 /* usage of it in the code depends on a value from this section */
715 /*-----------------------------------------------------------------*/
716 FBYNAME (okToRemoveSLOC
)
719 const char *sloc
, *p
;
720 int dummy1
, dummy2
, dummy3
;
722 /* assumes that %1 as the SLOC name */
723 sloc
= hTabItemWithKey (vars
, 1);
724 if (sloc
== NULL
) return FALSE
;
725 p
= strstr(sloc
, "sloc");
726 if (p
== NULL
) return FALSE
;
728 if (sscanf(p
, "%d_%d_%d", &dummy1
, &dummy2
, &dummy3
) != 3) return FALSE
;
729 /*TODO: ultra-paranoid: get function name from "head" and check that */
730 /* the sloc name begins with that. Probably not really necessary */
732 /* Look for any occurrence of this SLOC before the peephole match */
733 for (pl
= currPl
->prev
; pl
; pl
= pl
->prev
) {
734 if (pl
->line
&& !pl
->isDebug
&& !pl
->isComment
735 && *pl
->line
!= ';' && strstr(pl
->line
, sloc
))
738 /* Look for any occurrence of this SLOC after the peephole match */
739 for (pl
= endPl
->next
; pl
; pl
= pl
->next
) {
740 if (pl
->line
&& !pl
->isDebug
&& !pl
->isComment
741 && *pl
->line
!= ';' && strstr(pl
->line
, sloc
))
744 return TRUE
; /* safe for a peephole to remove it :) */
747 /*-----------------------------------------------------------------*/
748 /* deadMove - Check, if a pop/push pair can be removed */
749 /*-----------------------------------------------------------------*/
752 const char *reg
= hTabItemWithKey (vars
, 1);
754 if (port
->peep
.deadMove
)
755 return port
->peep
.deadMove (reg
, currPl
, head
);
757 fprintf (stderr
, "Function deadMove not initialized in port structure\n");
761 /*-----------------------------------------------------------------*/
762 /* labelHashEntry- searches for a label in the list labelHash */
763 /* Builds labelHash, if it does not yet exist. */
764 /* Returns the labelHashEntry or NULL */
765 /*-----------------------------------------------------------------*/
767 getLabelRef (const char *label
, lineNode
*head
)
769 labelHashEntry
*entry
;
771 /* If we don't have the label hash table yet, build it. */
774 buildLabelRefCountHash (head
);
777 entry
= hTabFirstItemWK (labelHash
, hashSymbolName (label
));
781 if (!strcmp (label
, entry
->name
))
785 entry
= hTabNextItemWK (labelHash
);
792 * takes two parameters: a variable (bound to a label name)
793 * and an expected reference count.
795 * Returns TRUE if that label is defined and referenced exactly
796 * the given number of times.
798 FBYNAME (labelRefCount
)
800 int varNumber
, expectedRefCount
;
803 if (sscanf (cmdLine
, "%*[ \t%]%d %d", &varNumber
, &expectedRefCount
) == 2)
805 char *label
= hTabItemWithKey (vars
, varNumber
);
809 labelHashEntry
*entry
= getLabelRef (label
, head
);
815 fprintf (stderr
, "labelRefCount: %s has refCount %d, want %d\n",
816 label
, entry
->refCount
, expectedRefCount
);
819 rc
= (expectedRefCount
== entry
->refCount
);
823 // Not a local label. We do not know how often it might be referenced.
829 fprintf (stderr
, "*** internal error: var %d not bound"
830 " in peephole labelRefCount rule.\n",
837 "*** internal error: labelRefCount peephole restriction"
838 " malformed: %s\n", cmdLine
);
843 /* labelRefCountChange:
844 * takes two parameters: a variable (bound to a label name)
845 * and a signed int for changing the reference count.
847 * Please note, this function is not a conditional. It unconditionally
848 * changes the label. It should be passed as the 'last' function
849 * so it only is applied if all other conditions have been met.
851 * should always return TRUE
853 FBYNAME (labelRefCountChange
)
855 int varNumber
, RefCountDelta
;
858 /* If we don't have the label hash table yet, build it. */
861 buildLabelRefCountHash (head
);
864 if (sscanf (cmdLine
, "%*[ \t%]%d %i", &varNumber
, &RefCountDelta
) == 2)
866 char *label
= hTabItemWithKey (vars
, varNumber
);
870 labelHashEntry
*entry
;
872 entry
= hTabFirstItemWK (labelHash
, hashSymbolName (label
));
876 if (!strcmp (label
, entry
->name
))
880 entry
= hTabNextItemWK (labelHash
);
884 if (0 <= entry
->refCount
+ RefCountDelta
)
886 entry
->refCount
+= RefCountDelta
;
891 fprintf (stderr
, "*** internal error: label %s may not get"
892 " negative refCount in %s peephole.\n",
898 // Not a local label. We do not know how often it might be referenced.
904 fprintf (stderr
, "*** internal error: var %d not bound"
905 " in peephole %s rule.\n",
906 varNumber
, __func__
);
912 "*** internal error: labelRefCountChange peephole restriction"
913 " malformed: %s\n", cmdLine
);
918 /* newLabel creates new dollar-label and returns it in the specified container.
919 * Optional second operand may specify initial reference count, by default 1.
920 * return TRUE if no errors detected
926 switch (sscanf (cmdLine
, " %%%d %u", &varNumber
, &refCount
))
935 "*** internal error: newLabel peephole restriction"
936 " malformed: %s\n", cmdLine
);
942 fprintf (stderr
, "*** internal error: invalid container %%%d"
943 " in peephole %s rule.\n",
944 varNumber
, __func__
);
948 if (labelHash
== NULL
)
949 buildLabelRefCountHash (head
);
951 labelHashEntry
*entry
;
953 unsigned maxLabel
= 100; // do not use labels below than 00100$
954 for (entry
= hTabFirstItem (labelHash
, &key
); entry
;
955 entry
= hTabNextItem (labelHash
, &key
))
957 const char *name
= entry
->name
;
959 if (!ISCHARDIGIT (name
[0]))
961 if (name
[strlen (name
)-1] != '$')
964 if (sscanf (name
, "%u$", &n
) != 1)
970 entry
= traceAlloc (&_G
.labels
, Safe_alloc (sizeof (*entry
)));
971 int len
= snprintf (entry
->name
, SDCC_NAME_MAX
, "%05u$", maxLabel
);
972 entry
->name
[len
] = 0;
973 entry
->refCount
= refCount
;
974 hTabAddItem (&labelHash
, hashSymbolName (entry
->name
), entry
);
976 char *value
= traceAlloc (&_G
.values
, Safe_strdup(entry
->name
));
977 hTabAddItem (&vars
, varNumber
, value
);
982 /* Within the context of the lines currPl through endPl, determine
983 ** if the variable var contains a symbol that is volatile. Returns
984 ** TRUE only if it is certain that this was not volatile (the symbol
985 ** was found and not volatile, or var was a constant or CPU register).
986 ** Returns FALSE if the symbol was found and volatile, the symbol was
987 ** not found, or var was a indirect/pointer addressing mode.
990 notVolatileVariable(const char *var
, lineNode
*currPl
, lineNode
*endPl
)
992 char symname
[SDCC_NAME_MAX
+ 1];
994 const char *vp
= var
;
999 const bool global_not_volatile
= currFunc
? !currFunc
->funcUsesVolatile
: false;
1001 /* Can't tell if indirect accesses are volatile or not, so
1002 ** assume they are (if there is a volatile access in the function at all), just to be safe.
1004 if (TARGET_IS_MCS51
|| TARGET_IS_DS390
|| TARGET_IS_DS400
)
1007 return global_not_volatile
;
1009 if (TARGET_Z80_LIKE
)
1014 return global_not_volatile
;
1015 if (strstr (var
, "(bc)"))
1016 return global_not_volatile
;
1017 if (strstr (var
, "(de)"))
1018 return global_not_volatile
;
1019 if (strstr (var
, "(hl"))
1020 return global_not_volatile
;
1021 if (strstr (var
, "(ix"))
1022 return global_not_volatile
;
1023 if (strstr (var
, "(iy"))
1024 return global_not_volatile
;
1025 // sm83-specific ldh can be volatile
1026 // but HRAM doesn't have to be volatile
1027 if (TARGET_ID_SM83
&& strstr (var
, "(c)"))
1028 return global_not_volatile
;
1036 return global_not_volatile
;
1037 if (strstr (var
, "(x)"))
1038 return global_not_volatile
;
1039 if (strstr (var
, "(y)"))
1040 return global_not_volatile
;
1041 if (strstr (var
, ", x)"))
1042 return global_not_volatile
;
1043 if (strstr (var
, ", y)"))
1044 return global_not_volatile
;
1045 if (strstr (var
, ", sp)"))
1046 return global_not_volatile
;
1047 if (strchr (var
, '[') && strchr (var
, ']'))
1048 return global_not_volatile
;
1049 if (strstr(var
, "0x") || strstr(var
, "0X") || isdigit(var
[0]))
1050 return global_not_volatile
;
1053 if (TARGET_PDK_LIKE
)
1057 if (!strcmp (var
, "a") || !strcmp (var
, "p"))
1061 if (TARGET_HC08_LIKE
|| TARGET_IS_MOS6502
)
1065 if (strstr(var
, "0x") || strstr(var
, "0X") || isdigit(var
[0]))
1066 return global_not_volatile
;
1069 /* Extract a symbol name from the variable */
1070 while (*vp
&& (*vp
!='_'))
1072 while (*vp
&& (ISCHARALNUM(*vp
) || *vp
=='_'))
1078 /* Nothing resembling a symbol name was found, so it can't
1085 for (cl
= currPl
; cl
!=endPl
->next
; cl
= cl
->next
)
1087 if (cl
->ic
&& (cl
->ic
!=last_ic
))
1093 op
= IC_COND (cl
->ic
);
1094 if (IS_SYMOP (op
) &&
1095 ( !strcmp(OP_SYMBOL (op
)->rname
, symname
) ||
1096 (OP_SYMBOL (op
)->isspilt
&&
1098 !strcmp(SPIL_LOC (op
)->rname
, symname
)) ))
1100 return !op
->isvolatile
;
1103 op
= IC_JTCOND (cl
->ic
);
1104 if (IS_SYMOP (op
) &&
1105 ( !strcmp(OP_SYMBOL (op
)->rname
, symname
) ||
1106 (OP_SYMBOL (op
)->isspilt
&&
1108 !strcmp(SPIL_LOC (op
)->rname
, symname
)) ))
1110 return !op
->isvolatile
;
1113 op
= IC_LEFT (cl
->ic
);
1114 if (IS_SYMOP (op
) &&
1115 ( !strcmp(OP_SYMBOL (op
)->rname
, symname
) ||
1116 (OP_SYMBOL (op
)->isspilt
&&
1118 !strcmp(SPIL_LOC (op
)->rname
, symname
)) ))
1120 return !op
->isvolatile
;
1122 op
= IC_RIGHT (cl
->ic
);
1123 if (IS_SYMOP (op
) &&
1124 ( !strcmp(OP_SYMBOL (op
)->rname
, symname
) ||
1125 (OP_SYMBOL (op
)->isspilt
&&
1127 !strcmp(SPIL_LOC (op
)->rname
, symname
)) ))
1129 return !op
->isvolatile
;
1131 op
= IC_RESULT (cl
->ic
);
1132 if (IS_SYMOP (op
) &&
1133 ( !strcmp(OP_SYMBOL (op
)->rname
, symname
) ||
1134 (OP_SYMBOL (op
)->isspilt
&&
1136 !strcmp(SPIL_LOC (op
)->rname
, symname
)) ))
1138 return !op
->isvolatile
;
1144 /* Couldn't find the symbol for some reason. Assume volatile if the current function touches anything volatile. */
1145 return global_not_volatile
;
1150 * This rule restriction has two different behaviours depending on
1151 * the number of parameters given.
1153 * if notVolatile (no parameters given)
1154 * The rule is applied only if none of the iCodes originating
1155 * the matched pattern reference a volatile operand.
1157 * if notVolatile %1 ... (one or more parameters given)
1158 * The rule is applied if the parameters are not expressions
1159 * containing volatile symbols and are not pointer accesses.
1162 FBYNAME (notVolatile
)
1172 /* If no parameters given, just scan the iCodes for volatile operands */
1173 for (cl
= currPl
; cl
!=endPl
->next
; cl
= cl
->next
)
1180 op
= IC_COND (cl
->ic
);
1181 if (IS_SYMOP (op
) && op
->isvolatile
)
1184 op
= IC_JTCOND (cl
->ic
);
1185 if (IS_SYMOP (op
) && op
->isvolatile
)
1188 op
= IC_LEFT (cl
->ic
);
1189 if (IS_SYMOP (op
) && op
->isvolatile
)
1191 op
= IC_RIGHT (cl
->ic
);
1192 if (IS_SYMOP (op
) && op
->isvolatile
)
1194 op
= IC_RESULT (cl
->ic
);
1195 if (IS_SYMOP (op
) && op
->isvolatile
)
1203 /* There were parameters; check the volatility of each */
1204 while (*cmdLine
&& ISCHARSPACE(*cmdLine
))
1211 if (!ISCHARDIGIT(*cmdLine
))
1213 varNumber
= strtol(cmdLine
, &digitend
, 10);
1215 while (*cmdLine
&& ISCHARSPACE(*cmdLine
))
1218 var
= hTabItemWithKey (vars
, varNumber
);
1222 if (!notVolatileVariable (var
, currPl
, endPl
))
1227 fprintf (stderr
, "*** internal error: var %d not bound"
1228 " in peephole notVolatile rule.\n",
1238 "*** internal error: notVolatile peephole restriction"
1239 " malformed: %s\n", cmdLine
);
1243 /*------------------------------------------------------------------*/
1244 /* setFromConditionArgs - parse a peephole condition's arguments */
1245 /* to produce a set of strings, one per argument. Variables %x will */
1246 /* be replaced with their values. String literals (in single quotes)*/
1247 /* are accepted and return in unquoted form. */
1248 /*------------------------------------------------------------------*/
1250 setFromConditionArgs (char *cmdLine
, hTab
* vars
)
1255 set
*operands
= NULL
;
1260 while (*cmdLine
&& ISCHARSPACE(*cmdLine
))
1265 if (*cmdLine
== '%')
1268 if (!ISCHARDIGIT(*cmdLine
))
1270 varNumber
= strtol(cmdLine
, &digitend
, 10);
1273 var
= hTabItemWithKey (vars
, varNumber
);
1277 addSetHead (&operands
, var
);
1282 else if (*cmdLine
== '\'' )
1284 char quote
= *cmdLine
;
1287 while (*cmdLine
&& *cmdLine
!= quote
)
1289 if (*cmdLine
== quote
)
1293 addSetHead (&operands
, var
);
1298 while (*cmdLine
&& ISCHARSPACE(*cmdLine
))
1305 deleteSet (&operands
);
1310 operandBaseName (const char *op
)
1312 if (TARGET_IS_MCS51
|| TARGET_IS_DS390
|| TARGET_IS_DS400
)
1314 if (!strncmp (op
, "ar", 2) && ISCHARDIGIT(*(op
+2)) && !*(op
+3))
1316 if (!strcmp (op
, "ab"))
1318 if (!strcmp (op
, "acc") || !strncmp (op
, "acc.", 4) || *op
== 'a')
1320 // bug 1739475, temp fix
1322 return operandBaseName(op
+1);
1324 if (TARGET_Z80_LIKE
)
1326 if (!strcmp (op
, "d") || !strcmp (op
, "e") || !strcmp (op
, "(de)"))
1328 if (!strcmp (op
, "b") || !strcmp (op
, "c") || !strcmp (op
, "(bc)"))
1330 if (!strcmp (op
, "h") || !strcmp (op
, "l") || !strcmp (op
, "(hl)") || !strcmp (op
, "(hl+)") || !strcmp (op
, "(hl-)"))
1332 if (!strcmp (op
, "iyh") || !strcmp (op
, "iyl") || strstr (op
, "iy"))
1334 if (!strcmp (op
, "ixh") || !strcmp (op
, "ixl") || strstr (op
, "ix"))
1336 if (!strcmp (op
, "a"))
1343 /*------------------------------------------------------------------*/
1344 /* optimizeFor - check optimization conditions */
1345 /* valid parameters: */
1346 /* code-size -> checks for optimize.codeSize > 0 */
1347 /* code-speed -> checks for optimize.codeSpeed > 0 */
1348 /* add the ! symbol before each parameter to negate the condition */
1349 /* combinations with multiple parameters */
1350 /* '!code-speed' '!code-size': apply for balanced opt. */
1351 /* '!code-size': apply for balanced and when optimizing for speed */
1352 /* '!code-speed': apply unless optimizing for code speed */
1353 /*------------------------------------------------------------------*/
1354 FBYNAME (optimizeFor
)
1357 int speed
= 0, size
= 0; // 0: nothing requested, >0 optimization requested, <0 negated optimization requested
1359 bool ret
= false, error
= false;
1361 set
*operands
= setFromConditionArgs (cmdLine
, vars
);
1366 "*** internal error: optimizeFor peephole restriction"
1367 " requires operand(s): %s\n", cmdLine
);
1371 // Loop through all conditions to check requested optimizations
1372 for (cond
= setFirstItem (operands
); !error
&& cond
!= NULL
; cond
= setNextItem (operands
))
1374 const char *condTextSpeed
= strstr (cond
, "code-speed");
1375 const char *condTextSize
= strstr (cond
, "code-size");
1376 const char *condNegated
= strstr (cond
, "!");
1377 const char *condText
= condTextSpeed
? condTextSpeed
: condTextSize
;
1379 // Check for invalid conditions or invalid combinations in the same string
1380 if (!condText
|| condTextSpeed
&& condTextSize
|| condNegated
&& (condNegated
+ 1 != condText
))
1388 size
= condNegated
? -1 : 1;
1395 speed
= condNegated
? -1 : 1;
1400 // check error, invalid combination of both speed and size or nothing
1401 if (error
|| (speed
!= -1) && (speed
== size
) )
1404 "*** internal error: optimizeFor peephole restriction"
1405 " malformed: %s\n", cmdLine
);
1409 { // Check conditions and generate return value
1412 ret
&= (speed
< 0) ^ (optimize
.codeSpeed
> 0);
1415 ret
&= (size
< 0) ^ (optimize
.codeSize
> 0);
1418 deleteSet(&operands
);
1422 /*-----------------------------------------------------------------*/
1423 /* notUsed - Check, if values in all registers are not read again */
1424 /*-----------------------------------------------------------------*/
1430 if (!port
->peep
.notUsed
)
1432 fprintf (stderr
, "Function notUsed not initialized in port structure\n");
1436 set
*operands
= setFromConditionArgs (cmdLine
, vars
);
1441 "*** internal error: notUsed peephole restriction"
1442 " requires operand(s): %s\n", cmdLine
);
1446 what
= setFirstItem (operands
);
1447 for (ret
= TRUE
; ret
&& what
!= NULL
; what
= setNextItem (operands
))
1448 ret
= port
->peep
.notUsed (what
, endPl
, head
);
1450 deleteSet(&operands
);
1455 /*-----------------------------------------------------------------*/
1456 /* notUsedFrom - Check, if values in registers are not read again */
1457 /* starting from label */
1458 /* Registers are checked from left to right */
1459 /*-----------------------------------------------------------------*/
1460 FBYNAME (notUsedFrom
)
1462 const char *what
, *label
;
1465 if (!port
->peep
.notUsedFrom
)
1467 fprintf (stderr
, "Function notUsedFrom not initialized in port structure\n");
1471 set
*operands
= setFromConditionArgs (cmdLine
, vars
);
1476 "*** internal error: notUsedFrom peephole restriction"
1477 " requires operand(s): %s\n", cmdLine
);
1480 if (elementsInSet(operands
) < 2)
1483 "*** internal error: notUsedFrom peephole restriction"
1484 " malformed: %s\n", cmdLine
);
1485 deleteSet(&operands
);
1489 operands
= reverseSet(operands
);
1491 label
= setFirstItem (operands
);
1492 what
= setNextItem (operands
);
1494 for (ret
= true; ret
&& what
; what
= setNextItem (operands
))
1495 ret
= port
->peep
.notUsedFrom (what
, label
, head
);
1497 deleteSet(&operands
);
1502 /*-----------------------------------------------------------------*/
1503 /* unusedReg - find first unused register from specified list and */
1504 /* assign to container specified as first argument. Fails if all */
1505 /* of specified registers are accessed for reading. */
1506 /*-----------------------------------------------------------------*/
1511 if (sscanf (cmdLine
, " %%%d%n", &dst
, &n
) != 1 || dst
<= 0)
1514 "*** internal error: unusedReg peephole restriction"
1515 " malformed: %s\n", cmdLine
);
1519 set
*operands
= setFromConditionArgs (&cmdLine
[n
], vars
);
1520 if (!operands
|| elementsInSet (operands
) < 2 || elementsInSet (operands
) > 3)
1523 "*** internal error: unusedReg peephole restriction"
1524 " malformed: %s\n", cmdLine
);
1528 char *what
= setFirstItem (operands
);
1529 for (; what
!= NULL
; what
= setNextItem (operands
))
1530 if (port
->peep
.notUsed (what
, endPl
, head
))
1533 bool ret
= (what
!= NULL
);
1536 char *s
[] = {what
, NULL
};
1537 bindVar (dst
, s
, &vars
);
1540 deleteSet (&operands
);
1545 /*-----------------------------------------------------------------*/
1546 /* canAssign - Check, if we can do ld dst, src. */
1547 /*-----------------------------------------------------------------*/
1551 const char *dst
, *src
, *exotic
;
1553 operands
= setFromConditionArgs (cmdLine
, vars
);
1555 if (!operands
|| elementsInSet(operands
) < 2 || elementsInSet(operands
) > 3)
1558 "*** internal error: canAssign peephole restriction"
1559 " malformed: %s\n", cmdLine
);
1563 if(elementsInSet(operands
) == 3)
1565 exotic
= setFirstItem (operands
);
1566 src
= setNextItem (operands
);
1567 dst
= setNextItem (operands
);
1572 src
= setFirstItem (operands
);
1573 dst
= setNextItem (operands
);
1576 if (port
->peep
.canAssign
)
1578 bool ret
= port
->peep
.canAssign (dst
, src
, exotic
);
1579 deleteSet (&operands
);
1583 deleteSet (&operands
);
1585 fprintf (stderr
, "Function canAssign not initialized in port structure\n");
1589 /*-----------------------------------------------------------------*/
1590 /* canJoinRegs - joins set of registers to combined one, returns */
1591 /* true, if result register is valid. First operand can be */
1592 /* 'unordered' if order of registers is not sufficient. Last */
1593 /* operand should be wildcard. If result is not required, then */
1594 /* wildcard should be %0. If some of source registers is not */
1595 /* sufficient then empty string can be passed. */
1596 /*-----------------------------------------------------------------*/
1597 FBYNAME (canJoinRegs
)
1599 // Must be specified at least 3 parameters: reg_hi reg_lo and dst
1600 // If destination is not required, then %0 should be specified
1601 if (!port
->peep
.canJoinRegs
)
1603 fprintf (stderr
, "Function canJoinRegs not supported by the port\n");
1609 for (i
= strlen (cmdLine
)-1; i
>= 0 && ISCHARSPACE (cmdLine
[i
]); --i
)
1611 for (; i
>= 0 && !ISCHARSPACE (cmdLine
[i
]); --i
)
1613 if (i
< 0 || cmdLine
[i
+1] != '%' || (cmdLine
[i
+1] && (sscanf (&cmdLine
[i
+2], "%d", &dstKey
) != 1 || dstKey
< 0)))
1616 "*** internal error: canJoinRegs peephole restriction"
1617 " has bad result container: %s\n", &cmdLine
[i
+1]);
1620 //parse cmd line without last operand
1622 set
*operands
= setFromConditionArgs (cmdLine
, vars
);
1625 if (operands
== NULL
)
1628 "*** internal error: canJoinRegs peephole restriction"
1629 " malformed: %s\n", cmdLine
);
1633 bool unordered
= false;
1634 const char *first
= setFirstItem (operands
);
1635 if (first
&& !strcmp (first
, "unordered"))
1638 deleteSetItem (&operands
, (void*)first
);
1641 int size
= elementsInSet (operands
);
1645 "*** internal error: canJoinRegs peephole restriction"
1646 " requires at least 3 operands: %s\n", cmdLine
);
1650 const char **regs
= (const char**) Safe_alloc ( (size
+ 1) * sizeof (*regs
));
1652 regs
[size
] = NULL
; /* end of registers */
1653 //fill regs reversing order (operands have reversed order)
1654 for (set
*it
= operands
; it
; it
= it
->next
)
1655 regs
[--i
] = (const char*)it
->item
;
1657 //if unordered specified, then sort elements by ascending order
1659 qsort (regs
, size
, sizeof (*regs
), (int (*)(const void*,const void*))&strcmp
);
1665 result
= port
->peep
.canJoinRegs (regs
, dst
);
1666 if (result
|| !unordered
)
1669 //do next registers permutation
1671 //find last regs[i] < regs[i+1]
1672 for (i
= size
-2; i
>= 0; --i
)
1673 if (strcmp (regs
[i
+1], regs
[i
]) > 0)
1676 break; /* was last permutation */
1679 //find last regs[j] > regs[i], where j > i
1680 for (j
= size
-1; j
> i
; --j
)
1681 if (strcmp (regs
[j
], regs
[i
]) > 0)
1684 //swap regs[j] and regs[i]
1685 const char *t
= regs
[i
];
1688 //reverse order from j+1 to end
1689 for (j
= j
+1, i
= size
- 1; j
< i
; ++j
, --i
)
1699 if (result
&& dstKey
> 0)
1701 char *s
[] = { dst
, NULL
};
1702 bindVar (dstKey
, s
, &vars
);
1705 deleteSet (&operands
);
1709 /*-----------------------------------------------------------------*/
1710 /* canSplitReg - returns true, if register can be splitted. First */
1711 /* operand contains complex register name and is required. Other */
1712 /* operands should be wildcards. If result is not sufficient then */
1713 /* they can be omited. */
1714 /*-----------------------------------------------------------------*/
1715 FBYNAME (canSplitReg
)
1717 if (!port
->peep
.canSplitReg
)
1719 fprintf (stderr
, "Function canSplitReg not supported by the port\n");
1724 //find start of first operand
1725 for (i
= 0; cmdLine
[i
] && ISCHARSPACE (cmdLine
[i
]); ++i
)
1727 if (cmdLine
[i
] == '\0')
1730 "*** internal error: canSplitReg peephole restriction"
1731 " malformed: %s\n", cmdLine
);
1735 //find end of first operand
1736 for (; cmdLine
[i
] && !ISCHARSPACE (cmdLine
[i
]); ++i
)
1739 //parse first operand
1740 char t
= cmdLine
[i
];
1742 set
*operands
= setFromConditionArgs (cmdLine
, vars
);
1744 if (cmdLine
[i
] == '\0')
1747 "*** internal error: canSplitReg peephole restriction"
1748 " malformed: %s\n", cmdLine
);
1752 //scan remaining operands
1754 int *varIds
= (int*)Safe_alloc (size
* sizeof(*varIds
));
1755 const char *cl
= &cmdLine
[i
+1];
1761 varIds
= (int*)Safe_realloc (varIds
, size
* sizeof(*varIds
));
1764 if (sscanf (cl
, " %%%d%n", &varIds
[i
], &len
) != 1)
1769 "*** internal error: canSplitReg peephole restriction"
1770 " has invalid destination container: %s\n", cmdLine
);
1777 dst
= Safe_alloc (size
* sizeof (*dst
));
1778 bool ret
= port
->peep
.canSplitReg ((char*)setFirstItem (operands
), dst
, size
);
1779 for (i
= 0; ret
&& i
< size
; ++i
)
1783 char *s
[] = { dst
[i
], NULL
};
1784 bindVar (varIds
[i
], s
, &vars
);
1788 deleteSet (&operands
);
1792 /*-----------------------------------------------------------------*/
1793 /* operandsNotRelated - returns true if the condition's operands */
1794 /* are not related (taking into account register name aliases). */
1795 /* N-way comparison performed between all operands. */
1796 /*-----------------------------------------------------------------*/
1797 FBYNAME (operandsNotRelated
)
1800 const char *op1
, *op2
;
1802 operands
= setFromConditionArgs (cmdLine
, vars
);
1807 "*** internal error: operandsNotRelated peephole restriction"
1808 " malformed: %s\n", cmdLine
);
1813 while ((op1
= setFirstItem (operands
)))
1815 deleteSetItem (&operands
, (void*)op1
);
1816 op1
= operandBaseName (op1
);
1818 for (op2
= setFirstItem (operands
); op2
; op2
= setNextItem (operands
))
1820 if ((strchr(op1
, '(') || strchr(op1
, '[')) && (strchr(op2
, '(') || strchr(op2
, '['))) // Might be the same or overlapping memory locations; err on the safe side.
1826 op2
= operandBaseName (op2
);
1827 if (strcmp (op1
, op2
) == 0)
1833 if (TARGET_IS_MCS51
|| TARGET_IS_DS390
|| TARGET_IS_DS400
)
1835 /* handle overlapping 'dptr' vs. { 'dpl', 'dph' } */
1836 if (!strcmp (op1
, "dptr") && (!strcmp (op2
, "dpl") || !strcmp (op2
, "dph")) ||
1837 !strcmp (op2
, "dptr") && (!strcmp (op1
, "dpl") || !strcmp (op1
, "dph")) ||
1838 !strcmp (op1
, "ab") && (!strcmp (op2
, "a") || !strcmp (op2
, "b")) ||
1839 !strcmp (op2
, "ab") && (!strcmp (op1
, "a") || !strcmp (op1
, "b")))
1849 deleteSet (&operands
);
1853 /*-----------------------------------------------------------------*/
1854 /* notSimilar - Check, if one is another's substring */
1855 /*-----------------------------------------------------------------*/
1856 FBYNAME (notSimilar
)
1859 const char *op1
, *op2
;
1861 operands
= setFromConditionArgs (cmdLine
, vars
);
1866 "*** internal error: notSimilar peephole restriction"
1867 " malformed: %s\n", cmdLine
);
1871 while ((op1
= setFirstItem (operands
)))
1873 deleteSetItem (&operands
, (void*)op1
);
1875 for (op2
= setFirstItem (operands
); op2
; op2
= setNextItem (operands
))
1877 if (strstr (op1
, op2
) || strstr (op2
, op1
))
1879 deleteSet (&operands
);
1885 deleteSet (&operands
);
1889 /*-----------------------------------------------------------------*/
1890 /* symmParmStack - Caller readjusts stack by the number of bytes
1891 that were pushed in all calls to this function */
1892 /*-----------------------------------------------------------------*/
1893 FBYNAME (symmParmStack
)
1895 set
*operands
= setFromConditionArgs (cmdLine
, vars
);
1900 "*** internal error: symmParmStack peephole restriction"
1901 " requires operand: %s\n", cmdLine
);
1905 const char *name
= setFirstItem (operands
);
1909 if (port
->peep
.symmParmStack
)
1910 return port
->peep
.symmParmStack (name
);
1911 deleteSet(&operands
);
1916 /*-----------------------------------------------------------------*/
1917 /* notSame - Check, that arguments are pairwise not the same */
1918 /*-----------------------------------------------------------------*/
1922 const char *op1
, *op2
;
1924 operands
= setFromConditionArgs (cmdLine
, vars
);
1929 "*** internal error: notSame peephole restriction"
1930 " malformed: %s\n", cmdLine
);
1934 while ((op1
= setFirstItem (operands
)))
1936 deleteSetItem (&operands
, (void*)op1
);
1938 for (op2
= setFirstItem (operands
); op2
; op2
= setNextItem (operands
))
1940 if (strcmp (op1
, op2
) == 0)
1942 deleteSet (&operands
);
1948 deleteSet (&operands
);
1952 /*-----------------------------------------------------------------*/
1953 /* same - Check if first operand matches any of the remaining */
1954 /*-----------------------------------------------------------------*/
1958 const char *match
, *op
;
1960 operands
= setFromConditionArgs(cmdLine
, vars
);
1965 "*** internal error: same peephole restriction"
1966 " malformed: %s\n", cmdLine
);
1970 operands
= reverseSet(operands
);
1972 match
= setFirstItem(operands
);
1973 for (op
= setNextItem(operands
); op
; op
= setNextItem(operands
))
1975 if (strcmp(match
, op
) == 0)
1977 deleteSet(&operands
);
1982 deleteSet(&operands
);
1986 /*-----------------------------------------------------------------*/
1987 /* strIsSymbol - returns true if the parameter is a symbol */
1988 /* That is: an underscore followed by one or more chars */
1989 /*-----------------------------------------------------------------*/
1991 strIsSymbol(const char *str
)
1993 return *str
== '_' && str
[1] != '\0';
1996 /*-----------------------------------------------------------------*/
1997 /* strIsLiteral - returns true if the parameter is a literal */
1998 /* Checks these formats: binary, octal, decimal, hexadecimal */
1999 /* Skips preceding signs. */
2000 /*-----------------------------------------------------------------*/
2002 strIsLiteral(const char *str
)
2004 const char digits
[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
2005 unsigned char base
= 10;
2006 unsigned char validDigits
= 0;
2008 // has to start with a number or a sign
2009 if(!isdigit( (unsigned char)(*str
) ) && (*str
) != '-' && (*str
) != '+')
2012 if ((*str
) == '-' || (*str
) == '+')
2015 // handle 0b 0o 0d 0x
2018 const char nextChar
= tolower((unsigned char)(str
[1]));
2020 if (nextChar
== 'b')
2025 else if(nextChar
== 'o')
2030 else if(nextChar
== 'd')
2035 else if(nextChar
== 'x')
2041 validDigits
= 1; // the first '0' is a valid digit
2046 while((unsigned char)(*str
) != '\0'){
2048 for(i
= 0; i
< base
; ++i
){
2049 if(tolower((unsigned char)(*str
)) == digits
[i
])
2052 // number was too big or not valid
2058 return validDigits
> 0;
2061 /*-----------------------------------------------------------------*/
2062 /* operandsLiteral - returns true if the condition's operands are */
2064 /*-----------------------------------------------------------------*/
2065 FBYNAME (operandsLiteral
)
2067 set
*operands
= setFromConditionArgs (cmdLine
, vars
);
2073 "*** internal error: operandsLiteral peephole restriction"
2074 " malformed: %s\n", cmdLine
);
2078 for (op
= setFirstItem (operands
); op
; op
= setNextItem (operands
))
2080 if (!strIsLiteral(op
))
2082 deleteSet (&operands
);
2087 deleteSet (&operands
);
2091 /*-----------------------------------------------------------------*/
2092 /* strIsLiteralOrSymbol - returns true if the parameter is a */
2093 /* literal or compiler symbol */
2094 /*-----------------------------------------------------------------*/
2096 strIsLiteralOrSymbol(const char *str
)
2098 return strIsSymbol(str
) || strIsLiteral(str
);
2101 /*-----------------------------------------------------------------*/
2102 /* operandsLitOrSym - returns true if the condition's operands are */
2103 /* literals or compiler symbols. */
2104 /*-----------------------------------------------------------------*/
2105 FBYNAME (operandsLitOrSym
)
2110 operands
= setFromConditionArgs (cmdLine
, vars
);
2115 "*** internal error: operandsLitOrSym peephole restriction"
2116 " malformed: %s\n", cmdLine
);
2120 for (op
= setFirstItem (operands
); op
; op
= setNextItem (operands
))
2122 if (!strIsLiteralOrSymbol(op
))
2124 deleteSet (&operands
);
2129 deleteSet (&operands
);
2133 /*-----------------------------------------------------------------*/
2134 /* removeParentheses */
2135 /* First operand: parameter to be parsed */
2136 /* Second operand: result of conversion */
2137 /* The function removes the input parameter parentheses if present,*/
2138 /* else it copies the input directly to the output. */
2139 /* returns true if the input has not parentheses. */
2140 /* returns true if it has parametheses at first and last chars */
2141 /* and there was no other error */
2142 /*-----------------------------------------------------------------*/
2143 FBYNAME (removeParentheses
)
2148 // Find space previous to last operand
2149 for (i
= strlen (cmdLine
)-1; i
>= 0 && ISCHARSPACE (cmdLine
[i
]); --i
)
2151 for (; i
>= 0 && !ISCHARSPACE (cmdLine
[i
]); --i
)
2153 if (i
< 0 || cmdLine
[i
+1] != '%' || (cmdLine
[i
+1] && (sscanf (&cmdLine
[i
+2], "%d", &dstKey
) != 1 || dstKey
< 0)))
2156 "*** internal error: removeParentheses peephole restriction"
2157 " has bad result container: %s\n", &cmdLine
[i
+1]);
2160 //Parse cmd line without last operand
2162 set
*operands
= setFromConditionArgs (cmdLine
, vars
);
2163 cmdLine
[i
] = ' '; // Restore space
2165 if (!operands
|| elementsInSet(operands
) > 1)
2168 "*** internal error: removeParentheses peephole restriction"
2169 " malformed: %s\n", cmdLine
);
2173 // Parse the operand and remove the parenthesis
2175 const char *op
= setFirstItem (operands
);
2179 if(op
[strlen(op
)-1] == ')')
2180 op
++; // Skip start parenthesis
2183 // Abort if no matching closing parenthesis
2184 deleteSet (&operands
);
2188 if (strlen(op
) > 127) // Abort if string does not fit in buffer
2190 deleteSet (&operands
);
2194 // Do the copy and skip ending parenthesis
2210 // Abort if remaining chars in source or no chars copied into result string
2211 if ((*op
) || (i
== 0))
2213 deleteSet (&operands
);
2217 char *p
[] = {r
, NULL
};
2218 bindVar (dstKey
, p
, &vars
);
2220 deleteSet (&operands
);
2225 immdGet (const char *pc
, long *pl
)
2233 for (; ISCHARSPACE (*pc
); pc
++);
2235 for (; !ISCHARDIGIT (*pc
); pc
++)
2238 else if (*pc
== '+')
2243 if (pc
[0] == '0' && (pc
[1] == 'x' || pc
[1] == 'X'))
2245 if (sscanf (pc
+ 2, "%lx", pl
) != 1)
2250 if (sscanf (pc
, "%ld", pl
) != 1)
2259 immdError (const char *info
, const char *param
, const char *cmd
)
2261 fprintf (stderr
, "*** internal error: immdInRange gets "
2262 "%s: \"%s\" in \"%s\"\n", info
, param
, cmd
);
2266 /*-----------------------------------------------------------------*/
2267 /* isPowerOfTwo - true if n is a power of 2 */
2268 /*-----------------------------------------------------------------*/
2270 isPowerOfTwo(unsigned long n
)
2272 return (n
!= 0) && ((n
& (n
- 1)) == 0);
2275 /*-----------------------------------------------------------------*/
2276 /* findBitPosition - Returns the bit position set or cleared in n */
2278 /* n: value to be tested. */
2279 /* bits: number of positions to test. */
2280 /* complement: when true, the number must be bitwise complemented */
2282 /* -2 if bits is out of valid range (1..32) */
2283 /* -1 if n has more than one bit set or cleared */
2284 /* -1 if n has bits in positions over the bits param */
2285 /* bit position (starting at 0) when only 1 bit set or clear */
2287 /* n=0x02, bits=8, complemented=false -> 1 */
2288 /* n=0x7F, bits=8, complemented=true -> 7 */
2289 /*-----------------------------------------------------------------*/
2291 findBitPosition(unsigned long n
, unsigned long bits
, bool complement
)
2296 if ((bits
< 1) || (bits
> 32)) //bits out of range?
2298 mask
= (1ULL << bits
) -1;
2299 if (n
!= (n
& mask
)) // bits outside mask?
2304 if (!isPowerOfTwo (n
)) // Not valid if more than one bit is set
2308 // One by one move the only set bit to right till it reaches end
2312 bitPos
++; //count number of shifts
2318 /*-----------------------------------------------------------------*/
2319 /* swapOperation - Calculates a swap operation with given params */
2321 /* n: value to be swapped. */
2322 /* bits: length of value to be swapped, in bits. */
2323 /* Returns 0 if no error: */
2324 /* -2 if bits is out of valid range: even numbers (2..32) */
2325 /* -1 if n has bits in positions over the bits param */
2326 /*-----------------------------------------------------------------*/
2328 swapOperation (unsigned long n
, unsigned long bits
, unsigned long * result
)
2330 unsigned long mask
= (1ULL << bits
) -1;
2331 unsigned int shift
= bits
/ 2;
2333 if ((bits
< 1) || (bits
> 32) || (bits
& 0x01)) // bits out of range or odd
2335 if (n
!= (n
& mask
)) // bits outside mask?
2338 *result
= (((n
<< shift
) | (n
>> shift
)) & mask
);
2339 return 0; // no error.
2342 /*-----------------------------------------------------------------*/
2343 /* stringMatchesOperator - returns true if 'str' matches 'op' */
2344 /* 'str' matches 'op' if they contain the same string */
2345 /* 'str' also matches if surrounded by quotes or double quotes */
2346 /*-----------------------------------------------------------------*/
2348 stringMatchesOperator (const char * str
, const char *op
)
2352 if (strcmp(str
, op
) == 0)
2358 size_t length
= strlen(str
);
2359 // Check if quotes are present and they are the same at start and end.
2360 if ((length
>= 2) && ((str
[0] == '\'') || (str
[0] == '\"')) && (str
[0] == str
[length
-1]))
2361 return strncmp(&str
[1], op
, length
-2) == 0;
2366 /*-----------------------------------------------------------------*/
2367 /* immdInRange - returns true if the result of a given operation */
2368 /* of two immediates is in a give range. */
2369 /*-----------------------------------------------------------------*/
2370 FBYNAME (immdInRange
)
2372 char r
[64], operator[24];
2374 long i
, j
, k
, h
, low
, high
, left_l
, right_l
, order
;
2376 for (i
= order
= 0; order
< 6;)
2378 // pick up one parameter in the temp buffer r[64]
2379 for (; ISCHARSPACE (cmdLine
[i
]) && cmdLine
[i
]; i
++);
2380 for (j
= i
; !ISCHARSPACE (cmdLine
[j
]) && cmdLine
[j
]; j
++);
2381 if (!cmdLine
[i
]) // unexpected end
2382 return immdError ("no enough input", "", cmdLine
);
2384 return immdError ("buffer overflow", "", cmdLine
);
2387 for (k
= i
; k
< j
; k
++)
2388 r
[k
- i
] = cmdLine
[k
];
2391 // parse the string by order
2394 case 0: // lower bound
2395 if (!immdGet (r
, &low
))
2396 return immdError ("bad lower bound", r
, cmdLine
);
2398 case 1: // upper bound
2399 if (!immdGet (r
, &high
))
2400 return immdError ("bad upper bound", r
, cmdLine
);
2403 if (sscanf (r
, "%23s", operator) != 1)
2404 return immdError ("bad operator", r
, cmdLine
);
2406 case 3: // left operand
2407 if (immdGet (r
, &left_l
)) // the left operand is given directly
2410 else if (r
[0] == '%') // the left operand is passed via pattern match
2412 if (!immdGet (r
+ 1, &k
) || !(op
= hTabItemWithKey (vars
, (int) k
)))
2413 return immdError ("bad left operand", r
, cmdLine
);
2414 else if (!immdGet (op
, &left_l
))
2418 return immdError ("bad left operand", r
, cmdLine
);
2420 case 4: // right operand
2421 if (immdGet (r
, &right_l
)) // the right operand is given directly
2424 else if (r
[0] == '%') // the right operand is passed via pattern match
2426 if (!immdGet (r
+ 1, &k
) || !(op
= hTabItemWithKey (vars
, (int) k
)))
2427 return immdError ("bad right operand", r
, cmdLine
);
2428 else if (!immdGet (op
, &right_l
))
2429 return immdError ("bad right operand", op
, r
);
2432 return immdError ("bad right operand", r
, cmdLine
);
2435 if (r
[0] != '%' || !(immdGet (r
+ 1, &h
) || (r
[1] == 'x' && immdGet (r
+ 2, &h
))))
2436 return immdError ("bad result container", r
, cmdLine
);
2438 default: // should not reach
2439 return immdError ("unexpected input", "", cmdLine
);
2447 if (stringMatchesOperator (operator, "+")) // add
2449 i
= left_l
+ right_l
;
2451 else if (stringMatchesOperator (operator, "-")) // sub
2453 i
= left_l
- right_l
;
2455 else if (stringMatchesOperator (operator, "*")) // mul
2457 i
= left_l
* right_l
;
2459 else if (stringMatchesOperator (operator, "/")) // div
2462 return immdError ("division by zero", "", cmdLine
);
2463 i
= left_l
/ right_l
;
2465 else if (stringMatchesOperator (operator, "%")) // mod
2468 return immdError ("division by zero", "", cmdLine
);
2469 i
= left_l
% right_l
;
2471 else if (stringMatchesOperator (operator, "&")) // and
2473 i
= left_l
& right_l
;
2475 else if (stringMatchesOperator (operator, "^")) // xor
2477 i
= left_l
^ right_l
;
2479 else if (stringMatchesOperator (operator, "|")) // or
2481 i
= left_l
| right_l
;
2483 else if (stringMatchesOperator (operator, "singleSetBit") || stringMatchesOperator (operator, "singleResetBit")) // singleSetBit - singleResetBit
2485 i
= findBitPosition(left_l
, right_l
, stringMatchesOperator (operator, "singleResetBit"));
2487 return immdError ("bad right operand", operator, cmdLine
);
2491 else if (stringMatchesOperator (operator, "swap")) // swap
2493 if (swapOperation(left_l
, right_l
, (unsigned long *)&i
) != 0)
2494 return immdError ("bad right operand", operator, cmdLine
);
2497 return immdError ("bad operator", operator, cmdLine
);
2500 if ((low
<= i
&& i
<= high
) || (high
<= i
&& i
<= low
))
2507 char *p
[] = {r
, NULL
};
2509 sprintf (r
, "%ld", i
);
2511 sprintf (r
, "0x%lx", i
);
2512 bindVar ((int) h
, p
, &vars
);
2521 /*-----------------------------------------------------------------*/
2522 /* inSequence - Check that numerical constants are in sequence */
2523 /*-----------------------------------------------------------------*/
2524 FBYNAME (inSequence
)
2528 long seq
, val
, stride
;
2530 if ((operands
= setFromConditionArgs(cmdLine
, vars
)) == NULL
)
2533 "*** internal error: inSequence peephole restriction"
2534 " malformed: %s\n", cmdLine
);
2538 operands
= reverseSet(operands
);
2540 op
= setFirstItem(operands
);
2541 if ((immdGet(op
, &stride
) == NULL
) || ((op
= setNextItem(operands
)) == NULL
))
2544 "*** internal error: inSequence peephole restriction"
2545 " malformed: %s\n", cmdLine
);
2549 for (seq
= LONG_MIN
; op
; op
= setNextItem(operands
))
2551 if ((immdGet(op
, &val
) == NULL
) || ((seq
!= LONG_MIN
) && (val
!= seq
+stride
)))
2553 deleteSet(&operands
);
2559 deleteSet(&operands
);
2563 /*-----------------------------------------------------------------*/
2564 /* isPort - return true if port name matches one of args */
2565 /*-----------------------------------------------------------------*/
2571 set
*operands
= setFromConditionArgs(cmdLine
, vars
);
2576 "*** internal error: isPort peephole restriction"
2577 " malformed: %s\n", cmdLine
);
2581 while (name
= setFirstItem(operands
))
2583 deleteSetItem(&operands
, (void *)name
);
2585 if (strcmp(port
->target
, name
) == 0)
2592 deleteSet(&operands
);
2597 /*-----------------------------------------------------------------*/
2598 /* notInJumpTable - check that we are not in a jump table */
2599 /*-----------------------------------------------------------------*/
2600 FBYNAME (notInJumpTable
)
2602 return (currPl
->ic
&& currPl
->ic
->op
!= JUMPTABLE
);
2605 static const struct ftab
2608 int (*func
) (hTab
*, lineNode
*, lineNode
*, lineNode
*, char *);
2610 ftab
[] = // sorted on the number of times used
2611 { // in the peephole rules on 2010-06-12
2613 "labelRefCount", labelRefCount
// 161
2616 "notVolatile", notVolatile
// 118
2619 "notUsed", notUsed
// 96
2622 "labelRefCountChange", labelRefCountChange
// 86
2625 "labelInRange", labelInRange
// 51
2628 "notSame", notSame
// 28
2631 "operandsNotRelated", operandsNotRelated
// 28
2634 "same", same
// z88dk z80
2637 "labelJTInRange", labelJTInRange
// 13
2640 "24bitMode", flat24bitMode
// 9
2643 "canAssign", canAssign
// 8
2646 "inSequence", inSequence
// z88dk z80
2649 "optimizeFor", optimizeFor
2652 "optimizeReturn", optimizeReturn
// ? just a guess
2655 "notUsedFrom", notUsedFrom
// ? just a guess
2658 "labelIsReturnOnly", labelIsReturnOnly
// 6
2661 "operandsLiteral", operandsLiteral
// 6
2664 "operandsLitOrSym", operandsLitOrSym
2667 "removeParentheses", removeParentheses
2670 "labelIsUncondJump", labelIsUncondJump
// 4
2673 "deadMove", deadMove
// 2
2676 "useAcallAjmp", useAcallAjmp
// 2
2679 "xramMovcOption", xramMovcOption
// 2
2682 "okToRemoveSLOC", okToRemoveSLOC
// 0
2685 "immdInRange", immdInRange
2688 "notSimilar", notSimilar
2691 "symmParmStack", symmParmStack
2697 "canJoinRegs", canJoinRegs
2700 "canSplitReg", canSplitReg
2703 "unusedReg", unusedReg
2706 "newLabel", newLabel
2709 "notInJumpTable", notInJumpTable
2713 /*-----------------------------------------------------------------*/
2714 /* callFuncByName - calls a function as defined in the table */
2715 /*-----------------------------------------------------------------*/
2717 callFuncByName (char *fname
,
2719 lineNode
*currPl
, /* first source line matched */
2720 lineNode
*endPl
, /* last source line matched */
2724 char *cmdCopy
, *funcName
, *funcArgs
, *cmdTerm
;
2728 /* Isolate the function name part (we are passed the full condition
2729 * string including arguments)
2731 cmdTerm
= cmdCopy
= Safe_strdup(fname
);
2735 funcArgs
= funcName
= cmdTerm
;
2736 while ((c
= *funcArgs
) && c
!= ' ' && c
!= '\t' && c
!= '(')
2738 *funcArgs
= '\0'; /* terminate the function name */
2742 /* Find the start of the arguments */
2743 if (c
== ' ' || c
== '\t')
2744 while ((c
= *funcArgs
) && (c
== ' ' || c
== '\t'))
2747 /* If the arguments started with an opening parenthesis, */
2748 /* use the closing parenthesis for the end of the */
2749 /* arguments and look for the start of another condition */
2750 /* that can optionally follow. If there was no opening */
2751 /* parethesis, then everything that follows are arguments */
2752 /* and there can be no additional conditions. */
2756 int num_parenthesis
= 0;
2759 while ((c
= *cmdTerm
) && (c
!= ')' || num_parenthesis
))
2767 *cmdTerm
= '\0'; /* terminate the arguments */
2771 while ((c
= *cmdTerm
) && (c
== ' ' || c
== '\t' || c
== ','))
2777 cmdTerm
= NULL
; /* closing parenthesis missing */
2786 for (i
= 0; i
< ((sizeof (ftab
)) / (sizeof (struct ftab
))); i
++)
2788 if (strcmp (ftab
[i
].fname
, funcName
) == 0)
2790 rc
= (*ftab
[i
].func
) (vars
, currPl
, endPl
, head
, funcArgs
);
2798 "could not find named function \"%s\" in "
2799 "peephole function table\n",
2801 // If the function couldn't be found, let's assume it's
2802 // a bad rule and refuse it.
2807 while (rc
&& cmdTerm
);
2814 /*-----------------------------------------------------------------*/
2815 /* newPeepRule - creates a new peeprule and attach it to the root */
2816 /*-----------------------------------------------------------------*/
2818 newPeepRule (lineNode
* match
,
2826 pr
= Safe_alloc ( sizeof (peepRule
));
2828 pr
->replace
= replace
;
2829 pr
->restart
= restart
;
2830 pr
->barrier
= barrier
;
2834 pr
->cond
= Safe_strdup (cond
);
2839 pr
->vars
= newHashTable (16);
2841 /* if root is empty */
2843 rootRules
= currRule
= pr
;
2845 currRule
= currRule
->next
= pr
;
2850 #define SKIP_SPACE(x,y) { while (*x && (ISCHARSPACE(*x) || *x == '\n')) x++; \
2851 if (!*x) { fprintf(stderr,y); return ; } }
2853 #define EXPECT_STR(x,y,z) { while (*x && strncmp(x,y,strlen(y))) x++ ; \
2854 if (!*x) { fprintf(stderr,z); return ; } }
2855 #define EXPECT_CHR(x,y,z) { while (*x && *x != y) x++ ; \
2856 if (!*x) { fprintf(stderr,z); return ; } }
2858 /*-----------------------------------------------------------------*/
2859 /* getPeepLine - parses the peep lines */
2860 /*-----------------------------------------------------------------*/
2862 getPeepLine (lineNode
** head
, const char **bpp
)
2864 char lines
[MAX_PATTERN_LEN
];
2868 lineNode
*currL
= NULL
;
2869 const char *bp
= *bpp
;
2875 fprintf (stderr
, "unexpected end of match pattern\n");
2882 while (ISCHARSPACE (*bp
) ||
2893 /* read till end of line */
2895 while ((*bp
!= '\n' && *bp
!= '}') && *bp
)
2900 while (*lp
&& ISCHARSPACE(*lp
))
2902 isComment
= (*lp
== ';');
2904 if (!isComment
|| (isComment
&& !options
.noPeepComments
))
2910 *head
= currL
= newLineNode (lines
);
2912 currL
= connectLine (currL
, newLineNode (lines
));
2913 currL
->isComment
= isComment
;
2914 currL
->isLabel
= isLabelDefinition (currL
->line
, &dummy1
, &dummy2
,
2923 /*-----------------------------------------------------------------*/
2924 /* readRules - reads the rules from a string buffer */
2925 /*-----------------------------------------------------------------*/
2927 readRules (const char *bp
)
2929 char restart
= 0, barrier
= 0;
2930 char lines
[MAX_PATTERN_LEN
];
2931 size_t safetycounter
;
2936 lineNode
*currL
= NULL
;
2944 /* look for the token "replace" that is the
2946 while (*bp
&& strncmp (bp
, "replace", 7))
2948 if (!strncmp (bp
, "barrier", 7))
2957 /* then look for either "restart" or '{' */
2958 while (strncmp (bp
, "restart", 7) && *bp
!= '{' && bp
)
2964 fprintf (stderr
, "expected 'restart' or '{'\n");
2972 { /* must be restart */
2974 bp
+= strlen ("restart");
2976 EXPECT_CHR (bp
, '{', "expected '{'\n");
2980 /* skip thru all the blank space */
2981 SKIP_SPACE (bp
, "unexpected end of rule\n");
2983 match
= replace
= currL
= NULL
;
2984 /* we are the start of a rule */
2985 getPeepLine (&match
, &bp
);
2987 /* now look for by */
2988 EXPECT_STR (bp
, "by", "expected 'by'\n");
2990 /* then look for a '{' */
2991 EXPECT_CHR (bp
, '{', "expected '{'\n");
2994 /* save char position (needed for generating error msg) */
2997 SKIP_SPACE (bp
, "unexpected end of rule\n");
2998 getPeepLine (&replace
, &bp
);
3000 /* look for a 'if' */
3001 while ((ISCHARSPACE (*bp
) || *bp
== '\n' || (*bp
== '/' && *(bp
+1) == '/')) && *bp
)
3004 if (*bp
== '/') while (*bp
&& *bp
!= '\n') ++bp
;
3007 if (strncmp (bp
, "if", 2) == 0)
3010 while ((ISCHARSPACE (*bp
) || *bp
== '\n' || (*bp
== '/' && *(bp
+1) == '/')) && *bp
)
3014 while (*bp
&& *bp
!= '\n')
3019 fprintf (stderr
, "expected condition name\n");
3023 /* look for the condition */
3025 for (safetycounter
= 0; *bp
&& (*bp
!= '\n'); safetycounter
++)
3027 wassertl(safetycounter
< MAX_PATTERN_LEN
, "Peephole line too long.\n");
3032 newPeepRule (match
, replace
, lines
, restart
, barrier
);
3036 if (*bp
&& strncmp (bp
, "replace", 7) && strncmp (bp
, "barrier", 7))
3038 /* not the start of a new peeprule, so "if" should be here */
3043 /* go to the start of the line following "{" of the "by" token */
3044 while (*rp
&& (*rp
== '\n'))
3047 /* copy text of rule starting with line after "by {" */
3049 while (*rp
&& (rp
< bp
) && ((cp
- strbuff
) < sizeof(strbuff
)))
3052 /* and now the rest of the line */
3053 while (*rp
&& (*rp
!= '\n') && ((cp
- strbuff
) < sizeof(strbuff
)))
3057 fprintf (stderr
, "%s\nexpected '} if ...'\n", strbuff
);
3060 newPeepRule (match
, replace
, NULL
, restart
, barrier
);
3066 /*-----------------------------------------------------------------*/
3067 /* keyForVar - returns the numeric key for a var */
3068 /*-----------------------------------------------------------------*/
3070 keyForVar (const char *d
)
3074 while (ISCHARDIGIT (*d
))
3083 /*-----------------------------------------------------------------*/
3084 /* bindVar - binds a value to a variable in the given hashtable */
3085 /*-----------------------------------------------------------------*/
3087 bindVar (int key
, char **s
, hTab
** vtab
)
3089 char vval
[MAX_PATTERN_LEN
];
3093 /* first get the value of the variable */
3095 /* the value is ended by a ',' or space or newline or null or ) */
3098 !ISCHARSPACE (*vvx
) &&
3105 /* if we find a '(' then we need to balance it */
3117 // include the trailing ')'
3126 vvx
= traceAlloc (&_G
.values
, Safe_strdup(vval
));
3128 hTabAddItem (vtab
, key
, vvx
);
3131 /*-----------------------------------------------------------------*/
3132 /* matchLine - matches one line */
3133 /*-----------------------------------------------------------------*/
3135 matchLine (char *s
, const char *d
, hTab
** vars
)
3140 /* skip leading white spaces */
3141 while (ISCHARSPACE (*s
))
3143 while (ISCHARSPACE (*d
))
3148 /* skip white space in both */
3149 while (ISCHARSPACE(*s
))
3153 while (ISCHARSPACE(*d
))
3156 /* if the destination is a var */
3157 if (*d
== '%' && ISCHARDIGIT (*(d
+ 1)) && vars
)
3159 const char *v
= hTabItemWithKey (*vars
, keyForVar (d
+ 1));
3160 /* if the variable is already bound
3161 then it MUST match with dest */
3169 /* variable not bound we need to bind it */
3170 bindVar (keyForVar (d
+ 1), &s
, vars
);
3172 /* in either case go past the variable */
3174 while (ISCHARDIGIT (*d
))
3177 else if (*s
== ',' && *d
== ',') /* Allow comma to match comma */
3181 else if (*s
&& *d
) /* they should be an exact match otherwise */
3188 /* skip trailing whitespaces */
3190 while (ISCHARSPACE (*s
))
3193 /* skip trailing comments as well*/
3199 while (ISCHARSPACE (*d
))
3202 /* after all this if only one of them
3203 has something left over then no match */
3210 /*-----------------------------------------------------------------*/
3211 /* matchRule - matches a all the rule lines */
3212 /*-----------------------------------------------------------------*/
3214 matchRule (lineNode
* pl
,
3219 lineNode
*spl
; /* source pl */
3220 lineNode
*rpl
; /* rule peep line */
3222 /* setToNull((void *) &pr->vars); */
3223 /* pr->vars = newHashTable(100); */
3225 /* for all the lines defined in the rule */
3231 /* if the source line starts with a ';' then
3232 comment line don't process or the source line
3233 contains == . debugger information skip it */
3235 (*spl
->line
== ';' || spl
->isDebug
))
3241 if (!matchLine (spl
->line
, rpl
->line
, &pr
->vars
))
3249 /* if rules ended */
3252 /* if this rule has additional conditions */
3255 /* constraints which uses variables as destination container
3256 requires to vars table to be defined */
3258 pr
->vars
= newHashTable (128);
3260 if (callFuncByName (pr
->cond
, pr
->vars
, pl
, spl
, head
))
3279 reassociate_ic_down (lineNode
*shead
, lineNode
*stail
,
3280 lineNode
*rhead
, lineNode
*rtail
)
3282 lineNode
*csl
; /* current source line */
3283 lineNode
*crl
; /* current replacement line */
3289 /* skip over any comments */
3290 while (csl
!=stail
->next
&& csl
->isComment
)
3292 while (crl
!=rtail
->next
&& crl
->isComment
)
3295 /* quit if we reach the end */
3296 if ((csl
==stail
->next
) || (crl
==rtail
->next
) || crl
->ic
)
3299 if (matchLine(csl
->line
,crl
->line
,NULL
))
3311 reassociate_ic_up (lineNode
*shead
, lineNode
*stail
,
3312 lineNode
*rhead
, lineNode
*rtail
)
3314 lineNode
*csl
; /* current source line */
3315 lineNode
*crl
; /* current replacement line */
3321 /* skip over any comments */
3322 while (csl
!=shead
->prev
&& csl
->isComment
)
3324 while (crl
!=rhead
->prev
&& crl
->isComment
)
3327 /* quit if we reach the end */
3328 if ((csl
==shead
->prev
) || (crl
==rhead
->prev
) || crl
->ic
)
3331 if (matchLine(csl
->line
,crl
->line
,NULL
))
3342 /*------------------------------------------------------------------*/
3343 /* reassociate_ic - reassociate replacement lines with origin iCode */
3344 /*------------------------------------------------------------------*/
3346 reassociate_ic (lineNode
*shead
, lineNode
*stail
,
3347 lineNode
*rhead
, lineNode
*rtail
)
3349 lineNode
*csl
; /* current source line */
3350 lineNode
*crl
; /* current replacement line */
3354 /* Check to see if all the source lines (excluding comments) came
3355 ** for the same iCode
3358 for (csl
=shead
;csl
!=stail
->next
;csl
=csl
->next
)
3359 if (csl
->ic
&& !csl
->isComment
)
3364 single_iCode
= (ic
!=NULL
);
3365 for (csl
=shead
;csl
!=stail
->next
;csl
=csl
->next
)
3366 if ((csl
->ic
!= ic
) && !csl
->isComment
)
3368 /* More than one iCode was found. However, if it's just the
3369 ** last line with the different iCode and it was not changed
3370 ** in the replacement, everything else must be the first iCode.
3372 if ((csl
==stail
) && matchLine (stail
->line
, rtail
->line
, NULL
))
3374 rtail
->ic
= stail
->ic
;
3375 for (crl
=rhead
;crl
!=rtail
;crl
=crl
->next
)
3380 single_iCode
= FALSE
;
3384 /* If all of the source lines came from the same iCode, then so have
3385 ** all of the replacement lines too.
3389 for (crl
=rhead
;crl
!=rtail
->next
;crl
=crl
->next
)
3394 /* The source lines span iCodes, so we may end up with replacement
3395 ** lines that we don't know which iCode(s) to associate with. Do the
3396 ** best we can by using the following strategies:
3397 ** 1) Start at the top and scan down. As long as the source line
3398 ** matches the replacement line, they have the same iCode.
3399 ** 2) Start at the bottom and scan up. As long as the source line
3400 ** matches the replacement line, they have the same iCode.
3401 ** 3) For any label in the source, look for a matching label in
3402 ** the replacement. If found, they have the same iCode. From
3403 ** these matching labels, scan down for additional matching
3404 ** lines; if found, they also have the same iCode.
3407 /* Strategy #1: Start at the top and scan down for matches
3409 reassociate_ic_down(shead
,stail
,rhead
,rtail
);
3411 /* Strategy #2: Start at the bottom and scan up for matches
3413 reassociate_ic_up(shead
,stail
,rhead
,rtail
);
3415 /* Strategy #3: Try to match labels
3420 /* skip over any comments */
3421 while (csl
!=stail
->next
&& csl
->isComment
)
3423 if (csl
==stail
->next
)
3428 /* found a source line label; look for it in the replacement lines */
3432 while (crl
!=rtail
->next
&& crl
->isComment
)
3434 if (crl
==rtail
->next
)
3436 if (matchLine(csl
->line
, crl
->line
, NULL
))
3438 reassociate_ic_down(csl
,stail
,crl
,rtail
);
3448 /* Try to assign a meaningful iCode to any comment that is missing
3449 one. Since they are comments, it's ok to make mistakes; we are just
3450 trying to improve continuity to simplify other tests.
3453 for (crl
=rtail
;crl
!=rhead
->prev
;crl
=crl
->prev
)
3455 if (!crl
->ic
&& ic
&& crl
->isComment
)
3462 /*-----------------------------------------------------------------*/
3463 /* replaceRule - does replacement of a matching pattern */
3464 /*-----------------------------------------------------------------*/
3466 replaceRule (lineNode
**shead
, lineNode
*stail
, const peepRule
*pr
)
3468 lineNode
*cl
= NULL
;
3469 lineNode
*pl
= NULL
, *lhead
= NULL
;
3470 /* a long function name and long variable name can evaluate to
3471 4x max pattern length e.g. "mov dptr,((fie_var>>8)<<8)+fie_var" */
3472 char lb
[MAX_PATTERN_LEN
*4];
3474 lineNode
*comment
= NULL
;
3476 /* collect all the comment lines in the source */
3477 for (cl
= *shead
; cl
!= stail
; cl
= cl
->next
)
3479 if (cl
->line
&& (*cl
->line
== ';' || cl
->isDebug
))
3481 pl
= (pl
? connectLine (pl
, newLineNode (cl
->line
)) :
3482 (comment
= newLineNode (cl
->line
)));
3483 pl
->isDebug
= cl
->isDebug
;
3484 pl
->isComment
= cl
->isComment
|| (*cl
->line
== ';');
3489 /* for all the lines in the replacement pattern do */
3490 for (pl
= pr
->replace
; pl
; pl
= pl
->next
)
3500 /* if the line contains a variable */
3501 if (*l
== '%' && ISCHARDIGIT (*(l
+ 1)))
3503 v
= hTabItemWithKey (pr
->vars
, keyForVar (l
+ 1));
3506 fprintf (stderr
, "used unbound variable in replacement\n");
3514 while (ISCHARDIGIT (*l
)) {
3524 cl
= connectLine (cl
, newLineNode (lb
));
3526 lhead
= cl
= newLineNode (lb
);
3527 cl
->isComment
= pl
->isComment
;
3528 cl
->isLabel
= pl
->isLabel
;
3531 /* add the comments if any to the head of list */
3534 lineNode
*lc
= comment
;
3549 /* determine which iCodes the replacement lines relate to */
3550 reassociate_ic(*shead
,stail
,lhead
,cl
);
3552 /* now we need to connect / replace the original chain */
3553 /* if there is a prev then change it */
3556 (*shead
)->prev
->next
= lhead
;
3557 lhead
->prev
= (*shead
)->prev
;
3560 /* now for the tail */
3561 if (stail
&& stail
->next
)
3563 stail
->next
->prev
= cl
;
3564 cl
->next
= stail
->next
;
3569 /* the replacement is empty - delete the source lines */
3571 (*shead
)->prev
->next
= stail
->next
;
3573 stail
->next
->prev
= (*shead
)->prev
;
3574 *shead
= stail
->next
;
3578 /* Returns TRUE if this line is a label definition.
3580 * If so, start will point to the start of the label name,
3581 * and len will be it's length.
3584 isLabelDefinition (const char *line
, const char **start
, int *len
, bool isPeepRule
)
3586 const char *cp
= line
;
3588 /* This line is a label if it consists of:
3589 * [optional whitespace] followed by identifier chars
3590 * (alnum | $ | _ ) followed by a colon.
3593 while (*cp
&& ISCHARSPACE (*cp
))
3605 while (ISCHARALNUM (*cp
) || (*cp
== '$') || (*cp
== '_') ||
3606 (isPeepRule
&& (*cp
== '%')))
3611 if ((cp
== *start
) || (*cp
!= ':'))
3616 *len
= (cp
- (*start
));
3620 /* Not perfect, will not find all references yet.
3621 Will however find references in call on Z80, which is sufficient to fix #2970351. */
3623 isLabelReference (const char *line
, const char **start
, int *len
)
3626 if (!TARGET_Z80_LIKE
&& !TARGET_IS_STM8
&& !TARGET_PDK_LIKE
)
3630 while (ISCHARSPACE (*s
))
3633 if(strncmp(s
, "call", 4))
3637 while (ISCHARSPACE (*s
))
3640 /* Skip condition in conditional call */
3642 s
= strchr(s
, ',') + 1;
3645 while(*e
&& !ISCHARSPACE (*e
) && *e
!= ';')
3653 /* Quick & dirty string hash function. */
3655 hashSymbolName (const char *name
)
3661 hash
= ((unsigned)hash
<< 6) ^ *name
;
3670 return hash
% HTAB_SIZE
;
3673 /* Build a hash of all labels in the passed set of lines
3674 * and how many times they are referenced.
3677 buildLabelRefCountHash (lineNode
*head
)
3684 assert (labelHash
== NULL
);
3685 labelHash
= newHashTable (HTAB_SIZE
);
3687 /* First pass: locate all the labels. */
3688 for (line
= head
; line
; line
= line
->next
)
3691 /* run isLabelDefinition to:
3692 - look for labels in inline assembler
3693 - calculate labelLen
3695 if ((line
->isLabel
|| line
->isInline
) && isLabelDefinition (line
->line
, &label
, &labelLen
, FALSE
) ||
3696 (ref
= TRUE
) && isLabelReference (line
->line
, &label
, &labelLen
))
3698 labelHashEntry
*entry
, *e
;
3700 assert (labelLen
<= SDCC_NAME_MAX
);
3702 entry
= traceAlloc (&_G
.labels
, Safe_alloc(sizeof (labelHashEntry
)));
3704 memcpy (entry
->name
, label
, labelLen
);
3705 entry
->name
[labelLen
] = 0;
3706 entry
->refCount
= -1;
3708 for (e
= hTabFirstItemWK (labelHash
, hashSymbolName (entry
->name
)); e
; e
= hTabNextItemWK (labelHash
))
3709 if (!strcmp (entry
->name
, e
->name
))
3712 /* Assume function entry points are referenced somewhere, */
3713 /* even if we can't find a reference (might be from outside */
3715 if (line
->ic
&& (line
->ic
->op
== FUNCTION
) || ref
)
3718 hTabAddItem (&labelHash
, hashSymbolName (entry
->name
), entry
);
3724 /* Second pass: for each line, note all the referenced labels. */
3725 /* This is ugly, O(N^2) stuff. Optimizations welcome... */
3726 for (line
= head
; line
; line
= line
->next
)
3728 if (line
->isComment
)
3731 /* Padauk skip instructions */
3732 if (TARGET_PDK_LIKE
&& !line
->isInline
&&
3733 (!strncmp(line
->line
, "ceqsn", 5) || !strncmp(line
->line
, "cneqsn", 6) ||
3734 !strncmp(line
->line
, "t0sn", 4) || !strncmp(line
->line
, "t1sn", 4) ||
3735 !strncmp(line
->line
, "izsn", 4) || !strncmp(line
->line
, "dzsn", 4)))
3737 const lineNode
*l
= line
;
3738 // Skip over following inst.
3741 while(l
&& (l
->isComment
|| l
->isDebug
|| l
->isLabel
));
3745 while(l
&& (l
->isComment
|| l
->isDebug
));
3747 if (l
&& l
->isLabel
&& isLabelDefinition (l
->line
, &label
, &labelLen
, false))
3749 char name
[SDCC_NAME_MAX
];
3750 strcpy(name
, label
);
3754 for (e
= hTabFirstItemWK (labelHash
, hashSymbolName (name
)); e
; e
= hTabNextItemWK (labelHash
))
3755 if (!strcmp (name
, e
->name
))
3762 werror (E_NO_SKIP_TARGET
, line
->line
);
3765 for (i
= 0; i
< HTAB_SIZE
; i
++)
3767 labelHashEntry
*thisEntry
;
3769 thisEntry
= hTabFirstItemWK (labelHash
, i
);
3774 if ((s
= strstr (line
->line
, thisEntry
->name
)) && !ISCHARALNUM (*(s
+ strlen (thisEntry
->name
))) && (s
== line
->line
|| !ISCHARALNUM (*(s
- 1))))
3775 thisEntry
->refCount
++;
3777 thisEntry
= hTabNextItemWK (labelHash
);
3783 /* Spew the contents of the table. Debugging fun only. */
3784 for (i
= 0; i
< HTAB_SIZE
; i
++)
3786 labelHashEntry
*thisEntry
;
3788 thisEntry
= hTabFirstItemWK (labelHash
, i
);
3792 fprintf (stderr
, "label: %s (%p) ref %d\n",
3793 thisEntry
->name
, thisEntry
, thisEntry
->refCount
);
3794 thisEntry
= hTabNextItemWK (labelHash
);
3800 /* How does this work?
3806 replace and restart.
3811 Where is stuff allocated?
3815 /*-----------------------------------------------------------------*/
3816 /* peepHole - matches & substitutes rules */
3817 /*-----------------------------------------------------------------*/
3819 peepHole (lineNode
** pls
)
3823 lineNode
*mtail
= NULL
;
3824 bool restart
, replaced
;
3825 unsigned long rule_application_counter
= 0ul;
3827 #if !OPT_DISABLE_PIC14 || !OPT_DISABLE_PIC16
3828 /* The PIC port uses a different peep hole optimizer based on "pCode" */
3829 if (TARGET_PIC_LIKE
)
3833 assert(labelHash
== NULL
);
3840 for (pr
= rootRules
; pr
; pr
= pr
->next
)
3842 if (restart
&& pr
->barrier
)
3845 for (spl
= *pls
; spl
; spl
= replaced
? spl
: spl
->next
)
3849 // Break out of an infinite loop of rule applications.
3850 if (rule_application_counter
> 200000ul)
3852 werror (W_PEEPHOLE_RULE_LIMIT
);
3856 /* if inline assembler then no peep hole */
3860 /* don't waste time starting a match on debug symbol
3862 if (spl
->isDebug
|| spl
->isComment
|| *(spl
->line
)==';')
3867 /* Tidy up any data stored in the hTab */
3870 if (matchRule (spl
, &mtail
, pr
, *pls
))
3872 rule_application_counter
++;
3874 /* restart at the replaced line */
3880 replaceRule (pls
, mtail
, pr
);
3884 replaceRule (&spl
, mtail
, pr
);
3886 /* if restart rule type then
3887 start at the top again */
3896 hTabDeleteAll (pr
->vars
);
3897 Safe_free (pr
->vars
);
3901 freeTrace (&_G
.values
);
3904 } while (restart
== TRUE
);
3909 hTabDeleteAll (labelHash
);
3910 freeTrace (&_G
.labels
);
3916 /*-----------------------------------------------------------------*/
3917 /* readFileIntoBuffer - reads a file into a string buffer */
3918 /*-----------------------------------------------------------------*/
3920 readFileIntoBuffer (char *fname
)
3926 char lb
[MAX_PATTERN_LEN
];
3928 if (!(f
= fopen (fname
, "r")))
3930 fprintf (stderr
, "cannot open peep rule file\n");
3934 while ((ch
= fgetc (f
)) != EOF
)
3938 /* if we maxed out our local buffer */
3939 if (nch
>= (MAX_PATTERN_LEN
- 2))
3942 /* copy it into allocated buffer */
3945 rs
= Safe_realloc (rs
, strlen (rs
) + strlen (lb
) + 1);
3946 strncatz (rs
, lb
, strlen (rs
) + strlen (lb
) + 1);
3950 rs
= Safe_strdup (lb
);
3957 /* if some characters left over */
3961 /* copy it into allocated buffer */
3964 rs
= Safe_realloc (rs
, strlen (rs
) + strlen (lb
) + 1);
3965 strncatz (rs
, lb
, strlen (rs
) + strlen (lb
) + 1);
3969 rs
= Safe_strdup (lb
);
3975 /*-----------------------------------------------------------------*/
3976 /* initPeepHole - initialises the peep hole optimizer stuff */
3977 /*-----------------------------------------------------------------*/
3983 /* read in the default rules */
3984 if (!options
.nopeep
)
3986 readRules (port
->peep
.default_rules
);
3989 /* if we have any additional file read it too */
3990 if (options
.peep_file
)
3992 readRules (s
= readFileIntoBuffer (options
.peep_file
));
3993 setToNull ((void *) &s
);
3994 /* override nopeep setting, default rules have not been read */
3998 #if !OPT_DISABLE_PIC14
3999 /* Convert the peep rules into pcode.
4000 NOTE: this is only support in the PIC port (at the moment)
4002 if (TARGET_IS_PIC14
)
4003 peepRules2pCode (rootRules
);
4006 #if !OPT_DISABLE_PIC16
4007 /* Convert the peep rules into pcode.
4008 NOTE: this is only support in the PIC port (at the moment)
4009 and the PIC16 port (VR 030601)
4011 if (TARGET_IS_PIC16
)
4012 pic16_peepRules2pCode (rootRules
);
4017 /*-----------------------------------------------------------------*/
4018 /* StrStr - case-insensitive strstr implementation */
4019 /*-----------------------------------------------------------------*/
4020 const char * StrStr (const char * str1
, const char * str2
)
4022 const char * cp
= str1
;
4034 while ( *s1
&& *s2
&& !(tolower(*s1
)-tolower(*s2
)) )