builtins.c (expand_builtin_sync_operation, [...]): Care for extending CONST_INTs...
authorMichael Matz <matz@suse.de>
Mon, 19 Mar 2007 17:07:29 +0000 (17:07 +0000)
committerMichael Matz <matz@gcc.gnu.org>
Mon, 19 Mar 2007 17:07:29 +0000 (17:07 +0000)
        * builtins.c (expand_builtin_sync_operation,
        expand_builtin_compare_and_swap,
        expand_builtin_lock_test_and_set): Care for extending CONST_INTs
        correctly.

        * config/i386/sync.md (sync_double_compare_and_swapdi_pic,
        sync_double_compare_and_swap_ccdi_pic): Use "SD" as constraint
        for operand 3.

From-SVN: r123064

gcc/ChangeLog
gcc/builtins.c
gcc/config/i386/sync.md

index d2f0566..fb839f5 100644 (file)
@@ -1,3 +1,14 @@
+2007-03-19  Michael Matz  <matz@suse.de>
+
+       * builtins.c (expand_builtin_sync_operation,
+       expand_builtin_compare_and_swap,
+       expand_builtin_lock_test_and_set): Care for extending CONST_INTs
+       correctly.
+
+       * config/i386/sync.md (sync_double_compare_and_swapdi_pic,
+       sync_double_compare_and_swap_ccdi_pic): Use "SD" as constraint
+       for operand 3.
+
 2007-03-19  Andreas Krebbel  <krebbel1@de.ibm.com>
 
        * doc/tm.texi: Add brackets around the return type of
index 0bb1489..989b8d7 100644 (file)
@@ -5771,13 +5771,18 @@ expand_builtin_sync_operation (enum machine_mode mode, tree exp,
                               rtx target, bool ignore)
 {
   rtx val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
   val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  */
-  val = convert_to_mode (mode, val, 1);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  val = convert_modes (mode, old_mode, val, 1);
 
   if (ignore)
     return expand_sync_operation (mem, val, code);
@@ -5795,18 +5800,27 @@ expand_builtin_compare_and_swap (enum machine_mode mode, tree exp,
                                 bool is_bool, rtx target)
 {
   rtx old_val, new_val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
 
   old_val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If OLD_VAL is promoted to a wider mode, convert it back to MODE.  */
-  old_val = convert_to_mode (mode, old_val, 1);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (old_val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  old_val = convert_modes (mode, old_mode, old_val, 1);
 
   new_val = expand_expr (CALL_EXPR_ARG (exp, 2), NULL, mode, EXPAND_NORMAL);
-  /* If NEW_VAL is promoted to a wider mode, convert it back to MODE.  */
-  new_val = convert_to_mode (mode, new_val, 1);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (new_val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 2)));
+  new_val = convert_modes (mode, old_mode, new_val, 1);
 
   if (is_bool)
     return expand_bool_compare_and_swap (mem, old_val, new_val, target);
@@ -5825,12 +5839,17 @@ expand_builtin_lock_test_and_set (enum machine_mode mode, tree exp,
                                  rtx target)
 {
   rtx val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
   val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  */
-  val = convert_to_mode (mode, val, 1);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  val = convert_modes (mode, old_mode, val, 1);
 
   return expand_sync_lock_test_and_set (mem, val, target);
 }
index 58e047b..9a0ae3f 100644 (file)
   ""
   "lock{\;| }cmpxchg<doublemodesuffix>b{\t| }%1")
 
+;; Theoretically we'd like to use constraint "r" (any reg) for operand
+;; 3, but that includes ecx.  If operand 3 and 4 are the same (like when
+;; the input is -1LL) GCC might chose to allocate operand 3 to ecx, like
+;; operand 4.  This breaks, as the xchg will move the PIC register contents
+;; to %ecx then --> boom.  Operands 3 and 4 really need to be different
+;; registers, which in this case means operand 3 must not be ecx.
+;; Instead of playing tricks with fake early clobbers or the like we
+;; just enumerate all regs possible here, which (as this is !TARGET_64BIT)
+;; 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"))
        (unspec_volatile:DI
          [(match_dup 1)
           (match_operand:DI 2 "register_operand" "A")
-          (match_operand:SI 3 "register_operand" "r")
+          (match_operand:SI 3 "register_operand" "SD")
           (match_operand:SI 4 "register_operand" "c")]
          UNSPECV_CMPXCHG_1))
    (clobber (reg:CC FLAGS_REG))]
   ""
   "lock{\;| }cmpxchg<doublemodesuffix>b{\t| }%1")
 
+;; See above for the explanation of using the constraint "SD" for
+;; 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"))
        (unspec_volatile:DI
          [(match_dup 1)
           (match_operand:DI 2 "register_operand" "A")
-          (match_operand:SI 3 "register_operand" "r")
+          (match_operand:SI 3 "register_operand" "SD")
           (match_operand:SI 4 "register_operand" "c")]
          UNSPECV_CMPXCHG_1))
    (set (reg:CCZ FLAGS_REG)