aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gimple-harden-conditionals.cc67
-rw-r--r--gcc/testsuite/gcc.target/aarch64/pr103149.c14
2 files changed, 75 insertions, 6 deletions
diff --git a/gcc/gimple-harden-conditionals.cc b/gcc/gimple-harden-conditionals.cc
index cfa2361..81867d6 100644
--- a/gcc/gimple-harden-conditionals.cc
+++ b/gcc/gimple-harden-conditionals.cc
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "backend.h"
+#include "target.h"
+#include "rtl.h"
#include "tree.h"
#include "fold-const.h"
#include "gimple.h"
@@ -132,25 +134,78 @@ detach_value (location_t loc, gimple_stmt_iterator *gsip, tree val)
tree ret = make_ssa_name (TREE_TYPE (val));
SET_SSA_NAME_VAR_OR_IDENTIFIER (ret, SSA_NAME_IDENTIFIER (val));
- /* Output asm ("" : "=g" (ret) : "0" (val)); */
+ /* Some modes won't fit in general regs, so we fall back to memory
+ for them. ??? It would be ideal to try to identify an alternate,
+ wider or more suitable register class, and use the corresponding
+ constraint, but there's no logic to go from register class to
+ constraint, even if there is a corresponding constraint, and even
+ if we could enumerate constraints, we can't get to their string
+ either. So this will do for now. */
+ bool need_memory = true;
+ enum machine_mode mode = TYPE_MODE (TREE_TYPE (val));
+ if (mode != BLKmode)
+ for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i)
+ && targetm.hard_regno_mode_ok (i, mode))
+ {
+ need_memory = false;
+ break;
+ }
+
+ tree asminput = val;
+ tree asmoutput = ret;
+ const char *constraint_out = need_memory ? "=m" : "=g";
+ const char *constraint_in = need_memory ? "m" : "0";
+
+ if (need_memory)
+ {
+ tree temp = create_tmp_var (TREE_TYPE (val), "dtch");
+ mark_addressable (temp);
+
+ gassign *copyin = gimple_build_assign (temp, asminput);
+ gimple_set_location (copyin, loc);
+ gsi_insert_before (gsip, copyin, GSI_SAME_STMT);
+
+ asminput = asmoutput = temp;
+ }
+
+ /* Output an asm statement with matching input and output. It does
+ nothing, but after it the compiler no longer knows the output
+ still holds the same value as the input. */
vec<tree, va_gc> *inputs = NULL;
vec<tree, va_gc> *outputs = NULL;
vec_safe_push (outputs,
build_tree_list
(build_tree_list
- (NULL_TREE, build_string (2, "=g")),
- ret));
+ (NULL_TREE, build_string (strlen (constraint_out),
+ constraint_out)),
+ asmoutput));
vec_safe_push (inputs,
build_tree_list
(build_tree_list
- (NULL_TREE, build_string (1, "0")),
- val));
+ (NULL_TREE, build_string (strlen (constraint_in),
+ constraint_in)),
+ asminput));
gasm *detach = gimple_build_asm_vec ("", inputs, outputs,
NULL, NULL);
gimple_set_location (detach, loc);
gsi_insert_before (gsip, detach, GSI_SAME_STMT);
- SSA_NAME_DEF_STMT (ret) = detach;
+ if (need_memory)
+ {
+ gassign *copyout = gimple_build_assign (ret, asmoutput);
+ gimple_set_location (copyout, loc);
+ gsi_insert_before (gsip, copyout, GSI_SAME_STMT);
+ SSA_NAME_DEF_STMT (ret) = copyout;
+
+ gassign *clobber = gimple_build_assign (asmoutput,
+ build_clobber
+ (TREE_TYPE (asmoutput)));
+ gimple_set_location (clobber, loc);
+ gsi_insert_before (gsip, clobber, GSI_SAME_STMT);
+ }
+ else
+ SSA_NAME_DEF_STMT (ret) = detach;
return ret;
}
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103149.c b/gcc/testsuite/gcc.target/aarch64/pr103149.c
new file mode 100644
index 0000000..906bc9a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103149.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=armv8-a+sve -O2 -fharden-conditional-branches -fno-tree-scev-cprop" } */
+
+/* -fharden-conditional-branches prevents optimization of its redundant
+ compares by detaching values from the operands with asm statements. They
+ used to require GENERAL_REGS, but the vectorized booleans, generated while
+ vectorizing this function, can't be held in GENERAL_REGS. */
+
+void
+foo (int *p)
+{
+ while (*p < 1)
+ ++*p;
+}