https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125327
Bug ID: 125327
Summary: Target option state can be lost when an optimization
attribute implicitly updates target options
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: Chris.Bazley at arm dot com
Target Milestone: ---
Created attachment 64464
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=64464&action=edit
A reproducer test that could be added to gcc/gcc/testsuite/gcc.target/powerpc/
If the optimize() attribute is not applied correctly, then the values of any
target-specific options already set by the target() attribute can be lost.
The bug is in similar handle_optimize_attribute functions that exist in the C
and D language front-ends. This function rebuilds the target options after
parsing optimization options, and replaces the current target option node if
rebuilding resulted in a fresh target option node. Any target options already
associated with the function being modified are not applied before parsing
optimization options, therefore they are lost if that function's target option
node is replaced.
The failing test case I observed was {{__attribute__ ((target ("+sve"),
optimize ("O2"))) }} in
gcc/gcc/testsuite/gcc.target/aarch64/sve/target_optimization-1.c
This existing test only fails if -O2 has a side-effect on the target-specific
options, which is not currently true for AArch64 but might be in future if we
add support for -munroll-only-small-loops.
The i386 definition of the target-specific option of the same name is:
munroll-only-small-loops
Target Var(ix86_unroll_only_small_loops) Init(0) Optimization
Enable conservative small loop unrolling.
whereas the rs6000 and s390 definitions are:
munroll-only-small-loops
Target Undocumented Var(unroll_only_small_loops) Init(0) Save
; Use conservative small loop unrolling.
Because the i386 definition does not have the "Save" tag, GCC does not "build
the cl_target_option structure to hold a copy of the option, add the functions
cl_target_option_save and cl_target_option_restore to save and restore the
options". See https://gcc.gnu.org/onlinedocs/gccint/Option-properties.html
build_target_option_node relies on cl_target_option_save to copy target
options. Without "Save", the value of unroll_only_small_loops is not copied to
the new node, therefore prev_target_node == target_node in
handle_optimize_attribute (unless some other option that is saved was changed
by applying the optimize attribute) and DECL_FUNCTION_SPECIFIC_TARGET (*node)
is not replaced.
The only options set implicitly by a default_options initializer resembling {
OPT_LEVELS_*, OPT_*, NULL, 1 } and which have both "Save" and "Target" set in
the relevant .opt file are:
- s390: mmvcle
- rs6000: munroll-only-small-loops
- s390: munroll-only-small-loops
s390 is a non-starter for writing a reproducer:
gcc/gcc/testsuite/gcc.target/s390/cjb.c:4:1: warning: ‘target’ attribute is not
supported on this machine [-Wattributes]
4 | void foo (char *d, const char *s) __attribute__ ((target ("mvcle")));
| ^~~~
The only reproducer I have managed to create is for IBM RS/6000 (PowerPC). This
reproducer should be compiled with -O1 -mcpu=power8 -mno-vsx.
The vector/scalar (VSX) instruction enablement flag associated with foo()
should be preserved when the optimization level is changed from 1 to 2, because
neither -mvsx nor -mno-vsx is implied by -O2; however, an unrelated
target-specific option, -munroll-only-small-loops, *is* implied by -O2, which
requires the function's target option node to be rebuilt. When that happens,
the existing value of the VSX flag is lost:
v2df __attribute__ ((target ("vsx"), optimize("O2")))
foo (double a, double b)
{
return (v2df){a, b};
}
The assembly language output from GCC should use the VSX instruction xxpermdi,
but it does not.