diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/config/i386/predicates.md | 28 | ||||
-rw-r--r-- | gcc/config/i386/sync.md | 28 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr39431.c | 15 |
5 files changed, 82 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9c17490..2282b89 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2008-03-12 Jakub Jelinek <jakub@redhat.com> + + PR target/39431 + * config/i386/predicates.md (cmpxchg8b_pic_memory_operand): New + predicate. + * config/i386/sync.md (sync_compare_and_swap<mode>, + sync_compare_and_swap_cc<mode>): For DImode with -m32 -fpic check + if operands[1] is cmpxchg8b_pic_memory_operand, if not force address + into a register. + (sync_double_compare_and_swapdi_pic, + sync_double_compare_and_swap_ccdi_pic): Require operand 1 to be + cmpxchg8b_pic_memory_operand instead of just memory_operand. + 2009-03-12 H.J. Lu <hongjiu.lu@intel.com> PR target/39445 diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index b2bef64..f1c7103 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -887,6 +887,34 @@ return parts.disp != NULL_RTX; }) +;; Returns 1 if OP is memory operand which will need zero or +;; one register at most, not counting stack pointer or frame pointer. +(define_predicate "cmpxchg8b_pic_memory_operand" + (match_operand 0 "memory_operand") +{ + struct ix86_address parts; + int ok; + + ok = ix86_decompose_address (XEXP (op, 0), &parts); + gcc_assert (ok); + if (parts.base == NULL_RTX + || parts.base == arg_pointer_rtx + || parts.base == frame_pointer_rtx + || parts.base == hard_frame_pointer_rtx + || parts.base == stack_pointer_rtx) + return 1; + + if (parts.index == NULL_RTX + || parts.index == arg_pointer_rtx + || parts.index == frame_pointer_rtx + || parts.index == hard_frame_pointer_rtx + || parts.index == stack_pointer_rtx) + return 1; + + return 0; +}) + + ;; Returns 1 if OP is memory operand that cannot be represented ;; by the modRM array. (define_predicate "long_memory_operand" diff --git a/gcc/config/i386/sync.md b/gcc/config/i386/sync.md index e267574..05aad00 100644 --- a/gcc/config/i386/sync.md +++ b/gcc/config/i386/sync.md @@ -1,5 +1,5 @@ ;; GCC machine description for i386 synchronization instructions. -;; Copyright (C) 2005, 2006, 2007, 2008 +;; Copyright (C) 2005, 2006, 2007, 2008, 2009 ;; Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -82,8 +82,15 @@ low = force_reg (hmode, low); high = force_reg (hmode, high); if (<MODE>mode == DImode) - emit_insn (gen_sync_double_compare_and_swapdi - (operands[0], operands[1], operands[2], low, high)); + { + if (flag_pic && !cmpxchg8b_pic_memory_operand (operands[1], DImode)) + operands[1] = replace_equiv_address (operands[1], + force_reg (Pmode, + XEXP (operands[1], + 0))); + emit_insn (gen_sync_double_compare_and_swapdi + (operands[0], operands[1], operands[2], low, high)); + } else if (<MODE>mode == TImode) emit_insn (gen_sync_double_compare_and_swapti (operands[0], operands[1], operands[2], low, high)); @@ -131,7 +138,7 @@ ;; are just esi and edi. (define_insn "*sync_double_compare_and_swapdi_pic" [(set (match_operand:DI 0 "register_operand" "=A") - (match_operand:DI 1 "memory_operand" "+m")) + (match_operand:DI 1 "cmpxchg8b_pic_memory_operand" "+m")) (set (match_dup 1) (unspec_volatile:DI [(match_dup 1) @@ -173,8 +180,15 @@ low = force_reg (hmode, low); high = force_reg (hmode, high); if (<MODE>mode == DImode) - emit_insn (gen_sync_double_compare_and_swap_ccdi - (operands[0], operands[1], operands[2], low, high)); + { + if (flag_pic && !cmpxchg8b_pic_memory_operand (operands[1], DImode)) + operands[1] = replace_equiv_address (operands[1], + force_reg (Pmode, + XEXP (operands[1], + 0))); + emit_insn (gen_sync_double_compare_and_swap_ccdi + (operands[0], operands[1], operands[2], low, high)); + } else if (<MODE>mode == TImode) emit_insn (gen_sync_double_compare_and_swap_ccti (operands[0], operands[1], operands[2], low, high)); @@ -224,7 +238,7 @@ ;; operand 3. (define_insn "*sync_double_compare_and_swap_ccdi_pic" [(set (match_operand:DI 0 "register_operand" "=A") - (match_operand:DI 1 "memory_operand" "+m")) + (match_operand:DI 1 "cmpxchg8b_pic_memory_operand" "+m")) (set (match_dup 1) (unspec_volatile:DI [(match_dup 1) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8c9a362..1940fe5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-03-12 Jakub Jelinek <jakub@redhat.com> + + PR target/39431 + * gcc.target/i386/pr39431.c: New test. + 2009-03-12 H.J. Lu <hongjiu.lu@intel.com> PR target/39445 diff --git a/gcc/testsuite/gcc.target/i386/pr39431.c b/gcc/testsuite/gcc.target/i386/pr39431.c new file mode 100644 index 0000000..756bdb9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr39431.c @@ -0,0 +1,15 @@ +/* PR target/39431 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-options "-O2 -march=i686 -fpic" { target { ilp32 && fpic } } } */ + +extern void bar (char *, int); + +int +foo (long long *p, long long oldv, long long *q, int n) +{ + char buf[n]; + bar (buf, n); + p[256 + n] = __sync_val_compare_and_swap (p + n, oldv, oldv + 6); + return __sync_bool_compare_and_swap (q + n, oldv, oldv + 8); +} |