On Sun, Oct 19, 2025 at 2:27 PM H.J. Lu <[email protected]> wrote:
>
> On Fri, Oct 17, 2025 at 5:40 PM Josef Melcr <[email protected]> wrote:
> >
> > Hi,
> > I pushed the patched below to master. It is largely the same as the v5
> > (link: https://gcc.gnu.org/pipermail/gcc-patches/2025-October/697470.html),
> > but I took out all the oacc bits, as they did not apply (discussed in
> > https://gcc.gnu.org/pipermail/gcc-patches/2025-October/697527.html).
> >
> > ==========
> >
> > 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.
>
> These run-time tests should be moved to libgomp to avoid
>
> xgcc: fatal error: cannot read spec file 'libgomp.spec': No such file
> or directory
> compilation terminated.
> compiler exited with status 1
> FAIL: gcc.dg/ipa/ipcp-cb1.c (test for excess errors)
No what Josef is doing is correct.
The testcases have already:
/* { dg-require-effective-target fopenmp } */
That is how gcc.dg/gomp/gomp.exp and others handles this already.
e.g. c-c++-common/gomp/assume-3.c c-c++-common/gomp/pr60823-2.c
gcc.dg/gomp/pr114075.c etc.
target-supports.exp has:
```
proc check_effective_target_fopenmp {} {
# nvptx/amdgcn can be built with the device-side bits of libgomp, but it
# does not make sense to test it as an openmp host.
if [istarget nvptx-*-*] { return 0 }
if [istarget amdgcn-*-*] { return 0 }
return [check_no_compiler_messages fopenmp object {
void foo (void) { }
} "-fopenmp"]
}
```
I am not sure why this is not working for you. Unless the other
testcases are failing in a similar way.
>
> --
> H.J.