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)
234 if( strstr(pl->line + 3, "hl") == 0 && strcmp("a", what) == 0)
239 if(strncmp(pl->line, "pop\t", 4) == 0)
242 if(strncmp(pl->line, "push\t", 5) == 0)
243 return(strstr(pl->line + 5, what) != 0);
246 strncmp(pl->line, "dec\t", 4) == 0 ||
247 strncmp(pl->line, "inc\t", 4) == 0 ||
248 strncmp(pl->line, "rl\t", 3) == 0 ||
249 strncmp(pl->line, "rr\t", 3) == 0 ||
250 strncmp(pl->line, "sla\t", 4) == 0 ||
251 strncmp(pl->line, "sra\t", 4) == 0 ||
252 strncmp(pl->line, "srl\t", 4) == 0)
254 return (strstr(pl->line + 3, what) != 0);
257 if(strncmp(pl->line, "jp\t", 3) == 0 ||
258 (bool)(strncmp(pl->line, "jr\t", 3)) == 0)
261 if(strncmp(pl->line, "djnz\t", 5) == 0)
262 return(strchr(what, 'b') != 0);
264 if(strncmp(pl->line, "rla", 3) == 0 ||
265 strncmp(pl->line, "rlca", 4) == 0)
266 return(strcmp(what, "a") == 0);
272 z80UncondJump(const lineNode *pl)
274 if((strncmp(pl->line, "jp\t", 3) == 0 ||
275 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') == 0)
281 z80CondJump(const lineNode *pl)
283 if((strncmp(pl->line, "jp\t", 3) == 0 ||
284 strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') != 0 ||
285 strncmp(pl->line, "djnz\t", 5) == 0)
291 z80SurelyWrites(const lineNode *pl, const char *what)
293 if(strcmp(pl->line, "xor\ta,a") == 0 && strcmp(what, "a") == 0)
295 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "hl", 2) == 0 && (what[0] == 'h' || what[0] == 'l'))
297 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "de", 2) == 0 && (what[0] == 'd' || what[0] == 'e'))
299 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "bc", 2) == 0 && (what[0] == 'b' || what[0] == 'c'))
301 if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, what, strlen(what)) == 0 && pl->line[3 + strlen(what)] == ',')
303 if(strncmp(pl->line, "pop\t", 4) == 0 && strstr(pl->line + 4, what))
305 if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
307 if(strcmp(pl->line, "ret") == 0)
309 if(strncmp(pl->line, "ld\tiy", 5) == 0 && strncmp(what, "iy", 2) == 0)
315 z80SurelyReturns(const lineNode *pl)
317 if(strcmp(pl->line, "\tret") == 0)
322 /*-----------------------------------------------------------------*/
323 /* scan4op - "executes" and examines the assembler opcodes, */
324 /* follows conditional and un-conditional jumps. */
325 /* Moreover it registers all passed labels. */
329 /* scanning starts from pl; */
330 /* pl also returns the last scanned line */
331 /* const char *pReg */
332 /* points to a register (e.g. "ar0"). scan4op() tests for */
333 /* read or write operations with this register */
334 /* const char *untilOp */
335 /* points to NULL or a opcode (e.g. "push"). */
336 /* scan4op() returns if it hits this opcode. */
337 /* lineNode **plCond */
338 /* If a conditional branch is met plCond points to the */
339 /* lineNode of the conditional branch */
345 /* hit lineNode with "visited" flag set: scan4op() already */
346 /* scanned this opcode. */
347 /* S4O_FOUNDOPCODE */
348 /* found opcode and operand, to which untilOp and pReg are */
350 /* S4O_RD_OP, S4O_WR_OP */
351 /* hit an opcode reading or writing from pReg */
353 /* hit a conditional jump opcode. pl and plCond return the */
354 /* two possible branches. */
356 /* acall, lcall, ret and reti "terminate" a scan. */
357 /*-----------------------------------------------------------------*/
359 scan4op (lineNode **pl, const char *what, const char *untilOp,
362 for (; *pl; *pl = (*pl)->next)
364 if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment || (*pl)->isLabel)
366 D(("Scanning %s for %s\n", (*pl)->line, what));
367 /* don't optimize across inline assembler,
368 e.g. isLabel doesn't work there */
374 (*pl)->visited = TRUE;
376 if(z80MightRead(*pl, what))
382 if(z80UncondJump(*pl))
384 *pl = findLabel (*pl);
393 *plCond = findLabel (*pl);
399 D(("S4O_CONDJMP\n"));
403 if(z80SurelyWrites(*pl, what))
409 /* Don't need to check for de, hl since z80MightRead() does that */
410 if(z80SurelyReturns(*pl))
420 /*-----------------------------------------------------------------*/
421 /* doTermScan - scan through area 2. This small wrapper handles: */
422 /* - action required on different return values */
423 /* - recursion in case of conditional branches */
424 /*-----------------------------------------------------------------*/
426 doTermScan (lineNode **pl, const char *what)
428 lineNode *plConditional;
430 for (;; *pl = (*pl)->next)
432 switch (scan4op (pl, what, NULL, &plConditional))
437 /* all these are terminating condtions */
440 /* two possible destinations: recurse */
442 lineNode *pl2 = plConditional;
443 D(("CONDJMP trying other branch first\n"));
444 if (!doTermScan (&pl2, what))
446 D(("Other branch OK.\n"));
458 isReg(const char *what)
460 if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
462 if(strlen(what) != 1)
479 isRegPair(const char *what)
481 if(strlen(what) != 2)
483 if(strcmp(what, "bc") == 0)
485 if(strcmp(what, "de") == 0)
487 if(strcmp(what, "hl") == 0)
489 if(strcmp(what, "iy") == 0)
494 /* Check that what is never read after endPl. */
497 z80notUsed (const char *what, lineNode *endPl, lineNode *head)
500 D(("Checking for %s\n", what));
503 char low[2], high[2];
508 if(strcmp(what, "iy") == 0)
509 return(z80notUsed("iyl", endPl, head) && z80notUsed("iyh", endPl, head));
510 return(z80notUsed(low, endPl, head) && z80notUsed(high, endPl, head));
518 unvisitLines (_G.head);
521 if (!doTermScan (&pl, what))