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)
196 z80MightRead(const lineNode *pl, const char *what)
198 if(strcmp(pl->line, "call\t__initrleblock") == 0)
201 if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
204 if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
207 if(strncmp(pl->line, "ret", 3) == 0 && !isReturned(what))
210 if(strcmp(pl->line, "ex\tde,hl") == 0 && strchr(what, 'h') == 0 && strchr(what, 'l') == 0 && strchr(what, 'd') == 0&& strchr(what, 'e') == 0)
212 if(strncmp(pl->line, "ld\t", 3) == 0)
214 if(strstr(strchr(pl->line, ','), what) && strchr(pl->line, ',')[1] != '#')
216 if(*(strchr(pl->line, ',') - 1) == ')' && strstr(pl->line + 3, what) && (strchr(pl->line, '#') == 0 || strchr(pl->line, '#') > strchr(pl->line, ',')))
221 if(strcmp(pl->line, "xor\ta,a") == 0)
224 if(strncmp(pl->line, "adc\t", 4) == 0 ||
225 strncmp(pl->line, "add\t", 4) == 0 ||
226 strncmp(pl->line, "and\t", 4) == 0 ||
227 strncmp(pl->line, "or\t", 3) == 0 ||
228 strncmp(pl->line, "sbc\t", 4) == 0 ||
229 strncmp(pl->line, "sub\t", 4) == 0 ||
230 strncmp(pl->line, "xor\t", 4) == 0)
232 if( strstr(pl->line + 3, what) == 0 && strcmp("a", what))
236 if(strncmp(pl->line, "pop\t", 4) == 0)
239 if(strncmp(pl->line, "push\t", 5) == 0)
240 return(strstr(pl->line + 5, what) != 0);
243 strncmp(pl->line, "dec\t", 4) == 0 ||
244 strncmp(pl->line, "inc\t", 4) == 0 ||
245 strncmp(pl->line, "rl\t", 3) == 0 ||
246 strncmp(pl->line, "rr\t", 3) == 0 ||
247 strncmp(pl->line, "sla\t", 4) == 0 ||
248 strncmp(pl->line, "sra\t", 4) == 0 ||
249 strncmp(pl->line, "srl\t", 4) == 0)
251 return (strstr(pl->line + 3, what) != 0);
254 if(strncmp(pl->line, "jp\t", 3) == 0 ||
255 (bool)(strncmp(pl->line, "jr\t", 3)) == 0)
258 if(strncmp(pl->line, "rla", 3) == 0 ||
259 strncmp(pl->line, "rlca", 4) == 0)
260 return(strcmp(what, "a") == 0);
266 z80UncondJump(const lineNode *pl)
268 if((strncmp(pl->line, "jp\t", 3) == 0 ||
269 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') == 0)
275 z80CondJump(const lineNode *pl)
277 if((strncmp(pl->line, "jp\t", 3) == 0 ||
278 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') != 0)
284 z80SurelyWrites(const lineNode *pl, const char *what)
286 if(strcmp(pl->line, "xor\ta,a") == 0 && strcmp(what, "a") == 0)
288 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "hl", 2) == 0 && (what[0] == 'h' || what[0] == 'l'))
290 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "de", 2) == 0 && (what[0] == 'd' || what[0] == 'e'))
292 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "bc", 2) == 0 && (what[0] == 'b' || what[0] == 'c'))
294 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, what, strlen(what)) == 0 && pl->line[3 + strlen(what)] == ',')
296 if(strncmp(pl->line, "pop\t", 4) == 0 && strstr(pl->line + 4, what))
298 if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
300 if(strcmp(pl->line, "ret") == 0)
302 if(strncmp(pl->line, "ld\tiy", 5) == 0 && strncmp(what, "iy", 2) == 0)
308 z80SurelyReturns(const lineNode *pl)
310 if(strcmp(pl->line, "\tret") == 0)
315 /*-----------------------------------------------------------------*/
316 /* scan4op - "executes" and examines the assembler opcodes, */
317 /* follows conditional and un-conditional jumps. */
318 /* Moreover it registers all passed labels. */
322 /* scanning starts from pl; */
323 /* pl also returns the last scanned line */
324 /* const char *pReg */
325 /* points to a register (e.g. "ar0"). scan4op() tests for */
326 /* read or write operations with this register */
327 /* const char *untilOp */
328 /* points to NULL or a opcode (e.g. "push"). */
329 /* scan4op() returns if it hits this opcode. */
330 /* lineNode **plCond */
331 /* If a conditional branch is met plCond points to the */
332 /* lineNode of the conditional branch */
338 /* hit lineNode with "visited" flag set: scan4op() already */
339 /* scanned this opcode. */
340 /* S4O_FOUNDOPCODE */
341 /* found opcode and operand, to which untilOp and pReg are */
343 /* S4O_RD_OP, S4O_WR_OP */
344 /* hit an opcode reading or writing from pReg */
346 /* hit a conditional jump opcode. pl and plCond return the */
347 /* two possible branches. */
349 /* acall, lcall, ret and reti "terminate" a scan. */
350 /*-----------------------------------------------------------------*/
352 scan4op (lineNode **pl, const char *what, const char *untilOp,
355 for (; *pl; *pl = (*pl)->next)
357 if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment || (*pl)->isLabel)
359 D(("Scanning %s for %s\n", (*pl)->line, what));
360 /* don't optimize across inline assembler,
361 e.g. isLabel doesn't work there */
367 (*pl)->visited = TRUE;
369 if(z80MightRead(*pl, what))
375 if(z80UncondJump(*pl))
377 *pl = findLabel (*pl);
386 *plCond = findLabel (*pl);
392 D(("S4O_CONDJMP\n"));
396 if(z80SurelyWrites(*pl, what))
402 /* Don't need to check for de, hl since z80MightRead() does that */
403 if(z80SurelyReturns(*pl))
413 /*-----------------------------------------------------------------*/
414 /* doTermScan - scan through area 2. This small wrapper handles: */
415 /* - action required on different return values */
416 /* - recursion in case of conditional branches */
417 /*-----------------------------------------------------------------*/
419 doTermScan (lineNode **pl, const char *what)
421 lineNode *plConditional;
423 for (;; *pl = (*pl)->next)
425 switch (scan4op (pl, what, NULL, &plConditional))
430 /* all these are terminating condtions */
433 /* two possible destinations: recurse */
435 lineNode *pl2 = plConditional;
436 D(("CONDJMP trying other branch first\n"));
437 if (!doTermScan (&pl2, what))
439 D(("Other branch OK.\n"));
451 isReg(const char *what)
453 if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
455 if(strlen(what) != 1)
472 isRegPair(const char *what)
474 if(strlen(what) != 2)
476 if(strcmp(what, "bc") == 0)
478 if(strcmp(what, "de") == 0)
480 if(strcmp(what, "hl") == 0)
482 if(strcmp(what, "iy") == 0)
487 /* Check that what is never read after endPl. */
490 z80notUsed (const char *what, lineNode *endPl, lineNode *head)
493 D(("Checking for %s\n", what));
496 char low[2], high[2];
501 if(strcmp(what, "iy") == 0)
502 return(z80notUsed("iyl", endPl, head) && z80notUsed("iyh", endPl, head));
503 return(z80notUsed(low, endPl, head) && z80notUsed(high, endPl, head));
511 unvisitLines (_G.head);
514 if (!doTermScan (&pl, what))