Files
gcc-reflection/gcc/cif-code.def
Josef Melcr 7cd91c7c42 ipa, cgraph: Enable constant propagation to OpenMP kernels.
This patch enables constant propagation to outlined OpenMP kernels.
It does so using a new function attribute called ' callback' (note the
space).

The attribute ' callback' captures the notion of a function calling one
of its arguments with some of its parameters as arguments.  An OpenMP
example of such function is GOMP_parallel.
We implement the attribute with new callgraph edges called callback
edges. They are imaginary edges pointing from the caller of the function
with the attribute (e.g. caller of GOMP_parallel) to the body function
itself (e.g. the outlined OpenMP body).  They share their call statement
with the edge from which they are derived (direct edge caller -> GOMP_parallel
in this case).  These edges allow passes such as ipa-cp to see the hidden
call site to the body function and optimize the function accordingly.

To illustrate on an example, the body GOMP_parallel looks something
like this:

void GOMP_parallel (void (*fn) (void *), void *data, /* ... */)
{
  /* ... */
  fn (data);
  /* ... */
}

If we extend it with the attribute ' callback(1, 2)', we express that the
function calls its first argument and passes it its second argument.
This is represented in the call graph in this manner:

             direct                         indirect
caller -----------------> GOMP_parallel ---------------> fn
  |
  ----------------------> fn
          callback

The direct edge is then the callback-carrying edge, all new edges
are the derived callback edges.
While constant propagation is the main focus of this patch, callback
edges can be useful for different passes (for example, they improve icf
for OpenMP kernels), as they allow for address redirection.
If the outlined body function gets optimized and cloned, from body_fn to
body_fn.optimized, the callback edge allows us to replace the
address in the arguments list:

GOMP_parallel (body_fn, &data_struct, /* ... */);

becomes

GOMP_parallel (body_fn.optimized, &data_struct, /* ... */);

This redirection is possible for any function with the attribute.

This callback attribute implementation is partially compatible with
clang's implementation. Its semantics, arguments and argument indexing style are
the same, but we represent an unknown argument position with 0
(precedent set by attributes such as 'format'), while clang uses -1 or '?'.
We use the index 1 for the 'this' pointer in member functions, clang
uses 0. We also allow for multiple callback attributes on the same function,
while clang only allows one.

The attribute is currently for GCC internal use only, thanks to the
space in its name.  Originally, it was supposed to be called
'callback' like its clang counterpart, but we cannot use this name, as
clang uses non-standard indexing style, leading to inconsistencies.  The
attribute will be introduced into the public API as 'gnu::callback_only'
in a future patch.

The attribute allows us to propagate constants into body functions of
OpenMP constructs. Currently, GCC won't propagate the value 'c' into the
OpenMP body in the following example:

int a[100];
void test(int c) {
#pragma omp parallel for
  for (int i = 0; i < c; i++) {
    if (!__builtin_constant_p(c)) {
      __builtin_abort();
    }
    a[i] = i;
  }
}
int main() {
  test(100);
  return a[5] - 5;
}

With this patch, the body function will get cloned and the constant 'c'
will get propagated.

Some functions may utilize the attribute's infrastructure without being
declared with it, for example GOMP_task.  These functions are special
cases and use the special case functions found in attr-callback.h.  Special
cases use the attribute under certain circumstances, for example
GOMP_task uses it when the copy function is not being used required.

gcc/ChangeLog:

	* Makefile.in: Add attr-callback.o to OBJS.
	* builtin-attrs.def (ATTR_CALLBACK): Callback attr identifier.
	(DEF_CALLBACK_ATTRIBUTE): Macro for callback attr creation.
	(GOMP): Attr for libgomp functions.
	(ATTR_CALLBACK_GOMP_LIST): ATTR_NOTHROW_LIST with GOMP callback
	attr added.
	* cgraph.cc (cgraph_add_edge_to_call_site_hash): Always hash the
	callback-carrying edge.
	(cgraph_node::get_edge): Always return the callback-carrying
	edge.
	(cgraph_edge::set_call_stmt): Add cascade for callback edges.
	(symbol_table::create_edge): Allow callback edges to share call
	stmts, initialize new flags.
	(cgraph_edge::make_callback): New method, derives a new callback
	edge.
	(cgraph_edge::get_callback_carrying_edge): New method.
	(cgraph_edge::first_callback_edge): Likewise.
	(cgraph_edge::next_callback_edge): Likewise.
	(cgraph_edge::purge_callback_edges): Likewise.
	(cgraph_edge::redirect_callee): When redirecting a callback
	edge, redirect its ref as well.
	(cgraph_edge::redirect_call_stmt_to_callee): Add callback edge
	redirection logic, set update_derived_edges to true hwne
	redirecting the carrying edge.
	(cgraph_node::remove_callers): Add cascade for callback edges.
	(cgraph_edge::dump_edge_flags): Print callback flags.
	(cgraph_node::verify_node): Add sanity checks for callback
	edges.
	* cgraph.h: Add new 1 bit flags and 16 bit callback_id to
	cgraph_edge class.
	* cgraphclones.cc (cgraph_edge::clone): Copy over callback data.
	* cif-code.def (CALLBACK_EDGE): Add CIF_CALLBACK_EDGE code.
	* ipa-cp.cc (purge_useless_callback_edges): New function,
	deletes callback edges when necessary.
	(ipcp_decision_stage): Call purge_useless_callback_edges.
	* ipa-fnsummary.cc (ipa_call_summary_t::duplicate): Add
	an exception for callback edges.
	(analyze_function_body): Copy over summary from carrying to
	callback edge.
	* ipa-inline-analysis.cc (do_estimate_growth_1): Skip callback
	edges when estimating growth.
	* ipa-inline-transform.cc (inline_transform): Add redirection
	cascade for callback edges.
	* ipa-param-manipulation.cc
	(drop_decl_attribute_if_params_changed_p): New function.
	(ipa_param_adjustments::build_new_function_type): Add
	args_modified out param.
	(ipa_param_adjustments::adjust_decl): Drop callback attrs when
	modifying args.
	* ipa-param-manipulation.h: Adjust decl of
	build_new_function_type.
	* ipa-prop.cc (ipa_duplicate_jump_function): Add decl.
	(init_callback_edge_summary): New function.
	(ipa_compute_jump_functions_for_edge): Add callback edge
	creation logic.
	* lto-cgraph.cc (lto_output_edge): Stream out callback data.
	(input_edge): Input callback data.
	* omp-builtins.def (BUILT_IN_GOMP_PARALLEL_LOOP_STATIC): Use new
	attr list.
	(BUILT_IN_GOMP_PARALLEL_LOOP_GUIDED): Likewise.
	(BUILT_IN_GOMP_PARALLEL_LOOP_NONMONOTONIC_DYNAMIC): Likewise.
	(BUILT_IN_GOMP_PARALLEL_LOOP_NONMONOTONIC_RUNTIME): Likewise.
	(BUILT_IN_GOMP_PARALLEL): Likewise.
	(BUILT_IN_GOMP_PARALLEL_SECTIONS): Likewise.
	(BUILT_IN_GOMP_TEAMS_REG): Likewise.
	* tree-core.h (ECF_CB_1_2): New constant for callback(1,2).
	* tree-inline.cc (copy_bb): Copy callback edges when copying the
	carrying edge.
	(redirect_all_calls): Redirect callback edges.
	* tree.cc (set_call_expr_flags): Create callback attr according
	to the ECF_CB flag.
	* attr-callback.cc: New file.
	* attr-callback.h: New file.

gcc/c-family/ChangeLog:

	* c-attribs.cc: Define callback attr.

gcc/fortran/ChangeLog:

	* f95-lang.cc (ATTR_CALLBACK_GOMP_LIST): New attr list
	corresponding to the list in builtin-attrs.def.

gcc/testsuite/ChangeLog:

	* gcc.dg/ipa/ipcp-cb-spec1.c: New test.
	* gcc.dg/ipa/ipcp-cb-spec2.c: New test.
	* gcc.dg/ipa/ipcp-cb1.c: New test.

Signed-off-by: Josef Melcr <jmelcr02@gmail.com>
2025-10-17 11:31:38 +02:00

150 lines
5.7 KiB
Modula-2

/* This file contains the definitions of the cgraph_inline_failed_t
enums used in GCC.
Copyright (C) 2008-2025 Free Software Foundation, Inc.
Contributed by Doug Kwan <dougkwan@google.com>
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/>. */
/* The format of this file is
DEFCIFCODE(code, string).
Where symbol is the enumeration name without the ``''.
The argument STRING is a explain the failure. Except for OK,
which is a NULL pointer. */
/* Inlining successful. This must be the first code. */
DEFCIFCODE(OK, CIF_FINAL_NORMAL, NULL)
/* Inlining failed for an unspecified reason. */
DEFCIFCODE(UNSPECIFIED, CIF_FINAL_ERROR, "")
/* Function has not be considered for inlining. This is the code for
functions that have not been rejected for inlining yet. */
DEFCIFCODE(FUNCTION_NOT_CONSIDERED, CIF_FINAL_NORMAL,
N_("function not considered for inlining"))
/* Caller is compiled with optimizations disabled. */
DEFCIFCODE(FUNCTION_NOT_OPTIMIZED, CIF_FINAL_ERROR,
N_("caller is not optimized"))
/* Inlining failed owing to unavailable function body. */
DEFCIFCODE(BODY_NOT_AVAILABLE, CIF_FINAL_ERROR,
N_("function body not available"))
/* Extern inline function that has been redefined. */
DEFCIFCODE(REDEFINED_EXTERN_INLINE, CIF_FINAL_ERROR,
N_("redefined extern inline functions are not considered for "
"inlining"))
/* Function is not inlinable. */
DEFCIFCODE(FUNCTION_NOT_INLINABLE, CIF_FINAL_ERROR,
N_("function not inlinable"))
/* Function is overwritable. */
DEFCIFCODE(OVERWRITABLE, CIF_FINAL_ERROR,
N_("function body can be overwritten at link time"))
/* Function is not an inlining candidate. */
DEFCIFCODE(FUNCTION_NOT_INLINE_CANDIDATE, CIF_FINAL_NORMAL,
N_("function not inline candidate"))
/* Inlining failed because of various limit parameters. */
DEFCIFCODE(LARGE_FUNCTION_GROWTH_LIMIT, CIF_FINAL_NORMAL,
N_("--param large-function-growth limit reached"))
DEFCIFCODE(LARGE_STACK_FRAME_GROWTH_LIMIT, CIF_FINAL_NORMAL,
N_("--param large-stack-frame-growth limit reached"))
DEFCIFCODE(MAX_INLINE_INSNS_SINGLE_LIMIT, CIF_FINAL_NORMAL,
N_("--param max-inline-insns-single limit reached"))
DEFCIFCODE(MAX_INLINE_INSNS_AUTO_LIMIT, CIF_FINAL_NORMAL,
N_("--param max-inline-insns-auto limit reached"))
DEFCIFCODE(INLINE_UNIT_GROWTH_LIMIT, CIF_FINAL_NORMAL,
N_("--param inline-unit-growth limit reached"))
/* Recursive inlining. */
DEFCIFCODE(RECURSIVE_INLINING, CIF_FINAL_NORMAL,
N_("recursive inlining"))
/* Call is unlikely. */
DEFCIFCODE(UNLIKELY_CALL, CIF_FINAL_NORMAL,
N_("call is unlikely and code size would grow"))
/* Call is considered never executed. */
DEFCIFCODE(NEVER_CALL, CIF_FINAL_NORMAL,
N_("call is considered never executed and code size would grow"))
/* Function is not declared as inline. */
DEFCIFCODE(NOT_DECLARED_INLINED, CIF_FINAL_NORMAL,
N_("function not declared inline and code size would grow"))
/* Caller and callee disagree on the arguments. */
DEFCIFCODE(LTO_MISMATCHED_DECLARATIONS, CIF_FINAL_ERROR,
N_("mismatched declarations during linktime optimization"))
/* Caller is variadic thunk. */
DEFCIFCODE(VARIADIC_THUNK, CIF_FINAL_ERROR,
N_("variadic thunk call"))
/* Call was originally indirect. */
DEFCIFCODE(ORIGINALLY_INDIRECT_CALL, CIF_FINAL_NORMAL,
N_("originally indirect function call not considered for inlining"))
/* Ths edge represents an indirect edge with a yet-undetermined callee . */
DEFCIFCODE(INDIRECT_UNKNOWN_CALL, CIF_FINAL_NORMAL,
N_("indirect function call with a yet undetermined callee"))
/* We can't inline different EH personalities together. */
DEFCIFCODE(EH_PERSONALITY, CIF_FINAL_ERROR,
N_("exception handling personality mismatch"))
/* We can't inline if the callee can throw non-call exceptions but the
caller cannot. */
DEFCIFCODE(NON_CALL_EXCEPTIONS, CIF_FINAL_ERROR,
N_("non-call exception handling mismatch"))
/* We can't inline because of mismatched target specific options. */
DEFCIFCODE(TARGET_OPTION_MISMATCH, CIF_FINAL_ERROR,
N_("target specific option mismatch"))
/* We can't inline because of mismatched optimization levels. */
DEFCIFCODE(OPTIMIZATION_MISMATCH, CIF_FINAL_ERROR,
N_("optimization level attribute mismatch"))
/* We can't inline because the callee refers to comdat-local symbols. */
DEFCIFCODE(USES_COMDAT_LOCAL, CIF_FINAL_NORMAL,
N_("callee refers to comdat-local symbols"))
/* We can't inline because of mismatched caller/callee
sanitizer attributes. */
DEFCIFCODE(SANITIZE_ATTRIBUTE_MISMATCH, CIF_FINAL_ERROR,
N_("sanitizer function attribute mismatch"))
/* We can't inline because the user requests only static functions
but the function has external linkage for live patching purpose. */
DEFCIFCODE(EXTERN_LIVE_ONLY_STATIC, CIF_FINAL_ERROR,
N_("function has external linkage when the user requests only"
" inlining static for live patching"))
/* We proved that the call is unreachable. */
DEFCIFCODE(UNREACHABLE, CIF_FINAL_ERROR,
N_("unreachable"))
/* Callback edges cannot be inlined, as the corresponding call
statement does not exist. */
DEFCIFCODE(CALLBACK_EDGE, CIF_FINAL_ERROR,
N_("callback edges cannot be inlined"))