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, "srl\t", 4) == 0)
250 return (strstr(pl->line + 3, what) != 0);
253 if(strncmp(pl->line, "jp\t", 3) == 0 ||
254 (bool)(strncmp(pl->line, "jr\t", 3)) == 0)
257 if(strncmp(pl->line, "rla", 3) == 0 ||
258 strncmp(pl->line, "rlca", 4) == 0)
259 return(strcmp(what, "a") == 0);
265 z80UncondJump(const lineNode *pl)
267 if((strncmp(pl->line, "jp\t", 3) == 0 ||
268 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') == 0)
274 z80CondJump(const lineNode *pl)
276 if((strncmp(pl->line, "jp\t", 3) == 0 ||
277 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') != 0)
283 z80SurelyWrites(const lineNode *pl, const char *what)
285 if(strcmp(pl->line, "xor\ta,a") == 0 && strcmp(what, "a") == 0)
287 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "hl", 2) == 0 && (what[0] == 'h' || what[0] == 'l'))
289 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "de", 2) == 0 && (what[0] == 'd' || what[0] == 'e'))
291 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "bc", 2) == 0 && (what[0] == 'b' || what[0] == 'c'))
293 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, what, strlen(what)) == 0 && pl->line[3 + strlen(what)] == ',')
295 if(strncmp(pl->line, "pop\t", 4) == 0 && strstr(pl->line + 4, what))
297 if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
299 if(strcmp(pl->line, "ret") == 0)
301 if(strncmp(pl->line, "ld\tiy", 5) == 0 && strncmp(what, "iy", 2) == 0)
307 z80SurelyReturns(const lineNode *pl)
309 if(strcmp(pl->line, "\tret") == 0)
314 /*-----------------------------------------------------------------*/
315 /* scan4op - "executes" and examines the assembler opcodes, */
316 /* follows conditional and un-conditional jumps. */
317 /* Moreover it registers all passed labels. */
321 /* scanning starts from pl; */
322 /* pl also returns the last scanned line */
323 /* const char *pReg */
324 /* points to a register (e.g. "ar0"). scan4op() tests for */
325 /* read or write operations with this register */
326 /* const char *untilOp */
327 /* points to NULL or a opcode (e.g. "push"). */
328 /* scan4op() returns if it hits this opcode. */
329 /* lineNode **plCond */
330 /* If a conditional branch is met plCond points to the */
331 /* lineNode of the conditional branch */
337 /* hit lineNode with "visited" flag set: scan4op() already */
338 /* scanned this opcode. */
339 /* S4O_FOUNDOPCODE */
340 /* found opcode and operand, to which untilOp and pReg are */
342 /* S4O_RD_OP, S4O_WR_OP */
343 /* hit an opcode reading or writing from pReg */
345 /* hit a conditional jump opcode. pl and plCond return the */
346 /* two possible branches. */
348 /* acall, lcall, ret and reti "terminate" a scan. */
349 /*-----------------------------------------------------------------*/
351 scan4op (lineNode **pl, const char *what, const char *untilOp,
354 for (; *pl; *pl = (*pl)->next)
356 if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment || (*pl)->isLabel)
358 D(("Scanning %s for %s\n", (*pl)->line, what));
359 /* don't optimize across inline assembler,
360 e.g. isLabel doesn't work there */
366 (*pl)->visited = TRUE;
368 if(z80MightRead(*pl, what))
374 if(z80UncondJump(*pl))
376 *pl = findLabel (*pl);
385 *plCond = findLabel (*pl);
391 D(("S4O_CONDJMP\n"));
395 if(z80SurelyWrites(*pl, what))
401 /* Don't need to check for de, hl since z80MightRead() does that */
402 if(z80SurelyReturns(*pl))
412 /*-----------------------------------------------------------------*/
413 /* doTermScan - scan through area 2. This small wrapper handles: */
414 /* - action required on different return values */
415 /* - recursion in case of conditional branches */
416 /*-----------------------------------------------------------------*/
418 doTermScan (lineNode **pl, const char *what)
420 lineNode *plConditional;
422 for (;; *pl = (*pl)->next)
424 switch (scan4op (pl, what, NULL, &plConditional))
429 /* all these are terminating condtions */
432 /* two possible destinations: recurse */
434 lineNode *pl2 = plConditional;
435 D(("CONDJMP trying other branch first\n"));
436 if (!doTermScan (&pl2, what))
438 D(("Other branch OK.\n"));
450 isReg(const char *what)
452 if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
454 if(strlen(what) != 1)
471 isRegPair(const char *what)
473 if(strlen(what) != 2)
475 if(strcmp(what, "bc") == 0)
477 if(strcmp(what, "de") == 0)
479 if(strcmp(what, "hl") == 0)
481 if(strcmp(what, "iy") == 0)
486 /* Check that what is never read after endPl. */
489 z80notUsed (const char *what, lineNode *endPl, lineNode *head)
492 D(("Checking for %s\n", what));
495 char low[2], high[2];
500 if(strcmp(what, "iy") == 0)
501 return(z80notUsed("iyl", endPl, head) && z80notUsed("iyh", endPl, head));
502 return(z80notUsed(low, endPl, head) && z80notUsed(high, endPl, head));
510 unvisitLines (_G.head);
513 if (!doTermScan (&pl, what))