+2018-09-06 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ PR target/80080
+ * config/s390/predicates.md: Add nonsym_memory_operand.
+ * config/s390/s390.c (s390_legitimize_cs_operand): If operand
+ contains a SYMBOL_REF, load it into an intermediate pseudo.
+ (s390_emit_compare_and_swap): Legitimize operand.
+ * config/s390/s390.md: Use the new nonsym_memory_operand
+ with UNSPECV_CAS patterns.
+
2018-09-06 Ilya Leoshkevich <iii@linux.ibm.com>
PR target/80080
unsigned HOST_WIDE_INT val = INTVAL (op);
return val <= 128 && val % 8 == 0;
})
+
+;; Certain operations (e.g. CS) cannot access SYMBOL_REF directly, it needs to
+;; be loaded into some register first. In theory, if we put a SYMBOL_REF into
+;; a corresponding insn anyway, reload will generate a load for it, but, when
+;; coupled with constant propagation, this will lead to an inefficient code
+;; (see PR 80080).
+
+(define_predicate "nonsym_memory_operand"
+ (match_code "mem")
+{
+ return memory_operand (op, mode) && !contains_symbol_ref_p (op);
+})
return gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx);
}
+/* If MEM is not a legitimate compare-and-swap memory operand, return a new
+ MEM, whose address is a pseudo containing the original MEM's address. */
+
+static rtx
+s390_legitimize_cs_operand (rtx mem)
+{
+ rtx tmp;
+
+ if (!contains_symbol_ref_p (mem))
+ return mem;
+ tmp = gen_reg_rtx (Pmode);
+ emit_move_insn (tmp, copy_rtx (XEXP (mem, 0)));
+ return change_address (mem, VOIDmode, tmp);
+}
+
/* Emit a SImode compare and swap instruction setting MEM to NEW_RTX if OLD
matches CMP.
Return the correct condition RTL to be placed in the IF_THEN_ELSE of the
{
rtx cc;
+ mem = s390_legitimize_cs_operand (mem);
cc = gen_rtx_REG (ccmode, CC_REGNUM);
switch (GET_MODE (mem))
{
; cdsg, csg
(define_insn "*atomic_compare_and_swap<mode>_1"
[(set (match_operand:TDI 0 "register_operand" "=r")
- (match_operand:TDI 1 "memory_operand" "+S"))
+ (match_operand:TDI 1 "nonsym_memory_operand" "+S"))
(set (match_dup 1)
(unspec_volatile:TDI
[(match_dup 1)
; cds, cdsy
(define_insn "*atomic_compare_and_swapdi_2"
[(set (match_operand:DI 0 "register_operand" "=r,r")
- (match_operand:DI 1 "memory_operand" "+Q,S"))
+ (match_operand:DI 1 "nonsym_memory_operand" "+Q,S"))
(set (match_dup 1)
(unspec_volatile:DI
[(match_dup 1)
; cs, csy
(define_insn "*atomic_compare_and_swapsi_3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
- (match_operand:SI 1 "memory_operand" "+Q,S"))
+ (match_operand:SI 1 "nonsym_memory_operand" "+Q,S"))
(set (match_dup 1)
(unspec_volatile:SI
[(match_dup 1)
+2018-09-06 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ PR target/80080
+ * gcc.target/s390/pr80080-3.c: New test.
+ * gcc.target/s390/s390.exp: Make sure the new test passes
+ on all optimization levels.
+
2018-09-05 Marek Polacek <polacek@redhat.com>
PR c++/86982, -Wreturn-local-addr and std::move and std::forward.
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-march=z10" } */
+
+extern int foo3_mem;
+int foo3 (void)
+{
+ return __atomic_exchange_n (&foo3_mem, 5, __ATOMIC_ACQUIRE);
+}
+
+/* { dg-final { scan-assembler "\n\(\\.L\\d+):\n\tcs\t.*\n\tjne\t\\1\n" } } */
gcc-dg-runtest [lsort [glob -nocomplain $md_tests]] "" "$DEFAULT_CFLAGS"
torture-finish
+# Tests that should pass on all optimization levels.
+foreach t [list $srcdir/$subdir/pr80080-3.c] {
+ torture-init
+ set-torture-options [list -O1 -O2 -O3 -O0 -Os -Ofast -Og]
+ gcc-dg-runtest [list $t] \
+ "" $DEFAULT_CFLAGS
+ torture-finish
+}
+
# All done.
dg-finish