1 /*-------------------------------------------------------------------------
2 peep.c - source file for peephole optimizer helper functions
4 Written By - Philipp Klaus Krause
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.
20 In other words, you are welcome to use, share and improve this program.
21 You are forbidden to forbid anyone else to use, share and improve
22 what you give them. Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
26 #include "SDCCicode.h"
28 #include "SDCCglobl.h"
29 #include "SDCCpeeph.h"
32 #define NOTUSEDERROR() do {werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "error in notUsed()");} while(0)
34 /*#define D(_s) { printf _s; fflush(stdout); }*/
53 /*-----------------------------------------------------------------*/
54 /* univisitLines - clear "visited" flag in all lines */
55 /*-----------------------------------------------------------------*/
57 unvisitLines (lineNode *pl)
59 for (; pl; pl = pl->next)
63 #define AOP(op) op->aop
64 #define AOP_SIZE(op) AOP(op)->size
67 isReturned(const char *what)
74 if(strncmp(what, "iy", 2) == 0)
83 } while(l->ic->op != FUNCTION);
85 sym = OP_SYMBOL(IC_LEFT(_G.head->next->next->ic));
87 if(sym && IS_DECL(sym->type))
89 // Find size of return value.
91 if(sym->type->select.d.dcl_type != FUNCTION)
93 spec = &(sym->etype->select.s);
94 if(spec->noun == V_VOID)
96 else if(spec->noun == V_CHAR)
98 else if(spec->noun == V_INT && !(spec->b_long))
103 // Check for returned pointer.
105 while (sym_lnk && !IS_PTR (sym_lnk))
106 sym_lnk = sym_lnk->next;
131 /*-----------------------------------------------------------------*/
132 /* incLabelJmpToCount - increment counter "jmpToCount" in entry */
133 /* of the list labelHash */
134 /*-----------------------------------------------------------------*/
136 incLabelJmpToCount (const char *label)
138 labelHashEntry *entry;
140 entry = getLabelRef (label, _G.head);
147 /*-----------------------------------------------------------------*/
149 /* 1. extracts label in the opcode pl */
150 /* 2. increment "label jump-to count" in labelHash */
151 /* 3. search lineNode with label definition and return it */
152 /*-----------------------------------------------------------------*/
154 findLabel (const lineNode *pl)
159 /* 1. extract label in opcode */
161 /* In each mcs51 jumping opcode the label is at the end of the opcode */
162 p = strlen (pl->line) - 1 + pl->line;
164 /* scan backward until ',' or '\t' */
165 for (; p > pl->line; p--)
166 if (*p == ',' || *p == '\t')
176 /* skip ',' resp. '\t' */
179 /* 2. increment "label jump-to count" */
180 if (!incLabelJmpToCount (p))
183 /* 3. search lineNode with label definition and return it */
184 for (cpl = _G.head; cpl; cpl = cpl->next)
187 && strncmp (p, cpl->line, strlen(p)) == 0)
195 /* Check if reading arg implies reading what. */
196 static bool argCont(const char *arg, const char *what)
198 return (arg[0] == '#') ? FALSE : strstr(arg, what) != NULL;
202 z80MightRead(const lineNode *pl, const char *what)
204 if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
207 if(strcmp(pl->line, "call\t__initrleblock") == 0)
210 if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
213 if(strncmp(pl->line, "ret", 3) == 0 && !isReturned(what))
216 if(strcmp(pl->line, "ex\tde,hl") == 0 && strchr(what, 'h') == 0 && strchr(what, 'l') == 0 && strchr(what, 'd') == 0&& strchr(what, 'e') == 0)
218 if(strncmp(pl->line, "ld\t", 3) == 0)
220 if(strstr(strchr(pl->line, ','), what) && strchr(pl->line, ',')[1] != '#')
222 if(*(strchr(pl->line, ',') - 1) == ')' && strstr(pl->line + 3, what) && (strchr(pl->line, '#') == 0 || strchr(pl->line, '#') > strchr(pl->line, ',')))
227 if(strcmp(pl->line, "xor\ta,a") == 0)
230 if(strncmp(pl->line, "adc\t", 4) == 0 ||
231 strncmp(pl->line, "add\t", 4) == 0 ||
232 strncmp(pl->line, "and\t", 4) == 0 ||
233 strncmp(pl->line, "sbc\t", 4) == 0 ||
234 strncmp(pl->line, "sub\t", 4) == 0 ||
235 strncmp(pl->line, "xor\t", 4) == 0)
237 if(argCont(pl->line + 4, what))
239 if(strstr(pl->line + 4, "hl") == 0 && strcmp("a", what) == 0)
244 if(strncmp(pl->line, "or\t", 3) == 0)
246 if(argCont(pl->line + 3, what))
248 if(strcmp("a", what) == 0)
253 if(strncmp(pl->line, "pop\t", 4) == 0)
256 if(strncmp(pl->line, "push\t", 5) == 0)
257 return(strstr(pl->line + 5, what) != 0);
260 strncmp(pl->line, "dec\t", 4) == 0 ||
261 strncmp(pl->line, "inc\t", 4) == 0 ||
262 strncmp(pl->line, "rl\t", 4) == 0 ||
263 strncmp(pl->line, "rr\t", 4) == 0 ||
264 strncmp(pl->line, "sla\t", 4) == 0 ||
265 strncmp(pl->line, "sra\t", 4) == 0 ||
266 strncmp(pl->line, "srl\t", 4) == 0)
268 return (argCont(pl->line + 4, what));
272 strncmp(pl->line, "rl\t", 3) == 0 ||
273 strncmp(pl->line, "rr\t", 3) == 0)
275 return (argCont(pl->line + 3, what));
278 if(strncmp(pl->line, "jp\t", 3) == 0 ||
279 (bool)(strncmp(pl->line, "jr\t", 3)) == 0)
282 if(strncmp(pl->line, "djnz\t", 5) == 0)
283 return(strchr(what, 'b') != 0);
285 if(strncmp(pl->line, "rla", 3) == 0 ||
286 strncmp(pl->line, "rlca", 4) == 0)
287 return(strcmp(what, "a") == 0);
293 z80UncondJump(const lineNode *pl)
295 if((strncmp(pl->line, "jp\t", 3) == 0 ||
296 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') == 0)
302 z80CondJump(const lineNode *pl)
304 if(((strncmp(pl->line, "jp\t", 3) == 0 ||
305 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') != 0) ||
306 strncmp(pl->line, "djnz\t", 5) == 0)
312 z80SurelyWrites(const lineNode *pl, const char *what)
314 if(strcmp(pl->line, "xor\ta,a") == 0 && strcmp(what, "a") == 0)
316 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "hl", 2) == 0 && (what[0] == 'h' || what[0] == 'l'))
318 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "de", 2) == 0 && (what[0] == 'd' || what[0] == 'e'))
320 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "bc", 2) == 0 && (what[0] == 'b' || what[0] == 'c'))
322 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, what, strlen(what)) == 0 && pl->line[3 + strlen(what)] == ',')
324 if(strncmp(pl->line, "pop\t", 4) == 0 && strstr(pl->line + 4, what))
326 if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
328 if(strcmp(pl->line, "ret") == 0)
330 if(strncmp(pl->line, "ld\tiy", 5) == 0 && strncmp(what, "iy", 2) == 0)
336 z80SurelyReturns(const lineNode *pl)
338 if(strcmp(pl->line, "\tret") == 0)
343 /*-----------------------------------------------------------------*/
344 /* scan4op - "executes" and examines the assembler opcodes, */
345 /* follows conditional and un-conditional jumps. */
346 /* Moreover it registers all passed labels. */
350 /* scanning starts from pl; */
351 /* pl also returns the last scanned line */
352 /* const char *pReg */
353 /* points to a register (e.g. "ar0"). scan4op() tests for */
354 /* read or write operations with this register */
355 /* const char *untilOp */
356 /* points to NULL or a opcode (e.g. "push"). */
357 /* scan4op() returns if it hits this opcode. */
358 /* lineNode **plCond */
359 /* If a conditional branch is met plCond points to the */
360 /* lineNode of the conditional branch */
366 /* hit lineNode with "visited" flag set: scan4op() already */
367 /* scanned this opcode. */
368 /* S4O_FOUNDOPCODE */
369 /* found opcode and operand, to which untilOp and pReg are */
371 /* S4O_RD_OP, S4O_WR_OP */
372 /* hit an opcode reading or writing from pReg */
374 /* hit a conditional jump opcode. pl and plCond return the */
375 /* two possible branches. */
377 /* acall, lcall, ret and reti "terminate" a scan. */
378 /*-----------------------------------------------------------------*/
380 scan4op (lineNode **pl, const char *what, const char *untilOp,
383 for (; *pl; *pl = (*pl)->next)
385 if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment || (*pl)->isLabel)
387 D(("Scanning %s for %s\n", (*pl)->line, what));
388 /* don't optimize across inline assembler,
389 e.g. isLabel doesn't work there */
395 (*pl)->visited = TRUE;
397 if(z80MightRead(*pl, what))
403 if(z80UncondJump(*pl))
405 *pl = findLabel (*pl);
414 *plCond = findLabel (*pl);
420 D(("S4O_CONDJMP\n"));
424 if(z80SurelyWrites(*pl, what))
430 /* Don't need to check for de, hl since z80MightRead() does that */
431 if(z80SurelyReturns(*pl))
441 /*-----------------------------------------------------------------*/
442 /* doTermScan - scan through area 2. This small wrapper handles: */
443 /* - action required on different return values */
444 /* - recursion in case of conditional branches */
445 /*-----------------------------------------------------------------*/
447 doTermScan (lineNode **pl, const char *what)
449 lineNode *plConditional;
451 for (;; *pl = (*pl)->next)
453 switch (scan4op (pl, what, NULL, &plConditional))
458 /* all these are terminating condtions */
461 /* two possible destinations: recurse */
463 lineNode *pl2 = plConditional;
464 D(("CONDJMP trying other branch first\n"));
465 if (!doTermScan (&pl2, what))
467 D(("Other branch OK.\n"));
479 isReg(const char *what)
481 if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
483 if(strlen(what) != 1)
500 isRegPair(const char *what)
502 if(strlen(what) != 2)
504 if(strcmp(what, "bc") == 0)
506 if(strcmp(what, "de") == 0)
508 if(strcmp(what, "hl") == 0)
510 if(strcmp(what, "iy") == 0)
515 /* Check that what is never read after endPl. */
518 z80notUsed (const char *what, lineNode *endPl, lineNode *head)
521 D(("Checking for %s\n", what));
524 char low[2], high[2];
529 if(strcmp(what, "iy") == 0)
530 return(z80notUsed("iyl", endPl, head) && z80notUsed("iyh", endPl, head));
531 return(z80notUsed(low, endPl, head) && z80notUsed(high, endPl, head));
539 unvisitLines (_G.head);
542 if (!doTermScan (&pl, what))