struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / src / z80 / ralloc2.cc
blobeba5bfd5931f5df85bd3e69e753bc2d13683fd3c
1 // Philipp Klaus Krause, philipp@informatik.uni-frankfurt.de, pkk@spth.de, 2010 - 2011
2 //
3 // (c) 2010-2012 Goethe-Universität Frankfurt
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the
7 // Free Software Foundation; either version 2, or (at your option) any
8 // later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 // An optimal, polynomial-time register allocator.
21 // #define DEBUG_RALLOC_DEC // Uncomment to get debug messages while doing register allocation on the tree decomposition.
22 // #define DEBUG_RALLOC_DEC_ASS // Uncomment to get debug messages about assignments while doing register allocation on the tree decomposition (much more verbose than the one above).
24 #include "SDCCralloc.hpp"
25 #include "SDCCsalloc.hpp"
27 extern "C"
29 #include "z80.h"
30 float dryZ80iCode (iCode * ic);
31 bool z80_assignment_optimal;
32 bool should_omit_frame_ptr;
35 #define REG_A 0
36 #define REG_C 1
37 #define REG_B 2
38 #define REG_E 3
39 #define REG_D 4
40 #define REG_L 5
41 #define REG_H 6
42 #define REG_IYL 7
43 #define REG_IYH 8
45 template <class G_t, class I_t>
46 float default_operand_cost(const operand *o, const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
48 float c = 0.0f;
50 operand_map_t::const_iterator oi, oi_end;
52 var_t byteregs[4]; // Todo: Change this when sdcc supports variables larger than 4 bytes in registers.
53 unsigned short int size;
55 if(o && IS_SYMOP(o))
57 boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(o)->key);
58 if(oi != oi_end)
60 var_t v = oi->second;
62 // In registers.
63 if(std::binary_search(a.local.begin(), a.local.end(), v))
65 c += 1.0f;
66 byteregs[I[v].byte] = a.global[v];
67 size = 1;
69 while(++oi != oi_end)
71 v = oi->second;
72 c += (std::binary_search(a.local.begin(), a.local.end(), v) ? 1.0f : std::numeric_limits<float>::infinity());
73 byteregs[I[v].byte] = a.global[v];
74 size++;
77 // Penalty for not placing 2- and 4-byte variables in register pairs
78 // Todo: Extend this once the register allocator can use registers other than bc, de:
79 if ((size == 2 || size == 4) &&
80 (byteregs[1] != byteregs[0] + 1 || (byteregs[0] != REG_C && byteregs[0] != REG_E && byteregs[0] != REG_L)))
81 c += 2.0f;
82 if (size == 4 &&
83 (byteregs[3] != byteregs[2] + 1 || (byteregs[2] != REG_C && byteregs[2] != REG_E && byteregs[0] != REG_L)))
84 c += 2.0f;
86 // Code generator cannot handle variables only partially in A.
87 if(size > 1)
88 for(unsigned short int i = 0; i < size; i++)
89 if(byteregs[i] == REG_A)
90 c += std::numeric_limits<float>::infinity();
92 if(byteregs[0] == REG_A)
93 c -= 0.4f;
94 else if(byteregs[0] == REG_L)
95 c -= 0.1f;
96 else if((OPTRALLOC_IY && byteregs[0] == REG_IYL) || byteregs[0] == REG_IYH)
97 c += 0.1f;
99 // Spilt.
100 else
102 c += OP_SYMBOL_CONST(o)->remat ? 1.5f : 4.0f;
103 while(++oi != oi_end)
105 v = oi->second;
106 c += (!std::binary_search(a.local.begin(), a.local.end(), v) ? 4.0f : std::numeric_limits<float>::infinity());
112 return(c);
115 // Check that the operand is either fully in registers or fully in memory.
116 template <class G_t, class I_t>
117 static bool operand_sane(const operand *o, const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
119 if(!o || !IS_SYMOP(o))
120 return(true);
122 operand_map_t::const_iterator oi, oi_end;
123 boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(o)->key);
125 if(oi == oi_end)
126 return(true);
128 // In registers.
129 if(std::binary_search(a.local.begin(), a.local.end(), oi->second))
131 while(++oi != oi_end)
132 if(!std::binary_search(a.local.begin(), a.local.end(), oi->second))
133 return(false);
135 else
137 while(++oi != oi_end)
138 if(std::binary_search(a.local.begin(), a.local.end(), oi->second))
139 return(false);
142 return(true);
145 template <class G_t, class I_t>
146 static float default_instruction_cost(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
148 float c = 0.0f;
150 const iCode *ic = G[i].ic;
152 c += default_operand_cost(IC_RESULT(ic), a, i, G, I);
153 c += default_operand_cost(IC_LEFT(ic), a, i, G, I);
154 c += default_operand_cost(IC_RIGHT(ic), a, i, G, I);
156 return(c);
159 template <class G_t, class I_t>
160 static bool inst_sane(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
162 const iCode *ic = G[i].ic;
164 // for a sequence of built-in SENDs, all of the SENDs must be sane
165 if (ic->op == SEND && ic->builtinSEND && ic->next->op == SEND && !inst_sane(a, *(adjacent_vertices(i, G).first), G, I))
166 return(false);
168 return(operand_sane(IC_RESULT(ic), a, i, G, I) && operand_sane(IC_LEFT(ic), a, i, G, I) && operand_sane(IC_RIGHT(ic), a, i, G, I));
171 // Treat assignment separately to handle coalescing.
172 template <class G_t, class I_t> static float
173 assign_cost(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
175 float c = 0.0f;
177 const iCode *ic = G[i].ic;
179 const operand *right = IC_RIGHT(ic);
180 const operand *result = IC_RESULT(ic);
182 if(!right || !IS_SYMOP(right) || !result || !IS_SYMOP(result) || POINTER_GET(ic) || POINTER_SET(ic))
183 return(default_instruction_cost(a, i, G, I));
185 reg_t byteregs[4] = {-1, -1, -1, -1}; // Todo: Change this when sdcc supports variables larger than 4 bytes in register allocation for z80.
187 operand_map_t::const_iterator oi, oi_end;
189 int size1 = 0, size2 = 0;
191 boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(right)->key);
192 if(oi != oi_end)
194 var_t v = oi->second;
196 if(!std::binary_search(a.local.begin(), a.local.end(), v))
197 return(default_instruction_cost(a, i, G, I));
199 c += 1.0f;
200 byteregs[I[v].byte] = a.global[v];
201 size1 = 1;
203 while(++oi != oi_end)
205 v = oi->second;
206 c += (std::binary_search(a.local.begin(), a.local.end(), v) ? 1.0f : std::numeric_limits<float>::infinity());
207 byteregs[I[v].byte] = a.global[v];
208 size1++;
211 // Code generator cannot handle variables only partially in A.
212 if(size1 > 1)
213 for(unsigned short int i = 0; i < size1; i++)
214 if(byteregs[i] == REG_A)
215 c += std::numeric_limits<float>::infinity();
217 if(byteregs[0] == REG_A)
218 c -= 0.4f;
219 else if((OPTRALLOC_IY && byteregs[0] == REG_IYL) || byteregs[0] == REG_IYH)
220 c += 0.1f;
223 if(!size1)
224 return(default_instruction_cost(a, i, G, I));
226 boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(result)->key);
227 if(oi != oi_end)
229 var_t v = oi->second;
231 if(!std::binary_search(a.local.begin(), a.local.end(), v))
232 return(default_instruction_cost(a, i, G, I));
234 c += 1.0f;
235 if(byteregs[I[v].byte] == a.global[v])
236 c -= 2.0f;
237 size2 = 1;
239 while(++oi != oi_end)
241 v = oi->second;
242 c += (std::binary_search(a.local.begin(), a.local.end(), v) ? 1.0f : std::numeric_limits<float>::infinity());
243 if(byteregs[I[v].byte] == a.global[v])
244 c -= 2.0f;
245 size2++;
248 if(byteregs[0] == REG_A)
249 c -= 0.4f;
250 else if((OPTRALLOC_IY && byteregs[0] == REG_IYL) || byteregs[0] == REG_IYH)
251 c += 0.1f;
254 if(!size2)
255 return(default_instruction_cost(a, i, G, I));
257 return(c);
260 template <class G_t, class I_t> static float
261 return_cost(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
263 float c = 0.0f;
265 const iCode *ic = G[i].ic;
267 const operand *left = IC_LEFT(ic);
269 if(!left || !IS_SYMOP(left))
270 return(default_instruction_cost(a, i, G, I));
272 reg_t byteregs[4] = {-1, -1, -1, -1}; // Todo: Change this when sdcc supports variables larger than 4 bytes.
274 operand_map_t::const_iterator oi, oi_end;
276 int size = 0;
278 boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(left)->key);
279 if(oi != oi_end)
281 var_t v = oi->second;
283 if(!std::binary_search(a.local.begin(), a.local.end(), v))
284 return(default_instruction_cost(a, i, G, I));
286 c += 1.0f;
287 byteregs[I[v].byte] = a.global[v];
288 size = 1;
290 while(++oi != oi_end)
292 v = oi->second;
293 c += (std::binary_search(a.local.begin(), a.local.end(), v) ? 1.0f : std::numeric_limits<float>::infinity());
294 byteregs[I[v].byte] = a.global[v];
295 size++;
298 if(byteregs[0] == REG_A)
299 c -= 0.4f;
301 if(byteregs[0] == REG_L)
302 c -= 1.0f;
303 if(byteregs[1] == REG_H)
304 c -= 1.0f;
305 if(byteregs[2] == REG_E)
306 c -= 1.0f;
307 if(byteregs[3] == REG_D)
308 c -= 1.0f;
311 return(c);
314 template <class G_t, class I_t> static float
315 call_cost(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
317 float c = 0.0f;
319 const iCode *ic = G[i].ic;
321 const operand *result = IC_RESULT(ic);
323 if(!result || !IS_SYMOP(result))
324 return(default_instruction_cost(a, i, G, I));
326 reg_t byteregs[4] = {-1, -1, -1, -1}; // Todo: Change this when sdcc supports variables larger than 4 bytes.
328 operand_map_t::const_iterator oi, oi_end;
330 int size = 0;
332 boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(result)->key);
333 if(oi != oi_end)
335 var_t v = oi->second;
337 if(!std::binary_search(a.local.begin(), a.local.end(), v))
338 return(default_instruction_cost(a, i, G, I));
340 c += 1.0f;
341 byteregs[I[v].byte] = a.global[v];
342 size = 1;
344 while(++oi != oi_end)
346 v = oi->second;
347 c += (std::binary_search(a.local.begin(), a.local.end(), v) ? 1.0f : std::numeric_limits<float>::infinity());
348 byteregs[I[v].byte] = a.global[v];
349 size++;
352 // Code generator cannot handle variables only partially in A.
353 if(size > 1)
354 for(unsigned short int i = 0; i < size; i++)
355 if(byteregs[i] == REG_A)
356 c += std::numeric_limits<float>::infinity();
358 if(byteregs[0] == REG_A)
359 c -= 0.4f;
361 if(byteregs[0] == REG_L)
362 c -= 1.0f;
363 if(byteregs[1] == REG_H)
364 c -= 1.0f;
365 if(byteregs[2] == REG_E)
366 c -= 1.0f;
367 if(byteregs[3] == REG_D)
368 c -= 1.0f;
371 return(c);
374 template <class I_t>
375 static void add_operand_conflicts_in_node(const cfg_node &n, I_t &I)
377 const iCode *ic = n.ic;
379 const operand *result = IC_RESULT(ic);
380 const operand *left = IC_LEFT(ic);
381 const operand *right = IC_RIGHT(ic);
383 if(!result || !IS_SYMOP(result))
384 return;
386 if(!(ic->op == UNARYMINUS || ic->op == '+' || ic->op == '-' || ic->op == '|' || ic->op == BITWISEAND))
387 return; // Code generation can always handle all other operations. Todo: Handle |, BITWISEAND and float UNARYMINUS there as well.
389 operand_map_t::const_iterator oir, oir_end, oirs;
390 boost::tie(oir, oir_end) = n.operands.equal_range(OP_SYMBOL_CONST(result)->key);
391 if(oir == oir_end)
392 return;
394 operand_map_t::const_iterator oio, oio_end;
396 if(left && IS_SYMOP(left))
397 for(boost::tie(oio, oio_end) = n.operands.equal_range(OP_SYMBOL_CONST(left)->key); oio != oio_end; ++oio)
398 for(oirs = oir; oirs != oir_end; ++oirs)
400 var_t rvar = oirs->second;
401 var_t ovar = oio->second;
402 if(I[rvar].byte < I[ovar].byte)
403 boost::add_edge(rvar, ovar, I);
406 if(right && IS_SYMOP(right))
407 for(boost::tie(oio, oio_end) = n.operands.equal_range(OP_SYMBOL_CONST(right)->key); oio != oio_end; ++oio)
408 for(oirs = oir; oirs != oir_end; ++oirs)
410 var_t rvar = oirs->second;
411 var_t ovar = oio->second;
412 if(I[rvar].byte < I[ovar].byte)
413 boost::add_edge(rvar, ovar, I);
417 // Return true, iff the operand is placed (partially) in r.
418 template <class G_t>
419 static bool operand_in_reg(const operand *o, reg_t r, const i_assignment_t &ia, unsigned short int i, const G_t &G)
421 if(!o || !IS_SYMOP(o))
422 return(false);
424 if(r >= port->num_regs)
425 return(false);
427 operand_map_t::const_iterator oi, oi_end;
428 for(boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(o)->key); oi != oi_end; ++oi)
429 if(oi->second == ia.registers[r][1] || oi->second == ia.registers[r][0])
430 return(true);
432 return(false);
435 // Return true, iff the operand is placed in a reg.
436 template <class G_t>
437 static bool operand_in_reg(const operand *o, const i_assignment_t &ia, unsigned short int i, const G_t &G)
439 if(!o || !IS_SYMOP(o))
440 return(false);
442 operand_map_t::const_iterator oi, oi_end;
443 for(boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(o)->key); oi != oi_end; ++oi)
444 for(reg_t r = 0; r < port->num_regs; r++)
445 if(oi->second == ia.registers[r][1] || oi->second == ia.registers[r][0])
446 return(true);
448 return(false);
451 // Return true, iff the operand is placed in a reg.
452 template <class G_t>
453 static bool operand_byte_in_reg(const operand *o, int offset, reg_t r, const assignment &a, unsigned short int i, const G_t &G)
455 if(!o || !IS_SYMOP(o))
456 return(false);
458 operand_map_t::const_iterator oi, oi_end;
460 for(boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(o)->key); offset && oi != oi_end; offset--, oi++);
462 if(oi == oi_end)
463 return(false);
465 return(a.global[oi->second] == r);
468 // Return true, iff the operand is placed on the stack.
469 template <class G_t>
470 bool operand_on_stack(const operand *o, const assignment &a, unsigned short int i, const G_t &G)
472 if(!o || !IS_SYMOP(o))
473 return(false);
475 if(OP_SYMBOL_CONST(o)->remat)
476 return(false);
478 if(OP_SYMBOL_CONST(o)->_isparm && !IS_REGPARM (OP_SYMBOL_CONST(o)->etype))
479 return(true);
481 if(IS_TRUE_SYMOP(o) && OP_SYMBOL_CONST(o)->onStack)
482 return(true);
484 if(OP_SYMBOL_CONST(o)->nRegs > 4) // currently all variables > 4 Byte are spilt in ralloc.c.
485 return(true);
487 operand_map_t::const_iterator oi, oi_end;
488 for(boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(o)->key); oi != oi_end; ++oi)
489 if(a.global[oi->second] < 0)
490 return(true);
492 return(false);
495 template <class G_t>
496 static bool operand_is_pair(const operand *o, const assignment &a, unsigned short int i, const G_t &G)
498 if(!o || !IS_SYMOP(o))
499 return(false);
501 operand_map_t::const_iterator oi, oi2, oi3, oi_end;
502 boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(o)->key);
503 if(oi == oi_end)
504 return(false);
505 oi2 = oi;
506 ++oi2;
507 if(oi2 == oi_end)
508 return(false);
509 oi3 = oi2;
510 ++oi3;
511 if(oi3 != oi_end)
512 return(false);
514 if(a.global[oi->second] != REG_C && a.global[oi->second] != REG_E && a.global[oi->second] != REG_L && a.global[oi->second] != REG_IYL)
515 return(false);
516 if(a.global[oi->second] + 1 != a.global[oi2->second])
517 return(false);
519 return(true);
522 template <class G_t, class I_t>
523 static bool Ainst_ok(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
525 const iCode *ic = G[i].ic;
527 const i_assignment_t &ia = a.i_assignment;
529 operand *const left = IC_LEFT(ic);
530 operand *const right = IC_RIGHT(ic);
531 const operand *const result = IC_RESULT(ic);
533 if(ia.registers[REG_A][1] < 0)
534 return(true); // Register A not in use.
536 // Some instructions don't touch registers.
537 if(SKIP_IC2(ic))
538 return(true);
540 bool exstk = (should_omit_frame_ptr || (currFunc && currFunc->stack > 127) || IS_SM83);
542 //std::cout << "Ainst_ok at " << G[i].ic->key << ": A = (" << ia.registers[REG_A][0] << ", " << ia.registers[REG_A][1] << "), inst " << i << ", " << ic->key << "\n";
544 // Check if the result of this instruction is placed in A.
545 bool result_in_A = operand_in_reg(IC_RESULT(ic), REG_A, ia, i, G);
547 // Check if an input of this instruction is placed in A.
548 bool input_in_A = operand_in_reg(left, REG_A, ia, i, G) || operand_in_reg(right, REG_A, ia, i, G);
550 // sfr access needs to go through a.
551 if(input_in_A &&
552 (IS_TRUE_SYMOP (left) && IN_REGSP (SPEC_OCLS (OP_SYMBOL (left)->etype)) ||
553 IS_TRUE_SYMOP (right) && IN_REGSP (SPEC_OCLS (OP_SYMBOL (right)->etype))))
554 return(false);
556 // For some iCodes, we can handle anything.
557 if(ic->op == '~' || ic->op == IPUSH || ic->op == SEND || ic->op == LABEL || ic->op == GOTO ||
558 ic->op == '^' || ic->op == '|' || ic->op == BITWISEAND ||
559 ic->op == GETBYTE || ic->op == GETWORD ||
560 ic->op == ROT && (getSize(operandType(IC_RESULT (ic))) == 1 || operand_in_reg(result, ia, i, G) && IS_OP_LITERAL (IC_RIGHT (ic)) && operandLitValueUll (IC_RIGHT (ic)) * 2 == bitsForType (operandType (IC_LEFT (ic)))) ||
561 ic->op == LEFT_OP ||
562 ic->op == RECEIVE || ic->op == '=' && !POINTER_SET (ic) || ic->op == CAST)
563 return(true);
565 if (ic->op == RIGHT_OP && getSize(operandType(result)) == 1 && IS_OP_LITERAL(right))
566 return(true);
568 // Can use non-destructive cp on == and < (> might swap operands).
569 if((ic->op == EQ_OP || (ic->op == '<' || ic->op == '>') && SPEC_USIGN(getSpec(operandType(left))) && SPEC_USIGN(getSpec(operandType(right)))) &&
570 getSize(operandType(IC_LEFT(ic))) == 1 && ifxForOp (IC_RESULT(ic), ic) && operand_in_reg(left, REG_A, ia, i, G) &&
571 (IS_OP_LITERAL (right) || operand_in_reg(right, REG_C, ia, i, G) || operand_in_reg(right, REG_B, ia, i, G) || operand_in_reg(right, REG_E, ia, i, G) || operand_in_reg(right, REG_D, ia, i, G) || operand_in_reg(right, REG_H, ia, i, G) || operand_in_reg(right, REG_L, ia, i, G)))
572 return(true);
574 const cfg_dying_t &dying = G[i].dying;
575 const bool dying_A = result_in_A || dying.find(ia.registers[REG_A][1]) != dying.end() || dying.find(ia.registers[REG_A][0]) != dying.end();
577 if ((ic->op == EQ_OP || ic->op == NE_OP) && getSize(operandType(ic->left)) == 1 && (operand_in_reg(left, REG_A, ia, i, G) || operand_in_reg(right, REG_A, ia, i, G)) &&
578 (ifxForOp (ic->result, ic) || dying_A))
579 return(true);
581 if((ic->op == '+' || ic->op == '-' && !operand_in_reg(right, REG_A, ia, i, G) || ic->op == UNARYMINUS && !IS_SM83) &&
582 getSize(operandType(IC_RESULT(ic))) == 1 && dying_A)
583 return(true);
585 if((ic->op == '+' || ic->op == '-' && !operand_in_reg(right, REG_A, ia, i, G) || ic->op == UNARYMINUS && !IS_SM83) && // First byte of input and last byte of output may be in A.
586 IS_ITEMP(result) && dying_A &&
587 (IS_ITEMP(left) || IS_OP_LITERAL(left) || operand_on_stack(left, a, i, G)) &&
588 (!right || IS_ITEMP(right) || IS_OP_LITERAL(right) || operand_on_stack(right, a, i, G)))
591 if((operand_byte_in_reg(left, 0, REG_A, a, i, G) || !operand_in_reg(left, REG_A, ia, i, G)) &&
592 (operand_byte_in_reg(right, 0, REG_A, a, i, G) || !operand_in_reg(right, REG_A, ia, i, G)) &&
593 (operand_byte_in_reg(result, getSize(operandType(IC_RESULT(ic))) - 1, REG_A, a, i, G) || !result_in_A))
594 return(true);
597 // First two bytes of input may be in A.
598 if(ic->op == IFX && dying_A && (getSize(operandType(left)) >= 1 &&
599 operand_byte_in_reg(left, 0, REG_A, a, i, G) || getSize(operandType(left)) >= 2 && !IS_FLOAT (operandType(left)) && operand_byte_in_reg(left, 1, REG_A, a, i, G)))
600 return(true);
602 // Can test register via inc / dec.
603 if(ic->op == IFX && getSize(operandType(left)) == 1 &&
604 (operand_byte_in_reg(left, 0, REG_B, a, i, G) || operand_byte_in_reg(left, 0, REG_C, a, i, G) || operand_byte_in_reg(left, 0, REG_D, a, i, G) || operand_byte_in_reg(left, 0, REG_E, a, i, G) || operand_byte_in_reg(left, 0, REG_H, a, i, G) || operand_byte_in_reg(left, 0, REG_L, a, i, G)))
605 return(true);
607 // Last byte of output may be in A.
608 if(ic->op == GET_VALUE_AT_ADDRESS && IS_ITEMP(result) && operand_byte_in_reg(result, getSize(operandType(IC_RESULT(ic))) - 1, REG_A, a, i, G))
609 return(true);
611 // inc / dec does not affect a.
612 if ((ic->op == '+' || ic->op == '-') && IS_OP_LITERAL(right) && ulFromVal (OP_VALUE_CONST (right)) <= 2 &&
613 (getSize(operandType(IC_RESULT(ic))) == 2 && operand_is_pair(IC_RESULT(ic), a, i, G) || getSize(operandType(IC_RESULT(ic))) == 1 && operand_in_reg(result, ia, i, G) && operand_in_reg(result, ia, i, G)))
614 return(true);
616 if(ic->op == GET_VALUE_AT_ADDRESS) // Any register can be assigned from (hl) and (iy), so we don't need to go through a then.
617 return(!IS_BITVAR(getSpec(operandType(result))) &&
618 (getSize(operandType(result)) == 1 || operand_is_pair(left, a, i, G) && (operand_in_reg(left, REG_L, ia, i, G) && !ulFromVal (OP_VALUE_CONST (right)) || operand_in_reg(left, REG_IYL, ia, i, G) && ulFromVal (OP_VALUE_CONST (right)) <= 127)));
620 if(ic->op == '=' && POINTER_SET (ic) && // Any register can be assigned to (hl) and (iy), so we don't need to go through a then.
621 !(IS_BITVAR(getSpec(operandType (result))) || IS_BITVAR(getSpec(operandType (right)))) &&
622 (getSize(operandType(right)) == 1 || operand_is_pair(result, a, i, G) && (operand_in_reg(result, REG_L, ia, i, G) || operand_in_reg(result, REG_IYL, ia, i, G))))
623 return(true);
625 // Code generator mostly cannot handle variables that are only partially in A.
626 if(operand_in_reg(left, REG_A, ia, i, G) && getSize(operandType(left)) != 1 ||
627 operand_in_reg(right, REG_A, ia, i, G) && getSize(operandType(right)) != 1 ||
628 operand_in_reg(result, REG_A, ia, i, G) && getSize(operandType(result)) != 1)
629 return(false);
631 if(ic->op == '!' && getSize(operandType(left)) <= 2 && dying_A)
632 return(true);
634 if(ic->op == '=' && POINTER_SET (ic))
635 return(dying_A || !(IS_BITVAR(getSpec(operandType (result))) || IS_BITVAR(getSpec(operandType (right)))));
637 if(1)
639 // Variable in A is not used by this instruction
640 if(ic->op == '+' && IS_ITEMP (left) && IS_ITEMP (IC_RESULT(ic)) && IS_OP_LITERAL (right) &&
641 ulFromVal (OP_VALUE_CONST (right)) == 1 &&
642 OP_KEY (IC_RESULT(ic)) == OP_KEY (IC_LEFT(ic)))
643 return(true);
645 if(!result_in_A && !input_in_A)
646 return(false);
649 // Last use of operand in A.
650 if(input_in_A && dying_A)
652 if(ic->op != IFX &&
653 ic->op != RETURN &&
654 !((ic->op == RIGHT_OP || ic->op == LEFT_OP) &&
655 (IS_OP_LITERAL(right) || operand_in_reg(right, REG_A, ia, i, G) || getSize(operandType(IC_RESULT(ic))) == 1 && ia.registers[REG_B][1] < 0)) &&
656 !((ic->op == '=' || ic->op == CAST) && !(IY_RESERVED && POINTER_SET(ic))) &&
657 !(ic->op == '*' && (IS_ITEMP(IC_LEFT(ic)) || IS_OP_LITERAL(IC_LEFT(ic))) && (IS_ITEMP(IC_RIGHT(ic)) || IS_OP_LITERAL(IC_RIGHT(ic)))) &&
658 !((ic->op == '-' || ic->op == '+' || ic->op == EQ_OP) && IS_OP_LITERAL(IC_RIGHT(ic))))
660 //std::cout << "Last use: Dropping at " << i << ", " << ic->key << "(" << int(ic->op) << ")\n";
661 return(false);
664 // A is used, and has to be preserved for later use.
665 else if(input_in_A &&
666 ic->op != IFX &&
667 ic->op != JUMPTABLE)
669 //std::cout << "Intermediate use: Dropping at " << i << ", " << ic->key << "(" << int(ic->op) << "\n";
670 return(false);
673 // First use of operand in A.
674 if(result_in_A &&
675 !POINTER_GET(ic) &&
676 ic->op != '+' &&
677 ic->op != '-' &&
678 (ic->op != '*' || !IS_OP_LITERAL(IC_LEFT(ic)) && !IS_OP_LITERAL(right)) &&
679 ic->op != GET_VALUE_AT_ADDRESS &&
680 ic->op != '=' &&
681 ic->op != EQ_OP &&
682 ic->op != '<' &&
683 ic->op != '>' &&
684 ic->op != CALL &&
685 ic->op != PCALL &&
686 !((ic->op == LEFT_OP || ic->op == RIGHT_OP) && IS_OP_LITERAL(right)))
688 //std::cout << "First use: Dropping at " << i << ", " << ic->key << "(" << int(ic->op) << "\n";
689 return(false);
692 //std::cout << "Default OK\n";
694 return(true);
697 template <class G_t, class I_t>
698 static bool HLinst_ok(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
700 const iCode *ic = G[i].ic;
702 bool exstk = (should_omit_frame_ptr || (currFunc && currFunc->stack > 127) || IS_SM83);
704 const i_assignment_t &ia = a.i_assignment;
706 bool unused_L = (ia.registers[REG_L][1] < 0);
707 bool unused_H = (ia.registers[REG_H][1] < 0);
709 if(unused_L && unused_H)
710 return(true); // Register HL not in use.
712 #if 0
713 if (ic->key == 3)
714 std::cout << "HLinst_ok: at (" << i << ", " << ic->key << ")\nL = (" << ia.registers[REG_L][0] << ", " << ia.registers[REG_L][1] << "), H = (" << ia.registers[REG_H][0] << ", " << ia.registers[REG_H][1] << ")inst " << i << ", " << ic->key << "\n";
715 #endif
717 const operand *left = IC_LEFT(ic);
718 const operand *right = IC_RIGHT(ic);
719 const operand *result = IC_RESULT(ic);
721 bool result_in_L = operand_in_reg(result, REG_L, ia, i, G);
722 bool result_in_H = operand_in_reg(result, REG_H, ia, i, G);
723 bool result_in_HL = result_in_L || result_in_H;
725 bool input_in_L = operand_in_reg(left, REG_L, ia, i, G) || operand_in_reg(right, REG_L, ia, i, G);
726 bool input_in_H = operand_in_reg(left, REG_H, ia, i, G) || operand_in_reg(right, REG_H, ia, i, G);
727 bool input_in_HL = input_in_L || input_in_H;
729 const cfg_dying_t &dying = G[i].dying;
731 bool dying_L = result_in_L || dying.find(ia.registers[REG_L][1]) != dying.end() || dying.find(ia.registers[REG_L][0]) != dying.end();
732 bool dying_H = result_in_H || dying.find(ia.registers[REG_H][1]) != dying.end() || dying.find(ia.registers[REG_H][0]) != dying.end();
734 bool result_only_HL = (result_in_L || unused_L || dying_L) && (result_in_H || unused_H || dying_H);
736 #if 0
737 if (ic->key == 6)
739 std::cout << " Result in L: " << result_in_L << ", result in H: " << result_in_H << "\n";
740 std::cout << " Unsued L: " << unused_L << ", unused H: " << unused_H << "\n";
741 std::cout << " Dying L: " << dying_L << ", dying H: " << dying_H << "\n";
742 std::cout << " Result only HL: " << result_only_HL << "\n";
744 #endif
746 // For some iCodes, code generation can handle anything.
747 if(ic->op == '~' || ic->op == CALL || ic->op == RETURN || ic->op == LABEL || ic->op == GOTO ||
748 ic->op == '^' || ic->op == '|' || ic->op == BITWISEAND ||
749 ic->op == GETBYTE || ic->op == GETWORD ||
750 ic->op == ROT && (getSize(operandType(IC_RESULT(ic))) == 1 || operand_in_reg(result, ia, i, G) && IS_OP_LITERAL (IC_RIGHT (ic)) && operandLitValueUll (IC_RIGHT (ic)) * 2 == bitsForType (operandType (IC_LEFT (ic)))) ||
751 !((IS_SM83 || IY_RESERVED) && (operand_on_stack(result, a, i, G) || operand_on_stack(right, a, i, G))) && (ic->op == '=' && !POINTER_SET (ic) || ic->op == CAST) ||
752 ic->op == RECEIVE || ic->op == SEND ||
753 POINTER_SET(ic) && !IS_BITVAR (operandType (result)->next))
754 return(true);
756 if((ic->op == EQ_OP || ic->op == NE_OP) &&
757 (IS_VALOP(right) || operand_in_reg(right, ia, i, G) && !(exstk && operand_on_stack(ic->left, a, i, G)) && (!isOperandInDirSpace(ic->left) || getSize(operandType(ic->left)) == 1)))
758 return(true);
760 // Due to lack of ex hl, (sp), the generic push code generation fallback doesn't work for gbz80, so we need to be able to use hl if we can't just push a pair or use a.
761 if(IS_SM83 && ic->op == IPUSH && !operand_is_pair(left, a, i, G) && ia.registers[REG_A][1] >= 0 &&
762 !(getSize(operandType(left)) == 1 && (operand_in_reg(left, REG_A, ia, i, G) || operand_in_reg(left, REG_B, ia, i, G) || operand_in_reg(left, REG_D, ia, i, G) || operand_in_reg(left, REG_H, ia, i, G))))
763 return(false);
765 if(IS_SM83 && ic->op == GET_VALUE_AT_ADDRESS && !result_only_HL && (getSize(operandType(result)) >= 2 || !operand_is_pair(left, a, i, G)))
766 return(false);
768 // For some operations, the gbz80 stack access using hl will trash the value there.
769 if(IS_SM83 &&
770 (ic->op == IPUSH && operand_on_stack(left, a, i, G) || ic->op == IFX && operand_on_stack(IC_COND(ic), a, i, G)))
771 return(false);
772 if(IS_SM83 &&
773 (operand_on_stack(result, a, i, G) || operand_on_stack(left, a, i, G) || operand_on_stack(right, a, i, G)) &&
774 (ic->op == RIGHT_OP || ic->op == LEFT_OP || ic->op == '=' || ic->op == CAST || ic->op == '-' || ic->op == UNARYMINUS) &&
775 !(result_only_HL && getSize(operandType(result)) == 1)) // Size of result needs to be checked after checking ic->op to ensure that there is a result operand.
776 return(false);
778 if(IS_SM83 && ic->op == GET_VALUE_AT_ADDRESS && !(result_only_HL || getSize(operandType(result)) == 1))
779 return(false);
780 if(IS_SM83 && POINTER_GET(ic) && !(result_only_HL || getSize(operandType(right)) == 1))
781 return(false);
783 if((IS_SM83 || IY_RESERVED) && (IS_TRUE_SYMOP(left) && (!IS_PARM(left) || exstk) || IS_TRUE_SYMOP(right) && (!IS_PARM(right) || exstk)))
784 return(false);
786 if((IS_SM83 || IY_RESERVED) && IS_TRUE_SYMOP(result) && getSize(operandType(IC_RESULT(ic))) > 2)
787 return(false);
789 // __z88dk_fastcall passes parameter in hl
790 if(ic->op == PCALL && ic->prev && ic->prev->op == SEND && input_in_HL && IFFUNC_ISZ88DK_FASTCALL(operandType(IC_LEFT(ic))->next))
791 return(false);
793 // HL overwritten by result.
794 if(result_only_HL && ic->op == PCALL)
795 return(true);
797 if(ic->op == '-' && getSize(operandType(result)) == 2 && IS_TRUE_SYMOP (left) && IS_TRUE_SYMOP (right) && result_only_HL)
798 return(true);
800 if(exstk &&
801 (operand_on_stack(result, a, i, G) + operand_on_stack(left, a, i, G) + operand_on_stack(right, a, i, G) >= 2) &&
802 (result && IS_SYMOP(result) && getSize(operandType(result)) >= 2 || !result_only_HL))
803 // Todo: Make this more accurate to get better code when using --fomit-frame-pointer
804 return(false);
805 if(exstk && (operand_on_stack(left, a, i, G) || operand_on_stack(right, a, i, G)) && (ic->op == '>' || ic->op == '<'))
806 return(false);
807 if(ic->op == '+' && getSize(operandType(result)) >= 2 && input_in_HL &&
808 ((exstk ? operand_on_stack(left, a, i, G) : IS_TRUE_SYMOP (left) ) && (ia.registers[REG_L][1] > 0 || ia.registers[REG_H][1] > 0) ||
809 (exstk ? operand_on_stack(right, a, i, G) : IS_TRUE_SYMOP (right)) && (ia.registers[REG_L][1] > 0 || ia.registers[REG_H][1] > 0) ))
810 return(false);
812 if(ic->op == '+' && getSize(operandType(result)) == 2 &&
813 (IS_OP_LITERAL (right) && ulFromVal (OP_VALUE (IC_RIGHT(ic))) <= 3 || IS_OP_LITERAL (left) && ulFromVal (OP_VALUE (IC_LEFT(ic))) <= 3) &&
814 (operand_in_reg(result, REG_L, ia, i, G) && I[ia.registers[REG_L][1]].byte == 0 && operand_in_reg(result, REG_H, ia, i, G)))
815 return(true); // Uses inc hl.
817 if(!IS_SM83 && ic->op == '+' && getSize(operandType(result)) == 2 && !IS_TRUE_SYMOP (result) &&
818 (result_only_HL || operand_in_reg(result, REG_IYL, ia, i, G) && operand_in_reg(result, REG_IYH, ia, i, G)) &&
819 (ia.registers[REG_C][1] < 0 && ia.registers[REG_B][1] < 0 || ia.registers[REG_E][1] < 0 && ia.registers[REG_D][1] < 0)) // Can use ld rr, (nn) instead of (hl).
820 return(true);
822 if(!IS_SM83 && ic->op == '+' && getSize(operandType(result)) == 2 && IS_TRUE_SYMOP (left) &&
823 (IS_OP_LITERAL (right) && ulFromVal (OP_VALUE (IC_RIGHT(ic))) <= 3 || IS_OP_LITERAL (left) && ulFromVal (OP_VALUE (IC_LEFT(ic))) <= 3) &&
824 (operand_in_reg(result, REG_C, ia, i, G) && I[ia.registers[REG_C][1]].byte == 0 && operand_in_reg(result, REG_B, ia, i, G) || operand_in_reg(result, REG_E, ia, i, G) && I[ia.registers[REG_E][1]].byte == 0 && operand_in_reg(result, REG_D, ia, i, G))) // Can use ld rr, (nn) followed by inc rr
825 return(true);
827 if(!IS_SM83 && ic->op == '+' && getSize(operandType(result)) <= 2 && result_only_HL && !isOperandInDirSpace(ic->result))
828 return(true);
830 if((ic->op == '+' || ic->op == '-' || ic->op == UNARYMINUS) && getSize(operandType(result)) >= 2 &&
831 (IS_TRUE_SYMOP (result) && !operand_on_stack(result, a, i, G) || (operand_on_stack(left, a, i, G) ? exstk : IS_TRUE_SYMOP (left)) || (operand_on_stack(right, a, i, G) ? exstk : IS_TRUE_SYMOP (right)))) // Might use (hl).
832 return(false);
834 if(IS_SM83 && ic->op == '+' && getSize(operandType(result)) > 1 && input_in_HL && operand_on_stack(result, a, i, G))
835 return(false);
837 // HL overwritten by result.
838 if(result_only_HL && !POINTER_SET(ic) &&
839 (ic->op == ADDRESS_OF ||
840 ic->op == GET_VALUE_AT_ADDRESS ||
841 ic->op == '+' ||
842 ic->op == '*' ||
843 ic->op == '=' ||
844 ic->op == CAST))
845 return(true);
847 if(!exstk && !isOperandInDirSpace(IC_LEFT(ic)) && !isOperandInDirSpace(IC_RIGHT(ic)) && !isOperandInDirSpace(IC_RESULT(ic)) &&
848 (ic->op == '-' ||
849 ic->op == UNARYMINUS ||
850 ic->op == '<' ||
851 ic->op == '>'))
852 return(true);
854 if(ic->op == LEFT_OP && getSize(operandType(result)) <= 2 && IS_OP_LITERAL (right) && result_only_HL)
855 return(true);
856 if((ic->op == LEFT_OP || ic->op == RIGHT_OP) && (getSize(operandType(result)) <= 1 || !IS_TRUE_SYMOP(result) || !(IS_SM83 || IY_RESERVED)) &&
857 (!exstk ||
858 ((!operand_on_stack(left, a, i, G) || !input_in_HL && result_only_HL) &&
859 (!operand_on_stack(right, a, i, G) || !input_in_HL && result_only_HL) &&
860 !operand_on_stack(result, a, i, G))))
861 return(true);
863 if(result && IS_SYMOP(result) && isOperandInDirSpace(IC_RESULT(ic)))
864 return(false);
866 if((input_in_HL || !result_only_HL) && left && IS_SYMOP(left) && isOperandInDirSpace(IC_LEFT(ic)))
867 return(false);
869 if((input_in_HL || !result_only_HL) && right && IS_SYMOP(right) && isOperandInDirSpace(IC_RIGHT(ic)))
870 return(false);
872 // Operations that leave HL alone.
873 if(ic->op == IFX)
874 return(true);
875 if(SKIP_IC2(ic))
876 return(true);
877 if(ic->op == IPUSH) // Can handle anything.
878 return(true);
879 if(POINTER_GET(ic) && input_in_L && input_in_H && (getSize(operandType(IC_RESULT(ic))) == 1 || !result_in_HL))
880 return(true);
881 if(!IS_SM83 && ic->op == ADDRESS_OF &&
882 (operand_in_reg(result, REG_IYL, ia, i, G) && ia.registers[REG_IYL][1] > 0 && I[ia.registers[REG_IYL][1]].byte == 0 && operand_in_reg(result, REG_IYH, ia, i, G) ||
883 !OP_SYMBOL_CONST (left)->onStack && operand_in_reg(result, REG_C, ia, i, G) && ia.registers[REG_C][1] > 0 && I[ia.registers[REG_C][1]].byte == 0 && operand_in_reg(result, REG_B, ia, i, G) ||
884 !OP_SYMBOL_CONST (left)->onStack && operand_in_reg(result, REG_E, ia, i, G) && ia.registers[REG_E][1] > 0 && I[ia.registers[REG_E][1]].byte == 0 && operand_in_reg(result, REG_D, ia, i, G)))
885 return(true);
887 if(ic->op == LEFT_OP && isOperandLiteral(IC_RIGHT(ic)))
888 return(true);
890 if(exstk && !result_only_HL && (operand_on_stack(left, a, i, G) || operand_on_stack(right, a, i, G)) && ic->op == '+')
891 return(false);
893 if((!POINTER_SET(ic) && !POINTER_GET(ic) && (
894 (ic->op == '=' ||
895 ic->op == CAST ||
896 ic->op == UNARYMINUS ||
897 ic->op == RIGHT_OP ||
898 /*ic->op == '-' ||*/
899 IS_BITWISE_OP(ic) ||
900 /*ic->op == '>' ||
901 ic->op == '<' ||
902 ic->op == EQ_OP ||*/
903 (ic->op == '+' && getSize(operandType(IC_RESULT(ic))) == 1) ||
904 (ic->op == '+' && (result_only_HL || !IS_SM83)) )))) // addition on gbz80 might need to use add hl, rr.
905 return(true);
907 if((ic->op == '<' || ic->op == '>') && (IS_ITEMP(left) || IS_OP_LITERAL(left) || IS_ITEMP(right) || IS_OP_LITERAL(right))) // Todo: Fix for large stack.
908 return(true);
910 if(ic->op == CALL)
911 return(true);
913 if(ic->op == GET_VALUE_AT_ADDRESS && getSize(operandType(IC_RESULT(ic))) == 1 && !IS_BITVAR(getSpec(operandType(result))) &&
914 operand_is_pair(left, a, i, G) && // Use ld a, (dd) or ld r, 0 (iy).
915 IS_OP_LITERAL (right) && ulFromVal (OP_VALUE_CONST(right)) == 0)
916 return(true);
918 if(ic->op == '=' && POINTER_SET(ic) && operand_in_reg(result, REG_IYL, ia, i, G) && I[ia.registers[REG_IYL][1]].byte == 0 && operand_in_reg(result, REG_IYH, ia, i, G)) // Uses ld 0 (iy), l etc
919 return(true);
921 if(ic->op == '=' && POINTER_SET(ic) && !result_only_HL) // loads result pointer into (hl) first.
922 return(false);
924 if((ic->op == '=' || ic->op == CAST) && !POINTER_GET(ic) && !input_in_HL)
925 return(true);
927 #if 0
928 if(ic->key == 6)
930 std::cout << "HLinst_ok: L = (" << ia.registers[REG_L][0] << ", " << ia.registers[REG_L][1] << "), H = (" << ia.registers[REG_H][0] << ", " << ia.registers[REG_H][1] << ")inst " << i << ", " << ic->key << "\n";
931 std::cout << "Result in L: " << result_in_L << ", result in H: " << result_in_H << "\n";
932 std::cout << "HL default drop at " << ic->key << ", operation: " << ic->op << "\n";
934 #endif
936 // Replaces former default drop here.
937 if (ic->op == GET_VALUE_AT_ADDRESS || POINTER_SET(ic) || ic->op == ADDRESS_OF || ic->op == '*' || ic->op == JUMPTABLE) // Some operations always use hl. TODO: See if they can be changed to save / restore a hl in use or use hl only when free.
938 return(false);
939 if(exstk && (operand_on_stack(result, a, i, G) || IS_TRUE_SYMOP (result) || operand_on_stack(left, a, i, G) || IS_TRUE_SYMOP (left) || operand_on_stack(right, a, i, G) || IS_TRUE_SYMOP (right))) // hl used as pointer to operand.
940 return(false);
942 return(true);
945 template <class G_t, class I_t>
946 static bool IYinst_ok(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
948 const iCode *ic = G[i].ic;
950 // IY always unused on sm83.
951 if(IS_SM83)
952 return(true);
954 const i_assignment_t &ia = a.i_assignment;
956 /*if(ic->key == 40)
957 std::cout << "1IYinst_ok: at (" << i << ", " << ic->key << ")\nIYL = (" << ia.registers[REG_IYL][0] << ", " << ia.registers[REG_IYL][1] << "), IYH = (" << ia.registers[REG_IYH][0] << ", " << ia.registers[REG_IYH][1] << ")inst " << i << ", " << ic->key << "\n";*/
959 bool exstk = (should_omit_frame_ptr || (currFunc && currFunc->stack > 127));
961 bool unused_IYL = (ia.registers[REG_IYL][1] < 0);
962 bool unused_IYH = (ia.registers[REG_IYH][1] < 0);
964 const operand *left = IC_LEFT(ic);
965 const operand *right = IC_RIGHT(ic);
966 const operand *result = IC_RESULT(ic);
968 bool result_in_IYL = operand_in_reg(result, REG_IYL, ia, i, G);
969 bool result_in_IYH = operand_in_reg(result, REG_IYH, ia, i, G);
970 bool result_in_IY = result_in_IYL || result_in_IYH;
972 const cfg_dying_t &dying = G[i].dying;
974 bool dead_IYL = result_in_IYL || unused_IYL || dying.find(ia.registers[REG_IYL][1]) != dying.end() || dying.find(ia.registers[REG_IYL][0]) != dying.end();
975 bool dead_IYH = result_in_IYH || unused_IYH || dying.find(ia.registers[REG_IYH][1]) != dying.end() || dying.find(ia.registers[REG_IYH][0]) != dying.end();
977 bool dead_IY = dead_IYL && dead_IYH;
979 bool input_in_IYL = operand_in_reg(left, REG_IYL, ia, i, G) || operand_in_reg(right, REG_IYL, ia, i, G);
980 bool input_in_IYH = operand_in_reg(left, REG_IYH, ia, i, G) || operand_in_reg(right, REG_IYH, ia, i, G);
981 bool input_in_IY = input_in_IYL || input_in_IYH;
983 //const std::set<var_t> &dying = G[i].dying;
985 //bool dying_IYL = result_in_IYL || dying.find(ia.registers[REG_IYL][1]) != dying.end() || dying.find(ia.registers[REG_IYL][0]) != dying.end();
986 //bool dying_IYH = result_in_IYH || dying.find(ia.registers[REG_IYH][1]) != dying.end() || dying.find(ia.registers[REG_IYH][0]) != dying.end();
988 //bool result_only_IY = (result_in_IYL || unused_IYL || dying_IYL) && (result_in_IYH || unused_IYH || dying_IYH);
990 if(unused_IYL && unused_IYH)
991 return(true); // Register IY not in use.
993 if(SKIP_IC2(ic))
994 return(true);
996 if(exstk && (operand_on_stack(result, a, i, G) || operand_on_stack(left, a, i, G) || operand_on_stack(right, a, i, G))) // Todo: Make this more accurate to get better code when using --fomit-frame-pointer
997 return(false);
999 // Some instructions can handle anything.
1000 if(ic->op == IPUSH || ic->op == CALL ||
1001 ic->op == '+' ||
1002 ic->op == GETBYTE || ic->op == GETWORD ||
1003 ic->op == ROT && (getSize(operandType(IC_RESULT (ic))) == 1 || operand_in_reg(result, ia, i, G) && IS_OP_LITERAL (IC_RIGHT (ic)) && operandLitValueUll (IC_RIGHT (ic)) * 2 == bitsForType (operandType (IC_LEFT (ic)))) ||
1004 ic->op == '=' && !POINTER_SET(ic) ||
1005 ic->op == CAST ||
1006 ic->op == SEND)
1007 return(true);
1009 // Avoid overwriting operand in iy by use of iy as pointer reg to global operand.
1010 if(!result_in_IY && !input_in_IY &&
1011 !(IC_RESULT(ic) && isOperandInDirSpace(IC_RESULT(ic))) &&
1012 !(IC_RIGHT(ic) && IS_TRUE_SYMOP(IC_RIGHT(ic))) &&
1013 !(IC_LEFT(ic) && IS_TRUE_SYMOP(IC_LEFT(ic))))
1014 return(true);
1016 // Some instructions can handle anything if no operand is pointed to by iy.
1017 if((!(IC_RESULT(ic) && isOperandInDirSpace(IC_RESULT(ic))) || dead_IY && getSize(operandType(IC_RESULT (ic))) == 1) &&
1018 !(IC_RIGHT(ic) && IS_TRUE_SYMOP(IC_RIGHT(ic))) &&
1019 !(IC_LEFT(ic) && IS_TRUE_SYMOP(IC_LEFT(ic))) &&
1020 (ic->op == '|' ||
1021 ic->op == '^' ||
1022 ic->op == '~' ||
1023 ic->op == BITWISEAND))
1024 return(true);
1026 // Code generator mostly cannot handle variables that are only partially in IY.
1027 if(unused_IYL ^ unused_IYH)
1028 return(false);
1029 if(!unused_IYL && I[ia.registers[REG_IYL][1]].size != 2 || !unused_IYH && I[ia.registers[REG_IYH][1]].size != 2 ||
1030 ia.registers[REG_IYL][0] >= 0 && I[ia.registers[REG_IYL][0]].size != 2 || ia.registers[REG_IYH][0] >= 0 && I[ia.registers[REG_IYH][0]].size != 2)
1031 return(false);
1032 if(ia.registers[REG_IYL][1] >= 0 && (ia.registers[REG_IYH][1] <= 0 || I[ia.registers[REG_IYL][1]].v != I[ia.registers[REG_IYH][1]].v))
1033 return(false);
1034 if(ia.registers[REG_IYH][1] >= 0 && (ia.registers[REG_IYL][1] <= 0 || I[ia.registers[REG_IYH][1]].v != I[ia.registers[REG_IYL][1]].v))
1035 return(false);
1036 if(ia.registers[REG_IYL][0] >= 0 && (ia.registers[REG_IYH][0] <= 0 || I[ia.registers[REG_IYL][0]].v != I[ia.registers[REG_IYH][0]].v))
1037 return(false);
1038 if(ia.registers[REG_IYH][0] >= 0 && (ia.registers[REG_IYL][0] <= 0 || I[ia.registers[REG_IYH][0]].v != I[ia.registers[REG_IYL][0]].v))
1039 return(false);
1040 if(I[ia.registers[REG_IYL][1]].byte != 0 || I[ia.registers[REG_IYH][1]].byte != 1)
1041 return(false);
1042 if(ia.registers[REG_IYL][0] >= 0 && I[ia.registers[REG_IYL][0]].byte != 0 || ia.registers[REG_IYH][0] >= 0 && I[ia.registers[REG_IYH][0]].byte != 1)
1043 return(false);
1045 if(result_in_IY &&
1046 (ic->op == '-' || ic->op == UNARYMINUS)) // todo: More instructions that can write iy.
1047 return(true);
1049 // Todo: Multiplication.
1051 if(ic->op == LEFT_OP)
1052 return(true);
1054 #if 0
1055 if(ic->key == 32)
1057 std::cout << "B IYinst_ok: Assignment: ";
1058 //print_assignment(a);
1059 std::cout << "\n";
1060 std::cout << "2IYinst_ok: at (" << i << ", " << ic->key << ")\nIYL = (" << ia.registers[REG_IYL][0] << ", " << ia.registers[REG_IYL][1] << "), IYH = (" << ia.registers[REG_IYH][0] << ", " << ia.registers[REG_IYH][1] << ")inst " << i << ", " << ic->key << "\n";
1062 #endif
1064 if(!result_in_IY && !input_in_IY &&
1065 (ic->op == '=' || ic->op == CAST && getSize(operandType(IC_RIGHT (ic))) >= 2 && (getSize(operandType(IC_RESULT (ic))) <= getSize(operandType(IC_RIGHT (ic))) || !IS_SPEC(operandType(IC_RIGHT (ic))) || SPEC_USIGN(operandType(IC_RIGHT(ic))))) &&
1066 operand_is_pair(IC_RESULT(ic), a, i, G)) // DirSpace access won't use iy here.
1067 return(true);
1069 if(ic->op == GET_VALUE_AT_ADDRESS && isOperandInDirSpace(IC_RESULT(ic)))
1070 return(false);
1072 if(input_in_IY && !result_in_IY && ic->op == GET_VALUE_AT_ADDRESS)
1073 return(true);
1075 #if 0
1076 if(ic->key == 99)
1078 std::cout << "Default drop.\n";
1079 std::cout << "result is pair: " << operand_is_pair(IC_RESULT(ic), a, i, G) << "\n";
1081 #endif
1083 return(false);
1086 template <class G_t, class I_t>
1087 bool DEinst_ok(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
1089 if(!IS_SM83) // Only sm83 might need de for code generation.
1090 return(true);
1092 const i_assignment_t &ia = a.i_assignment;
1094 bool unused_E = (ia.registers[REG_E][1] < 0);
1095 bool unused_D = (ia.registers[REG_D][1] < 0);
1097 if(unused_E && unused_D)
1098 return(true); // Register DE not in use.
1100 const iCode *ic = G[i].ic;
1101 const operand *left = IC_LEFT(ic);
1102 const operand *right = IC_RIGHT(ic);
1103 const operand *result = IC_RESULT(ic);
1105 if(ic->op == PCALL)
1106 return(false);
1108 if(ic->op == GET_VALUE_AT_ADDRESS && (getSize(operandType(result)) >= 2 || !operand_is_pair(left, a, i, G)))
1109 return(false);
1111 if (ic->op == '=' && POINTER_SET(ic) && !operand_is_pair(result, a, i, G))
1112 return(false);
1114 if((ic->op == '=' || ic->op == CAST) && getSize(operandType(result)) > 2 &&
1115 (operand_on_stack(right, a, i, G) || operand_in_reg(right, REG_L, ia, i, G) || operand_in_reg(right, REG_H, ia, i, G)) &&
1116 (operand_on_stack(result, a, i, G) || operand_in_reg(result, REG_L, ia, i, G) || operand_in_reg(result, REG_H, ia, i, G)))
1117 return(false);
1119 if((ic->op == '+' || ic->op == '-' || ic->op == UNARYMINUS) && getSize(operandType(result)) >= 4)
1120 return(false);
1122 if((ic->op == '-' || ic->op == UNARYMINUS) && getSize(operandType(result)) >= 2 && // Stack access requires arithmetic that trashes carry.
1123 (operand_on_stack(result, a, i, G) || operand_on_stack(left, a, i, G) || operand_on_stack(right, a, i, G)))
1124 return(false);
1126 if(ic->op == '*')
1127 return(false);
1129 if((ic->op == '>' || ic->op == '<') && !SPEC_USIGN(getSpec(operandType(left))) && !SPEC_USIGN(getSpec(operandType(right))))
1130 return(false);
1132 return(true);
1135 template <class G_t, class I_t>
1136 static void set_surviving_regs(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
1138 iCode *ic = G[i].ic;
1140 bitVectClear(ic->rMask);
1141 bitVectClear(ic->rSurv);
1143 cfg_alive_t::const_iterator v, v_end;
1144 for (v = G[i].alive.begin(), v_end = G[i].alive.end(); v != v_end; ++v)
1146 if(a.global[*v] < 0)
1147 continue;
1148 ic->rMask = bitVectSetBit(ic->rMask, a.global[*v]);
1150 if(G[i].dying.find(*v) == G[i].dying.end())
1151 if(!((IC_RESULT(ic) && !POINTER_SET(ic)) && IS_SYMOP(IC_RESULT(ic)) && OP_SYMBOL_CONST(IC_RESULT(ic))->key == I[*v].v))
1152 ic->rSurv = bitVectSetBit(ic->rSurv, a.global[*v]);
1156 template <class G_t, class I_t>
1157 static void assign_operand_for_cost(operand *o, const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
1159 if(!o || !IS_SYMOP(o))
1160 return;
1161 symbol *sym = OP_SYMBOL(o);
1162 operand_map_t::const_iterator oi, oi_end;
1163 for(boost::tie(oi, oi_end) = G[i].operands.equal_range(OP_SYMBOL_CONST(o)->key); oi != oi_end; ++oi)
1165 var_t v = oi->second;
1166 if(a.global[v] >= 0)
1168 sym->regs[I[v].byte] = regsZ80 + a.global[v];
1169 sym->accuse = 0;
1170 sym->isspilt = false;
1171 sym->nRegs = I[v].size;
1173 else
1175 sym->isspilt = true;
1176 sym->accuse = 0;
1177 sym->nRegs = I[v].size;
1178 sym->regs[I[v].byte] = 0;
1183 template <class G_t, class I_t>
1184 static void assign_operands_for_cost(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
1186 const iCode *ic = G[i].ic;
1188 assign_operand_for_cost(IC_LEFT(ic), a, i, G, I);
1189 assign_operand_for_cost(IC_RIGHT(ic), a, i, G, I);
1190 assign_operand_for_cost(IC_RESULT(ic), a, i, G, I);
1192 if(ic->op == SEND && ic->builtinSEND)
1193 assign_operands_for_cost(a, (unsigned short)*(adjacent_vertices(i, G).first), G, I);
1196 // Cost function.
1197 template <class G_t, class I_t>
1198 static float instruction_cost(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
1200 iCode *ic = G[i].ic;
1201 float c;
1203 wassert (TARGET_Z80_LIKE);
1205 if(!inst_sane(a, i, G, I))
1206 return(std::numeric_limits<float>::infinity());
1208 if(ic->generated)
1209 return(0.0f);
1211 if(!Ainst_ok(a, i, G, I))
1212 return(std::numeric_limits<float>::infinity());
1214 if(!HLinst_ok(a, i, G, I))
1215 return(std::numeric_limits<float>::infinity());
1217 if(!DEinst_ok(a, i, G, I))
1218 return(std::numeric_limits<float>::infinity());
1220 if(OPTRALLOC_IY && !IYinst_ok(a, i, G, I))
1221 return(std::numeric_limits<float>::infinity());
1223 switch(ic->op)
1225 // Register assignment doesn't matter for these:
1226 case FUNCTION:
1227 case ENDFUNCTION:
1228 case LABEL:
1229 case GOTO:
1230 case INLINEASM:
1231 return(0.0f);
1233 // Exact cost:
1234 case '!':
1235 case '~':
1236 case UNARYMINUS:
1237 case '+':
1238 case '-':
1239 case '^':
1240 case '|':
1241 case BITWISEAND:
1242 case IPUSH:
1243 case IPUSH_VALUE_AT_ADDRESS:
1244 case CALL:
1245 case PCALL:
1246 case RETURN:
1247 case '*':
1248 case '>':
1249 case '<':
1250 case EQ_OP:
1251 case AND_OP:
1252 case OR_OP:
1253 case GETABIT:
1254 case GETBYTE:
1255 case GETWORD:
1256 case ROT:
1257 case LEFT_OP:
1258 case RIGHT_OP:
1259 case GET_VALUE_AT_ADDRESS:
1260 case '=':
1261 case IFX:
1262 case ADDRESS_OF:
1263 case JUMPTABLE:
1264 case CAST:
1265 case RECEIVE:
1266 case SEND:
1267 case DUMMY_READ_VOLATILE:
1268 case CRITICAL:
1269 case ENDCRITICAL:
1270 assign_operands_for_cost(a, i, G, I);
1271 set_surviving_regs(a, i, G, I);
1272 c = dryZ80iCode(ic);
1273 ic->generated = false;
1274 return(c);
1276 // Inexact cost:
1277 default:
1278 return(default_instruction_cost(a, i, G, I));
1282 template <class I_t>
1283 float weird_byte_order(const assignment &a, const I_t &I)
1285 float c = 0.0f;
1287 varset_t::const_iterator vi, vi_end;
1288 for(vi = a.local.begin(), vi_end = a.local.end(); vi != vi_end; ++vi)
1289 if(a.global[*vi] > 0 && (a.global[*vi] - 1) % 2 != I[*vi].byte % 2)
1290 c += 8.0f;
1292 return(c);
1295 // Check for gaps, i.e. higher bytes of a variable being assigned to regs, while lower byte are not.
1296 template <class I_t>
1297 bool local_assignment_insane(const assignment &a, const I_t &I, var_t lastvar)
1299 varset_t::const_iterator v, v_end, v_old;
1301 for(v = a.local.begin(), v_end = a.local.end(); v != v_end;)
1303 v_old = v;
1304 ++v;
1305 if(v == v_end)
1307 if(*v_old != lastvar && I[*v_old].byte != I[*v_old].size - 1)
1308 return(true);
1309 break;
1311 if(I[*v_old].v == I[*v].v)
1313 if(I[*v_old].byte != I[*v].byte - 1)
1314 return(true);
1316 else
1318 if(*v_old != lastvar && I[*v_old].byte != I[*v_old].size - 1 || I[*v].byte)
1319 return(true);
1323 return(false);
1326 // For early removal of assignments that cannot be extended to valid assignments.
1327 template <class G_t, class I_t>
1328 static bool assignment_hopeless(const assignment &a, unsigned short int i, const G_t &G, const I_t &I, const var_t lastvar)
1330 if(local_assignment_insane(a, I, lastvar))
1331 return(true);
1333 const i_assignment_t &ia = a.i_assignment;
1335 // Can only check for HLinst_ok() in some cases.
1336 if((ia.registers[REG_L][1] >= 0 && ia.registers[REG_H][1] >= 0) &&
1337 (ia.registers[REG_L][0] >= 0 && ia.registers[REG_H][0] >= 0) &&
1338 !HLinst_ok(a, i, G, I))
1339 return(true);
1341 // Can only check for IYinst_ok() in some cases.
1342 if(OPTRALLOC_IY &&
1343 (ia.registers[REG_IYL][1] >= 0 || ia.registers[REG_IYH][1] >= 0) &&
1344 !IYinst_ok(a, i, G, I))
1345 return(true);
1347 return(false);
1350 // Increase chance of finding good compatible assignments at join nodes.
1351 template <class T_t>
1352 static void get_best_local_assignment_biased(assignment &a, typename boost::graph_traits<T_t>::vertex_descriptor t, const T_t &T)
1354 const assignment_list_t &alist = T[t].assignments;
1356 assignment_list_t::const_iterator ai, ai_end, ai_best;
1357 for(ai = ai_best = alist.begin(), ai_end = alist.end(); ai != ai_end; ++ai)
1359 if(ai->s < ai_best->s)
1361 varset_t::const_iterator vi, vi_end;
1362 for(vi = ai->local.begin(), vi_end = ai->local.end(); vi != vi_end; ++vi)
1363 if(ai->global[*vi] == REG_A || (ai->global[*vi] == REG_H || ai->global[*vi] == REG_L) || OPTRALLOC_IY && (ai->global[*vi] == REG_IYH || ai->global[*vi] == REG_IYL))
1364 goto too_risky;
1365 ai_best = ai;
1367 too_risky:
1371 a = *ai_best;
1373 varset_t newlocal;
1374 std::set_union(T[t].alive.begin(), T[t].alive.end(), a.local.begin(), a.local.end(), std::inserter(newlocal, newlocal.end()));
1375 a.local = newlocal;
1378 template <class G_t, class I_t>
1379 static float rough_cost_estimate(const assignment &a, unsigned short int i, const G_t &G, const I_t &I)
1381 const i_assignment_t &ia = a.i_assignment;
1382 float c = 0.0f;
1384 c += weird_byte_order(a, I);
1386 if(ia.registers[REG_L][1] >= 0 &&
1387 ia.registers[REG_H][1] >= 0 &&
1388 ((ia.registers[REG_L][0] >= 0) == (ia.registers[REG_H][0] >= 0)) &&
1389 !HLinst_ok(a, i, G, I))
1390 c += 8.0f;
1392 if(ia.registers[REG_A][1] < 0)
1393 c += 0.03f;
1395 if(ia.registers[REG_L][1] < 0)
1396 c += 0.02f;
1398 // Using IY is rarely a good choice, so discard the IY-users first when in doubt.
1399 if(OPTRALLOC_IY)
1401 varset_t::const_iterator vi, vi_end;
1402 for(vi = a.local.begin(), vi_end = a.local.end(); vi != vi_end; ++vi)
1403 if(a.global[*vi] == REG_IYL || a.global[*vi] == REG_IYH)
1404 c += 2.0f;
1407 // An artificial ordering of assignments.
1408 if(ia.registers[REG_E][1] < 0)
1409 c += 0.001f;
1410 if(ia.registers[REG_D][1] < 0)
1411 c += 0.0001f;
1413 if(a.marked)
1414 c -= 0.5f;
1416 varset_t::const_iterator v, v_end;
1417 for(v = a.local.begin(), v_end = a.local.end(); v != v_end; ++v)
1419 const symbol *const sym = (symbol *)(hTabItemWithKey(liveRanges, I[*v].v));
1420 if(a.global[*v] < 0 && IS_REGISTER(sym->type)) // When in doubt, try to honour register keyword.
1421 c += 32.0f;
1422 if((I[*v].byte % 2) && (a.global[*v] == REG_L || a.global[*v] == REG_E || a.global[*v] == REG_C || a.global[*v] == REG_IYL)) // Try not to reverse bytes.
1423 c += 8.0f;
1424 if(!(I[*v].byte % 2) && I[*v].size > 1 && (a.global[*v] == REG_H || a.global[*v] == REG_D || a.global[*v] == REG_B || a.global[*v] == REG_IYH)) // Try not to reverse bytes.
1425 c += 8.0f;
1426 if(I[*v].byte == 0 && I[*v].size > 1 || I[*v].byte == 2 && I[*v].size > 3)
1428 if (a.global[*v] == REG_L && a.global[*v + 1] >= 0 && a.global[*v + 1] != REG_H)
1429 c += 16.0f;
1430 if (a.global[*v] == REG_E && a.global[*v + 1] >= 0 && a.global[*v + 1] != REG_D)
1431 c += 16.0f;
1432 if (a.global[*v] == REG_C && a.global[*v + 1] >= 0 && a.global[*v + 1] != REG_B)
1433 c += 16.0f;
1435 else if(I[*v].byte == 1 || I[*v].byte == 3)
1437 if (a.global[*v] == REG_H && a.global[*v - 1] >= 0 && a.global[*v - 1] != REG_L)
1438 c += 16.0f;
1439 if (a.global[*v] == REG_D && a.global[*v - 1] >= 0 && a.global[*v - 1] != REG_E)
1440 c += 16.0f;
1441 if (a.global[*v] == REG_B && a.global[*v - 1] >= 0 && a.global[*v - 1] != REG_C)
1442 c += 16.0f;
1446 c -= a.local.size() * 0.2f;
1448 return(c);
1451 // Code for another ic is generated when generating this one. Mark the other as generated.
1452 static void extra_ic_generated(iCode *ic)
1454 // djnz
1455 if(ic->op == '-' && ic->next && ic->next->op == IFX && ic->next->left->key == ic->result->key && getSize (operandType (ic->result)) == 1)
1457 iCode *ifx = ic->next;
1459 if (!IS_ITEMP (ic->result) /*&& !isOperandGlobal (ic->left)*/)
1460 return;
1462 if (!IS_OP_LITERAL (ic->right))
1463 return;
1465 if (ullFromVal (OP_VALUE (ic->right)) != 1)
1466 return;
1468 ifx->generated = true;
1469 return;
1472 if(ic->op == '>' || ic->op == '<' || ic->op == LE_OP || ic->op == GE_OP || ic->op == EQ_OP || ic->op == NE_OP ||
1473 (ic->op == '^' || ic->op == '|' || ic->op == BITWISEAND) && (IS_OP_LITERAL (IC_LEFT (ic)) || IS_OP_LITERAL (IC_RIGHT (ic))))
1475 iCode *ifx;
1476 if (ifx = ifxForOp (IC_RESULT (ic), ic))
1478 OP_SYMBOL (IC_RESULT (ic))->for_newralloc = false;
1479 OP_SYMBOL (IC_RESULT (ic))->regType = REG_CND;
1480 ifx->generated = true;
1484 if(ic->op == SEND && ic->builtinSEND && (!ic->prev || ic->prev->op != SEND || !ic->prev->builtinSEND))
1486 iCode *icn;
1487 for(icn = ic->next; icn->op != CALL; icn = icn->next)
1488 icn->generated = true;
1489 icn->generated = true;
1490 ic->generated = false;
1494 template <class T_t, class G_t, class I_t, class SI_t>
1495 static bool tree_dec_ralloc(T_t &T, G_t &G, const I_t &I, SI_t &SI)
1497 bool assignment_optimal;
1499 con2_t I2(boost::num_vertices(I));
1500 for(unsigned int i = 0; i < boost::num_vertices(I); i++)
1502 I2[i].v = I[i].v;
1503 I2[i].byte = I[i].byte;
1504 I2[i].size = I[i].size;
1505 I2[i].name = I[i].name;
1507 typename boost::graph_traits<I_t>::edge_iterator e, e_end;
1508 for(boost::tie(e, e_end) = boost::edges(I); e != e_end; ++e)
1509 add_edge(boost::source(*e, I), boost::target(*e, I), I2);
1511 assignment ac;
1512 ac.s = 0.0f;
1513 assignment_optimal = true;
1514 tree_dec_ralloc_nodes(T, find_root(T), G, I2, ac, &assignment_optimal);
1516 const assignment &winner = *(T[find_root(T)].assignments.begin());
1518 #ifdef DEBUG_RALLOC_DEC
1519 std::cout << "Winner: ";
1520 for(unsigned int i = 0; i < boost::num_vertices(I); i++)
1522 std::cout << "(" << i << ", " << int(winner.global[i]) << ") ";
1524 std::cout << "\n";
1525 std::cout << "Cost: " << winner.s << "\n";
1526 std::cout.flush();
1527 #endif
1529 // Todo: Make this an assertion
1530 if(winner.global.size() != boost::num_vertices(I))
1532 std::cerr << "ERROR: No Assignments at root\n";
1533 exit(-1);
1536 for(unsigned int v = 0; v < boost::num_vertices(I); v++)
1538 symbol *sym = (symbol *)(hTabItemWithKey(liveRanges, I[v].v));
1539 if(winner.global[v] >= 0)
1542 sym->regs[I[v].byte] = regsZ80 + winner.global[v];
1543 sym->accuse = 0;
1544 sym->isspilt = false;
1545 sym->nRegs = I[v].size;
1547 else
1549 for(int i = 0; i < I[v].size; i++)
1550 sym->regs[i] = 0;
1551 sym->accuse = 0;
1552 sym->nRegs = I[v].size;
1553 if (USE_OLDSALLOC)
1554 sym->isspilt = false; // Leave it to Z80RegFix, which can do some spillocation compaction.
1555 else
1556 z80SpillThis(sym);
1560 for(unsigned int i = 0; i < boost::num_vertices(G); i++)
1561 set_surviving_regs(winner, i, G, I);
1563 if (!USE_OLDSALLOC)
1564 set_spilt(G, I, SI);
1566 return(!assignment_optimal);
1569 // Omit the frame pointer for functions with low register pressure and few parameter accesses.
1570 // This is just a heuristic, including the magic value of 21. Many other, more complex heuristics have been tried, but didn't perform better for the regression tests.
1571 template <class G_t>
1572 static bool omit_frame_ptr(const G_t &G)
1574 if(IS_SM83 || IY_RESERVED || z80_opts.noOmitFramePtr)
1575 return(false);
1577 if(options.omitFramePtr)
1578 return(true);
1580 signed char omitcost = -10; // Overhead for setting up frame pointer is 10 bytes of code
1581 for(unsigned int i = 0; i < boost::num_vertices(G); i++)
1583 if((int)G[i].alive.size() > port->num_regs - 4)
1584 return(false);
1586 const iCode *const ic = G[i].ic;
1587 const operand *o;
1588 o = IC_RESULT(ic);
1589 // Accesses without frame pointer, when using iy, tend to cost 6 bytes of overhead per variable (there is no difference in per-byte-specific costs).
1590 if(o && IS_SYMOP(o) && OP_SYMBOL_CONST(o)->_isparm && !IS_REGPARM (OP_SYMBOL_CONST(o)->etype))
1591 omitcost += 6;
1592 o = IC_LEFT(ic);
1593 if(o && IS_SYMOP(o) && OP_SYMBOL_CONST(o)->_isparm && !IS_REGPARM (OP_SYMBOL_CONST(o)->etype))
1594 omitcost += 6;
1595 o = IC_RIGHT(ic);
1596 if(o && IS_SYMOP(o) && OP_SYMBOL_CONST(o)->_isparm && !IS_REGPARM (OP_SYMBOL_CONST(o)->etype))
1597 omitcost += 6;
1599 if(omitcost > 20) // Chosen greater than zero, since the peephole optimizer often can optimize the use of iy into use of hl, reducing the cost.
1600 return(false);
1603 return(true);
1606 // Adjust stack location when deciding to omit frame pointer.
1607 void move_parms(void)
1609 if(!currFunc || IS_SM83 || !should_omit_frame_ptr)
1610 return;
1612 for(value *val = FUNC_ARGS (currFunc->type); val; val = val->next)
1614 if(IS_REGPARM(val->sym->etype) || !val->sym->onStack)
1615 continue;
1617 val->sym->stack -= 2;
1621 iCode *z80_ralloc2_cc(ebbIndex *ebbi)
1623 eBBlock **const ebbs = ebbi->bbOrder;
1624 const int count = ebbi->count;
1626 #ifdef DEBUG_RALLOC_DEC
1627 std::cout << "Processing " << currFunc->name << " from " << dstFileName << "\n"; std::cout.flush();
1628 #endif
1630 cfg_t control_flow_graph;
1632 con_t conflict_graph;
1634 iCode *ic = create_cfg(control_flow_graph, conflict_graph, ebbi);
1636 if (optimize.genconstprop)
1637 recomputeValinfos (ic, ebbi, "_2");
1639 should_omit_frame_ptr = omit_frame_ptr(control_flow_graph);
1640 move_parms();
1642 if(options.dump_graphs)
1643 dump_cfg(control_flow_graph);
1645 guessCounts (ic, ebbi);
1647 if(options.dump_graphs)
1648 dump_con(conflict_graph);
1650 tree_dec_t tree_decomposition;
1652 get_nice_tree_decomposition(tree_decomposition, control_flow_graph);
1654 alive_tree_dec(tree_decomposition, control_flow_graph);
1656 good_re_root(tree_decomposition);
1657 nicify(tree_decomposition);
1658 alive_tree_dec(tree_decomposition, control_flow_graph);
1660 if(options.dump_graphs)
1661 dump_tree_decomposition(tree_decomposition);
1663 guessCounts (ic, ebbi);
1665 scon_t stack_conflict_graph;
1667 z80_assignment_optimal = !tree_dec_ralloc(tree_decomposition, control_flow_graph, conflict_graph, stack_conflict_graph);
1669 Z80RegFix (ebbs, count);
1671 if (USE_OLDSALLOC)
1672 redoStackOffsets ();
1673 else
1675 mergeSpiltParms(stack_conflict_graph); // try to reuse parameter locations
1676 chaitin_salloc(stack_conflict_graph); // new Chaitin-style stack allocator
1679 if(options.dump_graphs && !USE_OLDSALLOC)
1680 dump_scon(stack_conflict_graph);
1682 return(ic);