Commit 2b1969f6 by John David Anglin

pa.md (UNSPEC_MEMORY_BARRIER): New unspec enum.

	gcc
	* config/pa/pa.md (UNSPEC_MEMORY_BARRIER): New unspec enum.
	Update comment for atomic instructions.
	(atomic_storeqi, atomic_storehi, atomic_storesi, atomic_storesf,
	atomic_loaddf, atomic_loaddf_1, atomic_storedf, atomic_storedf_1):
	Remove.
	(atomic_loaddi): Revise fence expansion to only emit fence prior to
	load for __ATOMIC_SEQ_CST model.
	(atomic_loaddi_1): Remove float register target.
	(atomic_storedi): Handle CONST_INT values.
	(atomic_storedi_1): Remove float register source.  Add special case
	for zero value.
	(memory_barrier): New expander and insn.

	libgcc
	* config/pa/linux-atomic.c: Update comment.
	(FETCH_AND_OP_2, OP_AND_FETCH_2, FETCH_AND_OP_WORD, OP_AND_FETCH_WORD,
	COMPARE_AND_SWAP_2, __sync_val_compare_and_swap_4,
	SYNC_LOCK_TEST_AND_SET_2, __sync_lock_test_and_set_4): Use
	__ATOMIC_RELAXED for atomic loads.
	(SYNC_LOCK_RELEASE_1): New define.  Use __sync_synchronize() and
	unordered store to release lock.
	(__sync_lock_release_8): Likewise.
	(SYNC_LOCK_RELEASE_2): Remove define.

From-SVN: r263488
parent 8be591a9
2018-08-11 John David Anglin <danglin@gcc.gnu.org>
* config/pa/pa.md (UNSPEC_MEMORY_BARRIER): New unspec enum.
Update comment for atomic instructions.
(atomic_storeqi, atomic_storehi, atomic_storesi, atomic_storesf,
atomic_loaddf, atomic_loaddf_1, atomic_storedf, atomic_storedf_1):
Remove.
(atomic_loaddi): Revise fence expansion to only emit fence prior to
load for __ATOMIC_SEQ_CST model.
(atomic_loaddi_1): Remove float register target.
(atomic_storedi): Handle CONST_INT values.
(atomic_storedi_1): Remove float register source. Add special case
for zero value.
(memory_barrier): New expander and insn.
2018-08-11 Jakub Jelinek <jakub@redhat.com> 2018-08-11 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/86835 PR tree-optimization/86835
......
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
UNSPEC_TLSGD_PIC UNSPEC_TLSGD_PIC
UNSPEC_TLSLDM_PIC UNSPEC_TLSLDM_PIC
UNSPEC_TLSIE_PIC UNSPEC_TLSIE_PIC
UNSPEC_MEMORY_BARRIER
]) ])
;; UNSPEC_VOLATILE: ;; UNSPEC_VOLATILE:
...@@ -9955,84 +9956,8 @@ add,l %2,%3,%3\;bv,n %%r0(%3)" ...@@ -9955,84 +9956,8 @@ add,l %2,%3,%3\;bv,n %%r0(%3)"
;; doubleword loads and stores are not guaranteed to be atomic ;; doubleword loads and stores are not guaranteed to be atomic
;; when referencing the I/O address space. ;; when referencing the I/O address space.
;; The kernel cmpxchg operation on linux is not atomic with respect to
;; memory stores on SMP machines, so we must do stores using a cmpxchg
;; operation.
;; These patterns are at the bottom so the non atomic versions are preferred. ;; These patterns are at the bottom so the non atomic versions are preferred.
;; Implement atomic QImode store using exchange.
(define_expand "atomic_storeqi"
[(match_operand:QI 0 "memory_operand") ;; memory
(match_operand:QI 1 "register_operand") ;; val out
(match_operand:SI 2 "const_int_operand")] ;; model
""
{
if (TARGET_SYNC_LIBCALL)
{
rtx mem = operands[0];
rtx val = operands[1];
if (pa_maybe_emit_compare_and_swap_exchange_loop (NULL_RTX, mem, val))
DONE;
}
FAIL;
})
;; Implement atomic HImode stores using exchange.
(define_expand "atomic_storehi"
[(match_operand:HI 0 "memory_operand") ;; memory
(match_operand:HI 1 "register_operand") ;; val out
(match_operand:SI 2 "const_int_operand")] ;; model
""
{
if (TARGET_SYNC_LIBCALL)
{
rtx mem = operands[0];
rtx val = operands[1];
if (pa_maybe_emit_compare_and_swap_exchange_loop (NULL_RTX, mem, val))
DONE;
}
FAIL;
})
;; Implement atomic SImode store using exchange.
(define_expand "atomic_storesi"
[(match_operand:SI 0 "memory_operand") ;; memory
(match_operand:SI 1 "register_operand") ;; val out
(match_operand:SI 2 "const_int_operand")] ;; model
""
{
if (TARGET_SYNC_LIBCALL)
{
rtx mem = operands[0];
rtx val = operands[1];
if (pa_maybe_emit_compare_and_swap_exchange_loop (NULL_RTX, mem, val))
DONE;
}
FAIL;
})
;; Implement atomic SFmode store using exchange.
(define_expand "atomic_storesf"
[(match_operand:SF 0 "memory_operand") ;; memory
(match_operand:SF 1 "register_operand") ;; val out
(match_operand:SI 2 "const_int_operand")] ;; model
""
{
if (TARGET_SYNC_LIBCALL)
{
rtx mem = operands[0];
rtx val = operands[1];
if (pa_maybe_emit_compare_and_swap_exchange_loop (NULL_RTX, mem, val))
DONE;
}
FAIL;
})
;; Implement atomic DImode load using 64-bit floating point load. ;; Implement atomic DImode load using 64-bit floating point load.
(define_expand "atomic_loaddi" (define_expand "atomic_loaddi"
...@@ -10048,47 +9973,39 @@ add,l %2,%3,%3\;bv,n %%r0(%3)" ...@@ -10048,47 +9973,39 @@ add,l %2,%3,%3\;bv,n %%r0(%3)"
model = memmodel_from_int (INTVAL (operands[2])); model = memmodel_from_int (INTVAL (operands[2]));
operands[1] = force_reg (SImode, XEXP (operands[1], 0)); operands[1] = force_reg (SImode, XEXP (operands[1], 0));
expand_mem_thread_fence (model);
emit_insn (gen_atomic_loaddi_1 (operands[0], operands[1]));
if (is_mm_seq_cst (model)) if (is_mm_seq_cst (model))
expand_mem_thread_fence (model); expand_mem_thread_fence (model);
emit_insn (gen_atomic_loaddi_1 (operands[0], operands[1]));
expand_mem_thread_fence (model);
DONE; DONE;
}) })
(define_insn "atomic_loaddi_1" (define_insn "atomic_loaddi_1"
[(set (match_operand:DI 0 "register_operand" "=f,r") [(set (match_operand:DI 0 "register_operand" "=r")
(mem:DI (match_operand:SI 1 "register_operand" "r,r"))) (mem:DI (match_operand:SI 1 "register_operand" "r")))
(clobber (match_scratch:DI 2 "=X,f"))] (clobber (match_scratch:DI 2 "=f"))]
"!TARGET_64BIT && !TARGET_DISABLE_FPREGS && !TARGET_SOFT_FLOAT" "!TARGET_64BIT && !TARGET_DISABLE_FPREGS && !TARGET_SOFT_FLOAT"
"@ "{fldds|fldd} 0(%1),%2\n\t{fstds|fstd} %2,-16(%%sp)\n\t{ldws|ldw} -16(%%sp),%0\n\t{ldws|ldw} -12(%%sp),%R0"
{fldds|fldd} 0(%1),%0 [(set_attr "type" "move")
{fldds|fldd} 0(%1),%2\n\t{fstds|fstd} %2,-16(%%sp)\n\t{ldws|ldw} -16(%%sp),%0\n\t{ldws|ldw} -12(%%sp),%R0" (set_attr "length" "16")])
[(set_attr "type" "move,move")
(set_attr "length" "4,16")])
;; Implement atomic DImode store. ;; Implement atomic DImode store.
(define_expand "atomic_storedi" (define_expand "atomic_storedi"
[(match_operand:DI 0 "memory_operand") ;; memory [(match_operand:DI 0 "memory_operand") ;; memory
(match_operand:DI 1 "register_operand") ;; val out (match_operand:DI 1 "reg_or_cint_move_operand") ;; val out
(match_operand:SI 2 "const_int_operand")] ;; model (match_operand:SI 2 "const_int_operand")] ;; model
"" ""
{ {
enum memmodel model; enum memmodel model;
if (TARGET_SYNC_LIBCALL)
{
rtx mem = operands[0];
rtx val = operands[1];
if (pa_maybe_emit_compare_and_swap_exchange_loop (NULL_RTX, mem, val))
DONE;
}
if (TARGET_64BIT || TARGET_DISABLE_FPREGS || TARGET_SOFT_FLOAT) if (TARGET_64BIT || TARGET_DISABLE_FPREGS || TARGET_SOFT_FLOAT)
FAIL; FAIL;
model = memmodel_from_int (INTVAL (operands[2])); model = memmodel_from_int (INTVAL (operands[2]));
operands[0] = force_reg (SImode, XEXP (operands[0], 0)); operands[0] = force_reg (SImode, XEXP (operands[0], 0));
if (operands[1] != CONST0_RTX (DImode))
operands[1] = force_reg (DImode, operands[1]);
expand_mem_thread_fence (model); expand_mem_thread_fence (model);
emit_insn (gen_atomic_storedi_1 (operands[0], operands[1])); emit_insn (gen_atomic_storedi_1 (operands[0], operands[1]));
if (is_mm_seq_cst (model)) if (is_mm_seq_cst (model))
...@@ -10098,87 +10015,33 @@ add,l %2,%3,%3\;bv,n %%r0(%3)" ...@@ -10098,87 +10015,33 @@ add,l %2,%3,%3\;bv,n %%r0(%3)"
(define_insn "atomic_storedi_1" (define_insn "atomic_storedi_1"
[(set (mem:DI (match_operand:SI 0 "register_operand" "r,r")) [(set (mem:DI (match_operand:SI 0 "register_operand" "r,r"))
(match_operand:DI 1 "register_operand" "f,r")) (match_operand:DI 1 "reg_or_0_operand" "M,r"))
(clobber (match_scratch:DI 2 "=X,f"))] (clobber (match_scratch:DI 2 "=X,f"))]
"!TARGET_64BIT && !TARGET_DISABLE_FPREGS "!TARGET_64BIT && !TARGET_DISABLE_FPREGS && !TARGET_SOFT_FLOAT"
&& !TARGET_SOFT_FLOAT && !TARGET_SYNC_LIBCALL"
"@ "@
{fstds|fstd} %1,0(%0) {fstds|fstd} %%fr0,0(%0)
{stws|stw} %1,-16(%%sp)\n\t{stws|stw} %R1,-12(%%sp)\n\t{fldds|fldd} -16(%%sp),%2\n\t{fstds|fstd} %2,0(%0)" {stws|stw} %1,-16(%%sp)\n\t{stws|stw} %R1,-12(%%sp)\n\t{fldds|fldd} -16(%%sp),%2\n\t{fstds|fstd} %2,0(%0)"
[(set_attr "type" "move,move") [(set_attr "type" "move,move")
(set_attr "length" "4,16")]) (set_attr "length" "4,16")])
;; Implement atomic DFmode load using 64-bit floating point load. ;; PA 2.0 hardware supports out-of-order execution of loads and stores, so
;; we need a memory barrier to enforce program order for memory references.
;; Since we want PA 1.x code to be PA 2.0 compatible, we also need the
;; barrier when generating PA 1.x code.
(define_expand "atomic_loaddf" (define_expand "memory_barrier"
[(match_operand:DF 0 "register_operand") ;; val out [(set (match_dup 0)
(match_operand:DF 1 "memory_operand") ;; memory (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
(match_operand:SI 2 "const_int_operand")] ;; model
"" ""
{ {
enum memmodel model; operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
MEM_VOLATILE_P (operands[0]) = 1;
if (TARGET_64BIT || TARGET_DISABLE_FPREGS || TARGET_SOFT_FLOAT)
FAIL;
model = memmodel_from_int (INTVAL (operands[2]));
operands[1] = force_reg (SImode, XEXP (operands[1], 0));
expand_mem_thread_fence (model);
emit_insn (gen_atomic_loaddf_1 (operands[0], operands[1]));
if (is_mm_seq_cst (model))
expand_mem_thread_fence (model);
DONE;
}) })
(define_insn "atomic_loaddf_1" (define_insn "*memory_barrier"
[(set (match_operand:DF 0 "register_operand" "=f,r") [(set (match_operand:BLK 0 "" "")
(mem:DF (match_operand:SI 1 "register_operand" "r,r"))) (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
(clobber (match_scratch:DF 2 "=X,f"))]
"!TARGET_64BIT && !TARGET_DISABLE_FPREGS && !TARGET_SOFT_FLOAT"
"@
{fldds|fldd} 0(%1),%0
{fldds|fldd} 0(%1),%2\n\t{fstds|fstd} %2,-16(%%sp)\n\t{ldws|ldw} -16(%%sp),%0\n\t{ldws|ldw} -12(%%sp),%R0"
[(set_attr "type" "move,move")
(set_attr "length" "4,16")])
;; Implement atomic DFmode store using 64-bit floating point store.
(define_expand "atomic_storedf"
[(match_operand:DF 0 "memory_operand") ;; memory
(match_operand:DF 1 "register_operand") ;; val out
(match_operand:SI 2 "const_int_operand")] ;; model
"" ""
{ "sync"
enum memmodel model; [(set_attr "type" "binary")
(set_attr "length" "4")])
if (TARGET_SYNC_LIBCALL)
{
rtx mem = operands[0];
rtx val = operands[1];
if (pa_maybe_emit_compare_and_swap_exchange_loop (NULL_RTX, mem, val))
DONE;
}
if (TARGET_64BIT || TARGET_DISABLE_FPREGS || TARGET_SOFT_FLOAT)
FAIL;
model = memmodel_from_int (INTVAL (operands[2]));
operands[0] = force_reg (SImode, XEXP (operands[0], 0));
expand_mem_thread_fence (model);
emit_insn (gen_atomic_storedf_1 (operands[0], operands[1]));
if (is_mm_seq_cst (model))
expand_mem_thread_fence (model);
DONE;
})
(define_insn "atomic_storedf_1"
[(set (mem:DF (match_operand:SI 0 "register_operand" "r,r"))
(match_operand:DF 1 "register_operand" "f,r"))
(clobber (match_scratch:DF 2 "=X,f"))]
"!TARGET_64BIT && !TARGET_DISABLE_FPREGS
&& !TARGET_SOFT_FLOAT && !TARGET_SYNC_LIBCALL"
"@
{fstds|fstd} %1,0(%0)
{stws|stw} %1,-16(%%sp)\n\t{stws|stw} %R1,-12(%%sp)\n\t{fldds|fldd} -16(%%sp),%2\n\t{fstds|fstd} %2,0(%0)"
[(set_attr "type" "move,move")
(set_attr "length" "4,16")])
2018-08-11 John David Anglin <danglin@gcc.gnu.org>
* config/pa/linux-atomic.c: Update comment.
(FETCH_AND_OP_2, OP_AND_FETCH_2, FETCH_AND_OP_WORD, OP_AND_FETCH_WORD,
COMPARE_AND_SWAP_2, __sync_val_compare_and_swap_4,
SYNC_LOCK_TEST_AND_SET_2, __sync_lock_test_and_set_4): Use
__ATOMIC_RELAXED for atomic loads.
(SYNC_LOCK_RELEASE_1): New define. Use __sync_synchronize() and
unordered store to release lock.
(__sync_lock_release_8): Likewise.
(SYNC_LOCK_RELEASE_2): Remove define.
2018-08-02 Nicolas Pitre <nico@fluxnic.net> 2018-08-02 Nicolas Pitre <nico@fluxnic.net>
PR libgcc/86512 PR libgcc/86512
......
...@@ -28,14 +28,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -28,14 +28,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define EBUSY 16 #define EBUSY 16
#define ENOSYS 251 #define ENOSYS 251
/* All PA-RISC implementations supported by linux have strongly /* PA-RISC 2.0 supports out-of-order execution for loads and stores.
ordered loads and stores. Only cache flushes and purges can be Thus, we need to synchonize memory accesses. For more info, see:
delayed. The data cache implementations are all globally "Advanced Performance Features of the 64-bit PA-8000" by Doug Hunt.
coherent. Thus, there is no need to synchonize memory accesses.
GCC automatically issues a asm memory barrier when it encounters
a __sync_synchronize builtin. Thus, we do not need to define this
builtin.
We implement byte, short and int versions of each atomic operation We implement byte, short and int versions of each atomic operation
using the kernel helper defined below. There is no support for using the kernel helper defined below. There is no support for
...@@ -119,7 +114,7 @@ __kernel_cmpxchg2 (void *mem, const void *oldval, const void *newval, ...@@ -119,7 +114,7 @@ __kernel_cmpxchg2 (void *mem, const void *oldval, const void *newval,
long failure; \ long failure; \
\ \
do { \ do { \
tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ tmp = __atomic_load_n (ptr, __ATOMIC_RELAXED); \
newval = PFX_OP (tmp INF_OP val); \ newval = PFX_OP (tmp INF_OP val); \
failure = __kernel_cmpxchg2 (ptr, &tmp, &newval, INDEX); \ failure = __kernel_cmpxchg2 (ptr, &tmp, &newval, INDEX); \
} while (failure != 0); \ } while (failure != 0); \
...@@ -156,7 +151,7 @@ FETCH_AND_OP_2 (nand, ~, &, signed char, 1, 0) ...@@ -156,7 +151,7 @@ FETCH_AND_OP_2 (nand, ~, &, signed char, 1, 0)
long failure; \ long failure; \
\ \
do { \ do { \
tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ tmp = __atomic_load_n (ptr, __ATOMIC_RELAXED); \
newval = PFX_OP (tmp INF_OP val); \ newval = PFX_OP (tmp INF_OP val); \
failure = __kernel_cmpxchg2 (ptr, &tmp, &newval, INDEX); \ failure = __kernel_cmpxchg2 (ptr, &tmp, &newval, INDEX); \
} while (failure != 0); \ } while (failure != 0); \
...@@ -193,7 +188,7 @@ OP_AND_FETCH_2 (nand, ~, &, signed char, 1, 0) ...@@ -193,7 +188,7 @@ OP_AND_FETCH_2 (nand, ~, &, signed char, 1, 0)
long failure; \ long failure; \
\ \
do { \ do { \
tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ tmp = __atomic_load_n (ptr, __ATOMIC_RELAXED); \
failure = __kernel_cmpxchg (ptr, tmp, PFX_OP (tmp INF_OP val)); \ failure = __kernel_cmpxchg (ptr, tmp, PFX_OP (tmp INF_OP val)); \
} while (failure != 0); \ } while (failure != 0); \
\ \
...@@ -215,7 +210,7 @@ FETCH_AND_OP_WORD (nand, ~, &) ...@@ -215,7 +210,7 @@ FETCH_AND_OP_WORD (nand, ~, &)
long failure; \ long failure; \
\ \
do { \ do { \
tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ tmp = __atomic_load_n (ptr, __ATOMIC_RELAXED); \
failure = __kernel_cmpxchg (ptr, tmp, PFX_OP (tmp INF_OP val)); \ failure = __kernel_cmpxchg (ptr, tmp, PFX_OP (tmp INF_OP val)); \
} while (failure != 0); \ } while (failure != 0); \
\ \
...@@ -241,7 +236,7 @@ typedef unsigned char bool; ...@@ -241,7 +236,7 @@ typedef unsigned char bool;
\ \
while (1) \ while (1) \
{ \ { \
actual_oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ actual_oldval = __atomic_load_n (ptr, __ATOMIC_RELAXED); \
\ \
if (__builtin_expect (oldval != actual_oldval, 0)) \ if (__builtin_expect (oldval != actual_oldval, 0)) \
return actual_oldval; \ return actual_oldval; \
...@@ -273,7 +268,7 @@ __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) ...@@ -273,7 +268,7 @@ __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
while (1) while (1)
{ {
actual_oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); actual_oldval = __atomic_load_n (ptr, __ATOMIC_RELAXED);
if (__builtin_expect (oldval != actual_oldval, 0)) if (__builtin_expect (oldval != actual_oldval, 0))
return actual_oldval; return actual_oldval;
...@@ -300,7 +295,7 @@ TYPE HIDDEN \ ...@@ -300,7 +295,7 @@ TYPE HIDDEN \
long failure; \ long failure; \
\ \
do { \ do { \
oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ oldval = __atomic_load_n (ptr, __ATOMIC_RELAXED); \
failure = __kernel_cmpxchg2 (ptr, &oldval, &val, INDEX); \ failure = __kernel_cmpxchg2 (ptr, &oldval, &val, INDEX); \
} while (failure != 0); \ } while (failure != 0); \
\ \
...@@ -318,38 +313,31 @@ __sync_lock_test_and_set_4 (int *ptr, int val) ...@@ -318,38 +313,31 @@ __sync_lock_test_and_set_4 (int *ptr, int val)
int oldval; int oldval;
do { do {
oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); oldval = __atomic_load_n (ptr, __ATOMIC_RELAXED);
failure = __kernel_cmpxchg (ptr, oldval, val); failure = __kernel_cmpxchg (ptr, oldval, val);
} while (failure != 0); } while (failure != 0);
return oldval; return oldval;
} }
#define SYNC_LOCK_RELEASE_2(TYPE, WIDTH, INDEX) \ void HIDDEN
__sync_lock_release_8 (long long *ptr)
{
/* All accesses must be complete before we release the lock. */
__sync_synchronize ();
*(double *)ptr = 0;
}
#define SYNC_LOCK_RELEASE_1(TYPE, WIDTH) \
void HIDDEN \ void HIDDEN \
__sync_lock_release_##WIDTH (TYPE *ptr) \ __sync_lock_release_##WIDTH (TYPE *ptr) \
{ \ { \
TYPE oldval, zero = 0; \ /* All accesses must be complete before we release \
long failure; \ the lock. */ \
\ __sync_synchronize (); \
do { \ *ptr = 0; \
oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \
failure = __kernel_cmpxchg2 (ptr, &oldval, &zero, INDEX); \
} while (failure != 0); \
} }
SYNC_LOCK_RELEASE_2 (long long, 8, 3) SYNC_LOCK_RELEASE_1 (int, 4)
SYNC_LOCK_RELEASE_2 (short, 2, 1) SYNC_LOCK_RELEASE_1 (short, 2)
SYNC_LOCK_RELEASE_2 (signed char, 1, 0) SYNC_LOCK_RELEASE_1 (signed char, 1)
void HIDDEN
__sync_lock_release_4 (int *ptr)
{
long failure;
int oldval;
do {
oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);
failure = __kernel_cmpxchg (ptr, oldval, 0);
} while (failure != 0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment