bool can_throw;
};
+/* State used when we know nothing about function. */
+static struct funct_state_d varying_state
+ = { IPA_NEITHER, IPA_NEITHER, true, true, true };
+
+
typedef struct funct_state_d * funct_state;
/* The storage of the funct_state is abstracted because there is the
struct pointer_set_t *warned_about,
const char * attrib_name)
{
- if (!option_enabled (option))
+ if (!option_enabled (option, &global_options))
return warned_about;
if (TREE_THIS_VOLATILE (decl)
|| (known_finite && function_always_visible_to_compiler_p (decl)))
static inline funct_state
get_function_state (struct cgraph_node *node)
{
- static struct funct_state_d varying
- = { IPA_NEITHER, IPA_NEITHER, true, true, true };
if (!funct_state_vec
- || VEC_length (funct_state, funct_state_vec) <= (unsigned int)node->uid)
+ || VEC_length (funct_state, funct_state_vec) <= (unsigned int)node->uid
+ || !VEC_index (funct_state, funct_state_vec, node->uid))
/* We might want to put correct previously_known state into varying. */
- return &varying;
- return VEC_index (funct_state, funct_state_vec, node->uid);
+ return &varying_state;
+ return VEC_index (funct_state, funct_state_vec, node->uid);
}
/* Set the function state S for NODE. */
return;
}
else if (t
- && INDIRECT_REF_P (t)
+ && (INDIRECT_REF_P (t) || TREE_CODE (t) == MEM_REF)
&& TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME
&& !ptr_deref_may_alias_global_p (TREE_OPERAND (t, 0)))
{
*looping = MAX (*looping, looping2);
}
+/* Recognize special cases of builtins that are by themself not pure or const
+ but function using them is. */
+static bool
+special_builtin_state (enum pure_const_state_e *state, bool *looping,
+ tree callee)
+{
+ if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+ switch (DECL_FUNCTION_CODE (callee))
+ {
+ case BUILT_IN_RETURN:
+ case BUILT_IN_UNREACHABLE:
+ case BUILT_IN_ALLOCA:
+ case BUILT_IN_STACK_SAVE:
+ case BUILT_IN_STACK_RESTORE:
+ case BUILT_IN_EH_POINTER:
+ case BUILT_IN_EH_FILTER:
+ case BUILT_IN_UNWIND_RESUME:
+ case BUILT_IN_CXA_END_CLEANUP:
+ case BUILT_IN_EH_COPY_VALUES:
+ case BUILT_IN_FRAME_ADDRESS:
+ case BUILT_IN_APPLY:
+ case BUILT_IN_APPLY_ARGS:
+ *looping = false;
+ *state = IPA_CONST;
+ return true;
+ case BUILT_IN_PREFETCH:
+ *looping = true;
+ *state = IPA_CONST;
+ return true;
+ }
+ return false;
+}
+
/* Check the parameters of a function call to CALL_EXPR to see if
there are any references in the parameters that are not allowed for
pure or const functions. Also check to see if this is either an
graph. */
if (callee_t)
{
- /* built_in_return is really just an return statemnt. */
- if (gimple_call_builtin_p (call, BUILT_IN_RETURN))
- return;
+ enum pure_const_state_e call_state;
+ bool call_looping;
+
+ if (special_builtin_state (&call_state, &call_looping, callee_t))
+ {
+ worse_state (&local->pure_const_state, &local->looping,
+ call_state, call_looping);
+ return;
+ }
/* When bad things happen to bad functions, they cannot be const
or pure. */
if (setjmp_call_p (callee_t))
print_gimple_stmt (dump_file, stmt, 0, 0);
}
+ if (gimple_has_volatile_ops (stmt))
+ {
+ local->pure_const_state = IPA_NEITHER;
+ if (dump_file)
+ fprintf (dump_file, " Volatile stmt is not const/pure\n");
+ }
+
/* Look for loads and stores. */
walk_stmt_load_store_ops (stmt, local,
ipa ? check_ipa_load : check_load,
{
if (has_function_state (node))
{
- free (get_function_state (node));
+ funct_state l = get_function_state (node);
+ if (l != &varying_state)
+ free (l);
set_function_state (node, NULL);
}
}
node = csi_node (csi);
if (node->analyzed && has_function_state (node))
{
- struct bitpack_d *bp;
+ struct bitpack_d bp;
funct_state fs;
int node_ref;
lto_cgraph_encoder_t encoder;
/* Note that flags will need to be read in the opposite
order as we are pushing the bitflags into FLAGS. */
- bp = bitpack_create ();
- bp_pack_value (bp, fs->pure_const_state, 2);
- bp_pack_value (bp, fs->state_previously_known, 2);
- bp_pack_value (bp, fs->looping_previously_known, 1);
- bp_pack_value (bp, fs->looping, 1);
- bp_pack_value (bp, fs->can_throw, 1);
- lto_output_bitpack (ob->main_stream, bp);
- bitpack_delete (bp);
+ bp = bitpack_create (ob->main_stream);
+ bp_pack_value (&bp, fs->pure_const_state, 2);
+ bp_pack_value (&bp, fs->state_previously_known, 2);
+ bp_pack_value (&bp, fs->looping_previously_known, 1);
+ bp_pack_value (&bp, fs->looping, 1);
+ bp_pack_value (&bp, fs->can_throw, 1);
+ lto_output_bitpack (&bp);
}
}
{
unsigned int index;
struct cgraph_node *node;
- struct bitpack_d *bp;
+ struct bitpack_d bp;
funct_state fs;
lto_cgraph_encoder_t encoder;
pushed into FLAGS). */
bp = lto_input_bitpack (ib);
fs->pure_const_state
- = (enum pure_const_state_e) bp_unpack_value (bp, 2);
+ = (enum pure_const_state_e) bp_unpack_value (&bp, 2);
fs->state_previously_known
- = (enum pure_const_state_e) bp_unpack_value (bp, 2);
- fs->looping_previously_known = bp_unpack_value (bp, 1);
- fs->looping = bp_unpack_value (bp, 1);
- fs->can_throw = bp_unpack_value (bp, 1);
+ = (enum pure_const_state_e) bp_unpack_value (&bp, 2);
+ fs->looping_previously_known = bp_unpack_value (&bp, 1);
+ fs->looping = bp_unpack_value (&bp, 1);
+ fs->can_throw = bp_unpack_value (&bp, 1);
if (dump_file)
{
int flags = flags_from_decl_or_type (node->decl);
if (fs->can_throw)
fprintf (dump_file," function is locally throwing\n");
}
- bitpack_delete (bp);
}
lto_destroy_simple_input_block (file_data,
edge_looping = y_l->looping;
}
}
+ else if (special_builtin_state (&edge_state, &edge_looping,
+ y->decl))
+ ;
else
state_from_flags (&edge_state, &edge_looping,
- flags_from_decl_or_type (y->decl),
- cgraph_edge_cannot_lead_to_return (e));
+ flags_from_decl_or_type (y->decl),
+ cgraph_edge_cannot_lead_to_return (e));
/* Merge the results with what we already know. */
better_state (&edge_state, &edge_looping,
this_looping ? "looping " : "",
cgraph_node_name (w));
}
- cgraph_set_readonly_flag (w, true);
- cgraph_set_looping_const_or_pure_flag (w, this_looping);
+ cgraph_set_const_flag (w, true, this_looping);
break;
case IPA_PURE:
this_looping ? "looping " : "",
cgraph_node_name (w));
}
- cgraph_set_pure_flag (w, true);
- cgraph_set_looping_const_or_pure_flag (w, this_looping);
+ cgraph_set_pure_flag (w, true, this_looping);
break;
default:
&& skip)
return 0;
- /* First do NORETURN discovery. */
+ l = analyze_function (node, false);
+
+ /* Do NORETURN discovery. */
if (!skip && !TREE_THIS_VOLATILE (current_function_decl)
&& EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0)
{
changed = true;
}
- l = analyze_function (node, false);
switch (l->pure_const_state)
{
warn_function_const (current_function_decl, !l->looping);
if (!skip)
{
- cgraph_set_readonly_flag (node, true);
- cgraph_set_looping_const_or_pure_flag (node, l->looping);
+ cgraph_set_const_flag (node, true, l->looping);
changed = true;
}
if (dump_file)
{
if (!skip)
{
- cgraph_set_looping_const_or_pure_flag (node, false);
+ cgraph_set_const_flag (node, true, false);
changed = true;
}
if (dump_file)
{
if (!skip)
{
- cgraph_set_pure_flag (node, true);
- cgraph_set_looping_const_or_pure_flag (node, l->looping);
+ cgraph_set_pure_flag (node, true, l->looping);
changed = true;
}
warn_function_pure (current_function_decl, !l->looping);
{
if (!skip)
{
- cgraph_set_looping_const_or_pure_flag (node, false);
+ cgraph_set_pure_flag (node, true, false);
changed = true;
}
if (dump_file)