aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cgraph.cc4
-rw-r--r--gcc/cgraphunit.cc14
-rw-r--r--gcc/cp/cp-gimplify.cc15
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/parser.cc6
-rw-r--r--gcc/cp/pt.cc5
-rw-r--r--gcc/function.h4
-rw-r--r--gcc/gimple-low.cc395
-rw-r--r--gcc/gimple-pretty-print.cc29
-rw-r--r--gcc/gimple-walk.cc13
-rw-r--r--gcc/gimple.cc19
-rw-r--r--gcc/gimple.def5
-rw-r--r--gcc/gimple.h78
-rw-r--r--gcc/gimplify.cc28
-rw-r--r--gcc/gsstruct.def1
-rw-r--r--gcc/internal-fn.cc1
-rw-r--r--gcc/lto-streamer-in.cc1
-rw-r--r--gcc/lto-streamer-out.cc1
-rw-r--r--gcc/omp-low.cc4
-rw-r--r--gcc/omp-oacc-kernels-decompose.cc1
-rw-r--r--gcc/passes.cc9
-rw-r--r--gcc/passes.def1
-rw-r--r--gcc/testsuite/g++.dg/cpp23/attr-assume5.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp23/attr-assume6.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp23/attr-assume7.C56
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-cfg.cc7
-rw-r--r--gcc/tree-inline.cc5
-rw-r--r--gcc/tree-pass.h6
-rw-r--r--gcc/tree-ssa-ccp.cc6
-rw-r--r--gcc/tree-vrp.cc35
31 files changed, 745 insertions, 16 deletions
diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 8d6ed38..0417b05 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -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;
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index 7b5be0f..b05d790 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -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 ();
}
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 2608475..28c3398 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -3101,6 +3101,17 @@ process_stmt_hotness_attribute (tree std_attrs, location_t attrs_loc)
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_attrs, tree statement,
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);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e2607f0..60a2510 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 9ddfb02..a39c5f0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -46012,11 +46012,7 @@ cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok,
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,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e4dca9d..5eddad9 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -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;
diff --git a/gcc/function.h b/gcc/function.h
index 0986137..d7deaeb 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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. */
diff --git a/gcc/gimple-low.cc b/gcc/gimple-low.cc
index 4cd27dd..512aa9f 100644
--- a/gcc/gimple-low.cc
+++ b/gcc/gimple-low.cc
@@ -33,6 +33,14 @@ along with GCC; see the file COPYING3. If not see
#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_iterator *gsi, struct lower_data *data)
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, struct lower_data *data)
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)),
diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc
index a87e2ae..7ec079f 100644
--- a/gcc/gimple-pretty-print.cc
+++ b/gcc/gimple-pretty-print.cc
@@ -2052,6 +2052,31 @@ dump_gimple_omp_return (pretty_printer *buffer, const gimple *gs, int spc,
}
}
+/* 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, const gimple *gs, int spc,
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);
diff --git a/gcc/gimple-walk.cc b/gcc/gimple-walk.cc
index c40f280..cad36f7 100644
--- a/gcc/gimple-walk.cc
+++ b/gcc/gimple-walk.cc
@@ -485,6 +485,12 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op,
}
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);
@@ -707,6 +713,13 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
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 (
as_a <gtransaction *> (stmt)),
diff --git a/gcc/gimple.cc b/gcc/gimple.cc
index 4d45311..6c23dd7 100644
--- a/gcc/gimple.cc
+++ b/gcc/gimple.cc
@@ -1290,6 +1290,18 @@ gimple_build_omp_atomic_store (tree val, enum omp_memory_order mo)
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)));
diff --git a/gcc/gimple.def b/gcc/gimple.def
index 296c73c..7c617cd 100644
--- a/gcc/gimple.def
+++ b/gcc/gimple.def
@@ -406,3 +406,8 @@ DEFGSCODE(GIMPLE_PREDICT, "gimple_predict", GSS_BASE)
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)
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 77ac149..adbeb06 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -825,6 +825,20 @@ struct GTY((tag("GSS_OMP_ATOMIC_STORE_LAYOUT")))
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 (const gimple *gs)
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 (const gimple *gs)
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 (gimple_seq, tree);
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 (gomp_continue *cont_stmt, tree use)
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. */
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index d4209ea..42a996d 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -3569,7 +3569,33 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
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;
}
diff --git a/gcc/gsstruct.def b/gcc/gsstruct.def
index 19e1088..c3f64ef 100644
--- a/gcc/gsstruct.def
+++ b/gcc/gsstruct.def
@@ -50,4 +50,5 @@ DEFGSSTRUCT(GSS_OMP_SINGLE_LAYOUT, gimple_statement_omp_single_layout, false)
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)
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index de608bd4..9471f54 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -4526,5 +4526,4 @@ expand_TRAP (internal_fn, gcall *)
void
expand_ASSUME (internal_fn, gcall *)
{
- gcc_unreachable ();
}
diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc
index fa89634..5439651 100644
--- a/gcc/lto-streamer-in.cc
+++ b/gcc/lto-streamer-in.cc
@@ -1318,6 +1318,7 @@ input_struct_function_base (struct function *fn, class data_in *data_in,
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);
diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc
index 2e7af03..1e38904 100644
--- a/gcc/lto-streamer-out.cc
+++ b/gcc/lto-streamer-out.cc
@@ -2278,6 +2278,7 @@ output_struct_function_base (struct output_block *ob, struct function *fn)
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);
diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
index dc42c75..a880973 100644
--- a/gcc/omp-low.cc
+++ b/gcc/omp-low.cc
@@ -202,6 +202,7 @@ static bool omp_maybe_offloaded_ctx (omp_context *ctx);
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, omp_context *ctx)
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);
diff --git a/gcc/omp-oacc-kernels-decompose.cc b/gcc/omp-oacc-kernels-decompose.cc
index 524060e..df333ba 100644
--- a/gcc/omp-oacc-kernels-decompose.cc
+++ b/gcc/omp-oacc-kernels-decompose.cc
@@ -189,6 +189,7 @@ adjust_region_code_walk_stmt_fn (gimple_stmt_iterator *gsi_p,
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. */
diff --git a/gcc/passes.cc b/gcc/passes.cc
index 78a07f8..3bbf525 100644
--- a/gcc/passes.cc
+++ b/gcc/passes.cc
@@ -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);
diff --git a/gcc/passes.def b/gcc/passes.def
index 939ec3e..193b579 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -407,6 +407,7 @@ along with GCC; see the file COPYING3. If not see
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);
diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume5.C b/gcc/testsuite/g++.dg/cpp23/attr-assume5.C
new file mode 100644
index 0000000..fec2209
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/attr-assume5.C
@@ -0,0 +1,5 @@
+// P1774R8 - Portable assumptions
+// { dg-do run { target c++11 } }
+// { dg-options "-O2" }
+
+#include "attr-assume1.C"
diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume6.C b/gcc/testsuite/g++.dg/cpp23/attr-assume6.C
new file mode 100644
index 0000000..4a81df1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/attr-assume6.C
@@ -0,0 +1,5 @@
+// P1774R8 - Portable assumptions
+// { dg-do run { target c++11 } }
+// { dg-options "-O2" }
+
+#include "attr-assume3.C"
diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume7.C b/gcc/testsuite/g++.dg/cpp23/attr-assume7.C
new file mode 100644
index 0000000..441242c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/attr-assume7.C
@@ -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;
+}
diff --git a/gcc/timevar.def b/gcc/timevar.def
index eac4370..63d9b00 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -226,6 +226,7 @@ DEFTIMEVAR (TV_TREE_WIDEN_MUL , "gimple widening/fma detection")
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")
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index ae78187..9b2c0f6 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -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;
diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
index 01d4700..8091ba8 100644
--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -1736,6 +1736,11 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
(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);
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 4dfe05e..8480d41 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -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_prop (gcc::context *ctxt);
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);
diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc
index 85c0460..9778e77 100644
--- a/gcc/tree-ssa-ccp.cc
+++ b/gcc/tree-ssa-ccp.cc
@@ -4253,6 +4253,12 @@ pass_fold_builtins::execute (function *fun)
}
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);
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index 93482e5..1adb15c 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -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);
+}