From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2140) id E126A3857818; Tue, 30 Nov 2021 23:31:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E126A3857818 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)] introduce asmnesia internal function X-Act-Checkin: gcc X-Git-Author: Alexandre Oliva X-Git-Refname: refs/users/aoliva/heads/testme X-Git-Oldrev: 0fc26e6f0b5e5a40f2649e98db605f4c740e2c4e X-Git-Newrev: f4faa1c932f616384ee0de65ad2dc500ea0d19d2 Message-Id: <20211130233132.E126A3857818@sourceware.org> Date: Tue, 30 Nov 2021 23:31:32 +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: Tue, 30 Nov 2021 23:31:33 -0000 https://gcc.gnu.org/g:f4faa1c932f616384ee0de65ad2dc500ea0d19d2 commit f4faa1c932f616384ee0de65ad2dc500ea0d19d2 Author: Alexandre Oliva Date: Tue Nov 30 20:27:50 2021 -0300 introduce asmnesia internal function Diff: --- gcc/gimple-harden-conditionals.cc | 17 +------- gcc/internal-fn.c | 58 +++++++++++++++++++++++++++ gcc/internal-fn.def | 4 ++ gcc/recog.c | 84 +++++++++++++++++++++++++++++++++------ 4 files changed, 136 insertions(+), 27 deletions(-) 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 *inputs = NULL; - vec *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..3c3fd9cadfa 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -3234,6 +3234,64 @@ 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)); + + rtx temp = copy_to_mode_reg (mode, from_rtx); + + rtvec argvec = rtvec_alloc (1); + rtvec constraintvec = rtvec_alloc (1); + rtvec labelvec = rtvec_alloc (0); + + /* This is roughly equivalent to asm ("" : "+g,?X" (temp)); + + We use gX instead of just X to prefer GENERAL_REGS. without that, we may + end up with e.g. XFmode regs, and using those as input/output in asm stmts + end up triggering errors with e.g. the x87 FP stack, even though they would + have been perfectly fine. ??? Maybe the errors we 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, + which gimple doesn't. This is particularly important for X, because it + doesn't select any register class, and it gets confused in case of + different MEMs. */ + rtx body = gen_rtx_ASM_OPERANDS (mode, + ggc_strdup (""), + "=g,?X", 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,0", locus); + emit_insn (gen_rtx_SET (temp, body)); + + emit_move_insn (to_rtx, temp); +} + /* 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..6dd60e40a02 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; } @@ -2162,11 +2165,60 @@ 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); +} + +static int +check_match (rtx op, enum constraint_num cn, int res, + rtx *operands, int match_index) +{ + if (!res || match_index < 0 || !operands) + 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[match_index]; + + /* Avoid divergence between input and output when reload wouldn't be able to + fix it up. */ + if (op != mop + && ((allows_mem && MEM_P (op) && MEM_P (mop) + && (!allows_reg || rclass == NO_REGS || GET_MODE (mop) == BLKmode)) + /* ??? Maybe we could relax this for e.g. CONSTRAINT_X, + if reload picked some register class for it. */ + || (allows_reg && (rclass == NO_REGS || GET_MODE (mop) == BLKmode) + && (!allows_mem || !MEM_P (op) || !MEM_P (mop))) + || !general_operand (op, + GET_MODE (op) != VOIDmode + ? GET_MODE (op) + : GET_MODE (mop)))) + return 0; + + return res; +} + /* Check if an asm_operand matches its constraints. Return > 0 if ok, = 0 if bad, < 0 if inconclusive. */ -int -asm_operand_ok (rtx op, const char *constraint, const char **constraints) +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 +2229,7 @@ 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 (op, CONSTRAINT_X, 1, operands, match_index); while (*constraint) { @@ -2204,7 +2256,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 +2282,13 @@ 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 (op, CONSTRAINT_o, 1, operands, match_index); break; case 'g': if (general_operand (op, VOIDmode)) - result = 1; + result = check_match (op, CONSTRAINT__LIMIT, 1, + operands, match_index); break; case '<': @@ -2257,14 +2311,14 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) && reg_class_for_constraint (cn) != NO_REGS && GET_MODE (op) != BLKmode && register_operand (op, VOIDmode)) - result = 1; + result = check_match (op, cn, 1, 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 (op, cn, 1, operands, match_index); break; case CT_MEMORY: @@ -2275,16 +2329,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 (op, cn, + result || 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 (op, cn, + result || address_operand (op, VOIDmode), + operands, match_index); break; case CT_FIXED_FORM: - result = result || constraint_satisfied_p (op, cn); + result = check_match (op, cn, + result || constraint_satisfied_p (op, cn), + operands, match_index); break; } break;