builtins: Avoid useless char/short -> int promotions before atomics [PR96176]
authorJakub Jelinek <jakub@redhat.com>
Wed, 15 Jul 2020 09:26:22 +0000 (11:26 +0200)
committerJakub Jelinek <jakub@redhat.com>
Wed, 15 Jul 2020 09:26:22 +0000 (11:26 +0200)
As mentioned in the PR, we generate a useless movzbl insn before lock cmpxchg.
The problem is that the builtin for the char/short cases has the arguments
promoted to int and combine gives up, because the instructions have
MEM_VOLATILE_P arguments and recog in that case doesn't recognize anything
when volatile_ok is false, and nothing afterwards optimizes the
(reg:SI a) = (zero_extend:SI (reg:QI a))
... (subreg:QI (reg:SI a) 0) ...

The following patch fixes it at expansion time, we already have a function
that is meant to undo the promotion, so this just adds the very common case
to that.

2020-07-15  Jakub Jelinek  <jakub@redhat.com>

PR target/96176
* builtins.c: Include gimple-ssa.h, tree-ssa-live.h and
tree-outof-ssa.h.
(expand_expr_force_mode): If exp is a SSA_NAME with different mode
from MODE and get_gimple_for_ssa_name is a cast from MODE, use the
cast's rhs.

* gcc.target/i386/pr96176.c: New test.

gcc/builtins.c
gcc/testsuite/gcc.target/i386/pr96176.c [new file with mode: 0644]

index 4754602..eb66211 100644 (file)
@@ -73,6 +73,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "omp-general.h"
 #include "tree-dfa.h"
+#include "gimple-ssa.h"
+#include "tree-ssa-live.h"
+#include "tree-outof-ssa.h"
 
 struct target_builtins default_target_builtins;
 #if SWITCHABLE_TARGET
@@ -6671,6 +6674,27 @@ expand_expr_force_mode (tree exp, machine_mode mode)
   rtx val;
   machine_mode old_mode;
 
+  if (TREE_CODE (exp) == SSA_NAME
+      && TYPE_MODE (TREE_TYPE (exp)) != mode)
+    {
+      /* Undo argument promotion if possible, as combine might not
+        be able to do it later due to MEM_VOLATILE_P uses in the
+        patterns.  */
+      gimple *g = get_gimple_for_ssa_name (exp);
+      if (g && gimple_assign_cast_p (g))
+       {
+         tree rhs = gimple_assign_rhs1 (g);
+         tree_code code = gimple_assign_rhs_code (g);
+         if (CONVERT_EXPR_CODE_P (code)
+             && TYPE_MODE (TREE_TYPE (rhs)) == mode
+             && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+             && INTEGRAL_TYPE_P (TREE_TYPE (rhs))
+             && (TYPE_PRECISION (TREE_TYPE (exp))
+                 > TYPE_PRECISION (TREE_TYPE (rhs))))
+           exp = rhs;
+       }
+    }
+
   val = expand_expr (exp, NULL_RTX, mode, EXPAND_NORMAL);
   /* 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.  */
diff --git a/gcc/testsuite/gcc.target/i386/pr96176.c b/gcc/testsuite/gcc.target/i386/pr96176.c
new file mode 100644 (file)
index 0000000..b8df136
--- /dev/null
@@ -0,0 +1,13 @@
+/* PR target/96176 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "\tmovzbl\t" } } */
+
+unsigned char v;
+
+void
+foo (unsigned char *x, unsigned char y, unsigned char z)
+{
+  __atomic_compare_exchange_n (x, &y, z, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+  v = y;
+}