diff options
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/i386/predicates.md | 28 | ||||
-rw-r--r-- | gcc/config/i386/sync.md | 28 |
2 files changed, 49 insertions, 7 deletions
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) |