On Thu, Jan 19, 2006 at 08:49:34PM -0500, David Edelsohn wrote:
> >>>>> Jakub Jelinek writes:
>
> Jakub> * config/rs6000/rs6000.md (UNSPEC_LWSYNC, UNSPEC_ISYNC,
> Jakub> UNSPEC_SYNC_OP, UNSPEC_ATOMIC, UNSPEC_CMPXCHG, UNSPEC_XCHG): Rename
> Jakub> to...
> Jakub> (UNSPECV_LWSYNC, UNSPECV_ISYNC, UNSPECV_SYNC_OP, UNSPECV_ATOMIC,
> Jakub> UNSPECV_CMPXCHG, UNSPECV_XCHG): ... these.
>
> I thought Geoff and Richard agreed that volatile was not
> necessary.
I'm open to suggestions on how to fix it differently.
UNSPECV_* certainly works for me.
I'm pasting here parts of my earlier mails:
The problem seems to be miscompilation of libgomp/config/linux/bar.c
on ppc64, particularly that first scheduling swaps the two lines:
unsigned int generation = bar->generation;
gomp_mutex_unlock (&bar->mutex);
In life2 dump we have:
(insn 38 37 39 2 ../../../libgomp/config/linux/bar.c:47 (set (reg:SI 131 [
<variable>.generation ])
(mem/s:SI (plus:DI (reg/v/f:DI 126 [ bar ])
(const_int 12 [0xc])) [4 <variable>.generation+0 S4 A32])) 279
{*movsi_internal1} (nil)
(nil))
(insn 39 38 40 2 ../../../libgomp/config/linux/bar.c:47 (set (reg/v:DI 124 [
generation ])
(zero_extend:DI (reg:SI 131 [ <variable>.generation ]))) 14
{*zero_extendsidi2_internal1} (nil)
(nil))
(insn 40 39 41 2 ../../../libgomp/config/linux/bar.c:47 (set (reg/v/f:DI 122 [
mutex ])
(reg/v/f:DI 126 [ bar ])) 300 {*movdi_internal64} (nil)
(nil))
(note 41 40 42 2 ("../../../libgomp/config/linux/mutex.h") 54)
(insn 42 41 43 2 ../../../libgomp/config/linux/mutex.h:54 (parallel [
(set (reg:SI 132)
(mem/v:SI (reg/v/f:DI 122 [ mutex ]) [0 S4 A8]))
(set (mem/v:SI (reg/v/f:DI 122 [ mutex ]) [0 S4 A8])
(unspec:SI [
(const_int 0 [0x0])
] 43))
(clobber (scratch:SI))
(clobber (scratch:CC))
]) 543 {sync_lock_test_and_setsi} (nil)
(nil))
while in sched1 dump already:
(note:HI 41 43 42 2 ("../../../libgomp/config/linux/mutex.h") 54)
(insn:HI 42 41 128 2 ../../../libgomp/config/linux/mutex.h:54 (parallel [
(set (reg:SI 132)
(mem/v:SI (reg/v/f:DI 126 [ bar ]) [0 S4 A8]))
(set (mem/v:SI (reg/v/f:DI 126 [ bar ]) [0 S4 A8])
(unspec:SI [
(const_int 0 [0x0])
] 43))
(clobber (scratch:SI))
(clobber (scratch:CC))
]) 543 {sync_lock_test_and_setsi} (nil)
(expr_list:REG_UNUSED (scratch:CC)
(expr_list:REG_UNUSED (scratch:SI)
(nil))))
(note 128 42 39 2 ("../../../libgomp/config/linux/bar.c") 47)
(insn:HI 39 128 44 2 ../../../libgomp/config/linux/bar.c:47 (set (reg/v:DI 124
[ generation ])
(zero_extend:DI (mem/s:SI (plus:DI (reg/v/f:DI 126 [ bar ])
(const_int 12 [0xc])) [4 <variable>.generation+0 S4 A32])))
14 {*zero_extendsidi2_internal1} (nil)
(nil))
Not sure why sched allows that, because insn 42 clearly operates on volatile
memory. Do you think that's a bug in sched that it should be honoring
/v and not moving insns accross it, or that something is broken with the
ppc* patterns?
The mem in the sync insn has alias set 0 and no attributes
except MEM_VOLATLE_P. The reason why sched1 decided to move it anyway
is that it proved that the MEMs are different:
(insn 38 37 39 2 ../../../libgomp/config/linux/bar.c:47 (set (reg:SI 131 [
<variable>.generation ])
(mem/s:SI (plus:DI (reg/v/f:DI 126 [ bar ])
(const_int 12 [0xc])) [4 <variable>.generation+0 S4 A32])) 279
{*movsi_internal1} (nil)
(nil))
(insn 40 39 41 2 ../../../libgomp/config/linux/bar.c:47 (set (reg/v/f:DI 122 [
mutex ])
(reg/v/f:DI 126 [ bar ])) 300 {*movdi_internal64} (nil)
(nil))
(note 41 40 42 2 ("../../../libgomp/config/linux/mutex.h") 54)
(insn 42 41 43 2 ../../../libgomp/config/linux/mutex.h:54 (parallel [
(set (reg:SI 132)
(mem/v:SI (reg/v/f:DI 122 [ mutex ]) [0 S4 A8]))
(set (mem/v:SI (reg/v/f:DI 122 [ mutex ]) [0 S4 A8])
(unspec:SI [
(const_int 0 [0x0])
] 43))
(clobber (scratch:SI))
(clobber (scratch:CC))
]) 543 {sync_lock_test_and_setsi} (nil)
(nil))
as pseudo 122 is set to 126, both MEMs have the same base register, but one
is SI(%r126) and SI(%r126 + 12), so writing into one provably won't affect
the other one and vice versa.
I still don't understand why loop opts can (if they do that) hoist memory loads
out of loops if the loop has UNSPEC_VOLATLE before the original memory
reference.
Can it do the same with
for (...)
{
__asm __volatile ("...." : "=r" (x) : "r" (y));
z = mem;
...
}
=>
z = mem;
for (...)
{
__asm __volatile ("...." : "=r" (x) : "r" (y));
...
}
? If it can, can it do the same with
__asm __volatile ("...." : : : "memory");
? If it can't with "memory" clobber, then perhaps we should add
(clobber (mem:BLK (scratch)))
to the sync builtin insns.
Jakub