1 // Philipp Klaus Krause, philipp@informatik.uni-frankfurt.de, pkk@spth.de, 2010 - 2011
3 // (c) 2010-2012 Goethe-Universität Frankfurt
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
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"
30 float dryZ80iCode (iCode
* ic
);
31 bool z80_assignment_optimal
;
32 bool should_omit_frame_ptr
;
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
)
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
;
57 boost::tie(oi
, oi_end
) = G
[i
].operands
.equal_range(OP_SYMBOL_CONST(o
)->key
);
63 if(std::binary_search(a
.local
.begin(), a
.local
.end(), v
))
66 byteregs
[I
[v
].byte
] = a
.global
[v
];
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
];
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
)))
83 (byteregs
[3] != byteregs
[2] + 1 || (byteregs
[2] != REG_C
&& byteregs
[2] != REG_E
&& byteregs
[0] != REG_L
)))
86 // Code generator cannot handle variables only partially in A.
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
)
94 else if(byteregs
[0] == REG_L
)
96 else if((OPTRALLOC_IY
&& byteregs
[0] == REG_IYL
) || byteregs
[0] == REG_IYH
)
102 c
+= OP_SYMBOL_CONST(o
)->remat
? 1.5f
: 4.0f
;
103 while(++oi
!= oi_end
)
106 c
+= (!std::binary_search(a
.local
.begin(), a
.local
.end(), v
) ? 4.0f
: std::numeric_limits
<float>::infinity());
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
))
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
);
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
))
137 while(++oi
!= oi_end
)
138 if(std::binary_search(a
.local
.begin(), a
.local
.end(), oi
->second
))
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
)
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
);
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
))
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
)
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
);
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
));
200 byteregs
[I
[v
].byte
] = a
.global
[v
];
203 while(++oi
!= oi_end
)
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
];
211 // Code generator cannot handle variables only partially in A.
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
)
219 else if((OPTRALLOC_IY
&& byteregs
[0] == REG_IYL
) || byteregs
[0] == REG_IYH
)
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
);
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
));
235 if(byteregs
[I
[v
].byte
] == a
.global
[v
])
239 while(++oi
!= oi_end
)
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
])
248 if(byteregs
[0] == REG_A
)
250 else if((OPTRALLOC_IY
&& byteregs
[0] == REG_IYL
) || byteregs
[0] == REG_IYH
)
255 return(default_instruction_cost(a
, i
, G
, I
));
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
)
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
;
278 boost::tie(oi
, oi_end
) = G
[i
].operands
.equal_range(OP_SYMBOL_CONST(left
)->key
);
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
));
287 byteregs
[I
[v
].byte
] = a
.global
[v
];
290 while(++oi
!= oi_end
)
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
];
298 if(byteregs
[0] == REG_A
)
301 if(byteregs
[0] == REG_L
)
303 if(byteregs
[1] == REG_H
)
305 if(byteregs
[2] == REG_E
)
307 if(byteregs
[3] == REG_D
)
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
)
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
;
332 boost::tie(oi
, oi_end
) = G
[i
].operands
.equal_range(OP_SYMBOL_CONST(result
)->key
);
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
));
341 byteregs
[I
[v
].byte
] = a
.global
[v
];
344 while(++oi
!= oi_end
)
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
];
352 // Code generator cannot handle variables only partially in A.
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
)
361 if(byteregs
[0] == REG_L
)
363 if(byteregs
[1] == REG_H
)
365 if(byteregs
[2] == REG_E
)
367 if(byteregs
[3] == REG_D
)
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
))
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
);
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.
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
))
424 if(r
>= port
->num_regs
)
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])
435 // Return true, iff the operand is placed in a reg.
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
))
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])
451 // Return true, iff the operand is placed in a reg.
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
))
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
++);
465 return(a
.global
[oi
->second
] == r
);
468 // Return true, iff the operand is placed on the stack.
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
))
475 if(OP_SYMBOL_CONST(o
)->remat
)
478 if(OP_SYMBOL_CONST(o
)->_isparm
&& !IS_REGPARM (OP_SYMBOL_CONST(o
)->etype
))
481 if(IS_TRUE_SYMOP(o
) && OP_SYMBOL_CONST(o
)->onStack
)
484 if(OP_SYMBOL_CONST(o
)->nRegs
> 4) // currently all variables > 4 Byte are spilt in ralloc.c.
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)
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
))
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
);
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
)
516 if(a
.global
[oi
->second
] + 1 != a
.global
[oi2
->second
])
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.
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.
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
))))
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
)))) ||
562 ic
->op
== RECEIVE
|| ic
->op
== '=' && !POINTER_SET (ic
) || ic
->op
== CAST
)
565 if (ic
->op
== RIGHT_OP
&& getSize(operandType(result
)) == 1 && IS_OP_LITERAL(right
))
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
)))
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
))
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
)
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
))
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
)))
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
)))
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
))
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
)))
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
))))
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)
631 if(ic
->op
== '!' && getSize(operandType(left
)) <= 2 && dying_A
)
634 if(ic
->op
== '=' && POINTER_SET (ic
))
635 return(dying_A
|| !(IS_BITVAR(getSpec(operandType (result
))) || IS_BITVAR(getSpec(operandType (right
)))));
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
)))
645 if(!result_in_A
&& !input_in_A
)
649 // Last use of operand in A.
650 if(input_in_A
&& dying_A
)
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";
664 // A is used, and has to be preserved for later use.
665 else if(input_in_A
&&
669 //std::cout << "Intermediate use: Dropping at " << i << ", " << ic->key << "(" << int(ic->op) << "\n";
673 // First use of operand in A.
678 (ic
->op
!= '*' || !IS_OP_LITERAL(IC_LEFT(ic
)) && !IS_OP_LITERAL(right
)) &&
679 ic
->op
!= GET_VALUE_AT_ADDRESS
&&
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";
692 //std::cout << "Default OK\n";
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.
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";
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
);
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";
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
))
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)))
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
))))
765 if(IS_SM83
&& ic
->op
== GET_VALUE_AT_ADDRESS
&& !result_only_HL
&& (getSize(operandType(result
)) >= 2 || !operand_is_pair(left
, a
, i
, G
)))
768 // For some operations, the gbz80 stack access using hl will trash the value there.
770 (ic
->op
== IPUSH
&& operand_on_stack(left
, a
, i
, G
) || ic
->op
== IFX
&& operand_on_stack(IC_COND(ic
), a
, i
, G
)))
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.
778 if(IS_SM83
&& ic
->op
== GET_VALUE_AT_ADDRESS
&& !(result_only_HL
|| getSize(operandType(result
)) == 1))
780 if(IS_SM83
&& POINTER_GET(ic
) && !(result_only_HL
|| getSize(operandType(right
)) == 1))
783 if((IS_SM83
|| IY_RESERVED
) && (IS_TRUE_SYMOP(left
) && (!IS_PARM(left
) || exstk
) || IS_TRUE_SYMOP(right
) && (!IS_PARM(right
) || exstk
)))
786 if((IS_SM83
|| IY_RESERVED
) && IS_TRUE_SYMOP(result
) && getSize(operandType(IC_RESULT(ic
))) > 2)
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
))
793 // HL overwritten by result.
794 if(result_only_HL
&& ic
->op
== PCALL
)
797 if(ic
->op
== '-' && getSize(operandType(result
)) == 2 && IS_TRUE_SYMOP (left
) && IS_TRUE_SYMOP (right
) && result_only_HL
)
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
805 if(exstk
&& (operand_on_stack(left
, a
, i
, G
) || operand_on_stack(right
, a
, i
, G
)) && (ic
->op
== '>' || ic
->op
== '<'))
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) ))
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).
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
827 if(!IS_SM83
&& ic
->op
== '+' && getSize(operandType(result
)) <= 2 && result_only_HL
&& !isOperandInDirSpace(ic
->result
))
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).
834 if(IS_SM83
&& ic
->op
== '+' && getSize(operandType(result
)) > 1 && input_in_HL
&& operand_on_stack(result
, a
, i
, G
))
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
||
847 if(!exstk
&& !isOperandInDirSpace(IC_LEFT(ic
)) && !isOperandInDirSpace(IC_RIGHT(ic
)) && !isOperandInDirSpace(IC_RESULT(ic
)) &&
849 ic
->op
== UNARYMINUS
||
854 if(ic
->op
== LEFT_OP
&& getSize(operandType(result
)) <= 2 && IS_OP_LITERAL (right
) && result_only_HL
)
856 if((ic
->op
== LEFT_OP
|| ic
->op
== RIGHT_OP
) && (getSize(operandType(result
)) <= 1 || !IS_TRUE_SYMOP(result
) || !(IS_SM83
|| IY_RESERVED
)) &&
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
))))
863 if(result
&& IS_SYMOP(result
) && isOperandInDirSpace(IC_RESULT(ic
)))
866 if((input_in_HL
|| !result_only_HL
) && left
&& IS_SYMOP(left
) && isOperandInDirSpace(IC_LEFT(ic
)))
869 if((input_in_HL
|| !result_only_HL
) && right
&& IS_SYMOP(right
) && isOperandInDirSpace(IC_RIGHT(ic
)))
872 // Operations that leave HL alone.
877 if(ic
->op
== IPUSH
) // Can handle anything.
879 if(POINTER_GET(ic
) && input_in_L
&& input_in_H
&& (getSize(operandType(IC_RESULT(ic
))) == 1 || !result_in_HL
))
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
)))
887 if(ic
->op
== LEFT_OP
&& isOperandLiteral(IC_RIGHT(ic
)))
890 if(exstk
&& !result_only_HL
&& (operand_on_stack(left
, a
, i
, G
) || operand_on_stack(right
, a
, i
, G
)) && ic
->op
== '+')
893 if((!POINTER_SET(ic
) && !POINTER_GET(ic
) && (
896 ic
->op
== UNARYMINUS
||
897 ic
->op
== RIGHT_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.
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.
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)
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
921 if(ic
->op
== '=' && POINTER_SET(ic
) && !result_only_HL
) // loads result pointer into (hl) first.
924 if((ic
->op
== '=' || ic
->op
== CAST
) && !POINTER_GET(ic
) && !input_in_HL
)
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";
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.
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.
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.
954 const i_assignment_t
&ia
= a
.i_assignment
;
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.
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
999 // Some instructions can handle anything.
1000 if(ic
->op
== IPUSH
|| ic
->op
== CALL
||
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
) ||
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
))))
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
))) &&
1023 ic
->op
== BITWISEAND
))
1026 // Code generator mostly cannot handle variables that are only partially in IY.
1027 if(unused_IYL
^ unused_IYH
)
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)
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
))
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
))
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
))
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
))
1040 if(I
[ia
.registers
[REG_IYL
][1]].byte
!= 0 || I
[ia
.registers
[REG_IYH
][1]].byte
!= 1)
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)
1046 (ic
->op
== '-' || ic
->op
== UNARYMINUS
)) // todo: More instructions that can write iy.
1049 // Todo: Multiplication.
1051 if(ic
->op
== LEFT_OP
)
1057 std::cout
<< "B IYinst_ok: Assignment: ";
1058 //print_assignment(a);
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";
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.
1069 if(ic
->op
== GET_VALUE_AT_ADDRESS
&& isOperandInDirSpace(IC_RESULT(ic
)))
1072 if(input_in_IY
&& !result_in_IY
&& ic
->op
== GET_VALUE_AT_ADDRESS
)
1078 std::cout
<< "Default drop.\n";
1079 std::cout
<< "result is pair: " << operand_is_pair(IC_RESULT(ic
), a
, i
, G
) << "\n";
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.
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
);
1108 if(ic
->op
== GET_VALUE_AT_ADDRESS
&& (getSize(operandType(result
)) >= 2 || !operand_is_pair(left
, a
, i
, G
)))
1111 if (ic
->op
== '=' && POINTER_SET(ic
) && !operand_is_pair(result
, a
, i
, G
))
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
)))
1119 if((ic
->op
== '+' || ic
->op
== '-' || ic
->op
== UNARYMINUS
) && getSize(operandType(result
)) >= 4)
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
)))
1129 if((ic
->op
== '>' || ic
->op
== '<') && !SPEC_USIGN(getSpec(operandType(left
))) && !SPEC_USIGN(getSpec(operandType(right
))))
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)
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
))
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
];
1170 sym
->isspilt
= false;
1171 sym
->nRegs
= I
[v
].size
;
1175 sym
->isspilt
= true;
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
);
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
;
1203 wassert (TARGET_Z80_LIKE
);
1205 if(!inst_sane(a
, i
, G
, I
))
1206 return(std::numeric_limits
<float>::infinity());
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());
1225 // Register assignment doesn't matter for these:
1243 case IPUSH_VALUE_AT_ADDRESS
:
1259 case GET_VALUE_AT_ADDRESS
:
1267 case DUMMY_READ_VOLATILE
:
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;
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
)
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)
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
;)
1307 if(*v_old
!= lastvar
&& I
[*v_old
].byte
!= I
[*v_old
].size
- 1)
1311 if(I
[*v_old
].v
== I
[*v
].v
)
1313 if(I
[*v_old
].byte
!= I
[*v
].byte
- 1)
1318 if(*v_old
!= lastvar
&& I
[*v_old
].byte
!= I
[*v_old
].size
- 1 || I
[*v
].byte
)
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
))
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
))
1341 // Can only check for IYinst_ok() in some cases.
1343 (ia
.registers
[REG_IYL
][1] >= 0 || ia
.registers
[REG_IYH
][1] >= 0) &&
1344 !IYinst_ok(a
, i
, G
, I
))
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
))
1374 std::set_union(T
[t
].alive
.begin(), T
[t
].alive
.end(), a
.local
.begin(), a
.local
.end(), std::inserter(newlocal
, newlocal
.end()));
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
;
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
))
1392 if(ia
.registers
[REG_A
][1] < 0)
1395 if(ia
.registers
[REG_L
][1] < 0)
1398 // Using IY is rarely a good choice, so discard the IY-users first when in doubt.
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
)
1407 // An artificial ordering of assignments.
1408 if(ia
.registers
[REG_E
][1] < 0)
1410 if(ia
.registers
[REG_D
][1] < 0)
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.
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.
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.
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
)
1430 if (a
.global
[*v
] == REG_E
&& a
.global
[*v
+ 1] >= 0 && a
.global
[*v
+ 1] != REG_D
)
1432 if (a
.global
[*v
] == REG_C
&& a
.global
[*v
+ 1] >= 0 && a
.global
[*v
+ 1] != REG_B
)
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
)
1439 if (a
.global
[*v
] == REG_D
&& a
.global
[*v
- 1] >= 0 && a
.global
[*v
- 1] != REG_E
)
1441 if (a
.global
[*v
] == REG_B
&& a
.global
[*v
- 1] >= 0 && a
.global
[*v
- 1] != REG_C
)
1446 c
-= a
.local
.size() * 0.2f
;
1451 // Code for another ic is generated when generating this one. Mark the other as generated.
1452 static void extra_ic_generated(iCode
*ic
)
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)*/)
1462 if (!IS_OP_LITERAL (ic
->right
))
1465 if (ullFromVal (OP_VALUE (ic
->right
)) != 1)
1468 ifx
->generated
= true;
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
))))
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
))
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
++)
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
);
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
]) << ") ";
1525 std::cout
<< "Cost: " << winner
.s
<< "\n";
1529 // Todo: Make this an assertion
1530 if(winner
.global
.size() != boost::num_vertices(I
))
1532 std::cerr
<< "ERROR: No Assignments at root\n";
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
];
1544 sym
->isspilt
= false;
1545 sym
->nRegs
= I
[v
].size
;
1549 for(int i
= 0; i
< I
[v
].size
; i
++)
1552 sym
->nRegs
= I
[v
].size
;
1554 sym
->isspilt
= false; // Leave it to Z80RegFix, which can do some spillocation compaction.
1560 for(unsigned int i
= 0; i
< boost::num_vertices(G
); i
++)
1561 set_surviving_regs(winner
, i
, G
, I
);
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
)
1577 if(options
.omitFramePtr
)
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)
1586 const iCode
*const ic
= G
[i
].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
))
1593 if(o
&& IS_SYMOP(o
) && OP_SYMBOL_CONST(o
)->_isparm
&& !IS_REGPARM (OP_SYMBOL_CONST(o
)->etype
))
1596 if(o
&& IS_SYMOP(o
) && OP_SYMBOL_CONST(o
)->_isparm
&& !IS_REGPARM (OP_SYMBOL_CONST(o
)->etype
))
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.
1606 // Adjust stack location when deciding to omit frame pointer.
1607 void move_parms(void)
1609 if(!currFunc
|| IS_SM83
|| !should_omit_frame_ptr
)
1612 for(value
*val
= FUNC_ARGS (currFunc
->type
); val
; val
= val
->next
)
1614 if(IS_REGPARM(val
->sym
->etype
) || !val
->sym
->onStack
)
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();
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
);
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
);
1672 redoStackOffsets ();
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
);