GCC Middle and Back End API Reference
ipa-pure-const.c File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "gimple.h"
#include "tree-cfg.h"
#include "tree-ssa-loop-niter.h"
#include "tree-inline.h"
#include "tree-pass.h"
#include "langhooks.h"
#include "pointer-set.h"
#include "ggc.h"
#include "ipa-utils.h"
#include "flags.h"
#include "diagnostic.h"
#include "gimple-pretty-print.h"
#include "target.h"
#include "lto-streamer.h"
#include "data-streamer.h"
#include "tree-streamer.h"
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
#include "intl.h"
#include "opts.h"
Include dependency graph for ipa-pure-const.c:

Data Structures

struct  funct_state_d

Typedefs

typedef struct funct_state_dfunct_state

Enumerations

enum  pure_const_state_e { IPA_CONST, IPA_PURE, IPA_NEITHER }

Functions

static bool function_always_visible_to_compiler_p ()
static struct pointer_set_tsuggest_attribute (int option, tree decl, bool known_finite, struct pointer_set_t *warned_about, const char *attrib_name)
static void warn_function_pure ()
static void warn_function_const ()
static void warn_function_noreturn ()
static bool has_function_state ()
static funct_state get_function_state ()
static void set_function_state ()
static void check_decl (funct_state local, tree t, bool checking_write, bool ipa)
static void check_op ()
static void state_from_flags (enum pure_const_state_e *state, bool *looping, int flags, bool cannot_lead_to_return)
static void better_state (enum pure_const_state_e *state, bool *looping, enum pure_const_state_e state2, bool looping2)
static void worse_state (enum pure_const_state_e *state, bool *looping, enum pure_const_state_e state2, bool looping2)
static bool special_builtin_state (enum pure_const_state_e *state, bool *looping, tree callee)
static void check_call ()
static bool check_load ()
static bool check_store ()
static bool check_ipa_load ()
static bool check_ipa_store ()
static void check_stmt ()
static funct_state analyze_function ()
static void add_new_function ()
static void duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst, void *data)
static void remove_node_data ()
static void register_hooks ()
static void pure_const_generate_summary ()
static void pure_const_write_summary ()
static void pure_const_read_summary ()
static bool ignore_edge ()
static bool self_recursive_p ()
static void propagate_pure_const ()
static void propagate_nothrow ()
static unsigned int propagate ()
static bool gate_pure_const ()
ipa_opt_pass_dmake_pass_ipa_pure_const ()
static bool skip_function_for_local_pure_const ()
static unsigned int local_pure_const ()
gimple_opt_passmake_pass_local_pure_const ()
static unsigned int execute_warn_function_noreturn ()
static bool gate_warn_function_noreturn ()
gimple_opt_passmake_pass_warn_function_noreturn ()

Variables

static struct pointer_set_tvisited_nodes
const char * pure_const_names [3] = {"const", "pure", "neither"}
static struct funct_state_d varying_state = { IPA_NEITHER, IPA_NEITHER, true, true, true }
static vec< funct_statefunct_state_vec
static struct
cgraph_node_hook_list
function_insertion_hook_holder
static struct
cgraph_2node_hook_list
node_duplication_hook_holder
static struct
cgraph_node_hook_list
node_removal_hook_holder

Typedef Documentation

typedef struct funct_state_d* funct_state

Enumeration Type Documentation

Lattice values for const and pure functions. Everything starts out being const, then may drop to pure and then neither depending on what is found.

Enumerator:
IPA_CONST 
IPA_PURE 
IPA_NEITHER 

Function Documentation

static void add_new_function ( )
static

Called when new function is inserted to callgraph late.

There are some shared nodes, in particular the initializers on static declarations. We do not need to scan them more than once since all we would be interested in are the addressof operations.

static funct_state analyze_function ( )
static

This is the main routine for finding the reference patterns for global variables within a function FN.

     Thunk gets propagated through, so nothing interesting happens.   
     Const functions cannot have back edges (an
     indication of possible infinite loop side
     effect.   
         Preheaders are needed for SCEV to work.
         Simple latches and recorded exits improve chances that loop will
         proved to be finite in testcases such as in loop-15.c
         and loop-24.c   

References dump_file, dump_flags, finite_loop_p(), flow_loops_dump(), FOR_EACH_LOOP, FOR_EACH_LOOP_BREAK, loop_optimizer_finalize(), loop_optimizer_init(), funct_state_d::looping, LOOPS_HAVE_PREHEADERS, LOOPS_HAVE_RECORDED_EXITS, LOOPS_HAVE_SIMPLE_LATCHES, mark_irreducible_loops(), NULL, loop::num, scev_finalize(), and scev_initialize().

static void better_state ( enum pure_const_state_e state,
bool looping,
enum pure_const_state_e  state2,
bool  looping2 
)
inlinestatic

Merge STATE and STATE2 and LOOPING and LOOPING2 and store into STATE and LOOPING better of the two variants. Be sure to merge looping correctly. IPA_NEITHER functions have looping 0 even if they don't have to return.

References IPA_CONST.

static void check_call ( )
static

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 indirect call, a call outside the compilation unit, or has special attributes that may also effect the purity. The CALL_EXPR node for the entire call expression.

 The const and pure flags are set by a variety of places in the
 compiler (including here).  If someone has already set the flags
 for the callee, (such as for some of the builtins) we will use
 them, otherwise we will compute our own information.

 Const and pure functions have less clobber effects than other
 functions so we process these first.  Otherwise if it is a call
 outside the compilation unit or an indirect call we punt.  This
 leaves local calls which will be processed by following the call
 graph.   
     When bad things happen to bad functions, they cannot be const
     or pure.   
 When not in IPA mode, we can still handle self recursion.   
 Either callee is unknown or we are doing local analysis.
 Look to see if there are any bits available for the callee (such as by
 declaration or because it is builtin) and process solely on the basis of
 those bits.  
 Direct functions calls are handled by IPA propagation.   

References BUILT_IN_NORMAL, DECL_BUILT_IN_CLASS, DECL_FUNCTION_CODE, dump_file, IPA_NEITHER, funct_state_d::looping, funct_state_d::pure_const_state, setjmp_call_p(), special_builtin_state(), and worse_state().

Referenced by check_stmt().

static void check_decl ( funct_state  local,
tree  t,
bool  checking_write,
bool  ipa 
)
inlinestatic

Check to see if the use (or definition when CHECKING_WRITE is true) variable T is legal in a function that is either pure or const.

 Do not want to do anything with volatile except mark any
 function that uses one to be not const or pure.   
 Do not care about a local automatic that is not static.   
 If the variable has the "used" attribute, treat it as if it had a
 been touched by the devil.   
 In IPA mode we are not interested in checking actual loads and stores;
 they will be processed at propagation time using ipa_ref.   
 Since we have dealt with the locals and params cases above, if we
 are CHECKING_WRITE, this cannot be a pure or constant
 function.   
     Readonly reads are safe.   
         Just a regular read.   
     Compilation level statics can be read if they are readonly
     variables.   
     Just a regular read.   
static bool check_ipa_load ( )
static

Wrapper around check_decl for loads in ipa mode.

static bool check_ipa_store ( )
static

Wrapper around check_decl for stores in ipa mode.

static bool check_load ( )
static

Wrapper around check_decl for loads in local more.

static void check_op ( )
inlinestatic

Check to see if the use (or definition when CHECKING_WRITE is true) variable T is legal in a function that is either pure or const.

static void check_stmt ( )
static

Look into pointer pointed to by GSIP and figure out what interesting side effects it has.

 Look for loads and stores.   
       Target of long jump.  
         Abandon all hope, ye who enter here.  
         Abandon all hope, ye who enter here.  

References check_call(), DECL_NONLOCAL, dump_file, gimple_asm_clobbers_memory_p(), gimple_asm_volatile_p(), gimple_label_label(), IPA_NEITHER, funct_state_d::looping, and funct_state_d::pure_const_state.

static bool check_store ( )
static

Wrapper around check_decl for stores in local more.

References dump_file, and print_gimple_stmt().

static void duplicate_node_data ( struct cgraph_node src,
struct cgraph_node dst,
void *  data 
)
static

Called when new clone is inserted to callgraph late.

static unsigned int execute_warn_function_noreturn ( )
static

Emit noreturn warnings.

static bool function_always_visible_to_compiler_p ( )
static

Try to guess if function body will always be visible to compiler when compiling the call and whether compiler will be able to propagate the information by itself.

References option_enabled(), pointer_set_contains(), pointer_set_create(), and TREE_THIS_VOLATILE.

static bool gate_pure_const ( )
static

Don't bother doing anything if the program has errors.

static bool gate_warn_function_noreturn ( )
static
static funct_state get_function_state ( )
inlinestatic

Return the function state from NODE.

We might want to put correct previously_known state into varying.

static bool has_function_state ( )
inlinestatic

Return true if we have a function state for NODE.

static bool ignore_edge ( )
static

Referenced by searchc().

static unsigned int local_pure_const ( )
static

Simple local pass for pure const discovery reusing the analysis from ipa_pure_const. This pass is effective when executed together with other optimization passes in early optimization pass queue.

Do NORETURN discovery.

     Update declaration and reduce profile to executed once.   
ipa_opt_pass_d* make_pass_ipa_pure_const ( )
gimple_opt_pass* make_pass_local_pure_const ( )
gimple_opt_pass* make_pass_warn_function_noreturn ( )
static unsigned int propagate ( )
static

Produce the global information by preforming a transitive closure on the local information that was produced by generate_summary.

Nothrow makes more function to not lead to return and improve later analysis.

 Cleanup.  
static void propagate_nothrow ( )
static

Produce transitive closure over the callgraph and compute nothrow attributes.

 Propagate the local information through the call graph to produce
 the global information.  All the nodes within a cycle will have
 the same info so we collapse cycles first.  Then we can do the
 propagation in one pass from the leaves to the roots.   
     Find the worst state for any node in the cycle.   
     Copy back the region's pure_const_state which is shared by
     all nodes in the region.   
static void propagate_pure_const ( )
static

Produce transitive closure over the callgraph and compute pure/const attributes.

 Propagate the local information through the call graph to produce
 the global information.  All the nodes within a cycle will have
 the same info so we collapse cycles first.  Then we can do the
 propagation in one pass from the leaves to the roots.   
     Find the worst state for any node in the cycle.   
         First merge in function body properties.   
         For overwritable nodes we can not assume anything.   
         We consider recursive cycles as possibly infinite.
         This might be relaxed since infinite recursion leads to stack
         overflow.   
         Now walk the edges and merge in callee properties.   
             Merge the results with what we already know.   
         Now process the indirect call.   
             Merge the results with what we already know.   
         And finally all loads and stores.   
                 readonly reads are safe.   
     Copy back the region's pure_const_state which is shared by
     all nodes in the region.   
         All nodes within a cycle share the same info.   
static void pure_const_generate_summary ( )
static

Analyze each function in the cgraph to see if it is locally PURE or CONST.

There are some shared nodes, in particular the initializers on static declarations. We do not need to scan them more than once since all we would be interested in are the addressof operations.

 Process all of the functions.

 We process AVAIL_OVERWRITABLE functions.  We can not use the results
 by default, but the info can be used at LTO with -fwhole-program or
 when function got cloned and the clone is AVAILABLE.   
static void pure_const_read_summary ( )
static

Deserialize the ipa info for lto.

Note that the flags must be read in the opposite order in which they were written (the bitflags were pushed into FLAGS).

static void pure_const_write_summary ( )
static

Serialize the ipa info for lto.

Process all of the functions.

         Note that flags will need to be read in the opposite
         order as we are pushing the bitflags into FLAGS.   
static void register_hooks ( )
static
static void remove_node_data ( )
static

Called when new clone is inserted to callgraph late.

References count, lto_create_simple_output_block(), and LTO_section_ipa_pure_const.

static bool self_recursive_p ( )
static

Return true if NODE is self recursive function. Indirectly recursive functions appears as non-trivial strongly connected components, so we need to care about self recursion only.

References dump_file, dump_flags, funct_state_d::looping_previously_known, pure_const_names, funct_state_d::state_previously_known, and worse_state().

static void set_function_state ( )
inlinestatic

Set the function state S for NODE.

static bool skip_function_for_local_pure_const ( )
static

Return true if function should be skipped for local pure const analysis.

Because we do not schedule pass_fixup_cfg over whole program after early optimizations we must not promote functions that are called by already processed functions.

References cgraph_set_pure_flag(), and funct_state_d::looping.

static bool special_builtin_state ( enum pure_const_state_e state,
bool looping,
tree  callee 
)
static

Recognize special cases of builtins that are by themselves not pure or const but function using them is.

References funct_state_d::can_throw, cfun, dump_file, gimple_call_flags(), gimple_call_fndecl(), gimple_num_ops(), gimple_op(), funct_state_d::looping, stmt_can_throw_external(), stmt_could_throw_p(), and tree_could_throw_p().

Referenced by check_call().

static void state_from_flags ( enum pure_const_state_e state,
bool looping,
int  flags,
bool  cannot_lead_to_return 
)
static

compute state based on ECF FLAGS and store to STATE and LOOPING.

static struct pointer_set_t* suggest_attribute ( int  option,
tree  decl,
bool  known_finite,
struct pointer_set_t warned_about,
const char *  attrib_name 
)
staticread

Emit suggestion about attribute ATTRIB_NAME for DECL. KNOWN_FINITE is true if the function is known to be finite. The diagnostic is controlled by OPTION. WARNED_ABOUT is a pointer_set unique for OPTION, this function may initialize it and it is always returned by the function.

static void warn_function_const ( )
static

Emit suggestion about __attribute_((const)) for DECL. KNOWN_FINITE is true if the function is known to be finite.

static void warn_function_noreturn ( )
static
static void warn_function_pure ( )
static

Emit suggestion about __attribute_((pure)) for DECL. KNOWN_FINITE is true if the function is known to be finite.

static void worse_state ( enum pure_const_state_e state,
bool looping,
enum pure_const_state_e  state2,
bool  looping2 
)
inlinestatic

Merge STATE and STATE2 and LOOPING and LOOPING2 and store into STATE and LOOPING worse of the two variants.

Referenced by check_call(), and self_recursive_p().


Variable Documentation

vec<funct_state> funct_state_vec
static

The storage of the funct_state is abstracted because there is the possibility that it may be desirable to move this to the cgraph local info. Array, indexed by cgraph node uid, of function states.

struct cgraph_node_hook_list* function_insertion_hook_holder
static

Holders of ipa cgraph hooks:

struct cgraph_2node_hook_list* node_duplication_hook_holder
static
struct cgraph_node_hook_list* node_removal_hook_holder
static
const char* pure_const_names[3] = {"const", "pure", "neither"}

Referenced by self_recursive_p().

struct funct_state_d varying_state = { IPA_NEITHER, IPA_NEITHER, true, true, true }
static

State used when we know nothing about function.

struct pointer_set_t* visited_nodes
static

Callgraph based analysis of static variables. Copyright (C) 2004-2013 Free Software Foundation, Inc. Contributed by Kenneth Zadeck zadec.nosp@m.k@na.nosp@m.tural.nosp@m.brid.nosp@m.ge.co.nosp@m.m

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see http://www.gnu.org/licenses/. This file marks functions as being either const (TREE_READONLY) or pure (DECL_PURE_P). It can also set a variant of these that are allowed to loop indefinitely (DECL_LOOPING_CONST_PURE_P).

This must be run after inlining decisions have been made since otherwise, the local sets will not contain information that is consistent with post inlined state. The global sets are not prone to this problem since they are by definition transitive. The code in this module is called by the ipa pass manager. It should be one of the later passes since it's information is used by the rest of the compilation.