In the Fix for PR122103 an ambiguity was introduced when it comes to fortran
due to an inconsistency in libmvec headers.
A reproducer is
!GCC$ builtin (expf) attributes simd (notinbranch)
SUBROUTINE a(b)
REAL, DIMENSION(:) :: b
c: DO i = 1, d
IF (e <= f) THEN
g = EXP(h)
r = g
IF (r > s) THEN
b(i) = t
END IF
END IF
END DO c
END
compiled with -O2 -march=armv8-a+sve, note that fortran, unlike C provides the
libmvec header math-vector-fortran.h unconditionally, which is a separate bug
PR118955 which causes the functions to become available outside of -Ofast.
This means the cases for MASK_CALL and trapping math overlap for fortran at -O2.
The new masking code shouldn't handle SIMD clones.
Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues.
Pushed.
Thanks,
Tamar
gcc/ChangeLog:
PR tree-optimization/122103
PR tree-optimization/123628
* tree-if-conv.cc (if_convertible_simdclone_stmt_p): New.
(if_convertible_stmt_p, predicate_statements): Use it.
gcc/testsuite/ChangeLog:
PR tree-optimization/122103
PR tree-optimization/123628
* gfortran.target/aarch64/pr123628.f90: New test.
---
diff --git a/gcc/testsuite/gfortran.target/aarch64/pr123628.f90
b/gcc/testsuite/gfortran.target/aarch64/pr123628.f90
new file mode 100644
index
0000000000000000000000000000000000000000..5a42434890c332c7eb1619b84d9eac486fe89d86
--- /dev/null
+++ b/gcc/testsuite/gfortran.target/aarch64/pr123628.f90
@@ -0,0 +1,16 @@
+! { dg-do compile }
+! { dg-options "-O2 -march=armv9-a -fdump-tree-ifcvt -w" }
+! { dg-final { scan-tree-dump {.MASK_CALL \(__builtin_expf, } ifcvt } }
+!GCC$ builtin (expf) attributes simd (notinbranch)
+SUBROUTINE a(b)
+ REAL, DIMENSION(:) :: b
+ c: DO i = 1, d
+ IF (e <= f) THEN
+ g = EXP(h)
+ r = g
+ IF (r > s) THEN
+ b(i) = t
+ END IF
+ END IF
+ END DO c
+END
diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc
index
51fbcc128c671d749bd97dfa91f6f4b605eb8f82..d728f7c5221c66c2fd963d3e3ab55b232e628cb0
100644
--- a/gcc/tree-if-conv.cc
+++ b/gcc/tree-if-conv.cc
@@ -1120,6 +1120,36 @@ if_convertible_switch_p (gswitch *sw)
return true;
}
+/* Return true when STMT is an if-convertible SIMD clone stmts.
+
+ A SIMD clone statement is if-convertible if:
+ - it is an GIMPLE_CALL,
+ - it has a FNDECL,
+ - it has SIMD clones,
+ - it has at least one inbranch clone. */
+static bool
+if_convertible_simdclone_stmt_p (gimple *stmt)
+{
+ if (!is_gimple_call (stmt))
+ return false;
+
+ tree fndecl = gimple_call_fndecl (stmt);
+ if (fndecl)
+ {
+ /* We can vectorize some builtins and functions with SIMD "inbranch"
+ clones. */
+ struct cgraph_node *node = cgraph_node::get (fndecl);
+ if (node && node->simd_clones != NULL)
+ /* Ensure that at least one clone can be "inbranch". */
+ for (struct cgraph_node *n = node->simd_clones; n != NULL;
+ n = n->simdclone->next_clone)
+ if (n->simdclone->inbranch)
+ return true;
+ }
+
+ return false;
+}
+
/* Return true when STMT is if-convertible.
A statement is if-convertible if:
@@ -1147,22 +1177,12 @@ if_convertible_stmt_p (gimple *stmt,
vec<data_reference_p> refs)
case GIMPLE_CALL:
{
- tree fndecl = gimple_call_fndecl (stmt);
- if (fndecl)
+ /* Check if stmt is a simd clone first. */
+ if (if_convertible_simdclone_stmt_p (stmt))
{
- /* We can vectorize some builtins and functions with SIMD
- "inbranch" clones. */
- struct cgraph_node *node = cgraph_node::get (fndecl);
- if (node && node->simd_clones != NULL)
- /* Ensure that at least one clone can be "inbranch". */
- for (struct cgraph_node *n = node->simd_clones; n != NULL;
- n = n->simdclone->next_clone)
- if (n->simdclone->inbranch)
- {
- gimple_set_plf (stmt, GF_PLF_2, true);
- need_to_predicate = true;
- return true;
- }
+ gimple_set_plf (stmt, GF_PLF_2, true);
+ need_to_predicate = true;
+ return true;
}
/* Check if the call can trap and if so require predication. */
@@ -3108,7 +3128,8 @@ predicate_statements (loop_p loop)
}
else if (gimple_plf (stmt, GF_PLF_2)
&& (is_gimple_assign (stmt)
- || gimple_call_builtin_p (stmt)))
+ || (gimple_call_builtin_p (stmt)
+ && !if_convertible_simdclone_stmt_p (stmt))))
{
tree lhs = gimple_get_lhs (stmt);
/* ?? Assume that calls without an LHS are not data processing
--
diff --git a/gcc/testsuite/gfortran.target/aarch64/pr123628.f90 b/gcc/testsuite/gfortran.target/aarch64/pr123628.f90
new file mode 100644
index 0000000000000000000000000000000000000000..5a42434890c332c7eb1619b84d9eac486fe89d86
--- /dev/null
+++ b/gcc/testsuite/gfortran.target/aarch64/pr123628.f90
@@ -0,0 +1,16 @@
+! { dg-do compile }
+! { dg-options "-O2 -march=armv9-a -fdump-tree-ifcvt -w" }
+! { dg-final { scan-tree-dump {.MASK_CALL \(__builtin_expf, } ifcvt } }
+!GCC$ builtin (expf) attributes simd (notinbranch)
+SUBROUTINE a(b)
+ REAL, DIMENSION(:) :: b
+ c: DO i = 1, d
+ IF (e <= f) THEN
+ g = EXP(h)
+ r = g
+ IF (r > s) THEN
+ b(i) = t
+ END IF
+ END IF
+ END DO c
+END
diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc
index 51fbcc128c671d749bd97dfa91f6f4b605eb8f82..d728f7c5221c66c2fd963d3e3ab55b232e628cb0 100644
--- a/gcc/tree-if-conv.cc
+++ b/gcc/tree-if-conv.cc
@@ -1120,6 +1120,36 @@ if_convertible_switch_p (gswitch *sw)
return true;
}
+/* Return true when STMT is an if-convertible SIMD clone stmts.
+
+ A SIMD clone statement is if-convertible if:
+ - it is an GIMPLE_CALL,
+ - it has a FNDECL,
+ - it has SIMD clones,
+ - it has at least one inbranch clone. */
+static bool
+if_convertible_simdclone_stmt_p (gimple *stmt)
+{
+ if (!is_gimple_call (stmt))
+ return false;
+
+ tree fndecl = gimple_call_fndecl (stmt);
+ if (fndecl)
+ {
+ /* We can vectorize some builtins and functions with SIMD "inbranch"
+ clones. */
+ struct cgraph_node *node = cgraph_node::get (fndecl);
+ if (node && node->simd_clones != NULL)
+ /* Ensure that at least one clone can be "inbranch". */
+ for (struct cgraph_node *n = node->simd_clones; n != NULL;
+ n = n->simdclone->next_clone)
+ if (n->simdclone->inbranch)
+ return true;
+ }
+
+ return false;
+}
+
/* Return true when STMT is if-convertible.
A statement is if-convertible if:
@@ -1147,22 +1177,12 @@ if_convertible_stmt_p (gimple *stmt, vec<data_reference_p> refs)
case GIMPLE_CALL:
{
- tree fndecl = gimple_call_fndecl (stmt);
- if (fndecl)
+ /* Check if stmt is a simd clone first. */
+ if (if_convertible_simdclone_stmt_p (stmt))
{
- /* We can vectorize some builtins and functions with SIMD
- "inbranch" clones. */
- struct cgraph_node *node = cgraph_node::get (fndecl);
- if (node && node->simd_clones != NULL)
- /* Ensure that at least one clone can be "inbranch". */
- for (struct cgraph_node *n = node->simd_clones; n != NULL;
- n = n->simdclone->next_clone)
- if (n->simdclone->inbranch)
- {
- gimple_set_plf (stmt, GF_PLF_2, true);
- need_to_predicate = true;
- return true;
- }
+ gimple_set_plf (stmt, GF_PLF_2, true);
+ need_to_predicate = true;
+ return true;
}
/* Check if the call can trap and if so require predication. */
@@ -3108,7 +3128,8 @@ predicate_statements (loop_p loop)
}
else if (gimple_plf (stmt, GF_PLF_2)
&& (is_gimple_assign (stmt)
- || gimple_call_builtin_p (stmt)))
+ || (gimple_call_builtin_p (stmt)
+ && !if_convertible_simdclone_stmt_p (stmt))))
{
tree lhs = gimple_get_lhs (stmt);
/* ?? Assume that calls without an LHS are not data processing