132 lines
4.9 KiB
C
132 lines
4.9 KiB
C
/* Search for references that a functions loads or stores.
|
|
Copyright (C) 2019-2023 Free Software Foundation, Inc.
|
|
|
|
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/>. */
|
|
|
|
#ifndef IPA_MODREF_H
|
|
#define IPA_MODREF_H
|
|
|
|
typedef modref_tree <alias_set_type> modref_records;
|
|
typedef unsigned short eaf_flags_t;
|
|
|
|
/* Single function summary. */
|
|
|
|
struct GTY(()) modref_summary
|
|
{
|
|
/* Load and stores in function (transitively closed to all callees) */
|
|
modref_records *loads;
|
|
modref_records *stores;
|
|
auto_vec<modref_access_node> GTY((skip)) kills;
|
|
auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
|
|
|
|
eaf_flags_t retslot_flags;
|
|
eaf_flags_t static_chain_flags;
|
|
|
|
unsigned writes_errno : 1;
|
|
/* Side effects does not include memory loads and stores which are
|
|
expressed using loads, stores and calls_interposable fields. */
|
|
unsigned side_effects : 1;
|
|
/* If true function can not be CSE optimized because it may behave
|
|
differently even if invoked with same inputs. */
|
|
unsigned nondeterministic : 1;
|
|
/* IF true the function may read any reachable memory but not use
|
|
it for anything useful. This may happen i.e. when interposing
|
|
function with optimized out conditional with unoptimized one.
|
|
|
|
In this situation the loads summary is not useful for DSE but
|
|
it is still useful for CSE. */
|
|
unsigned calls_interposable : 1;
|
|
|
|
/* Flags computed by finalize method. */
|
|
|
|
/* Total number of accesses in loads tree. */
|
|
unsigned int load_accesses;
|
|
/* global_memory_read is not set for functions calling functions
|
|
with !binds_to_current_def which, after interposition, may read global
|
|
memory but do nothing useful with it (except for crashing if some
|
|
stores are optimized out. */
|
|
unsigned global_memory_read : 1;
|
|
unsigned global_memory_written : 1;
|
|
unsigned try_dse : 1;
|
|
|
|
|
|
modref_summary ();
|
|
~modref_summary ();
|
|
void dump (FILE *);
|
|
bool useful_p (int ecf_flags, bool check_flags = true);
|
|
void finalize (tree);
|
|
};
|
|
|
|
modref_summary *get_modref_function_summary (cgraph_node *func);
|
|
modref_summary *get_modref_function_summary (gcall *call, bool *interposed);
|
|
void ipa_modref_cc_finalize ();
|
|
void ipa_merge_modref_summary_after_inlining (cgraph_edge *e);
|
|
|
|
/* All flags that are implied by the ECF_CONST functions. */
|
|
static const int implicit_const_eaf_flags
|
|
= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
|
|
| EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
|
|
| EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
|
|
| EAF_NOT_RETURNED_INDIRECTLY;
|
|
|
|
/* All flags that are implied by the ECF_PURE function. */
|
|
static const int implicit_pure_eaf_flags
|
|
= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
|
|
| EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE;
|
|
|
|
/* All flags implied when we know we can ignore stores (i.e. when handling
|
|
call to noreturn). */
|
|
static const int ignore_stores_eaf_flags
|
|
= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
|
|
| EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE;
|
|
|
|
/* Return slot is write-only. */
|
|
static const int implicit_retslot_eaf_flags
|
|
= EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
|
|
| EAF_NO_INDIRECT_ESCAPE | EAF_NO_INDIRECT_CLOBBER
|
|
| EAF_NOT_RETURNED_INDIRECTLY;
|
|
|
|
/* If function does not bind to current def (i.e. it is inline in comdat
|
|
section), the modref analysis may not match the behavior of function
|
|
which will be later symbol interposed to. All side effects must match
|
|
however it is possible that the other function body contains more loads
|
|
which may trap.
|
|
MODREF_FLAGS are flags determined by analysis of function body while
|
|
FLAGS are flags known otherwise (i.e. by fnspec, pure/const attributes
|
|
etc.) */
|
|
inline int
|
|
interposable_eaf_flags (int modref_flags, int flags)
|
|
{
|
|
/* If parameter was previously unused, we know it is only read
|
|
and its value is not used. */
|
|
if ((modref_flags & EAF_UNUSED) && !(flags & EAF_UNUSED))
|
|
{
|
|
modref_flags &= ~EAF_UNUSED;
|
|
modref_flags |= EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
|
|
| EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
|
|
| EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER;
|
|
}
|
|
/* We can not determine that value is not read at all. */
|
|
if ((modref_flags & EAF_NO_DIRECT_READ) && !(flags & EAF_NO_DIRECT_READ))
|
|
modref_flags &= ~EAF_NO_DIRECT_READ;
|
|
if ((modref_flags & EAF_NO_INDIRECT_READ) && !(flags & EAF_NO_INDIRECT_READ))
|
|
modref_flags &= ~EAF_NO_INDIRECT_READ;
|
|
return modref_flags;
|
|
}
|
|
|
|
#endif
|