On 11/13/2010 08:40 PM, Peter Bergner wrote:
On Sat, 2010-11-13 at 11:27 +0100, Paolo Bonzini wrote:
On 11/12/2010 03:25 PM, H.J. Lu wrote:
IRA may move instructions across an unspec_volatile,
Do you have a testcase?
Are you sure it's IRA and not our old friend update_equiv_regs()
which IRA calls? http://gcc.gnu.org/PR41171 shows an example
where update_equiv_regs() moves code around.
Peter
I'm just having a similar issue on SH4. The machine description inserts
a unspec_volatile when generating a PIC access to the stack_chk_guard
symbol to avoid combine them into a mem (R0,Rx) addressing mode,
generating a unable to find a register to spill in class 'R0_REGS' spill
failure.
The simplified RTL sequence was like, before ira:
(insn 33 32 34 5 (set (reg:SI 175)
(plus:SI (reg/f:SI 174)
(reg:SI 12 r12)))
(insn 34 33 35 5 (unspec_volatile [
(const_int 0 [0])
] 0)
(insn 35 34 36 5 (set (reg/f:SI 173)
(mem/u/c:SI (reg:SI 175) [0 S4 A32]))
Then during IRA :
(insn 35 56 55 5 (set (reg/f:SI 1 r1 [173])
(mem/u/c:SI (plus:SI (reg/f:SI 1 r1 [174])
(reg:SI 12 r12)) [0 S4 A32]))
So insn 33 has been moved across the unspec_volatile by
'update_equiv_regs'.
So, back to the original question. Is unspec_volatile expected to avoid
this ?
The conservative illustrative attached patch fixed my problem, but this
should clearly need to refined because it's also prevents combines of
insns that are not concerned by the blockage. I also suspect that there
are other places in the compiler where instructions could be combined
without checking the unspec_volatile.
Index: ira.c
===================================================================
--- ira.c (revision 166230)
+++ ira.c (working copy)
@@ -2304,6 +2304,16 @@
only mark all destinations as having no known equivalence. */
if (set == 0)
{
+ if (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE)
+ {
+ int i;
+ /* UNSPEC_VOLATILE is considered to use and clobber all hard
+ registers and all of memory. This blocks insns from being
+ combined across this point. */
+ for (i = FIRST_PSEUDO_REGISTER; i < reg_equiv_init_size; i++)
+ reg_equiv[i].replace = 0;
+ }
+
note_stores (PATTERN (insn), no_equiv, NULL);
continue;
}