From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) by sourceware.org (Postfix) with ESMTPS id 620FF3858D32 for ; Tue, 18 Oct 2022 07:00:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 620FF3858D32 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.de Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out2.suse.de (Postfix) with ESMTP id 346FE2081D; Tue, 18 Oct 2022 07:00:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1666076442; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=qdDWs1bAFnPN5sNebFBKywjpsRVjOJDwddWQMof5bqw=; b=LNeY2kg3P502CKkQhcDKpjG7EvtZkhk8l5grNXk8O7zgXcWQtfIdjfZjdIn8DIaAwYKMAB yNTJu0nStUErdHiK4H8L37fGDSN2un1s1wX7Sjfd5AHCZAyWTwF2qdkV7Okz6RMKzMLBj+ rY7ACcNQCTWhPIXGjpGOiXe1ikOBhPM= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1666076442; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=qdDWs1bAFnPN5sNebFBKywjpsRVjOJDwddWQMof5bqw=; b=obK+UBIrffx4bbi9Q/+fsFu97L7vfDE7hOrHZ6aytJv/rGLuLepRJ2Rsmm0gGvIh/8SA0t 5m/izwWG0D9GdDDQ== Received: from wotan.suse.de (wotan.suse.de [10.160.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id 0A3492C141; Tue, 18 Oct 2022 07:00:42 +0000 (UTC) Date: Tue, 18 Oct 2022 07:00:41 +0000 (UTC) From: Richard Biener To: Jakub Jelinek cc: Jason Merrill , Jan Hubicka , gcc-patches@gcc.gnu.org Subject: Re: [PATCH] middle-end, v4: IFN_ASSUME support [PR106654] In-Reply-To: Message-ID: References: <479fa663-fb3e-a90d-ae7a-0fdd5acbfa00@redhat.com> User-Agent: Alpine 2.22 (LSU 394 2020-01-19) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-5.4 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: 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 > > PR c++/106654 > gcc/ > * gimple.def (GIMPLE_ASSUME): New statement kind. > * gimple.h (struct gimple_statement_assume): New type. > (is_a_helper ::test, > is_a_helper ::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 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 ::test (con > template <> > template <> > inline bool > +is_a_helper ::test (gimple *gs) > +{ > + return gs->code == GIMPLE_ASSUME; > +} > + > +template <> > +template <> > +inline bool > is_a_helper ::test (gimple *gs) > { > return gs->code == GIMPLE_TRANSACTION; > @@ -1497,6 +1519,14 @@ is_a_helper ::test (con > template <> > template <> > inline bool > +is_a_helper ::test (const gimple *gs) > +{ > + return gs->code == GIMPLE_ASSUME; > +} > + > +template <> > +template <> > +inline bool > is_a_helper ::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 (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 (gs); > + assume_stmt->guard = guard; > +} > + > +static inline tree * > +gimple_assume_guard_ptr (gimple *gs) > +{ > + gimple_statement_assume *assume_stmt = as_a (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 (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 (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_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 (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 (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 (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 (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 (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 (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 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 (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 (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 (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 (stmt)); > + else > + lab = gimple_cond_false_label (as_a (stmt)); > + } > + else if (gimple_code (stmt) == GIMPLE_LABEL) > + { > + tree label = gimple_label_label (as_a (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 (stmt), > + data->return_false_label); > + else if (idx == 0) > + gimple_cond_set_true_label (as_a (stmt), > + data->return_false_label); > + else > + gimple_cond_set_false_label (as_a (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 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 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 (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 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 (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 (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 SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman; HRB 36809 (AG Nuernberg)