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)
200 return(strstr(arg, what));;
204 z80MightRead(const lineNode *pl, const char *what)
206 if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
209 if(strcmp(pl->line, "call\t__initrleblock") == 0)
212 if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
215 if(strncmp(pl->line, "ret", 3) == 0 && !isReturned(what))
218 if(strcmp(pl->line, "ex\tde,hl") == 0 && strchr(what, 'h') == 0 && strchr(what, 'l') == 0 && strchr(what, 'd') == 0&& strchr(what, 'e') == 0)
220 if(strncmp(pl->line, "ld\t", 3) == 0)
222 if(strstr(strchr(pl->line, ','), what) && strchr(pl->line, ',')[1] != '#')
224 if(*(strchr(pl->line, ',') - 1) == ')' && strstr(pl->line + 3, what) && (strchr(pl->line, '#') == 0 || strchr(pl->line, '#') > strchr(pl->line, ',')))
229 if(strcmp(pl->line, "xor\ta,a") == 0)
232 if(strncmp(pl->line, "adc\t", 4) == 0 ||
233 strncmp(pl->line, "add\t", 4) == 0 ||
234 strncmp(pl->line, "and\t", 4) == 0 ||
235 strncmp(pl->line, "sbc\t", 4) == 0 ||
236 strncmp(pl->line, "sub\t", 4) == 0 ||
237 strncmp(pl->line, "xor\t", 4) == 0)
239 if(argCont(pl->line + 4, what))
241 if(strstr(pl->line + 4, "hl") == 0 && strcmp("a", what) == 0)
246 if(strncmp(pl->line, "or\t", 3) == 0)
248 if(argCont(pl->line + 3, what))
250 if(strcmp("a", what) == 0)
255 if(strncmp(pl->line, "pop\t", 4) == 0)
258 if(strncmp(pl->line, "push\t", 5) == 0)
259 return(strstr(pl->line + 5, what) != 0);
262 strncmp(pl->line, "dec\t", 4) == 0 ||
263 strncmp(pl->line, "inc\t", 4) == 0 ||
264 strncmp(pl->line, "rl\t", 4) == 0 ||
265 strncmp(pl->line, "rr\t", 4) == 0 ||
266 strncmp(pl->line, "sla\t", 4) == 0 ||
267 strncmp(pl->line, "sra\t", 4) == 0 ||
268 strncmp(pl->line, "srl\t", 4) == 0)
270 return (argCont(pl->line + 4, what));
274 strncmp(pl->line, "rl\t", 3) == 0 ||
275 strncmp(pl->line, "rr\t", 3) == 0)
277 return (argCont(pl->line + 3, what));
280 if(strncmp(pl->line, "jp\t", 3) == 0 ||
281 (bool)(strncmp(pl->line, "jr\t", 3)) == 0)
284 if(strncmp(pl->line, "djnz\t", 5) == 0)
285 return(strchr(what, 'b') != 0);
287 if(strncmp(pl->line, "rla", 3) == 0 ||
288 strncmp(pl->line, "rlca", 4) == 0)
289 return(strcmp(what, "a") == 0);
295 z80UncondJump(const lineNode *pl)
297 if((strncmp(pl->line, "jp\t", 3) == 0 ||
298 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') == 0)
304 z80CondJump(const lineNode *pl)
306 if(((strncmp(pl->line, "jp\t", 3) == 0 ||
307 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') != 0) ||
308 strncmp(pl->line, "djnz\t", 5) == 0)
314 z80SurelyWrites(const lineNode *pl, const char *what)
316 if(strcmp(pl->line, "xor\ta,a") == 0 && strcmp(what, "a") == 0)
318 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "hl", 2) == 0 && (what[0] == 'h' || what[0] == 'l'))
320 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "de", 2) == 0 && (what[0] == 'd' || what[0] == 'e'))
322 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "bc", 2) == 0 && (what[0] == 'b' || what[0] == 'c'))
324 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, what, strlen(what)) == 0 && pl->line[3 + strlen(what)] == ',')
326 if(strncmp(pl->line, "pop\t", 4) == 0 && strstr(pl->line + 4, what))
328 if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
330 if(strcmp(pl->line, "ret") == 0)
332 if(strncmp(pl->line, "ld\tiy", 5) == 0 && strncmp(what, "iy", 2) == 0)
338 z80SurelyReturns(const lineNode *pl)
340 if(strcmp(pl->line, "\tret") == 0)
345 /*-----------------------------------------------------------------*/
346 /* scan4op - "executes" and examines the assembler opcodes, */
347 /* follows conditional and un-conditional jumps. */
348 /* Moreover it registers all passed labels. */
352 /* scanning starts from pl; */
353 /* pl also returns the last scanned line */
354 /* const char *pReg */
355 /* points to a register (e.g. "ar0"). scan4op() tests for */
356 /* read or write operations with this register */
357 /* const char *untilOp */
358 /* points to NULL or a opcode (e.g. "push"). */
359 /* scan4op() returns if it hits this opcode. */
360 /* lineNode **plCond */
361 /* If a conditional branch is met plCond points to the */
362 /* lineNode of the conditional branch */
368 /* hit lineNode with "visited" flag set: scan4op() already */
369 /* scanned this opcode. */
370 /* S4O_FOUNDOPCODE */
371 /* found opcode and operand, to which untilOp and pReg are */
373 /* S4O_RD_OP, S4O_WR_OP */
374 /* hit an opcode reading or writing from pReg */
376 /* hit a conditional jump opcode. pl and plCond return the */
377 /* two possible branches. */
379 /* acall, lcall, ret and reti "terminate" a scan. */
380 /*-----------------------------------------------------------------*/
382 scan4op (lineNode **pl, const char *what, const char *untilOp,
385 for (; *pl; *pl = (*pl)->next)
387 if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment || (*pl)->isLabel)
389 D(("Scanning %s for %s\n", (*pl)->line, what));
390 /* don't optimize across inline assembler,
391 e.g. isLabel doesn't work there */
397 (*pl)->visited = TRUE;
399 if(z80MightRead(*pl, what))
405 if(z80UncondJump(*pl))
407 *pl = findLabel (*pl);
416 *plCond = findLabel (*pl);
422 D(("S4O_CONDJMP\n"));
426 if(z80SurelyWrites(*pl, what))
432 /* Don't need to check for de, hl since z80MightRead() does that */
433 if(z80SurelyReturns(*pl))
443 /*-----------------------------------------------------------------*/
444 /* doTermScan - scan through area 2. This small wrapper handles: */
445 /* - action required on different return values */
446 /* - recursion in case of conditional branches */
447 /*-----------------------------------------------------------------*/
449 doTermScan (lineNode **pl, const char *what)
451 lineNode *plConditional;
453 for (;; *pl = (*pl)->next)
455 switch (scan4op (pl, what, NULL, &plConditional))
460 /* all these are terminating condtions */
463 /* two possible destinations: recurse */
465 lineNode *pl2 = plConditional;
466 D(("CONDJMP trying other branch first\n"));
467 if (!doTermScan (&pl2, what))
469 D(("Other branch OK.\n"));
481 isReg(const char *what)
483 if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
485 if(strlen(what) != 1)
502 isRegPair(const char *what)
504 if(strlen(what) != 2)
506 if(strcmp(what, "bc") == 0)
508 if(strcmp(what, "de") == 0)
510 if(strcmp(what, "hl") == 0)
512 if(strcmp(what, "iy") == 0)
517 /* Check that what is never read after endPl. */
520 z80notUsed (const char *what, lineNode *endPl, lineNode *head)
523 D(("Checking for %s\n", what));
526 char low[2], high[2];
531 if(strcmp(what, "iy") == 0)
532 return(z80notUsed("iyl", endPl, head) && z80notUsed("iyh", endPl, head));
533 return(z80notUsed(low, endPl, head) && z80notUsed(high, endPl, head));
541 unvisitLines (_G.head);
544 if (!doTermScan (&pl, what))