From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2140) id 87ED43858407; Sat, 4 Dec 2021 09:22:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 87ED43858407 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Alexandre Oliva To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/aoliva/heads/testme)] [PR103149] detach values through mem only if general regs won't do X-Act-Checkin: gcc X-Git-Author: Alexandre Oliva X-Git-Refname: refs/users/aoliva/heads/testme X-Git-Oldrev: 6accaabd567a66a4067afec3435bd5494659de6a X-Git-Newrev: f590bee0231b2e146ffb314e920e9f3f2f63d9b6 Message-Id: <20211204092223.87ED43858407@sourceware.org> Date: Sat, 4 Dec 2021 09:22:23 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 04 Dec 2021 09:22:23 -0000 https://gcc.gnu.org/g:f590bee0231b2e146ffb314e920e9f3f2f63d9b6 commit f590bee0231b2e146ffb314e920e9f3f2f63d9b6 Author: Alexandre Oliva Date: Sat Dec 4 00:17:18 2021 -0300 [PR103149] detach values through mem only if general regs won't do When hardening compares or conditional branches, we perform redundant tests, and to prevent them from being optimized out, we use asm statements that preserve a value used in a compare, but in a way that the compiler can no longer assume it's the same value, so it can't optimize the redundant test away. We used to use +g, but that requires general regs or mem. You might think that, if a reg constraint can't be satisfied, the register allocator will fall back to memory, but that's not so: we decide on matching MEMs very early on, by using the same addressable operand on both input and output, and only if the constraint does not allow registers. If it does, we use gimple registers and then pseudos as inputs and outputs, and then inputs can be substituted by equivalent expressions, and then, if no register contraint fits (e.g. because that mode won't fit in general regs, or won't fit in regs at all), the register allocator will give up before even trying to allocate some temporary memory to unify input and output. This patch arranges for us to create and use the temporary stack slot if we can tell the mode requires memory, or won't otherwise fit in general regs, and thus to use +m for that asm. for gcc/ChangeLog PR middle-end/103149 * gimple-harden-conditionals.cc (detach_value): Use memory if general regs won't do. for gcc/testsuite/ChangeLog PR middle-end/103149 * gcc.target/aarch64/pr103149.c: New. Diff: --- gcc/gimple-harden-conditionals.cc | 67 ++++++++++++++++++++++++++--- gcc/testsuite/gcc.target/aarch64/pr103149.c | 14 ++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/gcc/gimple-harden-conditionals.cc b/gcc/gimple-harden-conditionals.cc index ee332f9e8db..5e709c66416 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" @@ -133,25 +135,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 *inputs = NULL; vec *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 00000000000..906bc9ae066 --- /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; +}