public inbox for gcc-cvs@sourceware.org help / color / mirror / Atom feed
From: Alexandre Oliva <aoliva@gcc.gnu.org> To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function Date: Wed, 1 Dec 2021 23:57:17 +0000 (GMT) [thread overview] Message-ID: <20211201235717.C8B4E3858032@sourceware.org> (raw) https://gcc.gnu.org/g:5f2c9c6dbe83f30958fcf7f61e3946f6c7850489 commit 5f2c9c6dbe83f30958fcf7f61e3946f6c7850489 Author: Alexandre Oliva <oliva@adacore.com> Date: Tue Nov 30 20:27:50 2021 -0300 introduce asmnesia internal function Diff: --- gcc/cfgexpand.c | 6 +- gcc/gimple-harden-conditionals.cc | 17 +---- gcc/internal-fn.c | 81 ++++++++++++++++++++ gcc/internal-fn.def | 4 + gcc/recog.c | 114 +++++++++++++++++++++++----- gcc/testsuite/gcc.target/aarch64/pr103149.c | 13 ++++ gcc/testsuite/gcc.target/i386/pr85030.c | 2 +- gcc/testsuite/gcc.target/i386/pr93027.c | 2 + 8 files changed, 202 insertions(+), 37 deletions(-) diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index fb84d469f1e..f0272ba1ac9 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3374,10 +3374,10 @@ expand_asm_stmt (gasm *stmt) tree val = input_tvec[i]; tree type = TREE_TYPE (val); bool allows_reg, allows_mem, ok; - const char *constraint; + const char *constraint, *orig_constraint; rtx op; - constraint = constraints[i + noutputs]; + orig_constraint = constraint = constraints[i + noutputs]; ok = parse_input_constraint (&constraint, i, ninputs, noutputs, 0, constraints.address (), &allows_mem, &allows_reg); @@ -3397,7 +3397,7 @@ expand_asm_stmt (gasm *stmt) else if (MEM_P (op)) op = validize_mem (op); - if (asm_operand_ok (op, constraint, NULL) <= 0) + if (asm_operand_ok (op, orig_constraint, constraints.address ()) <= 0) { if (allows_reg && TYPE_MODE (type) != BLKmode) op = force_reg (TYPE_MODE (type), op); diff --git a/gcc/gimple-harden-conditionals.cc b/gcc/gimple-harden-conditionals.cc index cfa2361d65b..3768b2e23bd 100644 --- a/gcc/gimple-harden-conditionals.cc +++ b/gcc/gimple-harden-conditionals.cc @@ -132,21 +132,8 @@ 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)); */ - 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)); - vec_safe_push (inputs, - build_tree_list - (build_tree_list - (NULL_TREE, build_string (1, "0")), - val)); - gasm *detach = gimple_build_asm_vec ("", inputs, outputs, - NULL, NULL); + gcall *detach = gimple_build_call_internal (IFN_ASMNESIA, 1, val); + gimple_call_set_lhs (detach, ret); gimple_set_location (detach, loc); gsi_insert_before (gsip, detach, GSI_SAME_STMT); diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 6ac3460d538..a4a2ca91d9f 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -3234,6 +3234,87 @@ expand_LAUNDER (internal_fn, gcall *call) expand_assignment (lhs, gimple_call_arg (call, 0), false); } +/* Expand ASMNESIA to assignment and asm that makes the value unknown. */ + +static void +expand_ASMNESIA (internal_fn, gcall *call) +{ + tree to = gimple_call_lhs (call); + + if (!to) + return; + + location_t locus = gimple_location (call); + + tree from = gimple_call_arg (call, 0); + + rtx to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE); + + rtx from_rtx = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL); + + enum machine_mode mode = GET_MODE (to_rtx); + + gcc_checking_assert (mode != BLKmode && mode != VOIDmode + && (GET_MODE (from_rtx) == mode + || GET_MODE (from_rtx) == VOIDmode)); + + rtvec argvec = rtvec_alloc (1); + rtvec constraintvec = rtvec_alloc (1); + rtvec labelvec = rtvec_alloc (0); + + bool need_memory = true; + 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; + } + + rtx regtemp = copy_to_mode_reg (mode, from_rtx); + rtx temp = regtemp; + const char *constraint = "=g"; + + if (need_memory) + { + constraint = "=m"; + temp = assign_stack_temp (mode, GET_MODE_SIZE (mode)); + emit_move_insn (temp, regtemp); + } + + /* This is roughly equivalent to asm ("" : "+g" (temp)); + + We use +m instead of +g if we NEED_MEMORY, i.e., the mode is not suitable + for GENERAL_REGS. ??? Ideally, we'd choose a suitable register class, if + there is one, but how do we get a constraint type that maps to a it? +X is + at the same time too lax, because arbitrary RTL and x87 FP regs are not + desirable, and too strict, because it doesn't guide any register class. + ??? Maybe the errors reg-stack would flag on e.g. libgcc/_multc3 could be + conditioned on the operand's being referenced? + + Unlike expansion of gimple asm stmts, it doesn't go through + targetm.md_asm_adjust (we don't wish any clobbers). + + Furthermore, we ensure input and output start out with the same pseudo or + MEM, which gimple doesn't. This is particularly important for MEMs, since + reloads can't merge disparate ones, and it would be important for X because + it guides NO_REGS. */ + rtx body = gen_rtx_ASM_OPERANDS (mode, + ggc_strdup (""), + constraint, 0, + argvec, constraintvec, labelvec, + locus); + ASM_OPERANDS_INPUT (body, 0) = temp; + ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, 0) + = gen_rtx_ASM_INPUT_loc (mode, "0", locus); + emit_insn (gen_rtx_SET (temp, body)); + + if (need_memory) + emit_move_insn (regtemp, temp); + + emit_move_insn (to_rtx, regtemp); +} + /* Expand {MASK_,}SCATTER_STORE{S,U} call CALL using optab OPTAB. */ static void diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index acb0dbda556..f10b2201921 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -410,6 +410,10 @@ DEF_INTERNAL_FN (FALLTHROUGH, ECF_LEAF | ECF_NOTHROW, NULL) /* To implement __builtin_launder. */ DEF_INTERNAL_FN (LAUNDER, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL) +/* Copy a value while preventing optimizations based on knowledge + about the input operand. */ +DEF_INTERNAL_FN (ASMNESIA, ECF_LEAF | ECF_NOTHROW, NULL) + /* Divmod function. */ DEF_INTERNAL_FN (DIVMOD, ECF_CONST | ECF_LEAF, NULL) diff --git a/gcc/recog.c b/gcc/recog.c index 5a42c45361d..2f402daad55 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -53,6 +53,9 @@ along with GCC; see the file COPYING3. If not see static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx_insn *, bool); static void validate_replace_src_1 (rtx *, void *); static rtx_insn *split_insn (rtx_insn *); +static int asm_operand_ok_match (rtx op, const char *constraint, + const char **constraints, + rtx *operands, int match_index); struct target_recog default_target_recog; #if SWITCHABLE_TARGET @@ -170,7 +173,7 @@ check_asm_operands (rtx x) const char *c = constraints[i]; if (c[0] == '%') c++; - if (! asm_operand_ok (operands[i], c, constraints)) + if (! asm_operand_ok_match (operands[i], c, constraints, operands, -1)) return 0; } @@ -2167,6 +2170,67 @@ get_referenced_operands (const char *string, bool *used, int asm_operand_ok (rtx op, const char *constraint, const char **constraints) +{ + return asm_operand_ok_match (op, constraint, constraints, NULL, -1); +} + +/* Combine a previous cummulative result PREVRES with RES. If MATCH_INDEX is + nonnegative, check that OP is compatible with the matched operand, using + OPERANDS if not NULL, under the CN-implied requirements. + */ + +static int +check_match (int prevres, rtx op, enum constraint_num cn, int res, + rtx *operands, int match_index) +{ + if (prevres > 0 || !res) + return prevres; + + if (match_index < 0) + return res; + + bool allows_reg = false, allows_mem = false; + enum reg_class rclass = NO_REGS; + + if (cn == CONSTRAINT__LIMIT) + { + allows_reg = allows_mem = true; + rclass = GENERAL_REGS; + } + else + { + insn_extra_constraint_allows_reg_mem (cn, &allows_reg, &allows_mem); + if (allows_reg) + rclass = reg_class_for_constraint (cn); + } + + rtx mop = operands ? operands[match_index] : NULL_RTX; + + /* Avoid divergence between input and output when reload wouldn't be able to + fix it up. Keep matching MEMs identical if we can't have REGs, but allow + reloadable MEMs otherwise. Avoid immediates and rvalue expressions, since + they can't match outputs. */ + if (op != mop + && ((mop && allows_mem && MEM_P (op) && MEM_P (mop) + && (!allows_reg || rclass == NO_REGS || GET_MODE (mop) == BLKmode) + && !rtx_equal_p (op, mop)) + || (mop && allows_reg + && (rclass == NO_REGS || GET_MODE (mop) == BLKmode) + && (!allows_mem || !MEM_P (op) || !MEM_P (mop))) + || !nonimmediate_operand (op, VOIDmode))) + return prevres; + + return res; +} + +/* Check if an asm_operand matches its constraints. + If MATCH_INDEX is nonnegative, also check for potential compatibility + with the matched operand, using OPERANDS if non-NULL. + Return > 0 if ok, = 0 if bad, < 0 if inconclusive. */ + +static int +asm_operand_ok_match (rtx op, const char *constraint, const char **constraints, + rtx *operands, int match_index) { int result = 0; bool incdec_ok = false; @@ -2177,7 +2241,8 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) /* Empty constraint string is the same as "X,...,X", i.e. X for as many alternatives as required to match the other operands. */ if (*constraint == '\0') - result = 1; + result = check_match (result, op, CONSTRAINT_X, + 1, operands, match_index); while (*constraint) { @@ -2186,7 +2251,8 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) int len; switch (c) { - case ',': + case '&': case '?': case '!': case '#': case '*': + case '=': case '+': case ',': constraint++; continue; @@ -2204,7 +2270,8 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) match = strtoul (constraint, &end, 10); if (!result) - result = asm_operand_ok (op, constraints[match], NULL); + result = asm_operand_ok_match (op, constraints[match], NULL, + operands, match); constraint = (const char *) end; } else @@ -2229,12 +2296,14 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) offsettable address exists. */ case 'o': /* offsettable */ if (offsettable_nonstrict_memref_p (op)) - result = 1; + result = check_match (result, op, CONSTRAINT_o, 1, + operands, match_index); break; case 'g': if (general_operand (op, VOIDmode)) - result = 1; + result = check_match (result, op, CONSTRAINT__LIMIT, 1, + operands, match_index); break; case '<': @@ -2253,18 +2322,21 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) switch (get_constraint_type (cn)) { case CT_REGISTER: - if (!result - && reg_class_for_constraint (cn) != NO_REGS - && GET_MODE (op) != BLKmode - && register_operand (op, VOIDmode)) - result = 1; + /* Don't demand a register for a matched operand, see pr93027. */ + result = check_match (result, op, cn, + reg_class_for_constraint (cn) != NO_REGS + && GET_MODE (op) != BLKmode + && (match_index >= 0 + || register_operand (op, VOIDmode)), + operands, match_index); break; case CT_CONST_INT: - if (!result - && CONST_INT_P (op) - && insn_const_int_ok_for_constraint (INTVAL (op), cn)) - result = 1; + result = check_match (result, op, cn, + CONST_INT_P (op) + && (insn_const_int_ok_for_constraint + (INTVAL (op), cn)), + operands, match_index); break; case CT_MEMORY: @@ -2275,16 +2347,22 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) /* Every memory operand can be reloaded to fit. */ if (!mem) mem = extract_mem_from_operand (op); - result = result || memory_operand (mem, VOIDmode); + result = check_match (result, op, cn, + memory_operand (mem, VOIDmode), + operands, match_index); break; case CT_ADDRESS: /* Every address operand can be reloaded to fit. */ - result = result || address_operand (op, VOIDmode); + result = check_match (result, op, cn, + address_operand (op, VOIDmode), + operands, match_index); break; case CT_FIXED_FORM: - result = result || constraint_satisfied_p (op, cn); + result = check_match (result, op, cn, + constraint_satisfied_p (op, cn), + operands, match_index); break; } break; diff --git a/gcc/testsuite/gcc.target/aarch64/pr103149.c b/gcc/testsuite/gcc.target/aarch64/pr103149.c new file mode 100644 index 00000000000..e7283b4f569 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pr103149.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-march=armv8-a+sve -O2 -fharden-conditional-branches -fno-tree-scev-cprop" } */ + +/* -fharden-conditional-branches relies on ASMNESIA, that used to require + GENERAL_REGS even for vectorized booleans, which can't go on + GENERAL_REGS. */ + +void +foo (int *p) +{ + while (*p < 1) + ++*p; +} diff --git a/gcc/testsuite/gcc.target/i386/pr85030.c b/gcc/testsuite/gcc.target/i386/pr85030.c index ff41df6bb64..f24e690b8c1 100644 --- a/gcc/testsuite/gcc.target/i386/pr85030.c +++ b/gcc/testsuite/gcc.target/i386/pr85030.c @@ -6,5 +6,5 @@ void foo () { struct S a; - asm volatile ("" : "=rm" (a) : "0" (1)); /* { dg-error "inconsistent operand constraints in an 'asm'" } */ + asm volatile ("" : "=rm" (a) : "0" (1)); /* { dg-error "impossible constraint in 'asm'|inconsistent operand constraints in an 'asm'" } */ } diff --git a/gcc/testsuite/gcc.target/i386/pr93027.c b/gcc/testsuite/gcc.target/i386/pr93027.c index 378f8444c01..b19541f0f30 100644 --- a/gcc/testsuite/gcc.target/i386/pr93027.c +++ b/gcc/testsuite/gcc.target/i386/pr93027.c @@ -5,6 +5,8 @@ int main (void) { int f = 0, w; + /* ??? With optimization, reload overwrites the f input with &w before the + asm. */ asm volatile( "" : "+m&l"(f)
next reply other threads:[~2021-12-01 23:57 UTC|newest] Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-12-01 23:57 Alexandre Oliva [this message] -- strict thread matches above, loose matches on Subject: below -- 2021-12-01 21:34 Alexandre Oliva 2021-12-01 21:13 Alexandre Oliva 2021-12-01 20:47 Alexandre Oliva 2021-11-30 23:31 Alexandre Oliva 2021-11-30 23:05 Alexandre Oliva 2021-11-29 0:23 Alexandre Oliva 2021-11-29 0:17 Alexandre Oliva 2021-11-29 0:03 Alexandre Oliva 2021-11-28 23:35 Alexandre Oliva 2021-11-28 23:29 Alexandre Oliva 2021-11-26 21:39 Alexandre Oliva 2021-11-26 20:27 Alexandre Oliva 2021-11-20 14:50 Alexandre Oliva 2021-11-20 10:21 Alexandre Oliva 2021-11-20 9:52 Alexandre Oliva 2021-11-20 9:11 Alexandre Oliva
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20211201235717.C8B4E3858032@sourceware.org \ --to=aoliva@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).