1 /*-------------------------------------------------------------------------
2 peep.c - source file for peephole optimizer helper functions
4 Written By - Philipp Klaus Krause
5 Copyright (C) 2020, Sebastian 'basxto' Riedel <sdcc@basxto.de>
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 In other words, you are welcome to use, share and improve this program.
22 You are forbidden to forbid anyone else to use, share and improve
23 what you give them. Help stamp out software-hoarding!
24 -------------------------------------------------------------------------*/
27 #include "SDCCicode.h"
29 #include "SDCCglobl.h"
30 #include "SDCCpeeph.h"
33 #define NOTUSEDERROR() do {werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "error in notUsed()");} while(0)
36 #define D(_s) { printf _s; fflush(stdout); }
41 #define ISINST(l, i) (!STRNCASECMP((l), (i), sizeof(i) - 1) && (!(l)[sizeof(i) - 1] || isspace((unsigned char)((l)[sizeof(i) - 1]))))
59 extern bool z80_regs_used_as_parms_in_calls_from_current_function
[IYH_IDX
+ 1];
60 extern bool z80_symmParm_in_calls_from_current_function
;
61 extern bool z80_regs_preserved_in_calls_from_current_function
[IYH_IDX
+ 1];
63 /*-----------------------------------------------------------------*/
64 /* univisitLines - clear "visited" flag in all lines */
65 /*-----------------------------------------------------------------*/
67 unvisitLines (lineNode
*pl
)
69 for (; pl
; pl
= pl
->next
)
73 #define AOP(op) op->aop
74 #define AOP_SIZE(op) AOP(op)->size
76 /*-----------------------------------------------------------------*/
77 /* incLabelJmpToCount - increment counter "jmpToCount" in entry */
78 /* of the list labelHash */
79 /*-----------------------------------------------------------------*/
81 incLabelJmpToCount (const char *label
)
83 labelHashEntry
*entry
;
85 entry
= getLabelRef (label
, _G
.head
);
92 /*-----------------------------------------------------------------*/
94 /* 1. extracts label in the opcode pl */
95 /* 2. increment "label jump-to count" in labelHash */
96 /* 3. search lineNode with label definition and return it */
97 /*-----------------------------------------------------------------*/
99 findLabel (const lineNode
*pl
)
104 /* 1. extract label in opcode */
106 /* In each z80 jumping opcode the label is at the end of the opcode */
107 p
= strlen (pl
->line
) - 1 + pl
->line
;
109 /* scan backward until ',' or '\t' */
110 for (; p
> pl
->line
; p
--)
111 if (*p
== ',' || isspace(*p
))
121 /* skip ',' resp. '\t' */
124 /* 2. increment "label jump-to count" */
125 if (!incLabelJmpToCount (p
))
128 /* 3. search lineNode with label definition and return it */
129 for (cpl
= _G
.head
; cpl
; cpl
= cpl
->next
)
131 strncmp (p
, cpl
->line
, strlen(p
)) == 0 &&
132 cpl
->line
[strlen(p
)] == ':')
138 /* Check if reading arg implies reading what. */
139 static bool argCont(const char *arg
, const char *what
)
143 while(isspace (*arg
) || *arg
== ',')
146 if (arg
[0] == '#' || arg
[0] == '_')
149 if(arg
[0] == '(' && arg
[1] && arg
[2] && (arg
[2] != ')' && arg
[3] != ')')
150 && !(IS_SM83
&& (arg
[3] == '-' || arg
[3] == '+') && arg
[4] == ')'))
156 if (arg
[0] == '#' || arg
[0] == '_')
159 // Get suitable end to avoid reading into further arguments.
160 const char *end
= strchr(arg
, ',');
162 end
= arg
+ strlen(arg
);
164 const char *found
= StrStr(arg
, what
);
166 return(found
&& found
< end
);
170 z80MightBeParmInCallFromCurrentFunction(const char *what
)
172 if (strchr(what
, 'l') && z80_regs_used_as_parms_in_calls_from_current_function
[L_IDX
])
174 if (strchr(what
, 'h') && z80_regs_used_as_parms_in_calls_from_current_function
[H_IDX
])
176 if (strchr(what
, 'e') && z80_regs_used_as_parms_in_calls_from_current_function
[E_IDX
])
178 if (strchr(what
, 'd') && z80_regs_used_as_parms_in_calls_from_current_function
[D_IDX
])
180 if (strchr(what
, 'c') && z80_regs_used_as_parms_in_calls_from_current_function
[C_IDX
])
182 if (strchr(what
, 'b') && z80_regs_used_as_parms_in_calls_from_current_function
[B_IDX
])
184 if (strchr(what
, 'a') && z80_regs_used_as_parms_in_calls_from_current_function
[A_IDX
])
186 if (strstr(what
, "iy") && (z80_regs_used_as_parms_in_calls_from_current_function
[IYL_IDX
] || z80_regs_used_as_parms_in_calls_from_current_function
[IYH_IDX
]))
192 /* Check if the flag implies reading what. */
194 z80MightReadFlagCondition(const char *cond
, const char *what
)
196 while(isspace (*cond
))
199 if(!STRNCASECMP(cond
, "po", 2) || !STRNCASECMP(cond
, "pe", 2))
200 return !strcmp(what
, "pf");
201 if(tolower(cond
[0]) == 'm' || tolower(cond
[0]) == 'p')
202 return !strcmp(what
, "sf");
204 // skip inverted conditions
205 if(tolower(cond
[0]) == 'n')
208 if(tolower(cond
[0]) == 'c')
209 return !strcmp(what
, "cf");
210 if(tolower(cond
[0]) == 'z')
211 return !strcmp(what
, "zf");
216 z80MightReadFlag(const lineNode
*pl
, const char *what
)
218 if(ISINST(pl
->line
, "ld") ||
219 ISINST(pl
->line
, "or") ||
220 ISINST(pl
->line
, "cp") ||
221 ISINST(pl
->line
, "di") ||
222 ISINST(pl
->line
, "ei") ||
223 ISINST(pl
->line
, "im") ||
224 ISINST(pl
->line
, "in"))
226 if(ISINST(pl
->line
, "nop") ||
227 ISINST(pl
->line
, "add") ||
228 ISINST(pl
->line
, "sub") ||
229 ISINST(pl
->line
, "and") ||
230 ISINST(pl
->line
, "xor") ||
231 ISINST(pl
->line
, "dec") ||
232 ISINST(pl
->line
, "inc") ||
233 ISINST(pl
->line
, "cpl") ||
234 ISINST(pl
->line
, "bit") ||
235 ISINST(pl
->line
, "res") ||
236 ISINST(pl
->line
, "set") ||
237 ISINST(pl
->line
, "pop") ||
238 ISINST(pl
->line
, "rlc") ||
239 ISINST(pl
->line
, "rrc") ||
240 ISINST(pl
->line
, "sla") ||
241 ISINST(pl
->line
, "sra") ||
242 ISINST(pl
->line
, "srl") ||
243 ISINST(pl
->line
, "scf") ||
244 ISINST(pl
->line
, "cpd") ||
245 ISINST(pl
->line
, "cpi") ||
246 ISINST(pl
->line
, "ind") ||
247 ISINST(pl
->line
, "ini") ||
248 ISINST(pl
->line
, "ldd") ||
249 ISINST(pl
->line
, "ldi") ||
250 ISINST(pl
->line
, "neg") ||
251 ISINST(pl
->line
, "rld") ||
252 ISINST(pl
->line
, "rrd") ||
253 ISINST(pl
->line
, "mlt") ||
254 ISINST(pl
->line
, "out"))
256 if(ISINST(pl
->line
, "halt") ||
257 ISINST(pl
->line
, "rlca") ||
258 ISINST(pl
->line
, "rrca") ||
259 ISINST(pl
->line
, "cpdr") ||
260 ISINST(pl
->line
, "cpir") ||
261 ISINST(pl
->line
, "indr") ||
262 ISINST(pl
->line
, "inir") ||
263 ISINST(pl
->line
, "lddr") ||
264 ISINST(pl
->line
, "ldir") ||
265 ISINST(pl
->line
, "outd") ||
266 ISINST(pl
->line
, "outi") ||
267 ISINST(pl
->line
, "djnz"))
271 ISINST(pl
->line
, "bool"))
275 (ISINST(pl
->line
, "stop") ||
276 ISINST(pl
->line
, "ldh")))
279 if((IS_SM83
|| IS_Z80N
) &&
280 ISINST(pl
->line
, "swap"))
284 (ISINST(pl
->line
, "multu") ||
285 ISINST(pl
->line
, "multuw")))
288 if(ISINST(pl
->line
, "rl") ||
289 ISINST(pl
->line
, "rr") ||
290 ISINST(pl
->line
, "rla") ||
291 ISINST(pl
->line
, "rra") ||
292 ISINST(pl
->line
, "sbc") ||
293 ISINST(pl
->line
, "adc") ||
294 ISINST(pl
->line
, "ccf"))
295 return (!strcmp(what
, "cf"));
297 if(ISINST(pl
->line
, "daa"))
298 return (!strcmp(what
, "cf") || !strcmp(what
, "nf") ||
299 !strcmp(what
, "hf"));
301 if(ISINST(pl
->line
, "push"))
302 return (argCont(pl
->line
+ 4, "af"));
304 if(ISINST(pl
->line
, "ex"))
305 return (argCont(pl
->line
+ 2, "af"));
307 // catch c, nc, z, nz, po, pe, p and m
308 if(ISINST(pl
->line
, "jp") ||
309 ISINST(pl
->line
, "jr"))
310 return (strchr(pl
->line
, ',') && z80MightReadFlagCondition(pl
->line
+ 2, what
));
312 // flags don't matter according to calling convention
313 if(ISINST(pl
->line
, "reti") ||
314 ISINST(pl
->line
, "retn"))
317 if(ISINST(pl
->line
, "call"))
318 return (strchr(pl
->line
, ',') && z80MightReadFlagCondition(pl
->line
+ 4, what
));
320 if(ISINST(pl
->line
, "ret"))
321 return (pl
->line
[3] == '\t' && z80MightReadFlagCondition(pl
->line
+ 3, what
));
323 // we don't know anything about this
324 if(ISINST(pl
->line
, "rst"))
327 if (IS_SM83
&& ISINST(pl
->line
, "ldhl"))
330 if(IS_RAB
&& (ISINST(pl
->line
, "ioi") || ISINST(pl
->line
, "ioe") || ISINST(pl
->line
, "ipres")))
334 (ISINST(pl
->line
, "bsla") ||
335 ISINST(pl
->line
, "bsra") ||
336 ISINST(pl
->line
, "bsrl") ||
337 ISINST(pl
->line
, "bsrf") ||
338 ISINST(pl
->line
, "brlc")))
341 if((IS_Z180
|| IS_EZ80_Z80
|| IS_Z80N
) &&
342 ISINST(pl
->line
, "tst"))
345 return true; // Fail-safe: we have no idea what happens at this line, so assume it might read anything.
349 z80MightRead(const lineNode
*pl
, const char *what
)
351 if(strcmp(what
, "iyl") == 0 || strcmp(what
, "iyh") == 0)
353 if(strcmp(what
, "ixl") == 0 || strcmp(what
, "ixh") == 0)
356 if(ISINST(pl
->line
, "call") && strcmp(what
, "sp") == 0)
359 if(strcmp(pl
->line
, "call\t__initrleblock") == 0 && (strchr(what
, 'd') != 0 || strchr(what
, 'e') != 0))
362 if(strcmp(pl
->line
, "call\t___sdcc_call_hl") == 0 && (strchr(what
, 'h') != 0 || strchr(what
, 'l') != 0))
365 if(strcmp(pl
->line
, "call\t___sdcc_call_iy") == 0 && strstr(what
, "iy") != 0)
368 if(strncmp(pl
->line
, "call\t___sdcc_bcall_", 19) == 0)
369 if (strchr (what
, pl
->line
[19]) != 0 || strchr (what
, pl
->line
[20]) != 0 || strchr (what
, pl
->line
[21]) != 0)
372 if(ISINST(pl
->line
, "call") && strchr(pl
->line
, ',') == 0)
374 const symbol
*f
= findSym (SymbolTab
, 0, pl
->line
+ 6);
375 if (f
&& IS_FUNC (f
->type
))
376 return z80IsParmInCall(f
->type
, what
);
377 else // Fallback needed for calls through function pointers and for calls to literal addresses.
378 return z80MightBeParmInCallFromCurrentFunction(what
);
381 if(ISINST(pl
->line
, "reti") || ISINST(pl
->line
, "retn"))
382 return(strcmp(what
, "sp") == 0);
384 if(ISINST(pl
->line
, "ret")) // --reserve-regs-iy and the sm83 port use ret in code gen for calls through function pointers
385 return((IY_RESERVED
|| IS_SM83
) ? z80IsReturned(what
) || z80MightBeParmInCallFromCurrentFunction(what
) : z80IsReturned(what
)) || strcmp(what
, "sp") == 0;
387 if(!strcmp(pl
->line
, "ex\t(sp), hl") || !strcmp(pl
->line
, "ex\t(sp),hl"))
388 return(!strcmp(what
, "h") || !strcmp(what
, "l") || strcmp(what
, "sp") == 0);
389 if(!strcmp(pl
->line
, "ex\t(sp), ix") || !strcmp(pl
->line
, "ex\t(sp),ix"))
390 return(!!strstr(what
, "ix") || strcmp(what
, "sp") == 0);
391 if(!strcmp(pl
->line
, "ex\t(sp), iy") || !strcmp(pl
->line
, "ex\t(sp),iy"))
392 return(!!strstr(what
, "iy") || strcmp(what
, "sp") == 0);
393 if(!strcmp(pl
->line
, "ex\tde, hl") || !strcmp(pl
->line
, "ex\tde,hl"))
394 return(!strcmp(what
, "h") || !strcmp(what
, "l") || !strcmp(what
, "d") || !strcmp(what
, "e"));
395 if(ISINST(pl
->line
, "ld"))
397 if(argCont(strchr(pl
->line
, ','), what
))
399 if(*(strchr(pl
->line
, ',') - 1) == ')' && strstr(pl
->line
+ 3, what
) &&
400 (strchr(pl
->line
, '#') == 0 || strchr(pl
->line
, '#') > strchr(pl
->line
, ',')) &&
401 (strchr(pl
->line
, '_') == 0 || strchr(pl
->line
, '_') > strchr(pl
->line
, ',')))
403 if (!strcmp(what
, "sp") && strchr(pl
->line
, '(')) // Assume any indirect memory access to be a stack access. This avoids optimizing out stackframe setups for local variables (bug #3173).
409 if((ISINST(pl
->line
, "xor") || ISINST(pl
->line
, "sub")) &&
410 (!strcmp(pl
->line
+4, "a, a") || !strcmp(pl
->line
+4, "a,a") || (!strchr(pl
->line
, ',') && !strcmp(pl
->line
+4, "a"))))
414 if(!strcmp(pl
->line
, "and\ta, #0x00") || !strcmp(pl
->line
, "and\ta,#0x00") || !strcmp(pl
->line
, "and\t#0x00"))
418 if(!strcmp(pl
->line
, "or\ta, #0xff") || !strcmp(pl
->line
, "or\ta,#0xff") || !strcmp(pl
->line
, "or\t#0xff"))
421 if(ISINST(pl
->line
, "adc") ||
422 ISINST(pl
->line
, "add") ||
423 ISINST(pl
->line
, "and") ||
424 ISINST(pl
->line
, "sbc") ||
425 ISINST(pl
->line
, "sub") ||
426 ISINST(pl
->line
, "xor") ||
427 IS_R800
&& ISINST(pl
->line
, "multu") ||
428 IS_R800
&& ISINST(pl
->line
, "multuw"))
431 if (ISINST(pl
->line
, "multu"))
433 else if (ISINST(pl
->line
, "multuw"))
439 if(arg
[0] == 'a' && arg
[1] == ',')
441 if(!strcmp(what
, "a"))
445 else if(IS_Z80N
&& !strncmp(arg
, "bc", 2) && *(arg
+ 2) == ',')
447 if(!strcmp(what
, "b") || !strcmp(what
, "c"))
451 else if(IS_Z80N
&& !strncmp(arg
, "de", 2) && *(arg
+ 2) == ',')
453 if(!strcmp(what
, "d") || !strcmp(what
, "e"))
457 else if(!strncmp(arg
, "hl", 2) && arg
[2] == ',') // add hl, rr
459 if(!strcmp(what
, "h") || !strcmp(what
, "l"))
463 else if(!strncmp(arg
, "sp", 2) && arg
[2] == ',') // add sp, rr
465 if(!strcmp(what
, "sp"))
469 else if(arg
[0] == 'i') // add ix/y, rr
471 if(!strncmp(arg
, what
, 2))
475 return(argCont(arg
, what
));
478 if(ISINST(pl
->line
, "or") || ISINST(pl
->line
, "cp") )
480 const char *arg
= pl
->line
+ 3;
483 if(*arg
== 'a' && *(arg
+ 1) == ',')
485 if(!strcmp(what
, "a"))
489 else if(!strncmp(arg
, "hl", 2) && *(arg
+ 2) == ',')
491 if(!strcmp(what
, "h") || !strcmp(what
, "l"))
495 else if(!strncmp(arg
, "iy", 2) && *(arg
+ 2) == ',')
497 if(!strcmp(what
, "iy"))
501 return(argCont(arg
, what
));
504 if(ISINST(pl
->line
, "neg"))
505 return(strcmp(what
, "a") == 0);
507 if(ISINST(pl
->line
, "pop"))
508 return(strcmp(what
, "sp") == 0);
510 if(ISINST(pl
->line
, "push"))
511 return(strstr(pl
->line
+ 5, what
) != 0 || strcmp(what
, "sp") == 0);
513 if(ISINST(pl
->line
, "dec") ||
514 ISINST(pl
->line
, "inc"))
516 return(argCont(pl
->line
+ 4, what
));
519 if(ISINST(pl
->line
, "cpl"))
520 return(!strcmp(what
, "a"));
522 if(ISINST(pl
->line
, "di") || ISINST(pl
->line
, "ei"))
525 // Rotate and shift group
526 if(ISINST(pl
->line
, "rlca") ||
527 ISINST(pl
->line
, "rla") ||
528 ISINST(pl
->line
, "rrca") ||
529 ISINST(pl
->line
, "rra") ||
530 ISINST(pl
->line
, "daa"))
532 return(strcmp(what
, "a") == 0);
534 if(ISINST(pl
->line
, "rl") ||
535 ISINST(pl
->line
, "rr"))
537 return(argCont(pl
->line
+ 3, what
));
539 if(ISINST(pl
->line
, "rlc") ||
540 ISINST(pl
->line
, "sla") ||
541 ISINST(pl
->line
, "rrc") ||
542 ISINST(pl
->line
, "sra") ||
543 ISINST(pl
->line
, "srl"))
545 return(argCont(pl
->line
+ 4, what
));
547 if((IS_SM83
|| IS_Z80N
) && ISINST(pl
->line
, "swap"))
549 return(argCont(pl
->line
+ 5, what
));
551 if(!IS_SM83
&& !IS_RAB
&&
552 (ISINST(pl
->line
, "rld") ||
553 ISINST(pl
->line
, "rrd")))
554 return(!!strstr("ahl", what
));
556 // Bit set, reset and test group
557 if(ISINST(pl
->line
, "bit") ||
558 ISINST(pl
->line
, "set") ||
559 ISINST(pl
->line
, "res"))
561 return(argCont(strchr(pl
->line
+ 4, ','), what
));
564 if(ISINST(pl
->line
, "ccf") ||
565 ISINST(pl
->line
, "scf") ||
566 ISINST(pl
->line
, "nop") ||
567 ISINST(pl
->line
, "halt") ||
568 (IS_SM83
&& ISINST(pl
->line
, "stop")))
571 if(ISINST(pl
->line
, "jp") || ISINST(pl
->line
, "jr"))
574 if(ISINST(pl
->line
, "djnz"))
575 return(strchr(what
, 'b') != 0);
577 if(!IS_SM83
&& (ISINST(pl
->line
, "ldd") || ISINST(pl
->line
, "lddr") || ISINST(pl
->line
, "ldi") || ISINST(pl
->line
, "ldir")))
578 return(strchr("bcdehl", *what
));
579 if(IS_SM83
&& (ISINST(pl
->line
, "ldd") || ISINST(pl
->line
, "ldi")))
580 return(strchr("hl", *what
) || strstr(strchr(pl
->line
+ 4, ','), what
) != 0);
582 if(!IS_SM83
&& !IS_RAB
&& (ISINST(pl
->line
, "cpd") || ISINST(pl
->line
, "cpdr") || ISINST(pl
->line
, "cpi") || ISINST(pl
->line
, "cpir")))
583 return(strchr("abchl", *what
));
585 if(!IS_SM83
&& !IS_RAB
&& ISINST(pl
->line
, "out"))
586 return(strstr(strchr(pl
->line
+ 4, ','), what
) != 0 || strstr(pl
->line
+ 4, "(c)") && (!strcmp(what
, "b") || !strcmp(what
, "c")));
587 if(!IS_SM83
&& !IS_RAB
&& ISINST(pl
->line
, "in"))
588 return(!strstr(strchr(pl
->line
+ 4, ','), "(c)") && !strcmp(what
, "a") || strstr(strchr(pl
->line
+ 4, ','), "(c)") && (!strcmp(what
, "b") || !strcmp(what
, "c")));
590 if(IS_SM83
&& (ISINST(pl
->line
, "out") || ISINST(pl
->line
, "ldh") || ISINST(pl
->line
, "in")))
591 return(strstr(strchr(pl
->line
+ 3, ','), what
) != 0 || (!strcmp(what
, "c") && strstr(pl
->line
+ 3, "(c)")));
593 if(!IS_SM83
&& !IS_RAB
&&
594 (ISINST(pl
->line
, "ini") || ISINST(pl
->line
, "ind") || ISINST(pl
->line
, "inir") || ISINST(pl
->line
, "indr") ||
595 ISINST(pl
->line
, "outi") || ISINST(pl
->line
, "outd") || ISINST(pl
->line
, "otir") || ISINST(pl
->line
, "otdr")))
596 return(strchr("bchl", *what
));
598 if((IS_Z180
|| IS_EZ80_Z80
) && ISINST(pl
->line
, "in0"))
601 if((IS_Z180
|| IS_EZ80_Z80
|| IS_Z80N
) && ISINST(pl
->line
, "mlt"))
602 return(argCont(pl
->line
+ 4, what
));
604 if((IS_Z180
|| IS_EZ80_Z80
) &&
605 (ISINST(pl
->line
, "otim") || ISINST(pl
->line
, "otimr") || ISINST(pl
->line
, "otir") || ISINST(pl
->line
, "otirx")))
606 return(strchr("bchl", *what
));
608 if((IS_Z180
|| IS_EZ80_Z80
) && ISINST(pl
->line
, "slp"))
611 if((IS_Z180
|| IS_EZ80_Z80
|| IS_Z80N
) && ISINST(pl
->line
, "tst"))
612 return(argCont(pl
->line
+ 4, what
));
614 if((IS_Z180
|| IS_EZ80_Z80
) && ISINST(pl
->line
, "tstio"))
615 return(!strcmp(what
, "c"));
617 if(IS_RAB
&& (ISINST(pl
->line
, "ioi") || ISINST(pl
->line
, "ioe")))
620 if(IS_RAB
&& ISINST(pl
->line
, "mul"))
621 return(!strcmp(what
, "b") || !strcmp(what
, "c") || !strcmp(what
, "d") || !strcmp(what
, "e"));
623 if(IS_RAB
&& ISINST(pl
->line
, "bool"))
624 return(argCont(pl
->line
+ 5, what
));
626 if(IS_R3KA
&& ISINST(pl
->line
, "lsdr") || ISINST(pl
->line
, "lidr") || ISINST(pl
->line
, "lsddr") || ISINST(pl
->line
, "lsidr"))
627 return(strchr("bcdehl", *what
));
629 if(IS_EZ80_Z80
&& ISINST(pl
->line
, "lea"))
630 return(argCont(strchr(pl
->line
+ 4, ','), what
));
632 if(IS_EZ80_Z80
&& ISINST(pl
->line
, "pea"))
633 return(argCont(pl
->line
+ 4, what
) || !strcmp(what
, "sp"));
635 if (IS_SM83
&& (ISINST(pl
->line
, "lda") || ISINST(pl
->line
, "ldhl")))
636 return(!strcmp(what
, "sp"));
639 (ISINST(pl
->line
, "bsla") ||
640 ISINST(pl
->line
, "bsra") ||
641 ISINST(pl
->line
, "bsrl") ||
642 ISINST(pl
->line
, "bsrf") ||
643 ISINST(pl
->line
, "brlc")))
644 return(strchr("bde", *what
));
646 /* TODO: Can we know anything about rst? */
647 if(ISINST(pl
->line
, "rst"))
654 z80UncondJump(const lineNode
*pl
)
656 if((ISINST(pl
->line
, "jp") || ISINST(pl
->line
, "jr")) &&
657 strchr(pl
->line
, ',') == 0)
663 z80CondJump(const lineNode
*pl
)
665 if(((ISINST(pl
->line
, "jp") || ISINST(pl
->line
, "jr")) &&
666 strchr(pl
->line
, ',') != 0) ||
667 ISINST(pl
->line
, "djnz"))
672 // TODO: z80 flags only partly implemented
674 z80SurelyWritesFlag(const lineNode
*pl
, const char *what
)
676 /* LD instruction is never change flags except LD A,I and LD A,R.
677 But it is most popular instruction so place it first */
678 if(ISINST(pl
->line
, "ld"))
680 if(IS_SM83
|| IS_RAB
|| !!strcmp(what
, "pf") ||
681 !argCont(pl
->line
+3, "a"))
683 const char *p
= strchr(pl
->line
+4, ',');
685 return false; /* unknown instruction */
687 return argCont(p
, "i") || argCont(p
, "r");
690 if(ISINST(pl
->line
, "rlca") ||
691 ISINST(pl
->line
, "rrca") ||
692 ISINST(pl
->line
, "rra") ||
693 ISINST(pl
->line
, "rla"))
694 return (IS_SM83
|| !!strcmp(what
, "zf") && !!strcmp(what
, "sf") && !!strcmp(what
, "pf"));
696 if(ISINST(pl
->line
, "adc") ||
697 ISINST(pl
->line
, "and") ||
698 ISINST(pl
->line
, "sbc") ||
699 ISINST(pl
->line
, "sub") ||
700 ISINST(pl
->line
, "xor") ||
701 ISINST(pl
->line
, "and") ||
702 ISINST(pl
->line
, "rlc") ||
703 ISINST(pl
->line
, "rrc") ||
704 ISINST(pl
->line
, "sla") ||
705 ISINST(pl
->line
, "sra") ||
706 ISINST(pl
->line
, "srl") ||
707 ISINST(pl
->line
, "neg"))
710 if(ISINST(pl
->line
, "or") ||
711 ISINST(pl
->line
, "cp") ||
712 ISINST(pl
->line
, "rl") ||
713 ISINST(pl
->line
, "rr"))
716 if(ISINST(pl
->line
, "bit") ||
717 ISINST(pl
->line
, "cpd") ||
718 ISINST(pl
->line
, "cpi") ||
719 ISINST(pl
->line
, "ind") ||
720 ISINST(pl
->line
, "ini") ||
721 ISINST(pl
->line
, "rrd"))
722 return (!!strcmp(what
, "cf"));
724 if(ISINST(pl
->line
, "cpdr") ||
725 ISINST(pl
->line
, "cpir") ||
726 ISINST(pl
->line
, "indr") ||
727 ISINST(pl
->line
, "inir") ||
728 ISINST(pl
->line
, "otdr") ||
729 ISINST(pl
->line
, "otir") ||
730 ISINST(pl
->line
, "outd") ||
731 ISINST(pl
->line
, "outi"))
732 return (!!strcmp(what
, "cf"));
734 if(ISINST(pl
->line
, "daa"))
735 return (!!strcmp(what
, "nf"));
737 if(ISINST(pl
->line
, "ccf") ||
738 ISINST(pl
->line
, "scf"))
739 return (!strcmp(what
, "hf") || !strcmp(what
, "nf") || !strcmp(what
, "cf"));
741 if(ISINST(pl
->line
, "cpl"))
742 return (!strcmp(what
, "hf") || !strcmp(what
, "nf"));
744 if(ISINST(pl
->line
, "inc") || ISINST(pl
->line
, "dec"))
746 // 8-bit inc affects all flags other than c.
747 if (strlen(pl
->line
+ 4) == 1 || // 8-bit register
748 !strcmp(pl
->line
+ 4, "(hl)") ||
749 !strcmp(pl
->line
+ 6, "(ix)") ||
750 !strcmp(pl
->line
+ 6, "(iy)"))
751 return (!!strcmp(what
, "cf"));
752 return false; // 16-bit inc does not affect flags.
755 if(ISINST(pl
->line
, "add"))
756 return (argCont(pl
->line
+ 4, "a") ||
757 (!!strcmp(what
, "zf") && !!strcmp(what
, "sf") && !!strcmp(what
, "pf")));
759 if(ISINST(pl
->line
, "ldd") ||
760 ISINST(pl
->line
, "lddr") ||
761 ISINST(pl
->line
, "ldi") ||
762 ISINST(pl
->line
, "ldir"))
763 return (!strcmp(what
, "hf") || !strcmp(what
, "pf") || !strcmp(what
, "nf"));
766 if(ISINST(pl
->line
, "pop"))
767 return (argCont(pl
->line
+ 4, "af"));
769 // according to calling convention caller has to save flags
770 if(ISINST(pl
->line
, "ret") ||
771 ISINST(pl
->line
, "call"))
774 if(ISINST(pl
->line
, "rld") ||
775 ISINST(pl
->line
, "rrd"))
776 return (!strcmp(what
, "hf") || !strcmp(what
, "pf") || !strcmp(what
, "nf"));
778 if(ISINST(pl
->line
, "djnz") ||
779 ISINST(pl
->line
, "ex") ||
780 ISINST(pl
->line
, "nop") ||
781 ISINST(pl
->line
, "out") ||
782 ISINST(pl
->line
, "push") ||
783 ISINST(pl
->line
, "res") ||
784 ISINST(pl
->line
, "set"))
788 (ISINST(pl
->line
, "swap") ||
789 ISINST(pl
->line
, "ldhl") ||
790 ISINST(pl
->line
, "lda")))
794 ISINST(pl
->line
, "swap"))
797 /* handle IN0 r,(n) and IN r,(c) instructions */
798 if(ISINST(pl
->line
, "in0") || (!strncmp(pl
->line
, "in\t", 3) &&
799 (!strcmp(pl
->line
+5, "(c)") || !strcmp(pl
->line
+5, "(bc)"))))
800 return (!!strcmp(what
, "cf"));
803 ISINST(pl
->line
, "bool"))
807 ISINST(pl
->line
, "ipres"))
810 if(ISINST(pl
->line
, "mlt"))
813 if((IS_Z180
|| IS_EZ80_Z80
|| IS_Z80N
) &&
814 ISINST(pl
->line
, "tst"))
817 return false; // Fail-safe: we have no idea what happens at this line, so assume it writes nothing.
821 callSurelyWrites (const lineNode
*pl
, const char *what
)
824 if (ISINST(pl
->line
, "call") && !strchr(pl
->line
, ','))
825 f
= findSym (SymbolTab
, 0, pl
->line
+ 6);
826 else if ((ISINST(pl
->line
, "jp") || ISINST(pl
->line
, "jr")) && !strchr(pl
->line
, ','))
827 f
= findSym (SymbolTab
, 0, pl
->line
+ 4);
829 const bool *preserved_regs
;
831 if (f
&& (strlen(what
) == 2 && what
[1] == 'f')) // Flags are never preserved across function calls.
834 if(!strcmp(what
, "ix"))
838 preserved_regs
= f
->type
->funcAttrs
.preserved_regs
;
839 else if (ISINST(pl
->line
, "call"))
840 preserved_regs
= z80_regs_preserved_in_calls_from_current_function
;
841 else // Err on the safe side for jp and jr - might not be a function call, might e.g. be a jump table.
844 if (!strcmp (what
, "a"))
845 return !preserved_regs
[A_IDX
];
846 if (!strcmp (what
, "c"))
847 return !preserved_regs
[C_IDX
];
848 if (!strcmp (what
, "b"))
849 return !preserved_regs
[B_IDX
];
850 if (!strcmp (what
, "e"))
851 return !preserved_regs
[E_IDX
];
852 if (!strcmp (what
, "d"))
853 return !preserved_regs
[D_IDX
];
854 if (!strcmp (what
, "l"))
855 return !preserved_regs
[L_IDX
];
856 if (!strcmp (what
, "h"))
857 return !preserved_regs
[H_IDX
];
858 if (!strcmp (what
, "iyl"))
859 return !preserved_regs
[IYL_IDX
];
860 if (!strcmp (what
, "iyh"))
861 return !preserved_regs
[IYH_IDX
];
862 if (!strcmp (what
, "iy"))
863 return !preserved_regs
[IYL_IDX
] && !preserved_regs
[IYH_IDX
];
869 z80SurelyWrites (const lineNode
*pl
, const char *what
)
871 if(strcmp(what
, "iyl") == 0 || strcmp(what
, "iyh") == 0)
873 if(strcmp(what
, "ixl") == 0 || strcmp(what
, "ixh") == 0)
877 if((ISINST(pl
->line
, "xor") || ISINST(pl
->line
, "sub")) && !strcmp(what
, "a") &&
878 (!strcmp(pl
->line
+4, "a, a") || !strcmp(pl
->line
+4, "a,a") || (!strchr(pl
->line
, ',') && !strcmp(pl
->line
+4, "a"))))
882 if(!strcmp(what
, "a") && (!strcmp(pl
->line
, "and\ta, #0x00") || !strcmp(pl
->line
, "and\ta,#0x00") || !strcmp(pl
->line
, "and\t#0x00")))
886 if(!strcmp(what
, "a") && (!strcmp(pl
->line
, "or\ta, #0xff") || !strcmp(pl
->line
, "or\ta,#0xff") || !strcmp(pl
->line
, "or\t#0xff")))
889 if(ISINST(pl
->line
, "ld") && strncmp(pl
->line
+ 3, "hl", 2) == 0 && (what
[0] == 'h' || what
[0] == 'l'))
891 if(ISINST(pl
->line
, "ld") && strncmp(pl
->line
+ 3, "de", 2) == 0 && (what
[0] == 'd' || what
[0] == 'e'))
893 if(ISINST(pl
->line
, "ld") && strncmp(pl
->line
+ 3, "bc", 2) == 0 && (what
[0] == 'b' || what
[0] == 'c'))
895 if((ISINST(pl
->line
, "ld") || ISINST(pl
->line
, "in"))
896 && strncmp(pl
->line
+ 3, what
, strlen(what
)) == 0 && pl
->line
[3 + strlen(what
)] == ',')
899 if(IS_SM83
&& (ISINST(pl
->line
, "ldd") || ISINST(pl
->line
, "ldi") || ISINST(pl
->line
, "ldh")))
900 return(strncmp(pl
->line
+ 4, what
, strlen(what
)) == 0);
902 if(ISINST(pl
->line
, "pop") && strstr(pl
->line
+ 4, what
))
904 if (ISINST(pl
->line
, "call") && strchr(pl
->line
, ',') == 0)
905 return (callSurelyWrites (pl
, what
));
907 if(strcmp(pl
->line
, "ret") == 0)
910 if (IS_Z180
|| IS_EZ80_Z80
|| IS_Z80N
)
911 if (ISINST(pl
->line
, "mlt"))
912 return(strchr(pl
->line
+ 4, *what
) != 0);
915 if (ISINST(pl
->line
, "multu"))
916 return(strchr("hl", *what
) != NULL
);
919 if (ISINST(pl
->line
, "multuw"))
920 return(strchr("dehl", *what
) != NULL
);
922 if (IS_Z180
|| IS_EZ80_Z80
)
924 if (ISINST(pl
->line
, "otim") ||
925 ISINST(pl
->line
, "otimr") ||
926 ISINST(pl
->line
, "otdm") ||
927 ISINST(pl
->line
, "otdmr"))
928 return(strchr("bchl", *what
) != NULL
);
930 if (ISINST(pl
->line
, "in0"))
931 return(!strncmp(pl
->line
+ 4, what
, strlen(what
)));
934 if (IS_EZ80_Z80
&& ISINST(pl
->line
, "lea"))
935 return (strstr(pl
->line
+ 4, what
));
937 if (IS_SM83
&& ISINST(pl
->line
, "lda") && strncmp(pl
->line
+ 4, "hl", 2) == 0 && (what
[0] == 'h' || what
[0] == 'l'))
940 if (IS_SM83
&& ISINST(pl
->line
, "ldhl") && (what
[0] == 'h' || what
[0] == 'l'))
947 z80SurelyReturns(const lineNode
*pl
)
949 if(strcmp(pl
->line
, "ret") == 0)
954 /*-----------------------------------------------------------------*/
955 /* scan4op - "executes" and examines the assembler opcodes, */
956 /* follows conditional and un-conditional jumps. */
957 /* Moreover it registers all passed labels. */
961 /* scanning starts from pl; */
962 /* pl also returns the last scanned line */
963 /* const char *pReg */
964 /* points to a register (e.g. "ar0"). scan4op() tests for */
965 /* read or write operations with this register */
966 /* const char *untilOp */
967 /* points to NULL or a opcode (e.g. "push"). */
968 /* scan4op() returns if it hits this opcode. */
969 /* lineNode **plCond */
970 /* If a conditional branch is met plCond points to the */
971 /* lineNode of the conditional branch */
977 /* hit lineNode with "visited" flag set: scan4op() already */
978 /* scanned this opcode. */
979 /* S4O_FOUNDOPCODE */
980 /* found opcode and operand, to which untilOp and pReg are */
982 /* S4O_RD_OP, S4O_WR_OP */
983 /* hit an opcode reading or writing from pReg */
985 /* hit a conditional jump opcode. pl and plCond return the */
986 /* two possible branches. */
988 /* acall, lcall, ret and reti "terminate" a scan. */
989 /*-----------------------------------------------------------------*/
991 scan4op (lineNode
**pl
, const char *what
, const char *untilOp
,
994 bool isFlag
= (strlen(what
) == 2 && what
[1] == 'f');
995 for (; *pl
; *pl
= (*pl
)->next
)
997 if (!(*pl
)->line
|| (*pl
)->isDebug
|| (*pl
)->isComment
|| (*pl
)->isLabel
)
999 D(("Scanning %s for %s\n", (*pl
)->line
, what
));
1000 /* don't optimize across inline assembler,
1001 e.g. isLabel doesn't work there */
1002 if ((*pl
)->isInline
)
1004 D(("S4O_RD_OP: Inline asm\n"));
1010 D(("S4O_VISITED\n"));
1014 (*pl
)->visited
= TRUE
;
1018 if(z80MightReadFlag(*pl
, what
))
1020 D(("S4O_RD_OP (flag)\n"));
1026 if (z80MightRead (*pl
, what
))
1028 D (("S4O_RD_OP\n"));
1033 if (z80UncondJump (*pl
))
1035 lineNode
*tlbl
= findLabel (*pl
);
1036 if (!tlbl
) // jp/jr could be a tail call.
1038 const symbol
*f
= findSym (SymbolTab
, 0, (*pl
)->line
+ 4);
1039 if (f
&& z80IsParmInCall(f
->type
, what
))
1041 D (("S4O_RD_OP\n"));
1044 else if(callSurelyWrites (*pl
, what
))
1046 D (("S4O_WR_OP\n"));
1053 D (("S4O_ABORT\n"));
1057 if (z80CondJump(*pl
))
1059 *plCond
= findLabel (*pl
);
1062 D (("S4O_ABORT\n"));
1065 D (("S4O_CONDJMP\n"));
1071 if (z80SurelyWritesFlag (*pl
, what
))
1073 D (("S4O_WR_OP (flag)\n"));
1079 if(z80SurelyWrites(*pl
, what
))
1086 /* Don't need to check for de, hl since z80MightRead() does that */
1087 if(z80SurelyReturns(*pl
))
1097 /*-----------------------------------------------------------------*/
1098 /* doTermScan - scan through area 2. This small wrapper handles: */
1099 /* - action required on different return values */
1100 /* - recursion in case of conditional branches */
1101 /*-----------------------------------------------------------------*/
1103 doTermScan (lineNode
**pl
, const char *what
)
1105 lineNode
*plConditional
;
1107 for (;; *pl
= (*pl
)->next
)
1109 switch (scan4op (pl
, what
, NULL
, &plConditional
))
1114 /* all these are terminating conditions */
1117 /* two possible destinations: recurse */
1119 lineNode
*pl2
= plConditional
;
1120 D(("CONDJMP trying other branch first\n"));
1121 if (!doTermScan (&pl2
, what
))
1123 D(("Other branch OK.\n"));
1134 /* Regular 8 bit reg */
1136 isReg(const char *what
)
1138 if(strlen(what
) != 1)
1154 /* 8-Bit reg only accessible by 16-bit and undocumented instructions */
1156 isUReg(const char *what
)
1158 if(strcmp(what
, "iyl") == 0 || strcmp(what
, "iyh") == 0)
1160 if(strcmp(what
, "ixl") == 0 || strcmp(what
, "ixh") == 0)
1166 isRegPair(const char *what
)
1168 if(strlen(what
) != 2)
1170 if(strcmp(what
, "bc") == 0)
1172 if(strcmp(what
, "de") == 0)
1174 if(strcmp(what
, "hl") == 0)
1176 if(strcmp(what
, "ix") == 0)
1178 if(strcmp(what
, "iy") == 0)
1183 /* Check that what is never read after endPl. */
1186 z80notUsed (const char *what
, lineNode
*endPl
, lineNode
*head
)
1189 D(("Checking for %s\n", what
));
1191 if(strcmp(what
, "af") == 0)
1193 if(!z80notUsed("a", endPl
, head
))
1198 if(strcmp(what
, "f") == 0)
1199 return z80notUsed("zf", endPl
, head
) && z80notUsed("cf", endPl
, head
) &&
1200 z80notUsed("sf", endPl
, head
) && z80notUsed("pf", endPl
, head
) &&
1201 z80notUsed("nf", endPl
, head
) && z80notUsed("hf", endPl
, head
);
1203 if(strcmp(what
, "iy") == 0)
1207 return(z80notUsed("iyl", endPl
, head
) && z80notUsed("iyh", endPl
, head
));
1210 if(strcmp(what
, "ix") == 0)
1211 return(z80notUsed("ixl", endPl
, head
) && z80notUsed("ixh", endPl
, head
));
1215 char low
[2], high
[2];
1220 return(z80notUsed(low
, endPl
, head
) && z80notUsed(high
, endPl
, head
));
1223 // P/V and L/V (rabbits) are the same flag
1224 if(!strcmp(what
, "vf") || !strcmp(what
, "lf"))
1227 // SM83 does not use what it does not have
1228 // but this allows to write rules for all Z80ies
1229 if(IS_SM83
&& (!strcmp(what
, "sf") || !strcmp(what
, "pf")))
1231 D(("Flag %s does not exist\n", what
));
1235 // enable sp and flags
1236 if(!isReg(what
) && !isUReg(what
) &&
1237 strcmp(what
, "sp") && strcmp(what
+1, "f"))
1242 unvisitLines (_G
.head
);
1245 if (!doTermScan (&pl
, what
))
1252 z80notUsedFrom (const char *what
, const char *label
, lineNode
*head
)
1256 for (cpl
= head
; cpl
; cpl
= cpl
->next
)
1258 if (cpl
->isLabel
&& !strncmp (label
, cpl
->line
, strlen(label
)))
1260 return z80notUsed (what
, cpl
, head
);
1268 z80canAssign (const char *op1
, const char *op2
, const char *exotic
)
1270 const char *dst
, *src
;
1272 // Indexed accesses: One is the indexed one, the other one needs to be a reg or immediate.
1275 if(!strcmp(exotic
, "ix") || !strcmp(exotic
, "iy"))
1277 if(isReg(op1
) || (IS_EZ80_Z80
&& isRegPair(op1
)))
1280 else if(!strcmp(op2
, "ix") || !strcmp(op2
, "iy"))
1282 if(isReg(exotic
) || exotic
[0] == '#' || (IS_EZ80_Z80
&& isRegPair(exotic
)))
1293 // 8-bit regs can be assigned to each other directly.
1294 if(isReg(dst
) && isReg(src
))
1296 if(HAS_IYL_INST
) // With some restrictions also for iyl, iyh, ixl, ixh.
1298 if (isUReg(dst
) && isReg(src
) && src
[0] <= 'e')
1300 if (isUReg(src
) && isReg(dst
) && dst
[0] <= 'e')
1302 if (isUReg(dst
) && isUReg(src
) && src
[1] == dst
[1])
1306 // Immediates van be loaded into 8-bit registers.
1307 if((isReg(dst
) || HAS_IYL_INST
&& isUReg(dst
)) && src
[0] == '#')
1310 // Same if at most one of them is (hl).
1311 if((isReg(dst
) || (IS_EZ80_Z80
&& isRegPair(dst
))) && !strcmp(src
, "(hl)"))
1313 if(!strcmp(dst
, "(hl)") && (isReg(src
) || (IS_EZ80_Z80
&& isRegPair(src
))))
1316 // Can assign between a and (bc), (de), (hl+), (hl-)
1317 if(!strcmp(dst
, "a") &&
1318 (!strcmp(src
, "(bc)") || !strcmp(src
, "(de)") || !strcmp(src
, "(hl+)") || !strcmp(src
, "(hl-)")))
1320 if((!strcmp(dst
, "(bc)") || !strcmp(dst
, "(de)") || !strcmp(src
, "(hl+)") || !strcmp(src
, "(hl-)"))
1321 && !strcmp(src
, "a"))
1324 // Can load immediate values directly into registers and register pairs.
1325 if((isReg(dst
) || isRegPair(dst
) || !strcmp(src
, "sp")) && src
[0] == '#')
1328 if((!strcmp(dst
, "a") || (!IS_SM83
&& (isRegPair(dst
) || !strcmp(src
, "sp")))) && !strncmp(src
, "(#", 2))
1330 if(!strncmp(dst
, "(#", 2) && (!strcmp(src
, "a") || (!IS_SM83
&& isRegPair(src
)) || !strcmp(src
, "sp")))
1333 // Can load immediate values directly into (hl).
1334 if(!strcmp(dst
, "(hl)") && src
[0] == '#')
1337 // Can load between hl / ix / iy and sp.
1338 if(!strcmp(dst
, "sp") && (!strcmp(src
, "hl") || !strcmp(src
, "ix") || !strcmp(src
, "iy")) ||
1339 (!strcmp(dst
, "hl") || !strcmp(dst
, "ix") || !strcmp(dst
, "iy")) && !strcmp(src
, "sp"))
1342 // Rabbit can load between iy and hl.
1344 (!strcmp(dst
, "hl") && (!strcmp(src
, "ix") || !strcmp(src
, "iy")) ||
1345 (!strcmp(dst
, "ix") || !strcmp(dst
, "iy")) && !strcmp(src
, "hl")))
1352 registerBaseName (const char *op
)
1354 if (!strcmp (op
, "d") || !strcmp (op
, "e") || !strcmp (op
, "(de)"))
1356 if (!strcmp (op
, "b") || !strcmp (op
, "c") || !strcmp (op
, "(bc)"))
1358 if (!strcmp (op
, "h") || !strcmp (op
, "l") || !strcmp (op
, "(hl)") || !strcmp (op
, "(hl+)") || !strcmp (op
, "(hl-)"))
1360 if (!strcmp (op
, "iyh") || !strcmp (op
, "iyl") || strstr (op
, "iy"))
1362 if (!strcmp (op
, "ixh") || !strcmp (op
, "ixl") || strstr (op
, "ix"))
1364 if (!strcmp (op
, "a"))
1369 // canJoinRegs(reg_hi reg_lo [dst]) returns TRUE,
1370 bool z80canJoinRegs (const char **regs
, char dst
[20])
1372 //check for only 2 source registers
1373 if (!regs
[0] || !regs
[1] || regs
[2])
1375 size_t l1
= strlen (regs
[0]);
1376 size_t l2
= strlen (regs
[1]);
1379 if (l1
== 0 || l2
== 0)
1381 if (l1
== 0 && l2
== 0)
1383 strcpy (dst
, registerBaseName (regs
[l1
? 0 : 1]));
1387 memcpy (&dst
[0], regs
[0], l1
);
1388 memcpy (&dst
[l1
], regs
[1], l2
+ 1); //copy including \0
1390 if (!strcmp (dst
, "ixhixl") || !strcmp (dst
, "iyhiyl"))
1396 return isRegPair (dst
);
1399 bool z80canSplitReg (const char *reg
, char dst
[][16], int nDst
)
1402 if (nDst
< 0 || nDst
> 2)
1404 if (!strcmp (reg
, "bc") || !strcmp (reg
, "de") || !strcmp (reg
, "hl"))
1406 for (i
= 0; i
< nDst
; ++i
)
1412 else if (HAS_IYL_INST
&& (!strcmp (reg
, "ix") || !strcmp (reg
, "iy")))
1414 for (i
= 0; i
< nDst
; ++i
)
1418 dst
[i
][2] = "hl"[i
];
1428 int z80instructionSize(lineNode
*pl
)
1430 const char *op1start
, *op2start
;
1432 /* move to the first operand:
1433 * leading spaces are already removed, skip the mnemonic */
1434 for (op1start
= pl
->line
; *op1start
&& !isspace (*op1start
); ++op1start
);
1436 /* skip the spaces between mnemonic and the operand */
1437 while (isspace (*op1start
))
1444 /* move to the second operand:
1445 * find the comma and skip the following spaces */
1446 op2start
= strchr(op1start
, ',');
1451 while (isspace (*op2start
));
1453 if ('\0' == *op2start
)
1460 if(TARGET_IS_TLCS90
) // Todo: More accurate estimate.
1463 /* All ld instructions */
1464 if(ISINST(pl
->line
, "ld"))
1466 /* These 4 are the only cases of 4 byte long ld instructions. */
1467 if(!STRNCASECMP(op1start
, "ix", 2) || !STRNCASECMP(op1start
, "iy", 2))
1469 if((argCont(op1start
, "(ix)") || argCont(op1start
, "(iy)")) && op2start
[0] == '#')
1472 if(op1start
[0] == '(' && STRNCASECMP(op1start
, "(bc)", 4) &&
1473 STRNCASECMP(op1start
, "(de)", 4) && STRNCASECMP(op1start
, "(hl" , 3) &&
1474 STRNCASECMP(op2start
, "hl", 2) && STRNCASECMP(op2start
, "a", 1) &&
1475 (!IS_SM83
|| STRNCASECMP(op2start
, "sp", 2)) ||
1476 op2start
[0] == '(' && STRNCASECMP(op2start
, "(bc)", 4) &&
1477 STRNCASECMP(op1start
, "(de)", 4) && STRNCASECMP(op2start
, "(hl" , 3) &&
1478 STRNCASECMP(op1start
, "hl", 2) && STRNCASECMP(op1start
, "a", 1))
1481 /* Rabbit 16-bit pointer load */
1482 if(IS_RAB
&& !STRNCASECMP(op1start
, "hl", 2) && (argCont(op2start
, "(hl)") || argCont(op2start
, "(iy)")))
1484 if(IS_RAB
&& !STRNCASECMP(op1start
, "hl", 2) && (argCont(op2start
, "(sp)") || argCont(op2start
, "(ix)")))
1487 /* eZ80 16-bit pointer load */
1489 (!STRNCASECMP(op1start
, "bc", 2) || !STRNCASECMP(op1start
, "de", 2) || !STRNCASECMP(op1start
, "hl", 2) || !STRNCASECMP(op1start
, "ix", 2) || !STRNCASECMP(op1start
, "iy", 2)))
1491 if (!STRNCASECMP(op2start
, "(hl)", 4))
1493 if (argCont(op2start
, "(ix)") || argCont(op2start
, "(iy)"))
1497 (!STRNCASECMP(op2start
, "bc", 2) || !STRNCASECMP(op2start
, "de", 2) || !STRNCASECMP(op2start
, "hl", 2) || !STRNCASECMP(op2start
, "ix", 2) || !STRNCASECMP(op2start
, "iy", 2)))
1499 if (!STRNCASECMP(op1start
, "(hl)", 4))
1501 if (argCont(op1start
, "(ix)") || argCont(op1start
, "(iy)"))
1505 /* These 4 are the only remaining cases of 3 byte long ld instructions. */
1506 if(argCont(op2start
, "(ix)") || argCont(op2start
, "(iy)"))
1508 if(argCont(op1start
, "(ix)") || argCont(op1start
, "(iy)"))
1510 if((op1start
[0] == '(' && STRNCASECMP(op1start
, "(bc)", 4) && STRNCASECMP(op1start
, "(de)", 4) && STRNCASECMP(op1start
, "(hl", 3)) ||
1511 (op2start
[0] == '(' && STRNCASECMP(op2start
, "(bc)", 4) && STRNCASECMP(op2start
, "(de)", 4) && STRNCASECMP(op2start
, "(hl", 3)))
1513 if(op2start
[0] == '#' &&
1514 (!STRNCASECMP(op1start
, "bc", 2) || !STRNCASECMP(op1start
, "de", 2) || !STRNCASECMP(op1start
, "hl", 2) || !STRNCASECMP(op1start
, "sp", 2)))
1517 /* These 3 are the only remaining cases of 2 byte long ld instructions. */
1518 if(op2start
[0] == '#')
1520 if(!STRNCASECMP(op1start
, "i", 1) || !STRNCASECMP(op1start
, "r", 1) ||
1521 !STRNCASECMP(op2start
, "i", 1) || !STRNCASECMP(op2start
, "r", 1))
1523 if(!STRNCASECMP(op2start
, "ix", 2) || !STRNCASECMP(op2start
, "iy", 2))
1526 /* All other ld instructions */
1530 // load from sp with offset
1531 if(IS_SM83
&& (ISINST(pl
->line
, "lda") || ISINST(pl
->line
, "ldhl")))
1535 // load from/to 0xffXX addresses
1536 if(IS_SM83
&& (ISINST(pl
->line
, "ldh") || ISINST(pl
->line
, "in") || ISINST(pl
->line
, "out")))
1538 if(!STRNCASECMP(pl
->line
, "(c)", 3))
1544 if(ISINST(pl
->line
, "exx"))
1546 if(ISINST(pl
->line
, "ex"))
1550 werrorfl(pl
->ic
->filename
, pl
->ic
->lineno
, W_UNRECOGNIZED_ASM
, __FUNCTION__
, 4, pl
->line
);
1553 if(argCont(op1start
, "(sp)") && (IS_RAB
|| !STRNCASECMP(op2start
, "ix", 2) || !STRNCASECMP(op2start
, "iy", 2)))
1559 if(ISINST(pl
->line
, "push") && IS_Z80N
&& op1start
[0] == '#')
1561 if(ISINST(pl
->line
, "push") || ISINST(pl
->line
, "pop"))
1563 if(!STRNCASECMP(op1start
, "ix", 2) || !STRNCASECMP(op1start
, "iy", 2))
1568 /* 16 bit add / subtract / and / or */
1569 if(IS_Z80N
&& ISINST(pl
->line
, "add") && (!STRNCASECMP(op1start
, "bc", 2) || !STRNCASECMP(op1start
, "de", 2) || !STRNCASECMP(op1start
, "hl", 2)))
1571 if((ISINST(pl
->line
, "add") || ISINST(pl
->line
, "adc") || ISINST(pl
->line
, "sbc") || IS_RAB
&& (ISINST(pl
->line
, "and") || ISINST(pl
->line
, "or"))) &&
1572 !STRNCASECMP(op1start
, "hl", 2))
1574 if(ISINST(pl
->line
, "add") || ISINST(pl
->line
, "and") || ISINST(pl
->line
, "or"))
1578 if((ISINST(pl
->line
, "add") || IS_RAB
&& (ISINST(pl
->line
, "and") || ISINST(pl
->line
, "or")))&& (!STRNCASECMP(op1start
, "ix", 2) || !STRNCASECMP(op1start
, "iy", 2)))
1581 /* signed 8 bit adjustment to stack pointer */
1582 if((IS_RAB
|| IS_SM83
) && ISINST(pl
->line
, "add") && !STRNCASECMP(op1start
, "sp", 2))
1585 /* 16 bit adjustment to stack pointer */
1586 if(IS_TLCS90
&& ISINST(pl
->line
, "add") && !STRNCASECMP(op1start
, "sp", 2))
1589 /* 8 bit arithmetic, two operands */
1590 if(op2start
&& op1start
[0] == 'a' &&
1591 (ISINST(pl
->line
, "add") || ISINST(pl
->line
, "adc") || ISINST(pl
->line
, "sub") || ISINST(pl
->line
, "sbc") ||
1592 ISINST(pl
->line
, "cp") || ISINST(pl
->line
, "and") || ISINST(pl
->line
, "or") || ISINST(pl
->line
, "xor")))
1594 if(argCont(op2start
, "(ix)") || argCont(op2start
, "(iy)"))
1596 if(op2start
[0] == '#')
1600 /* 8 bit arithmetic, shorthand for a */
1602 (ISINST(pl
->line
, "add") || ISINST(pl
->line
, "adc") || ISINST(pl
->line
, "sub") || ISINST(pl
->line
, "sbc") ||
1603 ISINST(pl
->line
, "cp") || ISINST(pl
->line
, "and") || ISINST(pl
->line
, "or") || ISINST(pl
->line
, "xor")))
1605 if(argCont(op1start
, "(ix)") || argCont(op1start
, "(iy)"))
1607 if(op1start
[0] == '#')
1612 if(ISINST(pl
->line
, "rlca") || ISINST(pl
->line
, "rla") || ISINST(pl
->line
, "rrca") || ISINST(pl
->line
, "rra"))
1615 /* Increment / decrement */
1616 if(ISINST(pl
->line
, "inc") || ISINST(pl
->line
, "dec"))
1618 if(!STRNCASECMP(op1start
, "ix", 2) || !STRNCASECMP(op1start
, "iy", 2))
1620 if(argCont(op1start
, "(ix)") || argCont(op1start
, "(iy)"))
1625 if(ISINST(pl
->line
, "rlc") || ISINST(pl
->line
, "rl") || ISINST(pl
->line
, "rrc") || ISINST(pl
->line
, "rr") ||
1626 ISINST(pl
->line
, "sla") || ISINST(pl
->line
, "sra") || ISINST(pl
->line
, "srl"))
1628 if(argCont(op1start
, "(ix)") || argCont(op1start
, "(iy)"))
1633 if(ISINST(pl
->line
, "rld") || ISINST(pl
->line
, "rrd"))
1637 if(ISINST(pl
->line
, "bit") || ISINST(pl
->line
, "set") || ISINST(pl
->line
, "res"))
1639 if(argCont(op2start
, "(ix)") || argCont(op2start
, "(iy)"))
1644 if(ISINST(pl
->line
, "jr") || ISINST(pl
->line
, "djnz"))
1647 if(ISINST(pl
->line
, "jp"))
1649 if(!STRNCASECMP(op1start
, "(hl)", 4))
1651 if(!STRNCASECMP(op1start
, "(ix)", 4) || !STRNCASECMP(op1start
, "(iy)", 4))
1657 (ISINST(pl
->line
, "ipset3") || ISINST(pl
->line
, "ipset2") ||
1658 ISINST(pl
->line
, "ipset1") || ISINST(pl
->line
, "ipset0") ||
1659 ISINST(pl
->line
, "ipres")))
1662 if(!IS_SM83
&& (ISINST(pl
->line
, "reti") || ISINST(pl
->line
, "retn")))
1665 if(ISINST(pl
->line
, "ret") || ISINST(pl
->line
, "reti") || ISINST(pl
->line
, "rst"))
1668 if(ISINST(pl
->line
, "call"))
1671 /* Alias for ld a, (hl+)/(hld) etc */
1672 if(IS_SM83
&& (ISINST(pl
->line
, "ldi") || ISINST(pl
->line
, "ldd")))
1675 if(ISINST(pl
->line
, "ldi") || ISINST(pl
->line
, "ldd") || ISINST(pl
->line
, "cpi") || ISINST(pl
->line
, "cpd"))
1678 if(ISINST(pl
->line
, "neg"))
1681 if(ISINST(pl
->line
, "daa") || ISINST(pl
->line
, "cpl") || ISINST(pl
->line
, "ccf") || ISINST(pl
->line
, "scf") ||
1682 ISINST(pl
->line
, "nop") || ISINST(pl
->line
, "halt") || ISINST(pl
->line
, "ei") || ISINST(pl
->line
, "di"))
1685 /* We always emit 2B stop due to hardware bugs*/
1686 if (IS_SM83
&& ISINST(pl
->line
, "stop"))
1689 if(ISINST(pl
->line
, "im"))
1692 if(ISINST(pl
->line
, "in") || ISINST(pl
->line
, "out") || ISINST(pl
->line
, "ot") ||
1693 ISINST(pl
->line
, "ini") || ISINST(pl
->line
, "inir") || ISINST(pl
->line
, "ind") ||
1694 ISINST(pl
->line
, "indr") || ISINST(pl
->line
, "outi") || ISINST(pl
->line
, "otir") ||
1695 ISINST(pl
->line
, "outd") || ISINST(pl
->line
, "otdr"))
1700 if((IS_Z180
|| IS_EZ80_Z80
) && (ISINST(pl
->line
, "in0") || ISINST(pl
->line
, "out0")))
1703 if((IS_Z180
|| IS_EZ80_Z80
|| IS_Z80N
) && ISINST(pl
->line
, "mlt"))
1706 if (IS_R800
&& (ISINST(pl
->line
, "multu") || ISINST(pl
->line
, "multuw")))
1709 if((IS_Z180
|| IS_EZ80_Z80
|| IS_Z80N
) && ISINST(pl
->line
, "tst"))
1710 return((op1start
[0] == '#' || op2start
&& op1start
[0] == '#') ? 3 : 2);
1712 if(IS_RAB
&& (ISINST(pl
->line
, "ioi") || ISINST(pl
->line
, "ioe")))
1715 if(IS_RAB
&& ISINST(pl
->line
, "mul"))
1718 if(ISINST(pl
->line
, "lddr") || ISINST(pl
->line
, "ldir") || ISINST(pl
->line
, "cpir") || ISINST(pl
->line
, "cpdr"))
1722 (ISINST(pl
->line
, "lddsr") || ISINST(pl
->line
, "ldisr") ||
1723 ISINST(pl
->line
, "lsdr") || ISINST(pl
->line
, "lsir") ||
1724 ISINST(pl
->line
, "lsddr") || ISINST(pl
->line
, "lsidr")))
1727 if(IS_R3KA
&& (ISINST(pl
->line
, "uma") || ISINST(pl
->line
, "ums")))
1730 if(IS_RAB
&& ISINST(pl
->line
, "bool"))
1731 return(!STRNCASECMP(op1start
, "hl", 2) ? 1 : 2);
1733 if(IS_EZ80_Z80
&& (ISINST(pl
->line
, "lea") || ISINST(pl
->line
, "pea")))
1736 if((IS_SM83
|| IS_Z80N
) && ISINST(pl
->line
, "swap"))
1739 if(IS_Z80N
&& (ISINST(pl
->line
, "swapnib") || ISINST(pl
->line
, "mirror") || ISINST(pl
->line
, "mul") ||
1740 ISINST(pl
->line
, "outinb") || ISINST(pl
->line
, "ldix") || ISINST(pl
->line
, "ldirx") ||
1741 ISINST(pl
->line
, "lddx") || ISINST(pl
->line
, "lddrx") || ISINST(pl
->line
, "ldpirx")))
1745 (ISINST(pl
->line
, "bsla") ||
1746 ISINST(pl
->line
, "bsra") ||
1747 ISINST(pl
->line
, "bsrl") ||
1748 ISINST(pl
->line
, "bsrf") ||
1749 ISINST(pl
->line
, "brlc")))
1752 if(IS_Z80N
&& ISINST(pl
->line
, "nextreg"))
1753 return(op2start
&& !STRNCASECMP(op2start
, "a", 1) ? 3 : 4);
1755 if(ISINST(pl
->line
, ".db") || ISINST(pl
->line
, ".byte"))
1758 for(i
= 1, j
= 0; pl
->line
[j
]; i
+= pl
->line
[j
] == ',', j
++);
1762 if(ISINST(pl
->line
, ".dw") || ISINST(pl
->line
, ".word"))
1765 for(i
= 1, j
= 0; pl
->line
[j
]; i
+= pl
->line
[j
] == ',', j
++);
1769 if(IS_SM83
&& ISINST(pl
->line
, ".tile"))
1774 for (value
= pl
->line
; *value
&& !isspace (*value
); ++value
);
1776 for (; *value
&& isspace (*value
); ++value
);
1777 // just part of the syntax
1780 // delimiter can be freely chosen
1781 char delimiter
= *(value
++);
1782 for (i
= 0; *value
&& *value
!= delimiter
; ++value
, ++i
);
1783 // has to end with delimiter
1784 // 8 characters per 2B tile
1785 if (*value
== delimiter
&& i
%8 == 0)
1790 /* If the instruction is unrecognized, we shouldn't try to optimize. */
1791 /* For all we know it might be some .ds or similar possibly long line */
1792 /* Return a large value to discourage optimization. */
1794 werrorfl(pl
->ic
->filename
, pl
->ic
->lineno
, W_UNRECOGNIZED_ASM
, __func__
, 999, pl
->line
);
1796 werrorfl("unknown", 0, W_UNRECOGNIZED_ASM
, __func__
, 999, pl
->line
);
1800 bool z80symmParmStack (const char *name
)
1802 if (!strcmp (name
, "___sdcc_enter_ix"))
1804 return z80_symmParm_in_calls_from_current_function
;