From: Richard Biener <rguenther@suse.de>
To: Jakub Jelinek <jakub@redhat.com>
Cc: Jason Merrill <jason@redhat.com>, Jan Hubicka <jh@suse.cz>,
gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] middle-end, v4: IFN_ASSUME support [PR106654]
Date: Tue, 18 Oct 2022 07:00:41 +0000 (UTC) [thread overview]
Message-ID: <nycvar.YFH.7.77.849.2210180700290.18337@jbgna.fhfr.qr> (raw)
In-Reply-To: <Y014Rs9LF2AT3Dow@tucnak>
On Mon, 17 Oct 2022, Jakub Jelinek wrote:
> Hi!
>
> On Mon, Oct 17, 2022 at 06:55:40AM +0000, Richard Biener wrote:
> > > That is what I wrote in the patch description as alternative:
> > > "with the condition wrapped into a GIMPLE_BIND (I admit the above isn't
> > > extra clean but it is just something to hold it from gimplifier until
> > > gimple low pass; it reassembles if (condition_never_true) { cond; };
> > > an alternative would be introduce GOMP_ASSUME statement that would have
> > > the guard var as operand and the GIMPLE_BIND as body, but for the
> > > few passes (tree-nested and omp lowering) in between that looked like
> > > an overkill to me)"
> > > I can certainly implement that easily.
> >
> > I'd prefer that, it looks possibly less messy.
>
> Ok, introduced GIMPLE_ASSUME for this then.
>
> > Ah, they are all in all_passes :/ Maybe we can add something
> > like TODO_discard_function (or a property) that will not discard
> > the function but stop compiling it? I wonder if all cleanup
> > is properly done for the function - I suppose we want to keep the
> > body around for callers indefinitely.
> >
> > > What I had in the patch was just skip pass_expand
> > > and pass_rest_of_compilation, perhaps another possibility
> > > to do the former would be to define a gate on pass_expand.
> >
> > Or some gate in the pass manager, like in override_gate_status
> > check fun->properties & PROP_suspended and have some
> > pass_suspend_assume add that property for all assume function
> > bodies.
> >
> > In case you like any of the above give it a shot, otherwise what
> > you have isn't too bad, I just wondered if there's a nicer way.
>
> Turns out we already had TODO_discard_function, so I've reused it
> with the detail that assume function's bodies aren't actually dropped,
> and a new pass which returns that and where I'd like to have the
> backwards range walk implemented.
>
> > I suppose for now adding noipa is easiest, we'd still inline into
> > the body of course.
>
> Ok, done.
>
> On Fri, Oct 14, 2022 at 11:27:07AM +0000, Richard Biener wrote:
> > > @@ -237,6 +244,383 @@ lower_omp_directive (gimple_stmt_iterato
> > > gsi_next (gsi);
> > > }
> >
> > comment missing
>
> Added.
>
> > > +static tree
> > > +create_assumption_fn (location_t loc)
> > > +{
> > > + tree name = clone_function_name_numbered (current_function_decl, "_assume");
> > > + /* For now, will be changed later. */
> >
> > ?
>
> I've tried error_mark_node as the type, but that didn't work out, get
> various ICEs with it even for the short time before it is fixed up.
> But changed that to
> tree type = build_varargs_function_type_list (boolean_type_node, NULL_TREE);
> which is closer to what it ends up later.
>
> > > + DECL_FUNCTION_VERSIONED (decl)
> > > + = DECL_FUNCTION_VERSIONED (current_function_decl);
> >
> > what does it mean to copy DECL_FUNCTION_VERSIONED here?
>
> Dropped.
>
> > > + && !is_gimple_val (vargs[i - sz]))
> >
> > a few comments might be helpful here
>
> Added some to various places in that function.
> > > @@ -1490,7 +1494,14 @@ public:
> > >
> > > /* opt_pass methods: */
> > > opt_pass * clone () final override { return new pass_slp_vectorize (m_ctxt); }
> > > - bool gate (function *) final override { return flag_tree_slp_vectorize != 0; }
> > > + bool gate (function *fun) final override
> > > + {
> > > + /* Vectorization makes range analysis of assume functions harder,
> > > + not easier. */
> >
> > Can we split out these kind of considerations from the initial patch?
>
> Dropped for now.
>
> > Reading some of the patch I guessed you wanted to handle nested
> > assumes. So - is
> >
> > [[assume (a == 4 && ([[assume(b == 3)]], b != 2))]]
> >
> > a thing?
>
> Added 2 tests for nested assumptions (one with a simple assumption
> nested in complex one, one with side-effects one nested in complex one).
>
> So far lightly tested, will test fully overnight.
Looks good to me now.
Thanks,
Richard.
> 2022-10-17 Jakub Jelinek <jakub@redhat.com>
>
> PR c++/106654
> gcc/
> * gimple.def (GIMPLE_ASSUME): New statement kind.
> * gimple.h (struct gimple_statement_assume): New type.
> (is_a_helper <gimple_statement_assume *>::test,
> is_a_helper <const gimple_statement_assume *>::test): New.
> (gimple_build_assume): Declare.
> (gimple_has_substatements): Return true for GIMPLE_ASSUME.
> (gimple_assume_guard, gimple_assume_set_guard,
> gimple_assume_guard_ptr, gimple_assume_body_ptr, gimple_assume_body):
> New inline functions.
> * gsstruct.def (GSS_ASSUME): New.
> * gimple.cc (gimple_build_assume): New function.
> (gimple_copy): Handle GIMPLE_ASSUME.
> * gimple-pretty-print.cc (dump_gimple_assume): New function.
> (pp_gimple_stmt_1): Handle GIMPLE_ASSUME.
> * gimple-walk.cc (walk_gimple_op): Handle GIMPLE_ASSUME.
> * omp-low.cc (WALK_SUBSTMTS): Likewise.
> (lower_omp_1): Likewise.
> * omp-oacc-kernels-decompose.cc (adjust_region_code_walk_stmt_fn):
> Likewise.
> * tree-cfg.cc (verify_gimple_stmt, verify_gimple_in_seq_2): Likewise.
> * function.h (struct function): Add assume_function bitfield.
> * gimplify.cc (gimplify_call_expr): If the assumption isn't
> simple enough, expand it into GIMPLE_ASSUME wrapped block or
> for -O0 drop it.
> * gimple-low.cc: Include attribs.h.
> (create_assumption_fn): New function.
> (struct lower_assumption_data): New type.
> (find_assumption_locals_r, assumption_copy_decl,
> adjust_assumption_stmt_r, adjust_assumption_stmt_op,
> lower_assumption): New functions.
> (lower_stmt): Handle GIMPLE_ASSUME.
> * tree-ssa-ccp.cc (pass_fold_builtins::execute): Remove
> IFN_ASSUME calls.
> * lto-streamer-out.cc (output_struct_function_base): Pack
> assume_function bit.
> * lto-streamer-in.cc (input_struct_function_base): And unpack it.
> * cgraphunit.cc (cgraph_node::expand): Don't verify assume_function
> has TREE_ASM_WRITTEN set and don't release its body.
> (symbol_table::compile): Allow assume functions not to have released
> body.
> * internal-fn.cc (expand_ASSUME): Remove gcc_unreachable.
> * passes.cc (execute_one_pass): For TODO_discard_function don't
> release body of assume functions.
> * cgraph.cc (cgraph_node::verify_node): Don't verify cgraph nodes
> of PROP_assumptions_done functions.
> * tree-pass.h (PROP_assumptions_done): Define.
> (TODO_discard_function): Adjust comment.
> (make_pass_assumptions): Declare.
> * passes.def (pass_assumptions): Add.
> * tree-vrp.cc (pass_data_assumptions): New variable.
> (pass_assumptions): New class.
> (make_pass_assumptions): New function.
> gcc/cp/
> * cp-tree.h (build_assume_call): Declare.
> * parser.cc (cp_parser_omp_assumption_clauses): Use build_assume_call.
> * cp-gimplify.cc (build_assume_call): New function.
> (process_stmt_assume_attribute): Use build_assume_call.
> * pt.cc (tsubst_copy_and_build): Likewise.
> gcc/testsuite/
> * g++.dg/cpp23/attr-assume5.C: New test.
> * g++.dg/cpp23/attr-assume6.C: New test.
> * g++.dg/cpp23/attr-assume7.C: New test.
>
> --- gcc/gimple.def.jj 2022-05-30 14:07:01.989306541 +0200
> +++ gcc/gimple.def 2022-10-17 12:47:55.323049825 +0200
> @@ -406,3 +406,8 @@ DEFGSCODE(GIMPLE_PREDICT, "gimple_predic
>
> This tuple should not exist outside of the gimplifier proper. */
> DEFGSCODE(GIMPLE_WITH_CLEANUP_EXPR, "gimple_with_cleanup_expr", GSS_WCE)
> +
> +/* GIMPLE_ASSUME <GUARD, BODY> represents [[assume(cond)]].
> + BODY is the GIMPLE_BIND with the condition which sets GUARD to true
> + (otherwise UB). */
> +DEFGSCODE(GIMPLE_ASSUME, "gimple_assume", GSS_ASSUME)
> --- gcc/gimple.h.jj 2022-09-06 09:19:14.718561564 +0200
> +++ gcc/gimple.h 2022-10-17 14:11:16.142167827 +0200
> @@ -825,6 +825,20 @@ struct GTY((tag("GSS_OMP_ATOMIC_STORE_LA
> stmt->code == GIMPLE_OMP_RETURN. */
> };
>
> +/* Assumptions. */
> +
> +struct GTY((tag("GSS_ASSUME")))
> + gimple_statement_assume : public gimple
> +{
> + /* [ WORD 1-6 ] : base class */
> +
> + /* [ WORD 7 ] */
> + tree guard;
> +
> + /* [ WORD 8 ] */
> + gimple_seq body;
> +};
> +
> /* GIMPLE_TRANSACTION. */
>
> /* Bits to be stored in the GIMPLE_TRANSACTION subcode. */
> @@ -1271,6 +1285,14 @@ is_a_helper <const gswitch *>::test (con
> template <>
> template <>
> inline bool
> +is_a_helper <gimple_statement_assume *>::test (gimple *gs)
> +{
> + return gs->code == GIMPLE_ASSUME;
> +}
> +
> +template <>
> +template <>
> +inline bool
> is_a_helper <gtransaction *>::test (gimple *gs)
> {
> return gs->code == GIMPLE_TRANSACTION;
> @@ -1497,6 +1519,14 @@ is_a_helper <const greturn *>::test (con
> template <>
> template <>
> inline bool
> +is_a_helper <const gimple_statement_assume *>::test (const gimple *gs)
> +{
> + return gs->code == GIMPLE_ASSUME;
> +}
> +
> +template <>
> +template <>
> +inline bool
> is_a_helper <const gtransaction *>::test (const gimple *gs)
> {
> return gs->code == GIMPLE_TRANSACTION;
> @@ -1577,6 +1607,7 @@ gomp_teams *gimple_build_omp_teams (gimp
> gomp_atomic_load *gimple_build_omp_atomic_load (tree, tree,
> enum omp_memory_order);
> gomp_atomic_store *gimple_build_omp_atomic_store (tree, enum omp_memory_order);
> +gimple *gimple_build_assume (tree, gimple_seq);
> gtransaction *gimple_build_transaction (gimple_seq);
> extern void gimple_seq_add_stmt (gimple_seq *, gimple *);
> extern void gimple_seq_add_stmt_without_update (gimple_seq *, gimple *);
> @@ -1835,6 +1866,7 @@ gimple_has_substatements (gimple *g)
> {
> switch (gimple_code (g))
> {
> + case GIMPLE_ASSUME:
> case GIMPLE_BIND:
> case GIMPLE_CATCH:
> case GIMPLE_EH_FILTER:
> @@ -6520,6 +6552,52 @@ gimple_omp_continue_set_control_use (gom
> cont_stmt->control_use = use;
> }
>
> +/* Return the guard associated with the GIMPLE_ASSUME statement GS. */
> +
> +static inline tree
> +gimple_assume_guard (const gimple *gs)
> +{
> + const gimple_statement_assume *assume_stmt
> + = as_a <const gimple_statement_assume *> (gs);
> + return assume_stmt->guard;
> +}
> +
> +/* Set the guard associated with the GIMPLE_ASSUME statement GS. */
> +
> +static inline void
> +gimple_assume_set_guard (gimple *gs, tree guard)
> +{
> + gimple_statement_assume *assume_stmt = as_a <gimple_statement_assume *> (gs);
> + assume_stmt->guard = guard;
> +}
> +
> +static inline tree *
> +gimple_assume_guard_ptr (gimple *gs)
> +{
> + gimple_statement_assume *assume_stmt = as_a <gimple_statement_assume *> (gs);
> + return &assume_stmt->guard;
> +}
> +
> +/* Return the address of the GIMPLE sequence contained in the GIMPLE_ASSUME
> + statement GS. */
> +
> +static inline gimple_seq *
> +gimple_assume_body_ptr (gimple *gs)
> +{
> + gimple_statement_assume *assume_stmt = as_a <gimple_statement_assume *> (gs);
> + return &assume_stmt->body;
> +}
> +
> +/* Return the GIMPLE sequence contained in the GIMPLE_ASSUME statement GS. */
> +
> +static inline gimple_seq
> +gimple_assume_body (const gimple *gs)
> +{
> + const gimple_statement_assume *assume_stmt
> + = as_a <const gimple_statement_assume *> (gs);
> + return assume_stmt->body;
> +}
> +
> /* Return a pointer to the body for the GIMPLE_TRANSACTION statement
> TRANSACTION_STMT. */
>
> --- gcc/gsstruct.def.jj 2022-05-30 14:07:02.054305846 +0200
> +++ gcc/gsstruct.def 2022-10-17 14:12:35.775087795 +0200
> @@ -50,4 +50,5 @@ DEFGSSTRUCT(GSS_OMP_SINGLE_LAYOUT, gimpl
> DEFGSSTRUCT(GSS_OMP_CONTINUE, gomp_continue, false)
> DEFGSSTRUCT(GSS_OMP_ATOMIC_LOAD, gomp_atomic_load, false)
> DEFGSSTRUCT(GSS_OMP_ATOMIC_STORE_LAYOUT, gomp_atomic_store, false)
> +DEFGSSTRUCT(GSS_ASSUME, gimple_statement_assume, false)
> DEFGSSTRUCT(GSS_TRANSACTION, gtransaction, false)
> --- gcc/gimple.cc.jj 2022-09-08 20:22:07.765184796 +0200
> +++ gcc/gimple.cc 2022-10-17 14:13:06.372672818 +0200
> @@ -1290,6 +1290,18 @@ gimple_build_omp_atomic_store (tree val,
> return p;
> }
>
> +/* Build a GIMPLE_ASSUME statement. */
> +
> +gimple *
> +gimple_build_assume (tree guard, gimple_seq body)
> +{
> + gimple_statement_assume *p
> + = as_a <gimple_statement_assume *> (gimple_alloc (GIMPLE_ASSUME, 0));
> + gimple_assume_set_guard (p, guard);
> + *gimple_assume_body_ptr (p) = body;
> + return p;
> +}
> +
> /* Build a GIMPLE_TRANSACTION statement. */
>
> gtransaction *
> @@ -2135,6 +2147,13 @@ gimple_copy (gimple *stmt)
> gimple_omp_masked_set_clauses (copy, t);
> goto copy_omp_body;
>
> + case GIMPLE_ASSUME:
> + new_seq = gimple_seq_copy (gimple_assume_body (stmt));
> + *gimple_assume_body_ptr (copy) = new_seq;
> + gimple_assume_set_guard (copy,
> + unshare_expr (gimple_assume_guard (stmt)));
> + break;
> +
> case GIMPLE_TRANSACTION:
> new_seq = gimple_seq_copy (gimple_transaction_body (
> as_a <gtransaction *> (stmt)));
> --- gcc/gimple-pretty-print.cc.jj 2022-09-29 09:13:31.256642073 +0200
> +++ gcc/gimple-pretty-print.cc 2022-10-17 14:14:37.488437047 +0200
> @@ -2052,6 +2052,31 @@ dump_gimple_omp_return (pretty_printer *
> }
> }
>
> +/* Dump a GIMPLE_ASSUME tuple on the pretty_printer BUFFER. */
> +
> +static void
> +dump_gimple_assume (pretty_printer *buffer, const gimple *gs,
> + int spc, dump_flags_t flags)
> +{
> + if (flags & TDF_RAW)
> + dump_gimple_fmt (buffer, spc, flags,
> + "%G [GUARD=%T] <%+BODY <%S> >",
> + gs, gimple_assume_guard (gs),
> + gimple_assume_body (gs));
> + else
> + {
> + pp_string (buffer, "[[assume (");
> + dump_generic_node (buffer, gimple_assume_guard (gs), spc, flags, false);
> + pp_string (buffer, ")]]");
> + newline_and_indent (buffer, spc + 2);
> + pp_left_brace (buffer);
> + pp_newline (buffer);
> + dump_gimple_seq (buffer, gimple_assume_body (gs), spc + 4, flags);
> + newline_and_indent (buffer, spc + 2);
> + pp_right_brace (buffer);
> + }
> +}
> +
> /* Dump a GIMPLE_TRANSACTION tuple on the pretty_printer BUFFER. */
>
> static void
> @@ -2841,6 +2866,10 @@ pp_gimple_stmt_1 (pretty_printer *buffer
> pp_string (buffer, " predictor.");
> break;
>
> + case GIMPLE_ASSUME:
> + dump_gimple_assume (buffer, gs, spc, flags);
> + break;
> +
> case GIMPLE_TRANSACTION:
> dump_gimple_transaction (buffer, as_a <const gtransaction *> (gs), spc,
> flags);
> --- gcc/gimple-walk.cc.jj 2022-05-30 14:07:01.936307108 +0200
> +++ gcc/gimple-walk.cc 2022-10-17 13:43:10.796032556 +0200
> @@ -485,6 +485,12 @@ walk_gimple_op (gimple *stmt, walk_tree_
> }
> break;
>
> + case GIMPLE_ASSUME:
> + ret = walk_tree (gimple_assume_guard_ptr (stmt), callback_op, wi, pset);
> + if (ret)
> + return ret;
> + break;
> +
> case GIMPLE_TRANSACTION:
> {
> gtransaction *txn = as_a <gtransaction *> (stmt);
> @@ -706,6 +712,13 @@ walk_gimple_stmt (gimple_stmt_iterator *
> if (ret)
> return wi->callback_result;
> break;
> +
> + case GIMPLE_ASSUME:
> + ret = walk_gimple_seq_mod (gimple_assume_body_ptr (stmt),
> + callback_stmt, callback_op, wi);
> + if (ret)
> + return wi->callback_result;
> + break;
>
> case GIMPLE_TRANSACTION:
> ret = walk_gimple_seq_mod (gimple_transaction_body_ptr (
> --- gcc/omp-low.cc.jj 2022-09-26 18:47:27.056348383 +0200
> +++ gcc/omp-low.cc 2022-10-17 13:45:48.271895674 +0200
> @@ -202,6 +202,7 @@ static bool omp_maybe_offloaded_ctx (omp
> case GIMPLE_TRY: \
> case GIMPLE_CATCH: \
> case GIMPLE_EH_FILTER: \
> + case GIMPLE_ASSUME: \
> case GIMPLE_TRANSACTION: \
> /* The sub-statements for these should be walked. */ \
> *handled_ops_p = false; \
> @@ -14413,6 +14414,9 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
> lower_omp (gimple_try_eval_ptr (stmt), ctx);
> lower_omp (gimple_try_cleanup_ptr (stmt), ctx);
> break;
> + case GIMPLE_ASSUME:
> + lower_omp (gimple_assume_body_ptr (stmt), ctx);
> + break;
> case GIMPLE_TRANSACTION:
> lower_omp (gimple_transaction_body_ptr (as_a <gtransaction *> (stmt)),
> ctx);
> --- gcc/omp-oacc-kernels-decompose.cc.jj 2022-06-28 13:03:30.951689423 +0200
> +++ gcc/omp-oacc-kernels-decompose.cc 2022-10-17 13:47:10.470780243 +0200
> @@ -189,6 +189,7 @@ adjust_region_code_walk_stmt_fn (gimple_
> case GIMPLE_GOTO:
> case GIMPLE_SWITCH:
> case GIMPLE_ASM:
> + case GIMPLE_ASSUME:
> case GIMPLE_TRANSACTION:
> case GIMPLE_RETURN:
> /* Statement that might constitute some looping/control flow pattern. */
> --- gcc/tree-cfg.cc.jj 2022-10-17 13:48:32.782663305 +0200
> +++ gcc/tree-cfg.cc 2022-10-17 14:38:37.473858786 +0200
> @@ -5139,6 +5139,9 @@ verify_gimple_stmt (gimple *stmt)
> how to setup the parallel iteration. */
> return false;
>
> + case GIMPLE_ASSUME:
> + return false;
> +
> case GIMPLE_DEBUG:
> return verify_gimple_debug (stmt);
>
> @@ -5252,6 +5255,10 @@ verify_gimple_in_seq_2 (gimple_seq stmts
> as_a <gcatch *> (stmt)));
> break;
>
> + case GIMPLE_ASSUME:
> + err |= verify_gimple_in_seq_2 (gimple_assume_body (stmt));
> + break;
> +
> case GIMPLE_TRANSACTION:
> err |= verify_gimple_transaction (as_a <gtransaction *> (stmt));
> break;
> --- gcc/function.h.jj 2022-10-13 08:40:38.046532404 +0200
> +++ gcc/function.h 2022-10-17 12:40:45.574886412 +0200
> @@ -438,6 +438,10 @@ struct GTY(()) function {
>
> /* Set if there are any OMP_TARGET regions in the function. */
> unsigned int has_omp_target : 1;
> +
> + /* Set for artificial function created for [[assume (cond)]].
> + These should be GIMPLE optimized, but not expanded to RTL. */
> + unsigned int assume_function : 1;
> };
>
> /* Add the decl D to the local_decls list of FUN. */
> --- gcc/gimplify.cc.jj 2022-10-13 08:40:38.169530712 +0200
> +++ gcc/gimplify.cc 2022-10-17 14:15:05.616055561 +0200
> @@ -3569,7 +3569,33 @@ gimplify_call_expr (tree *expr_p, gimple
> fndecl, 0));
> return GS_OK;
> }
> - /* FIXME: Otherwise expand it specially. */
> + /* If not optimizing, ignore the assumptions. */
> + if (!optimize)
> + {
> + *expr_p = NULL_TREE;
> + return GS_ALL_DONE;
> + }
> + /* Temporarily, until gimple lowering, transform
> + .ASSUME (cond);
> + into:
> + [[assume (guard)]]
> + {
> + guard = cond;
> + }
> + such that gimple lowering can outline the condition into
> + a separate function easily. */
> + tree guard = create_tmp_var (boolean_type_node);
> + *expr_p = build2 (MODIFY_EXPR, void_type_node, guard,
> + CALL_EXPR_ARG (*expr_p, 0));
> + *expr_p = build3 (BIND_EXPR, void_type_node, NULL, *expr_p, NULL);
> + push_gimplify_context ();
> + gimple_seq body = NULL;
> + gimple *g = gimplify_and_return_first (*expr_p, &body);
> + pop_gimplify_context (g);
> + g = gimple_build_assume (guard, body);
> + gimple_set_location (g, loc);
> + gimplify_seq_add_stmt (pre_p, g);
> + *expr_p = NULL_TREE;
> return GS_ALL_DONE;
> }
>
> --- gcc/gimple-low.cc.jj 2022-10-13 08:40:38.091531785 +0200
> +++ gcc/gimple-low.cc 2022-10-17 16:17:42.154113603 +0200
> @@ -33,6 +33,14 @@ along with GCC; see the file COPYING3.
> #include "predict.h"
> #include "gimple-predict.h"
> #include "gimple-fold.h"
> +#include "cgraph.h"
> +#include "tree-ssa.h"
> +#include "value-range.h"
> +#include "stringpool.h"
> +#include "tree-ssanames.h"
> +#include "tree-inline.h"
> +#include "gimple-walk.h"
> +#include "attribs.h"
>
> /* The differences between High GIMPLE and Low GIMPLE are the
> following:
> @@ -237,6 +245,389 @@ lower_omp_directive (gimple_stmt_iterato
> gsi_next (gsi);
> }
>
> +/* Create an artificial FUNCTION_DECL for assumption at LOC. */
> +
> +static tree
> +create_assumption_fn (location_t loc)
> +{
> + tree name = clone_function_name_numbered (current_function_decl, "_assume");
> + /* Temporarily, until we determine all the arguments. */
> + tree type = build_varargs_function_type_list (boolean_type_node, NULL_TREE);
> + tree decl = build_decl (loc, FUNCTION_DECL, name, type);
> + TREE_STATIC (decl) = 1;
> + TREE_USED (decl) = 1;
> + DECL_ARTIFICIAL (decl) = 1;
> + DECL_IGNORED_P (decl) = 1;
> + DECL_NAMELESS (decl) = 1;
> + TREE_PUBLIC (decl) = 0;
> + DECL_UNINLINABLE (decl) = 1;
> + DECL_EXTERNAL (decl) = 0;
> + DECL_CONTEXT (decl) = NULL_TREE;
> + DECL_INITIAL (decl) = make_node (BLOCK);
> + tree attributes = DECL_ATTRIBUTES (current_function_decl);
> + if (lookup_attribute ("noipa", attributes) == NULL)
> + {
> + attributes = tree_cons (get_identifier ("noipa"), NULL, attributes);
> + if (lookup_attribute ("noinline", attributes) == NULL)
> + attributes = tree_cons (get_identifier ("noinline"), NULL, attributes);
> + if (lookup_attribute ("noclone", attributes) == NULL)
> + attributes = tree_cons (get_identifier ("noclone"), NULL, attributes);
> + if (lookup_attribute ("no_icf", attributes) == NULL)
> + attributes = tree_cons (get_identifier ("no_icf"), NULL, attributes);
> + }
> + DECL_ATTRIBUTES (decl) = attributes;
> + BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl;
> + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl)
> + = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (current_function_decl);
> + DECL_FUNCTION_SPECIFIC_TARGET (decl)
> + = DECL_FUNCTION_SPECIFIC_TARGET (current_function_decl);
> + tree t = build_decl (DECL_SOURCE_LOCATION (decl),
> + RESULT_DECL, NULL_TREE, boolean_type_node);
> + DECL_ARTIFICIAL (t) = 1;
> + DECL_IGNORED_P (t) = 1;
> + DECL_CONTEXT (t) = decl;
> + DECL_RESULT (decl) = t;
> + push_struct_function (decl);
> + cfun->function_end_locus = loc;
> + init_tree_ssa (cfun);
> + return decl;
> +}
> +
> +struct lower_assumption_data
> +{
> + copy_body_data id;
> + tree return_false_label;
> + tree guard_copy;
> + auto_vec<tree> decls;
> +};
> +
> +/* Helper function for lower_assumptions. Find local vars and labels
> + in the assumption sequence and remove debug stmts. */
> +
> +static tree
> +find_assumption_locals_r (gimple_stmt_iterator *gsi_p, bool *,
> + struct walk_stmt_info *wi)
> +{
> + lower_assumption_data *data = (lower_assumption_data *) wi->info;
> + gimple *stmt = gsi_stmt (*gsi_p);
> + tree lhs = gimple_get_lhs (stmt);
> + if (lhs && TREE_CODE (lhs) == SSA_NAME)
> + {
> + gcc_assert (SSA_NAME_VAR (lhs) == NULL_TREE);
> + data->id.decl_map->put (lhs, NULL_TREE);
> + data->decls.safe_push (lhs);
> + }
> + switch (gimple_code (stmt))
> + {
> + case GIMPLE_BIND:
> + for (tree var = gimple_bind_vars (as_a <gbind *> (stmt));
> + var; var = DECL_CHAIN (var))
> + if (VAR_P (var)
> + && !DECL_EXTERNAL (var)
> + && DECL_CONTEXT (var) == data->id.src_fn)
> + {
> + data->id.decl_map->put (var, var);
> + data->decls.safe_push (var);
> + }
> + break;
> + case GIMPLE_LABEL:
> + {
> + tree label = gimple_label_label (as_a <glabel *> (stmt));
> + data->id.decl_map->put (label, label);
> + break;
> + }
> + case GIMPLE_RETURN:
> + /* If something in assumption tries to return from parent function,
> + if it would be reached in hypothetical evaluation, it would be UB,
> + so transform such returns into return false; */
> + {
> + gimple *g = gimple_build_assign (data->guard_copy, boolean_false_node);
> + gsi_insert_before (gsi_p, g, GSI_SAME_STMT);
> + gimple_return_set_retval (as_a <greturn *> (stmt), data->guard_copy);
> + break;
> + }
> + case GIMPLE_DEBUG:
> + /* As assumptions won't be emitted, debug info stmts in them
> + are useless. */
> + gsi_remove (gsi_p, true);
> + wi->removed_stmt = true;
> + break;
> + default:
> + break;
> + }
> + return NULL_TREE;
> +}
> +
> +/* Create a new PARM_DECL that is indentical in all respect to DECL except that
> + DECL can be either a VAR_DECL, a PARM_DECL or RESULT_DECL. The original
> + DECL must come from ID->src_fn and the copy will be part of ID->dst_fn. */
> +
> +static tree
> +assumption_copy_decl (tree decl, copy_body_data *id)
> +{
> + tree type = TREE_TYPE (decl);
> +
> + if (is_global_var (decl))
> + return decl;
> +
> + gcc_assert (VAR_P (decl)
> + || TREE_CODE (decl) == PARM_DECL
> + || TREE_CODE (decl) == RESULT_DECL);
> + tree copy = build_decl (DECL_SOURCE_LOCATION (decl),
> + PARM_DECL, DECL_NAME (decl), type);
> + if (DECL_PT_UID_SET_P (decl))
> + SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
> + TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
> + TREE_READONLY (copy) = TREE_READONLY (decl);
> + TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
> + DECL_NOT_GIMPLE_REG_P (copy) = DECL_NOT_GIMPLE_REG_P (decl);
> + DECL_BY_REFERENCE (copy) = DECL_BY_REFERENCE (decl);
> + DECL_ARG_TYPE (copy) = type;
> + ((lower_assumption_data *) id)->decls.safe_push (decl);
> + return copy_decl_for_dup_finish (id, decl, copy);
> +}
> +
> +/* Transform gotos out of the assumption into return false. */
> +
> +static tree
> +adjust_assumption_stmt_r (gimple_stmt_iterator *gsi_p, bool *,
> + struct walk_stmt_info *wi)
> +{
> + lower_assumption_data *data = (lower_assumption_data *) wi->info;
> + gimple *stmt = gsi_stmt (*gsi_p);
> + tree lab = NULL_TREE;
> + unsigned int idx = 0;
> + if (gimple_code (stmt) == GIMPLE_GOTO)
> + lab = gimple_goto_dest (stmt);
> + else if (gimple_code (stmt) == GIMPLE_COND)
> + {
> + repeat:
> + if (idx == 0)
> + lab = gimple_cond_true_label (as_a <gcond *> (stmt));
> + else
> + lab = gimple_cond_false_label (as_a <gcond *> (stmt));
> + }
> + else if (gimple_code (stmt) == GIMPLE_LABEL)
> + {
> + tree label = gimple_label_label (as_a <glabel *> (stmt));
> + DECL_CONTEXT (label) = current_function_decl;
> + }
> + if (lab)
> + {
> + if (!data->id.decl_map->get (lab))
> + {
> + if (!data->return_false_label)
> + data->return_false_label
> + = create_artificial_label (UNKNOWN_LOCATION);
> + if (gimple_code (stmt) == GIMPLE_GOTO)
> + gimple_goto_set_dest (as_a <ggoto *> (stmt),
> + data->return_false_label);
> + else if (idx == 0)
> + gimple_cond_set_true_label (as_a <gcond *> (stmt),
> + data->return_false_label);
> + else
> + gimple_cond_set_false_label (as_a <gcond *> (stmt),
> + data->return_false_label);
> + }
> + if (gimple_code (stmt) == GIMPLE_COND && idx == 0)
> + {
> + idx = 1;
> + goto repeat;
> + }
> + }
> + return NULL_TREE;
> +}
> +
> +/* Adjust trees in the assumption body. Called through walk_tree. */
> +
> +static tree
> +adjust_assumption_stmt_op (tree *tp, int *, void *datap)
> +{
> + struct walk_stmt_info *wi = (struct walk_stmt_info *) datap;
> + lower_assumption_data *data = (lower_assumption_data *) wi->info;
> + tree t = *tp;
> + tree *newt;
> + switch (TREE_CODE (t))
> + {
> + case SSA_NAME:
> + newt = data->id.decl_map->get (t);
> + /* There shouldn't be SSA_NAMEs other than ones defined in the
> + assumption's body. */
> + gcc_assert (newt);
> + *tp = *newt;
> + break;
> + case LABEL_DECL:
> + newt = data->id.decl_map->get (t);
> + if (newt)
> + *tp = *newt;
> + break;
> + case VAR_DECL:
> + case PARM_DECL:
> + case RESULT_DECL:
> + *tp = remap_decl (t, &data->id);
> + break;
> + default:
> + break;
> + }
> + return NULL_TREE;
> +}
> +
> +/* Lower assumption.
> + The gimplifier transformed:
> + .ASSUME (cond);
> + into:
> + [[assume (guard)]]
> + {
> + guard = cond;
> + }
> + which we should transform into:
> + .ASSUME (&artificial_fn, args...);
> + where artificial_fn will look like:
> + bool artificial_fn (args...)
> + {
> + guard = cond;
> + return guard;
> + }
> + with any debug stmts in the block removed and jumps out of
> + the block or return stmts replaced with return false; */
> +
> +static void
> +lower_assumption (gimple_stmt_iterator *gsi, struct lower_data *data)
> +{
> + gimple *stmt = gsi_stmt (*gsi);
> + tree guard = gimple_assume_guard (stmt);
> + gimple *bind = gimple_assume_body (stmt);
> + location_t loc = gimple_location (stmt);
> + gcc_assert (gimple_code (bind) == GIMPLE_BIND);
> +
> + lower_assumption_data lad;
> + hash_map<tree, tree> decl_map;
> + memset (&lad.id, 0, sizeof (lad.id));
> + lad.return_false_label = NULL_TREE;
> + lad.id.src_fn = current_function_decl;
> + lad.id.dst_fn = create_assumption_fn (loc);
> + lad.id.src_cfun = DECL_STRUCT_FUNCTION (lad.id.src_fn);
> + lad.id.decl_map = &decl_map;
> + lad.id.copy_decl = assumption_copy_decl;
> + lad.id.transform_call_graph_edges = CB_CGE_DUPLICATE;
> + lad.id.transform_parameter = true;
> + lad.id.do_not_unshare = true;
> + lad.id.do_not_fold = true;
> + cfun->curr_properties = lad.id.src_cfun->curr_properties;
> + lad.guard_copy = create_tmp_var (boolean_type_node);
> + decl_map.put (lad.guard_copy, lad.guard_copy);
> + decl_map.put (guard, lad.guard_copy);
> + cfun->assume_function = 1;
> +
> + /* Find variables, labels and SSA_NAMEs local to the assume GIMPLE_BIND. */
> + gimple_stmt_iterator gsi2 = gsi_start (*gimple_assume_body_ptr (stmt));
> + struct walk_stmt_info wi;
> + memset (&wi, 0, sizeof (wi));
> + wi.info = (void *) &lad;
> + walk_gimple_stmt (&gsi2, find_assumption_locals_r, NULL, &wi);
> + unsigned int sz = lad.decls.length ();
> + for (unsigned i = 0; i < sz; ++i)
> + {
> + tree v = lad.decls[i];
> + tree newv;
> + /* SSA_NAMEs defined in the assume condition should be replaced
> + by new SSA_NAMEs in the artificial function. */
> + if (TREE_CODE (v) == SSA_NAME)
> + {
> + newv = make_ssa_name (remap_type (TREE_TYPE (v), &lad.id));
> + decl_map.put (v, newv);
> + }
> + /* Local vars should have context and type adjusted to the
> + new artificial function. */
> + else if (VAR_P (v))
> + {
> + if (is_global_var (v) && !DECL_ASSEMBLER_NAME_SET_P (v))
> + DECL_ASSEMBLER_NAME (v);
> + TREE_TYPE (v) = remap_type (TREE_TYPE (v), &lad.id);
> + DECL_CONTEXT (v) = current_function_decl;
> + }
> + }
> + /* References to other automatic vars should be replaced by
> + PARM_DECLs to the artificial function. */
> + memset (&wi, 0, sizeof (wi));
> + wi.info = (void *) &lad;
> + walk_gimple_stmt (&gsi2, adjust_assumption_stmt_r,
> + adjust_assumption_stmt_op, &wi);
> +
> + /* At the start prepend guard = false; */
> + gimple_seq body = NULL;
> + gimple *g = gimple_build_assign (lad.guard_copy, boolean_false_node);
> + gimple_seq_add_stmt (&body, g);
> + gimple_seq_add_stmt (&body, bind);
> + /* At the end add return guard; */
> + greturn *gr = gimple_build_return (lad.guard_copy);
> + gimple_seq_add_stmt (&body, gr);
> + /* If there were any jumps to labels outside of the condition,
> + replace them with a jump to
> + return_false_label:
> + guard = false;
> + return guard; */
> + if (lad.return_false_label)
> + {
> + g = gimple_build_label (lad.return_false_label);
> + gimple_seq_add_stmt (&body, g);
> + g = gimple_build_assign (lad.guard_copy, boolean_false_node);
> + gimple_seq_add_stmt (&body, g);
> + gr = gimple_build_return (lad.guard_copy);
> + gimple_seq_add_stmt (&body, gr);
> + }
> + bind = gimple_build_bind (NULL_TREE, body, NULL_TREE);
> + body = NULL;
> + gimple_seq_add_stmt (&body, bind);
> + gimple_set_body (current_function_decl, body);
> + pop_cfun ();
> +
> + tree parms = NULL_TREE;
> + tree parmt = void_list_node;
> + auto_vec<tree, 8> vargs;
> + vargs.safe_grow (1 + (lad.decls.length () - sz), true);
> + /* First argument to IFN_ASSUME will be address of the
> + artificial function. */
> + vargs[0] = build_fold_addr_expr (lad.id.dst_fn);
> + for (unsigned i = lad.decls.length (); i > sz; --i)
> + {
> + tree *v = decl_map.get (lad.decls[i - 1]);
> + gcc_assert (v && TREE_CODE (*v) == PARM_DECL);
> + DECL_CHAIN (*v) = parms;
> + parms = *v;
> + parmt = tree_cons (NULL_TREE, TREE_TYPE (*v), parmt);
> + /* Remaining arguments will be the variables/parameters
> + mentioned in the condition. */
> + vargs[i - sz] = lad.decls[i - 1];
> + /* If they have gimple types, we might need to regimplify
> + them to make the IFN_ASSUME call valid. */
> + if (is_gimple_reg_type (TREE_TYPE (vargs[i - sz]))
> + && !is_gimple_val (vargs[i - sz]))
> + {
> + tree t = make_ssa_name (TREE_TYPE (vargs[i - sz]));
> + g = gimple_build_assign (t, vargs[i - sz]);
> + gsi_insert_before (gsi, g, GSI_SAME_STMT);
> + vargs[i - sz] = t;
> + }
> + }
> + DECL_ARGUMENTS (lad.id.dst_fn) = parms;
> + TREE_TYPE (lad.id.dst_fn) = build_function_type (boolean_type_node, parmt);
> +
> + cgraph_node::add_new_function (lad.id.dst_fn, false);
> +
> + for (unsigned i = 0; i < sz; ++i)
> + {
> + tree v = lad.decls[i];
> + if (TREE_CODE (v) == SSA_NAME)
> + release_ssa_name (v);
> + }
> +
> + data->cannot_fallthru = false;
> + /* Replace GIMPLE_ASSUME statement with IFN_ASSUME call. */
> + gcall *call = gimple_build_call_internal_vec (IFN_ASSUME, vargs);
> + gimple_set_location (call, loc);
> + gsi_replace (gsi, call, true);
> +}
>
> /* Lower statement GSI. DATA is passed through the recursion. We try to
> track the fallthruness of statements and get rid of unreachable return
> @@ -403,6 +794,10 @@ lower_stmt (gimple_stmt_iterator *gsi, s
> data->cannot_fallthru = false;
> return;
>
> + case GIMPLE_ASSUME:
> + lower_assumption (gsi, data);
> + return;
> +
> case GIMPLE_TRANSACTION:
> lower_sequence (gimple_transaction_body_ptr (
> as_a <gtransaction *> (stmt)),
> --- gcc/tree-ssa-ccp.cc.jj 2022-10-13 08:40:38.478526460 +0200
> +++ gcc/tree-ssa-ccp.cc 2022-10-17 12:40:45.696884755 +0200
> @@ -4253,6 +4253,12 @@ pass_fold_builtins::execute (function *f
> }
>
> callee = gimple_call_fndecl (stmt);
> + if (!callee
> + && gimple_call_internal_p (stmt, IFN_ASSUME))
> + {
> + gsi_remove (&i, true);
> + continue;
> + }
> if (!callee || !fndecl_built_in_p (callee, BUILT_IN_NORMAL))
> {
> gsi_next (&i);
> --- gcc/lto-streamer-out.cc.jj 2022-10-13 08:40:38.373527904 +0200
> +++ gcc/lto-streamer-out.cc 2022-10-17 12:40:45.720884429 +0200
> @@ -2278,6 +2278,7 @@ output_struct_function_base (struct outp
> bp_pack_value (&bp, fn->calls_eh_return, 1);
> bp_pack_value (&bp, fn->has_force_vectorize_loops, 1);
> bp_pack_value (&bp, fn->has_simduid_loops, 1);
> + bp_pack_value (&bp, fn->assume_function, 1);
> bp_pack_value (&bp, fn->va_list_fpr_size, 8);
> bp_pack_value (&bp, fn->va_list_gpr_size, 8);
> bp_pack_value (&bp, fn->last_clique, sizeof (short) * 8);
> --- gcc/lto-streamer-in.cc.jj 2022-10-13 08:40:38.371527932 +0200
> +++ gcc/lto-streamer-in.cc 2022-10-17 12:40:45.741884143 +0200
> @@ -1318,6 +1318,7 @@ input_struct_function_base (struct funct
> fn->calls_eh_return = bp_unpack_value (&bp, 1);
> fn->has_force_vectorize_loops = bp_unpack_value (&bp, 1);
> fn->has_simduid_loops = bp_unpack_value (&bp, 1);
> + fn->assume_function = bp_unpack_value (&bp, 1);
> fn->va_list_fpr_size = bp_unpack_value (&bp, 8);
> fn->va_list_gpr_size = bp_unpack_value (&bp, 8);
> fn->last_clique = bp_unpack_value (&bp, sizeof (short) * 8);
> --- gcc/cgraphunit.cc.jj 2022-10-13 08:40:37.868534853 +0200
> +++ gcc/cgraphunit.cc 2022-10-17 16:45:46.995270327 +0200
> @@ -1882,6 +1882,16 @@ cgraph_node::expand (void)
> ggc_collect ();
> timevar_pop (TV_REST_OF_COMPILATION);
>
> + if (DECL_STRUCT_FUNCTION (decl)
> + && DECL_STRUCT_FUNCTION (decl)->assume_function)
> + {
> + /* Assume functions aren't expanded into RTL, on the other side
> + we don't want to release their body. */
> + if (cfun)
> + pop_cfun ();
> + return;
> + }
> +
> /* Make sure that BE didn't give up on compiling. */
> gcc_assert (TREE_ASM_WRITTEN (decl));
> if (cfun)
> @@ -2373,6 +2383,10 @@ symbol_table::compile (void)
> if (node->inlined_to
> || gimple_has_body_p (node->decl))
> {
> + if (DECL_STRUCT_FUNCTION (node->decl)
> + && (DECL_STRUCT_FUNCTION (node->decl)->curr_properties
> + & PROP_assumptions_done) != 0)
> + continue;
> error_found = true;
> node->debug ();
> }
> --- gcc/internal-fn.cc.jj 2022-10-13 08:40:38.218530037 +0200
> +++ gcc/internal-fn.cc 2022-10-17 12:40:45.782883587 +0200
> @@ -4526,5 +4526,4 @@ expand_TRAP (internal_fn, gcall *)
> void
> expand_ASSUME (internal_fn, gcall *)
> {
> - gcc_unreachable ();
> }
> --- gcc/passes.cc.jj 2022-10-13 08:40:38.419527272 +0200
> +++ gcc/passes.cc 2022-10-17 16:38:23.325283213 +0200
> @@ -2660,6 +2660,15 @@ execute_one_pass (opt_pass *pass)
> if (dom_info_available_p (CDI_POST_DOMINATORS))
> free_dominance_info (CDI_POST_DOMINATORS);
>
> + if (cfun->assume_function)
> + {
> + /* For assume functions, don't release body, keep it around. */
> + cfun->curr_properties |= PROP_assumptions_done;
> + pop_cfun ();
> + current_pass = NULL;
> + return true;
> + }
> +
> tree fn = cfun->decl;
> pop_cfun ();
> gcc_assert (!cfun);
> --- gcc/cgraph.cc.jj 2022-06-27 11:18:02.047066621 +0200
> +++ gcc/cgraph.cc 2022-10-17 16:40:24.319643418 +0200
> @@ -3751,7 +3751,9 @@ cgraph_node::verify_node (void)
> && (!DECL_EXTERNAL (decl) || inlined_to)
> && !flag_wpa)
> {
> - if (this_cfun->cfg)
> + if ((this_cfun->curr_properties & PROP_assumptions_done) != 0)
> + ;
> + else if (this_cfun->cfg)
> {
> hash_set<gimple *> stmts;
>
> --- gcc/tree-pass.h.jj 2022-07-26 10:32:24.020267414 +0200
> +++ gcc/tree-pass.h 2022-10-17 16:36:12.800052172 +0200
> @@ -227,6 +227,8 @@ protected:
> #define PROP_rtl_split_insns (1 << 17) /* RTL has insns split. */
> #define PROP_loop_opts_done (1 << 18) /* SSA loop optimizations
> have completed. */
> +#define PROP_assumptions_done (1 << 19) /* Assume function kept
> + around. */
>
> #define PROP_gimple \
> (PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_lomp)
> @@ -301,7 +303,8 @@ protected:
> /* Rebuild the callgraph edges. */
> #define TODO_rebuild_cgraph_edges (1 << 22)
>
> -/* Release function body and stop pass manager. */
> +/* Release function body (unless assumption function)
> + and stop pass manager. */
> #define TODO_discard_function (1 << 23)
>
> /* Internally used in execute_function_todo(). */
> @@ -465,6 +468,7 @@ extern gimple_opt_pass *make_pass_copy_p
> extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
> +extern gimple_opt_pass *make_pass_assumptions (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);
> extern gimple_opt_pass *make_pass_reassoc (gcc::context *ctxt);
> --- gcc/passes.def.jj 2022-09-23 09:02:56.876313524 +0200
> +++ gcc/passes.def 2022-10-17 16:11:58.526770578 +0200
> @@ -407,6 +407,7 @@ along with GCC; see the file COPYING3.
> and thus it should be run last. */
> NEXT_PASS (pass_uncprop);
> POP_INSERT_PASSES ()
> + NEXT_PASS (pass_assumptions);
> NEXT_PASS (pass_tm_init);
> PUSH_INSERT_PASSES_WITHIN (pass_tm_init)
> NEXT_PASS (pass_tm_mark);
> --- gcc/timevar.def.jj 2022-09-03 09:35:41.334986488 +0200
> +++ gcc/timevar.def 2022-10-17 16:06:57.336852424 +0200
> @@ -226,6 +226,7 @@ DEFTIMEVAR (TV_TREE_WIDEN_MUL , "
> DEFTIMEVAR (TV_TRANS_MEM , "transactional memory")
> DEFTIMEVAR (TV_TREE_STRLEN , "tree strlen optimization")
> DEFTIMEVAR (TV_TREE_MODREF , "tree modref")
> +DEFTIMEVAR (TV_TREE_ASSUMPTIONS , "tree assumptions")
> DEFTIMEVAR (TV_CGRAPH_VERIFY , "callgraph verifier")
> DEFTIMEVAR (TV_DOM_FRONTIERS , "dominance frontiers")
> DEFTIMEVAR (TV_DOMINANCE , "dominance computation")
> --- gcc/tree-inline.cc.jj 2022-10-07 09:08:43.887133549 +0200
> +++ gcc/tree-inline.cc 2022-10-17 13:50:11.755320277 +0200
> @@ -1736,6 +1736,11 @@ remap_gimple_stmt (gimple *stmt, copy_bo
> (as_a <gomp_critical *> (stmt)));
> break;
>
> + case GIMPLE_ASSUME:
> + s1 = remap_gimple_seq (gimple_assume_body (stmt), id);
> + copy = gimple_build_assume (gimple_assume_guard (stmt), s1);
> + break;
> +
> case GIMPLE_TRANSACTION:
> {
> gtransaction *old_trans_stmt = as_a <gtransaction *> (stmt);
> --- gcc/tree-vrp.cc.jj 2022-09-23 09:02:57.099310450 +0200
> +++ gcc/tree-vrp.cc 2022-10-17 16:37:10.623268518 +0200
> @@ -4441,6 +4441,35 @@ public:
> int my_pass;
> }; // class pass_vrp
>
> +const pass_data pass_data_assumptions =
> +{
> + GIMPLE_PASS, /* type */
> + "assumptions", /* name */
> + OPTGROUP_NONE, /* optinfo_flags */
> + TV_TREE_ASSUMPTIONS, /* tv_id */
> + PROP_ssa, /* properties_required */
> + PROP_assumptions_done, /* properties_provided */
> + 0, /* properties_destroyed */
> + 0, /* todo_flags_start */
> + 0, /* todo_flags_end */
> +};
> +
> +class pass_assumptions : public gimple_opt_pass
> +{
> +public:
> + pass_assumptions (gcc::context *ctxt)
> + : gimple_opt_pass (pass_data_assumptions, ctxt)
> + {}
> +
> + /* opt_pass methods: */
> + bool gate (function *fun) final override { return fun->assume_function; }
> + unsigned int execute (function *) final override
> + {
> + return TODO_discard_function;
> + }
> +
> +}; // class pass_assumptions
> +
> } // anon namespace
>
> gimple_opt_pass *
> @@ -4454,3 +4483,9 @@ make_pass_early_vrp (gcc::context *ctxt)
> {
> return new pass_vrp (ctxt, pass_data_early_vrp);
> }
> +
> +gimple_opt_pass *
> +make_pass_assumptions (gcc::context *ctx)
> +{
> + return new pass_assumptions (ctx);
> +}
> --- gcc/cp/cp-tree.h.jj 2022-10-14 09:35:56.201990233 +0200
> +++ gcc/cp/cp-tree.h 2022-10-17 12:40:45.842882772 +0200
> @@ -8280,6 +8280,7 @@ extern tree predeclare_vla (tree);
> extern void clear_fold_cache (void);
> extern tree lookup_hotness_attribute (tree);
> extern tree process_stmt_hotness_attribute (tree, location_t);
> +extern tree build_assume_call (location_t, tree);
> extern tree process_stmt_assume_attribute (tree, tree, location_t);
> extern bool simple_empty_class_p (tree, tree, tree_code);
> extern tree fold_builtin_source_location (location_t);
> --- gcc/cp/parser.cc.jj 2022-10-14 09:28:28.006164065 +0200
> +++ gcc/cp/parser.cc 2022-10-17 12:40:45.897882025 +0200
> @@ -46012,11 +46012,7 @@ cp_parser_omp_assumption_clauses (cp_par
> if (!type_dependent_expression_p (t))
> t = contextual_conv_bool (t, tf_warning_or_error);
> if (is_assume && !error_operand_p (t))
> - {
> - t = build_call_expr_internal_loc (eloc, IFN_ASSUME,
> - void_type_node, 1, t);
> - finish_expr_stmt (t);
> - }
> + finish_expr_stmt (build_assume_call (eloc, t));
> if (!parens.require_close (parser))
> cp_parser_skip_to_closing_parenthesis (parser,
> /*recovering=*/true,
> --- gcc/cp/cp-gimplify.cc.jj 2022-10-14 09:28:28.154162026 +0200
> +++ gcc/cp/cp-gimplify.cc 2022-10-17 12:40:45.931881563 +0200
> @@ -3101,6 +3101,17 @@ process_stmt_hotness_attribute (tree std
> return std_attrs;
> }
>
> +/* Build IFN_ASSUME internal call for assume condition ARG. */
> +
> +tree
> +build_assume_call (location_t loc, tree arg)
> +{
> + if (!processing_template_decl)
> + arg = fold_build_cleanup_point_expr (TREE_TYPE (arg), arg);
> + return build_call_expr_internal_loc (loc, IFN_ASSUME, void_type_node,
> + 1, arg);
> +}
> +
> /* If [[assume (cond)]] appears on this statement, handle it. */
>
> tree
> @@ -3137,9 +3148,7 @@ process_stmt_assume_attribute (tree std_
> arg = contextual_conv_bool (arg, tf_warning_or_error);
> if (error_operand_p (arg))
> continue;
> - statement = build_call_expr_internal_loc (attrs_loc, IFN_ASSUME,
> - void_type_node, 1, arg);
> - finish_expr_stmt (statement);
> + finish_expr_stmt (build_assume_call (attrs_loc, arg));
> }
> }
> return remove_attribute ("gnu", "assume", std_attrs);
> --- gcc/cp/pt.cc.jj 2022-10-14 09:28:28.135162288 +0200
> +++ gcc/cp/pt.cc 2022-10-17 12:40:45.985880829 +0200
> @@ -21140,10 +21140,7 @@ tsubst_copy_and_build (tree t,
> ret = error_mark_node;
> break;
> }
> - ret = build_call_expr_internal_loc (EXPR_LOCATION (t),
> - IFN_ASSUME,
> - void_type_node, 1,
> - arg);
> + ret = build_assume_call (EXPR_LOCATION (t), arg);
> RETURN (ret);
> }
> break;
> --- gcc/testsuite/g++.dg/cpp23/attr-assume5.C.jj 2022-10-17 12:40:45.985880829 +0200
> +++ gcc/testsuite/g++.dg/cpp23/attr-assume5.C 2022-10-17 12:40:45.985880829 +0200
> @@ -0,0 +1,5 @@
> +// P1774R8 - Portable assumptions
> +// { dg-do run { target c++11 } }
> +// { dg-options "-O2" }
> +
> +#include "attr-assume1.C"
> --- gcc/testsuite/g++.dg/cpp23/attr-assume6.C.jj 2022-10-17 12:40:45.986880816 +0200
> +++ gcc/testsuite/g++.dg/cpp23/attr-assume6.C 2022-10-17 12:40:45.986880816 +0200
> @@ -0,0 +1,5 @@
> +// P1774R8 - Portable assumptions
> +// { dg-do run { target c++11 } }
> +// { dg-options "-O2" }
> +
> +#include "attr-assume3.C"
> --- gcc/testsuite/g++.dg/cpp23/attr-assume7.C.jj 2022-10-17 12:40:45.986880816 +0200
> +++ gcc/testsuite/g++.dg/cpp23/attr-assume7.C 2022-10-17 17:39:43.992411442 +0200
> @@ -0,0 +1,56 @@
> +// P1774R8 - Portable assumptions
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-O2" }
> +
> +int
> +foo (int x)
> +{
> + [[assume (x == 42)]];
> + return x;
> +}
> +
> +int
> +bar (int x)
> +{
> + [[assume (++x == 43)]];
> + return x;
> +}
> +
> +int
> +baz (int x)
> +{
> + [[assume (({ int z = ++x; static int w; ++w; if (z == 51) return -1; if (z == 53) goto lab1; if (z == 64) throw 1; z == 43; }))]];
> +lab1:
> + return x;
> +}
> +
> +struct S { S (); S (const S &); ~S (); int a, b; int foo (); };
> +
> +int
> +qux ()
> +{
> + S s;
> + [[assume (s.a == 42 && s.b == 43)]];
> + return s.a + s.b;
> +}
> +
> +int
> +S::foo ()
> +{
> + [[assume (a == 42 && b == 43)]];
> + return a + b;
> +}
> +
> +int
> +corge (int x)
> +{
> + [[assume (({ [[assume (x < 42)]]; x > -42; }))]];
> + return x < 42;
> +}
> +
> +int
> +garply (int x)
> +{
> + [[assume (({ [[assume (++x < 43)]]; x > -42; }))]];
> + return x < 42;
> +}
>
>
> Jakub
>
>
--
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)
next prev parent reply other threads:[~2022-10-18 7:00 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-10 8:54 [PATCH] middle-end " Jakub Jelinek
2022-10-10 21:09 ` Jason Merrill
2022-10-10 21:19 ` Jakub Jelinek
2022-10-11 13:36 ` [PATCH] middle-end, v2: " Jakub Jelinek
2022-10-12 15:48 ` Jason Merrill
2022-10-13 6:50 ` [PATCH] middle-end, v3: " Jakub Jelinek
2022-10-14 11:27 ` Richard Biener
2022-10-14 18:33 ` Jakub Jelinek
2022-10-17 6:55 ` Richard Biener
2022-10-17 15:44 ` [PATCH] middle-end, v4: " Jakub Jelinek
2022-10-18 7:00 ` Richard Biener [this message]
2022-10-18 21:31 ` Andrew MacLeod
2022-10-19 16:06 ` Jakub Jelinek
2022-10-19 16:55 ` Andrew MacLeod
2022-10-19 17:39 ` Jakub Jelinek
2022-10-19 17:41 ` Jakub Jelinek
2022-10-19 18:25 ` Andrew MacLeod
2022-10-19 17:14 ` Andrew MacLeod
2022-10-11 18:05 ` [PATCH] middle-end " Andrew MacLeod
2022-10-12 10:15 ` Jakub Jelinek
2022-10-12 14:31 ` Andrew MacLeod
2022-10-12 14:39 ` Jakub Jelinek
2022-10-12 16:12 ` Andrew MacLeod
2022-10-13 8:11 ` Richard Biener
2022-10-13 9:53 ` Jakub Jelinek
2022-10-13 13:16 ` Andrew MacLeod
2022-10-13 9:57 ` Jakub Jelinek
2022-10-17 17:53 ` Andrew MacLeod
2022-10-14 20:43 ` Martin Uecker
2022-10-14 21:20 ` Jakub Jelinek
2022-10-15 8:07 ` Martin Uecker
2022-10-15 8:53 ` Jakub Jelinek
2022-10-17 5:52 ` Martin Uecker
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=nycvar.YFH.7.77.849.2210180700290.18337@jbgna.fhfr.qr \
--to=rguenther@suse.de \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
--cc=jason@redhat.com \
--cc=jh@suse.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).