Recently I tried to set a function's target attribute conditionally based on template parameters, eg.:
template<bool enable_sse> [[gnu::target (enable_sse ? "sse" : "")]] void func () { /* ... */ } I then discovered that this is currently not possible. This small patch resolves that. A possible alternative solution is to do this globally, eg. in decl_attributes. But doing so would trigger empty-string warnings from handle_target_attribute, and I don't know how safe it is to remove that. There likely isn't much use for this with other attributes, anyway. 2022-10-17 Jan W. Jagersma <jwjager...@gmail.com> gcc/ChangeLog: * config/i386/i386-options.cc (ix86_valid_target_attribute_inner_p): Dereference args string from ADDR_EXPR. gcc/testsuite/ChangeLog: * g++.target/i386/target-attr-conditional.C: New test. --- gcc/config/i386/i386-options.cc | 9 ++++ .../g++.target/i386/target-attr-conditional.C | 53 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 gcc/testsuite/g++.target/i386/target-attr-conditional.C diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc index acb2291e70f..915f3b0c1f0 100644 --- a/gcc/config/i386/i386-options.cc +++ b/gcc/config/i386/i386-options.cc @@ -1123,6 +1123,15 @@ ix86_valid_target_attribute_inner_p (tree fndecl, tree args, char *p_strings[], = fndecl == NULL ? UNKNOWN_LOCATION : DECL_SOURCE_LOCATION (fndecl); const char *attr_name = target_clone_attr ? "target_clone" : "target"; + args = tree_strip_nop_conversions (args); + + if (TREE_CODE (args) == ADDR_EXPR) + { + /* Attribute string is given by a constexpr function or conditional + expression. Dereference ADDR_EXPR, operand should be a STRING_CST. */ + args = TREE_OPERAND (args, 0); + } + /* If this is a list, recurse to get the options. */ if (TREE_CODE (args) == TREE_LIST) { diff --git a/gcc/testsuite/g++.target/i386/target-attr-conditional.C b/gcc/testsuite/g++.target/i386/target-attr-conditional.C new file mode 100644 index 00000000000..2d418ed90bf --- /dev/null +++ b/gcc/testsuite/g++.target/i386/target-attr-conditional.C @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-psabi -m32 -march=i386 -std=c++20" } */ + +#pragma GCC push_options +#pragma GCC target("sse") + +typedef int __m64 __attribute__ ((__vector_size__ (8), __may_alias__)); +typedef short __v4hi __attribute__ ((__vector_size__ (8))); + +extern __inline int __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_extract_pi16 (__m64 const __A, int const __N) +{ + return (unsigned short) __builtin_ia32_vec_ext_v4hi ((__v4hi)__A, __N); +} + +#pragma GCC pop_options + +consteval const char* +target_string (bool enable_sse) +{ + return enable_sse ? "sse" : ""; +} + +// Via consteval function +template<bool enable_sse> +[[gnu::target (target_string (enable_sse))]] +int +extract1 (__m64 const src) +{ + if constexpr (enable_sse) + return _mm_extract_pi16 (src, 0); + else + return reinterpret_cast<__v4hi>(src)[1]; +} + +// Via ternary operator +template<bool enable_sse> +[[gnu::target (enable_sse ? "sse" : "")]] +int +extract2 (__m64 const src) +{ + if constexpr (enable_sse) + return _mm_extract_pi16 (src, 2); + else + return reinterpret_cast<__v4hi>(src)[3]; +} + +int +test (__m64 const src) +{ + return extract1<true>(src) + extract1<false>(src) + + extract2<true>(src) + extract2<false>(src); +} -- 2.35.1