public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-29 0:03 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-29 0:03 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:a082bed792890bc93bae3b3e06bfe9f3e2213c27
commit a082bed792890bc93bae3b3e06bfe9f3e2213c27
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 +-------
gcc/internal-fn.c | 52 +++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++
gcc/recog.c | 82 +++++++++++++++++++++++++++++++++------
4 files changed, 128 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<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 e5b85f0db0e..5c21d3f84c0 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,58 @@ 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 ("" : "+X" (temp));
+
+ 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", 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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..7dc35075551 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,58 @@ 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))
+ /* ??? 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))
+ || !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 +2227,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 +2254,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 +2280,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 +2309,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 +2327,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;
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-12-01 23:57 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-12-01 23:57 UTC (permalink / raw)
To: gcc-cvs
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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-12-01 21:34 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-12-01 21:34 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:1fae24eed84a3264f7f534218dc79a1516c01e1a
commit 1fae24eed84a3264f7f534218dc79a1516c01e1a
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 | 58 ++++++++++++++++
gcc/internal-fn.def | 4 ++
gcc/recog.c | 117 ++++++++++++++++++++++++++------
gcc/testsuite/gcc.target/i386/pr85030.c | 2 +-
gcc/testsuite/gcc.target/i386/pr93027.c | 2 +
7 files changed, 167 insertions(+), 39 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..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..0d2d0e43be1 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,62 @@ get_referenced_operands (const char *string, bool *used,
}
}
+/* 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))
+ || (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. */
-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 +2231,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 +2241,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 +2260,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 +2286,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 +2312,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 +2337,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;
@@ -2314,6 +2382,15 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
return result;
}
+
+/* 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)
+{
+ return asm_operand_ok_match (op, constraint, constraints, NULL, -1);
+}
\f
/* Given an rtx *P, if it is a sum containing an integer constant term,
return the location (type rtx *) of the pointer to that constant term.
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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-12-01 21:13 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-12-01 21:13 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:a84fe20a4a44651b9890c053d272f9d4296168aa
commit a84fe20a4a44651b9890c053d272f9d4296168aa
Author: Alexandre Oliva <oliva@adacore.com>
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 | 117 ++++++++++++++++++++++++++------
gcc/testsuite/gcc.target/i386/pr85030.c | 2 +-
gcc/testsuite/gcc.target/i386/pr93027.c | 2 +
6 files changed, 164 insertions(+), 36 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<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..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..0d2d0e43be1 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,62 @@ get_referenced_operands (const char *string, bool *used,
}
}
+/* 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))
+ || (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. */
-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 +2231,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 +2241,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 +2260,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 +2286,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 +2312,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 +2337,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;
@@ -2314,6 +2382,15 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
return result;
}
+
+/* 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)
+{
+ return asm_operand_ok_match (op, constraint, constraints, NULL, -1);
+}
\f
/* Given an rtx *P, if it is a sum containing an integer constant term,
return the location (type rtx *) of the pointer to that constant term.
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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-12-01 20:47 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-12-01 20:47 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:179f4c600d6278afee4f53dc7387238ad7dc4df0
commit 179f4c600d6278afee4f53dc7387238ad7dc4df0
Author: Alexandre Oliva <oliva@adacore.com>
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 | 117 ++++++++++++++++++++++++++------
gcc/testsuite/gcc.target/i386/pr85030.c | 2 +-
gcc/testsuite/gcc.target/i386/pr93027.c | 2 +
6 files changed, 164 insertions(+), 36 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<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..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..95cea31754b 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,62 @@ get_referenced_operands (const char *string, bool *used,
}
}
+/* Combine a previous cummulative result PREVRES with RES.
+ If MATCH_INDEX is nonnegative and OPERANDS is not NULL,
+ check that OP is compatible with the matched operand,
+ under the CN 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 || !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. 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
+ && ((allows_mem && MEM_P (op) && MEM_P (mop)
+ && (!allows_reg || rclass == NO_REGS || GET_MODE (mop) == BLKmode))
+ || (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 and OPERANDS is non-NULL, also check for
+ compatibility with the matched operand.
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 +2231,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 +2241,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 +2260,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 +2286,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 +2312,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 +2337,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;
@@ -2314,6 +2382,15 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
return result;
}
+
+/* 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)
+{
+ return asm_operand_ok_match (op, constraint, constraints, NULL, -1);
+}
\f
/* Given an rtx *P, if it is a sum containing an integer constant term,
return the location (type rtx *) of the pointer to that constant term.
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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-30 23:31 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-30 23:31 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:f4faa1c932f616384ee0de65ad2dc500ea0d19d2
commit f4faa1c932f616384ee0de65ad2dc500ea0d19d2
Author: Alexandre Oliva <oliva@adacore.com>
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<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..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;
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-30 23:05 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-30 23:05 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:1473586da238c0f88ceaa6df2f445b64f2b4f3be
commit 1473586da238c0f88ceaa6df2f445b64f2b4f3be
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 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<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 e5b85f0db0e..63d8aaf72c5 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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;
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-29 0:23 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-29 0:23 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:11569a639bff6ff9b99304130edd6bd1ff978c69
commit 11569a639bff6ff9b99304130edd6bd1ff978c69
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 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<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 e5b85f0db0e..3212fd5d757 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 ("" : "+gX" (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 (""),
+ "=gX", 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));
+
+ 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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;
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-29 0:17 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-29 0:17 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:04d93b9662633fb0c9ffb4a5ab23996e07a0f71c
commit 04d93b9662633fb0c9ffb4a5ab23996e07a0f71c
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 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 | 82 +++++++++++++++++++++++++++++++++------
4 files changed, 134 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<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 e5b85f0db0e..3212fd5d757 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 ("" : "+gX" (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 (""),
+ "=gX", 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));
+
+ 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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..7dc35075551 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,58 @@ 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))
+ /* ??? 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))
+ || !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 +2227,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 +2254,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 +2280,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 +2309,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 +2327,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;
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-28 23:35 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-28 23:35 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:edead8ef9eaeb3048425bb6ba653e850772040d8
commit edead8ef9eaeb3048425bb6ba653e850772040d8
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 +-------
gcc/internal-fn.c | 52 +++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++
gcc/recog.c | 81 +++++++++++++++++++++++++++++++++------
4 files changed, 127 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<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 e5b85f0db0e..67641d39607 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,58 @@ 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 ("" : "+X" (temp));
+
+ 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 (""),
+ "=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", 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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..a59adfd6c0c 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,57 @@ 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))
+ /* ??? 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))
+ /* Use the mode of the output operand, since the input might be an
+ immediate. */
+ || !general_operand (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 +2226,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 +2253,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 +2279,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 +2308,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 +2326,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;
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-28 23:29 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-28 23:29 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:05e13cd55e74629caf3f30bb6a5387237e70cb45
commit 05e13cd55e74629caf3f30bb6a5387237e70cb45
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 +-------
gcc/internal-fn.c | 52 +++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++
gcc/recog.c | 81 +++++++++++++++++++++++++++++++++------
4 files changed, 127 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<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 e5b85f0db0e..67641d39607 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,58 @@ 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 ("" : "+X" (temp));
+
+ 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 (""),
+ "=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", 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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..725af42c50d 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,57 @@ 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))
+ /* ??? 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))
+ /* Use the mode of the output operand, since the input might be an
+ immediate. */
+ || !general_operand (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 +2226,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 +2253,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 +2279,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 +2308,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 +2326,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;
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-26 21:39 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-26 21:39 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:34c4acc1f57f56ae869d5354a0ac65a9f94fcbf7
commit 34c4acc1f57f56ae869d5354a0ac65a9f94fcbf7
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 ++--------------
gcc/internal-fn.c | 43 +++++++++++++++++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++++
3 files changed, 49 insertions(+), 15 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<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 e5b85f0db0e..4d2cf43e8f1 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,49 @@ 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);
+
+ rtx body = gen_rtx_ASM_OPERANDS (mode,
+ ggc_strdup (""),
+ "=X,r", 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-26 20:27 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-26 20:27 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:1961e929418bdf420bab9858e4b66be38598d300
commit 1961e929418bdf420bab9858e4b66be38598d300
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 ++--------------
gcc/internal-fn.c | 43 +++++++++++++++++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++++
3 files changed, 49 insertions(+), 15 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<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 e5b85f0db0e..d7ff0d93979 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,49 @@ 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);
+
+ rtx body = gen_rtx_ASM_OPERANDS (mode,
+ ggc_strdup (""),
+ "=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", 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-20 14:50 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-20 14:50 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:8446dc753a99b4f69e04eab136a2a836a59c8c70
commit 8446dc753a99b4f69e04eab136a2a836a59c8c70
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 ++-------------
gcc/internal-fn.c | 44 +++++++++++++++++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++++
3 files changed, 50 insertions(+), 15 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<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 e5b85f0db0e..db271921e1a 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,50 @@ 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);
+
+ rtx body = gen_rtx_ASM_OPERANDS (mode,
+ ggc_strdup (""),
+ "", 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,m", locus);
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = "=r,m";
+ 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-20 10:21 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-20 10:21 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:55a88503a8805a951fca74fdc91059bd6db5e0d1
commit 55a88503a8805a951fca74fdc91059bd6db5e0d1
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 ++-------------
gcc/internal-fn.c | 44 +++++++++++++++++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++++
3 files changed, 50 insertions(+), 15 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<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 e5b85f0db0e..503a81f3b06 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,50 @@ 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);
+
+ rtx body = gen_rtx_ASM_OPERANDS (mode,
+ ggc_strdup (""),
+ "", 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);
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = "=g";
+ 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-20 9:52 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-20 9:52 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:fb9654708bf23afa4300224c6e74bf771e06933d
commit fb9654708bf23afa4300224c6e74bf771e06933d
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 ++-------------
gcc/internal-fn.c | 44 +++++++++++++++++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++++
3 files changed, 50 insertions(+), 15 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<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 e5b85f0db0e..ff1e4413369 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,50 @@ 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);
+
+ rtx body = gen_rtx_ASM_OPERANDS (mode,
+ ggc_strdup (""),
+ "", 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);
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = "=^X,g";
+ 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function
@ 2021-11-20 9:11 Alexandre Oliva
0 siblings, 0 replies; 17+ messages in thread
From: Alexandre Oliva @ 2021-11-20 9:11 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:0b724fb1c201b0864bae2e27f8f845064e7209c2
commit 0b724fb1c201b0864bae2e27f8f845064e7209c2
Author: Alexandre Oliva <oliva@adacore.com>
Date: Sat Nov 20 06:10:25 2021 -0300
introduce asmnesia internal function
Diff:
---
gcc/gimple-harden-conditionals.cc | 17 ++-------------
gcc/internal-fn.c | 44 +++++++++++++++++++++++++++++++++++++++
gcc/internal-fn.def | 4 ++++
3 files changed, 50 insertions(+), 15 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<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 e5b85f0db0e..6bf6630037b 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -3234,6 +3234,50 @@ 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);
+
+ rtx body = gen_rtx_ASM_OPERANDS (mode,
+ ggc_strdup (""),
+ "", 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);
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = "=X";
+ 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 bb4d8ab8096..4fcb84231fd 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -406,6 +406,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)
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2021-12-01 23:57 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-29 0:03 [gcc(refs/users/aoliva/heads/testme)] introduce asmnesia internal function Alexandre Oliva
-- strict thread matches above, loose matches on Subject: below --
2021-12-01 23:57 Alexandre Oliva
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-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
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).