]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
AArch64: Flip svbool_t equal conditionals in ternary operators.
authorTejas Belagod <tejas.belagod@arm.com>
Tue, 11 Nov 2025 16:35:23 +0000 (16:35 +0000)
committerTejas Belagod <tejas.belagod@arm.com>
Fri, 12 Dec 2025 11:11:57 +0000 (11:11 +0000)
This patch flips == conditions:

  p == q ? s1 : s2;

to

  p != q ? s2 : s1;

where p and q are svbool_t expression types. This is an optimization
to avoid generating an extra bit inverse to check for equality.

gcc/

* config/aarch64/aarch64.cc (aarch64_instruction_selection): Flip
svbool_t == to != to avoid extra bit-inverse.

gcc/testsuite/

* g++.target/aarch64/sve/acle/general-c++/svbool_ternary.C: New test.

Co-authored-by: Tamar Christina <tamar.christina@arm.com>
gcc/config/aarch64/aarch64.cc
gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/svbool_ternary.C [new file with mode: 0644]

index f4bef646a92a21ff803a0f1760ddc202f12a23de..58914e3e684959d7b7d286cc6589ed97e45feaa2 100644 (file)
@@ -2207,6 +2207,68 @@ aarch64_preferred_else_value (unsigned, tree, unsigned int nops, tree *ops)
   return nops == 3 ? ops[2] : ops[0];
 }
 
+/* Implement TARGET_INSTRUCTION_SELECTION.  The target hook is used to
+   change generic sequences to a form AArch64 has an easier time expanding
+   instructions for.  It's not supposed to be used for generic rewriting that
+   all targets would benefit from.  */
+
+static bool
+aarch64_instruction_selection (function * /* fun */, gimple_stmt_iterator *gsi)
+{
+  auto stmt = gsi_stmt (*gsi);
+  gassign *assign = dyn_cast<gassign *> (stmt);
+
+  if (!assign)
+    return false;
+
+  /* Convert
+       p == q ? s1 : s2;
+     to
+       p != q ? s2 : s1;
+     where p and q are svbool_t expr.  Due to the absence of predicate
+     comparison instructions, we use bitwise xor for checking inequality.
+     Transforming == to != avoids an extra bitwise inversion to the xor.  */
+  if (gimple_assign_rhs_code (assign) != VEC_COND_EXPR)
+    return false;
+
+  tree lhs = gimple_assign_lhs (assign);
+  tree rhs1 = gimple_assign_rhs1 (assign);
+  tree rhs2 = gimple_assign_rhs2 (assign);
+  tree rhs3 = gimple_assign_rhs3 (assign);
+
+  if (TREE_CODE (rhs1) != SSA_NAME || !VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (rhs1)))
+    return false;
+
+  gassign *da = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (rhs1));
+
+  if (!da)
+    return false;
+
+  if (gimple_assign_rhs_code (da) != EQ_EXPR)
+    return false;
+
+  tree eqa = gimple_assign_rhs1 (da);
+  tree eqb = gimple_assign_rhs2 (da);
+
+  if (!VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (eqa))
+      || !VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (eqb)))
+    return false;
+
+  tree ne_expr_var = create_tmp_var (TREE_TYPE (rhs1));
+  gimple *ne_stmt = gimple_build_assign (ne_expr_var, NE_EXPR, eqa, eqb);
+  gsi_safe_insert_before (gsi, ne_stmt);
+
+  gimple *g = gimple_build_call_internal (IFN_VCOND_MASK, 3,
+                                         ne_expr_var, rhs3, rhs2);
+  if (!g)
+    return false;
+
+  gimple_set_lhs (g, lhs);
+  gsi_replace (gsi, g, false);
+
+  return true;
+}
+
 /* Implement TARGET_HARD_REGNO_NREGS.  */
 
 static unsigned int
@@ -33141,6 +33203,9 @@ aarch64_libgcc_floating_mode_supported_p
 #define TARGET_PREFERRED_ELSE_VALUE \
   aarch64_preferred_else_value
 
+#undef TARGET_INSTRUCTION_SELECTION
+#define TARGET_INSTRUCTION_SELECTION aarch64_instruction_selection
+
 #undef TARGET_INIT_LIBFUNCS
 #define TARGET_INIT_LIBFUNCS aarch64_init_libfuncs
 
diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/svbool_ternary.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/svbool_ternary.C
new file mode 100644 (file)
index 0000000..38de188
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <arm_sve.h>
+
+svbool_t g (svbool_t p, svbool_t q, svbool_t a, svbool_t b,
+            svbool_t c, svbool_t d)
+{
+  return (p == q) ? p : (a == b ? c : d);
+}
+
+/* { dg-final { scan-tree-dump-not {VEC_COND_EXPR} "optimized" } } */
+/* { dg-final { scan-assembler-times {\teor\tp[0-9]+\.b} 2 } } */