From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 9623C3858034 for ; Wed, 12 Oct 2022 15:48:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9623C3858034 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1665589712; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=K6INyfwC4wLl9caYqlxTGp9u8k7+7+WSMbPouPXkQho=; b=EW4m6AsCkdLlzbjz94xQn8+T4M6ALFuYL7ukhUDKHE1T721HYg18q56AaXc0diX4BjR2+p aRGuMjGjNR5LkRdBc0/LF9uDHmOaNxGF15w8oLSfecgWA5eIGMvWbLIXGJ/0n3q/GXWvDe bHqz4ub/bboWmuk8zNKwgzjFrU2zGc4= Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-278-NFTT539kMJ60DitFlyukLg-1; Wed, 12 Oct 2022 11:48:30 -0400 X-MC-Unique: NFTT539kMJ60DitFlyukLg-1 Received: by mail-qk1-f198.google.com with SMTP id u7-20020a05620a0c4700b006ee526183fcso5553084qki.8 for ; Wed, 12 Oct 2022 08:48:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=K6INyfwC4wLl9caYqlxTGp9u8k7+7+WSMbPouPXkQho=; b=E7RZSgl4j9MlxRID1TzmSZxCJmDuqeStqg+rmb/cIOVu83ul+gImOHKu+deWiRt2Jf hhS4LcvWmw4DrwQsqdnqd4HwhgNvjEWKvAjONLO3LkyKJc6wEIZKuHzZ8tYOSqkremAQ OGsrH9Co81TpYrateVZIpFoBqMH6nG+g3oD2gaPm5Jk5C05LS8OqpbmhiCG3VB0Bv+uY MUc9y2mBPiAgRuylpdV+a6ddjbqYApN7YbVzJb5RlqcEosbC24jbcwxvPY/eMrHgtS3K FkwskyeafhQR5Fq6Xo0b/Yf5JLW3gu/gxrZk0YuSDzDL4WgYcPKKSsmgoVklEmdzW+2h oVDQ== X-Gm-Message-State: ACrzQf3ilN1K9SUXGLCJFZ8/fsHwESQn3gF/0ikWayRrNuz4DC9cEdah KnlhpYA6LNyfPv025dz028uaSel6PhSLZdL6AE2WSJpsAhqTU2ykniUJYIge/46ew5dYPRf0xuc 0qh96xYhOZCsRJ06sDg== X-Received: by 2002:a05:620a:4726:b0:6e7:f8ca:86ec with SMTP id bs38-20020a05620a472600b006e7f8ca86ecmr19675097qkb.96.1665589710078; Wed, 12 Oct 2022 08:48:30 -0700 (PDT) X-Google-Smtp-Source: AMsMyM4jxXxouKUr1Pzi7GnO2usPUAuZAOdfMbGO1Flskz5TCL57FvM60K51z1K/Ralr2OLdUGOYdQ== X-Received: by 2002:a05:620a:4726:b0:6e7:f8ca:86ec with SMTP id bs38-20020a05620a472600b006e7f8ca86ecmr19675065qkb.96.1665589709557; Wed, 12 Oct 2022 08:48:29 -0700 (PDT) Received: from [192.168.1.101] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id t28-20020a37ea1c000000b006cdd0939ffbsm16026742qkj.86.2022.10.12.08.48.28 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 12 Oct 2022 08:48:28 -0700 (PDT) Message-ID: <479fa663-fb3e-a90d-ae7a-0fdd5acbfa00@redhat.com> Date: Wed, 12 Oct 2022 11:48:27 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.3.2 Subject: Re: [PATCH] middle-end, v2: IFN_ASSUME support [PR106654] To: Jakub Jelinek , Jan Hubicka , Richard Biener , gcc-patches@gcc.gnu.org References: From: Jason Merrill In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,NICE_REPLY_A,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE,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 10/11/22 09:36, Jakub Jelinek wrote: > On Mon, Oct 10, 2022 at 11:19:24PM +0200, Jakub Jelinek via Gcc-patches wrote: >> On Mon, Oct 10, 2022 at 05:09:29PM -0400, Jason Merrill wrote: >>> On 10/10/22 04:54, Jakub Jelinek via Gcc-patches wrote: >>>> My earlier patches gimplify the simplest non-side-effects assumptions >>>> into if (cond) ; else __builtin_unreachable (); and throw the rest >>>> on the floor. >>>> The following patch attempts to do something with the rest too. >>>> For -O0, it actually throws even the simplest assumptions on the floor, >>>> we don't expect optimizations and the assumptions are there to allow >>>> optimizations. >>> >>> I'd think we should trap on failed assume at -O0 (i.e. with >>> -funreachable-traps). >> >> For the simple conditions? Perhaps. But for the side-effects cases >> that doesn't seem to be easily possible. > > Here is an updated patch which will trap on failed simple assume. > > Bootstrapped/regtested successfully on x86_64-linux and i686-linux, the only > change was moving the !optimize handling from before the > if (cond); else __builtin_unreachable (); > gimplification to right after it. > > 2022-10-11 Jakub Jelinek > > PR c++/106654 > gcc/ > * function.h (struct function): Add assume_function bitfield. > * gimplify.cc (gimplify_call_expr): If the assumption isn't > simple enough, expand it into IFN_ASSUME guarded block or > for -O0 drop it. > * gimple-low.cc (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 IFN_ASSUME guarded block. > * 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. > * cfgexpand.cc (pass_expand::execute): Don't expand assume_function > into RTL, just destroy loops and exit. > * internal-fn.cc (expand_ASSUME): Remove gcc_unreachable. > * passes.cc (pass_rest_of_compilation::gate): Return false also for > fun->assume_function. > * tree-vectorizer.cc (pass_vectorize::gate, > pass_slp_vectorize::gate): Likewise. > * ipa-icf.cc (sem_function::parse): Punt for func->assume_function. > gcc/cp/ > * parser.cc (cp_parser_omp_assumption_clauses): Wrap IFN_ASSUME > argument with fold_build_cleanup_point_expr. > * cp-gimplify.cc (process_stmt_assume_attribute): Likewise. > * 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/function.h.jj 2022-10-10 09:31:22.051478926 +0200 > +++ gcc/function.h 2022-10-10 09:59:49.283646705 +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-10 09:31:57.518983613 +0200 > +++ gcc/gimplify.cc 2022-10-10 09:59:49.285646677 +0200 > @@ -3569,7 +3569,52 @@ 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: > + guard = .ASSUME (); > + if (guard) goto label_true; else label_false; > + label_true:; > + { > + guard = cond; > + } > + label_false:; > + .ASSUME (guard); > + such that gimple lowering can outline the condition into > + a separate function easily. */ > + tree guard = create_tmp_var (boolean_type_node); > + gcall *call = gimple_build_call_internal (ifn, 0); > + gimple_call_set_nothrow (call, TREE_NOTHROW (*expr_p)); > + gimple_set_location (call, loc); > + gimple_call_set_lhs (call, guard); > + gimple_seq_add_stmt (pre_p, call); > + *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); > + tree label_false = create_artificial_label (UNKNOWN_LOCATION); > + tree label_true = create_artificial_label (UNKNOWN_LOCATION); > + gcond *cond_stmt = gimple_build_cond (NE_EXPR, guard, > + boolean_false_node, > + label_true, label_false); > + gimplify_seq_add_stmt (pre_p, cond_stmt); > + gimplify_seq_add_stmt (pre_p, gimple_build_label (label_true)); > + push_gimplify_context (); > + gimple_seq body = NULL; > + gimple *g = gimplify_and_return_first (*expr_p, &body); > + pop_gimplify_context (g); > + gimplify_seq_add_seq (pre_p, body); > + gimplify_seq_add_stmt (pre_p, gimple_build_label (label_false)); > + call = gimple_build_call_internal (ifn, 1, guard); > + gimple_call_set_nothrow (call, TREE_NOTHROW (*expr_p)); > + gimple_set_location (call, loc); > + gimple_seq_add_stmt (pre_p, call); > + *expr_p = NULL_TREE; > return GS_ALL_DONE; > } > > --- gcc/gimple-low.cc.jj 2022-10-10 09:31:22.107478144 +0200 > +++ gcc/gimple-low.cc 2022-10-10 10:22:05.891999132 +0200 > @@ -33,6 +33,13 @@ 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" > > /* The differences between High GIMPLE and Low GIMPLE are the > following: > @@ -237,6 +244,383 @@ lower_omp_directive (gimple_stmt_iterato > gsi_next (gsi); > } > > +static tree > +create_assumption_fn (location_t loc) > +{ > + tree name = clone_function_name_numbered (current_function_decl, "_assume"); > + /* For now, will be changed later. */ > + tree type = TREE_TYPE (current_function_decl); > + 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); > + 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); > + DECL_FUNCTION_VERSIONED (decl) > + = DECL_FUNCTION_VERSIONED (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: > + guard = .ASSUME (); > + if (guard) goto label_true; else label_false; > + label_true:; > + { > + guard = cond; > + } > + label_false:; > + .ASSUME (guard); > + 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_call_lhs (stmt); > + location_t loc = gimple_location (stmt); > + gcc_assert (guard); > + gsi_remove (gsi, true); > + stmt = gsi_stmt (*gsi); > + gcond *cond = as_a (stmt); > + gcc_assert (gimple_cond_lhs (cond) == guard > + || gimple_cond_rhs (cond) == guard); > + tree l1 = gimple_cond_true_label (cond); > + tree l2 = gimple_cond_false_label (cond); > + gsi_remove (gsi, true); > + stmt = gsi_stmt (*gsi); > + glabel *lab = as_a (stmt); > + gcc_assert (gimple_label_label (lab) == l1 > + || gimple_label_label (lab) == l2); > + gsi_remove (gsi, true); > + gimple *bind = gsi_stmt (*gsi); > + 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; > + > + struct walk_stmt_info wi; > + memset (&wi, 0, sizeof (wi)); > + wi.info = (void *) &lad; > + walk_gimple_stmt (gsi, 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; > + if (TREE_CODE (v) == SSA_NAME) > + { > + newv = make_ssa_name (remap_type (TREE_TYPE (v), &lad.id)); > + decl_map.put (v, newv); > + } > + 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; > + } > + } > + memset (&wi, 0, sizeof (wi)); > + wi.info = (void *) &lad; > + walk_gimple_stmt (gsi, adjust_assumption_stmt_r, > + adjust_assumption_stmt_op, &wi); > + gsi_remove (gsi, 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); > + greturn *gr = gimple_build_return (lad.guard_copy); > + gimple_seq_add_stmt (&body, gr); > + 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); > + 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); > + vargs[i - sz] = lad.decls[i - 1]; > + 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); > + } > + > + stmt = gsi_stmt (*gsi); > + lab = as_a (stmt); > + gcc_assert (gimple_label_label (lab) == l1 > + || gimple_label_label (lab) == l2); > + gsi_remove (gsi, true); > + stmt = gsi_stmt (*gsi); > + gcc_assert (gimple_call_internal_p (stmt, IFN_ASSUME) > + && gimple_call_num_args (stmt) == 1 > + && gimple_call_arg (stmt, 0) == guard); > + data->cannot_fallthru = false; > + 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 > @@ -354,6 +738,13 @@ lower_stmt (gimple_stmt_iterator *gsi, s > tree decl = gimple_call_fndecl (stmt); > unsigned i; > > + if (gimple_call_internal_p (stmt, IFN_ASSUME) > + && gimple_call_num_args (stmt) == 0) > + { > + lower_assumption (gsi, data); > + return; > + } > + > for (i = 0; i < gimple_call_num_args (stmt); i++) > { > tree arg = gimple_call_arg (stmt, i); > --- gcc/tree-ssa-ccp.cc.jj 2022-10-10 09:31:22.472473047 +0200 > +++ gcc/tree-ssa-ccp.cc 2022-10-10 09:59:49.286646663 +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-10 09:31:22.331475016 +0200 > +++ gcc/lto-streamer-out.cc 2022-10-10 09:59:49.287646649 +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-10 09:31:22.329475044 +0200 > +++ gcc/lto-streamer-in.cc 2022-10-10 09:59:49.287646649 +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-10 09:31:21.647484568 +0200 > +++ gcc/cgraphunit.cc 2022-10-10 09:59:49.288646635 +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) > --- gcc/cfgexpand.cc.jj 2022-10-10 09:31:21.554485867 +0200 > +++ gcc/cfgexpand.cc 2022-10-10 09:59:49.288646635 +0200 > @@ -6597,6 +6597,14 @@ pass_expand::execute (function *fun) > rtx_insn *var_seq, *var_ret_seq; > unsigned i; > > + if (cfun->assume_function) > + { > + /* Assume functions should not be expanded to RTL. */ > + cfun->curr_properties &= ~PROP_loops; > + loop_optimizer_finalize (); > + return 0; > + } > + > timevar_push (TV_OUT_OF_SSA); > rewrite_out_of_ssa (&SA); > timevar_pop (TV_OUT_OF_SSA); > --- gcc/internal-fn.cc.jj 2022-10-10 09:31:22.246476203 +0200 > +++ gcc/internal-fn.cc 2022-10-10 09:59:49.289646621 +0200 > @@ -4526,5 +4526,4 @@ expand_TRAP (internal_fn, gcall *) > void > expand_ASSUME (internal_fn, gcall *) > { > - gcc_unreachable (); > } > --- gcc/passes.cc.jj 2022-10-10 09:31:22.379474346 +0200 > +++ gcc/passes.cc 2022-10-10 09:59:49.289646621 +0200 > @@ -647,11 +647,12 @@ public: > {} > > /* opt_pass methods: */ > - bool gate (function *) final override > + bool gate (function *fun) final override > { > /* Early return if there were errors. We can run afoul of our > consistency checks, and there's not really much point in fixing them. */ > - return !(rtl_dump_and_exit || flag_syntax_only || seen_error ()); > + return !(rtl_dump_and_exit || fun->assume_function > + || flag_syntax_only || seen_error ()); > } > > }; // class pass_rest_of_compilation > --- gcc/tree-vectorizer.cc.jj 2022-10-10 09:31:22.516472432 +0200 > +++ gcc/tree-vectorizer.cc 2022-10-10 09:59:49.290646607 +0200 > @@ -1213,6 +1213,10 @@ public: > /* opt_pass methods: */ > bool gate (function *fun) final override > { > + /* Vectorization makes range analysis of assume functions > + harder, not easier. */ > + if (fun->assume_function) > + return false; > return flag_tree_loop_vectorize || fun->has_force_vectorize_loops; > } > > @@ -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. */ > + if (fun->assume_function) > + return false; > + return flag_tree_slp_vectorize != 0; > + } > unsigned int execute (function *) final override; > > }; // class pass_slp_vectorize > --- gcc/ipa-icf.cc.jj 2022-06-28 13:03:30.834690968 +0200 > +++ gcc/ipa-icf.cc 2022-10-10 10:29:31.187766299 +0200 > @@ -1517,6 +1517,9 @@ sem_function::parse (cgraph_node *node, > if (!func || (!node->has_gimple_body_p () && !node->thunk)) > return NULL; > > + if (func->assume_function) > + return NULL; > + > if (lookup_attribute_by_prefix ("omp ", DECL_ATTRIBUTES (node->decl)) != NULL) > return NULL; > > --- gcc/cp/parser.cc.jj 2022-10-10 09:31:57.405985191 +0200 > +++ gcc/cp/parser.cc 2022-10-10 09:59:49.295646537 +0200 > @@ -46031,6 +46031,8 @@ cp_parser_omp_assumption_clauses (cp_par > t = contextual_conv_bool (t, tf_warning_or_error); > if (is_assume && !error_operand_p (t)) > { > + if (!processing_template_decl) > + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); > t = build_call_expr_internal_loc (eloc, IFN_ASSUME, > void_type_node, 1, t); > finish_expr_stmt (t); > --- gcc/cp/cp-gimplify.cc.jj 2022-10-10 09:31:57.309986531 +0200 > +++ gcc/cp/cp-gimplify.cc 2022-10-10 09:59:49.296646524 +0200 > @@ -3139,6 +3139,8 @@ process_stmt_assume_attribute (tree std_ > arg = contextual_conv_bool (arg, tf_warning_or_error); > if (error_operand_p (arg)) > continue; > + if (!processing_template_decl) > + arg = fold_build_cleanup_point_expr (TREE_TYPE (arg), arg); > statement = build_call_expr_internal_loc (attrs_loc, IFN_ASSUME, > void_type_node, 1, arg); > finish_expr_stmt (statement); > --- gcc/cp/pt.cc.jj 2022-10-10 09:31:21.947480379 +0200 > +++ gcc/cp/pt.cc 2022-10-10 09:59:49.299646482 +0200 > @@ -21105,6 +21105,8 @@ tsubst_copy_and_build (tree t, > ret = error_mark_node; > break; > } > + if (!processing_template_decl) > + arg = fold_build_cleanup_point_expr (TREE_TYPE (arg), arg); > ret = build_call_expr_internal_loc (EXPR_LOCATION (t), > IFN_ASSUME, > void_type_node, 1, This starts to seem worth factoring out a build_assume_call function. I'll leave the middle-end review to others. > --- gcc/testsuite/g++.dg/cpp23/attr-assume5.C.jj 2022-10-10 09:59:49.299646482 +0200 > +++ gcc/testsuite/g++.dg/cpp23/attr-assume5.C 2022-10-10 09:59:49.299646482 +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-10 09:59:49.300646468 +0200 > +++ gcc/testsuite/g++.dg/cpp23/attr-assume6.C 2022-10-10 09:59:49.300646468 +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-10 09:59:49.300646468 +0200 > +++ gcc/testsuite/g++.dg/cpp23/attr-assume7.C 2022-10-10 10:05:51.472593600 +0200 > @@ -0,0 +1,42 @@ > +// 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; > +} > > > Jakub >