From: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
To: gcc-patches@gcc.gnu.org
Cc: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>,
Bernhard Reutner-Fischer <aldot@gcc.gnu.org>,
gfortran ML <fortran@gcc.gnu.org>
Subject: [PATCH 2/2] Fortran: add attribute target_clones
Date: Wed, 9 Nov 2022 20:02:25 +0100 [thread overview]
Message-ID: <20221109190225.96037-3-aldot@gcc.gnu.org> (raw)
In-Reply-To: <20221109190225.96037-1-aldot@gcc.gnu.org>
Hi!
Add support for attribute target_clones:
!GCC$ ATTRIBUTES target_clones("arch1", "arch3","default") :: mysubroutine
Bootstrapped and regtested on x86_64-unknown-linux with
--target_board=unix'{-m32,-m64}'.
OK for trunk?
gcc/fortran/ChangeLog:
* decl.cc: Include fold-const.h for size_int.
(gfc_match_gcc_attribute_args): New internal helper function.
(gfc_match_gcc_attributes): Handle target_clones.
* f95-lang.cc (struct attribute_spec): Add target and
target_clones entries.
* gfortran.h (ext_attr_id_t): Add EXT_ATTR_TARGET_CLONES.
(struct symbol_attribute): Add field ext_attr_args.
* trans-decl.cc (add_attributes_to_decl): Also add ext_attr_args
to the decl's attributes.
* gfortran.texi: Document attribute target_clones.
gcc/testsuite/ChangeLog:
* gfortran.dg/attr_target_clones-1.F90: New test.
Cc: gfortran ML <fortran@gcc.gnu.org>
---
gcc/fortran/decl.cc | 104 ++++++++++++++++++
gcc/fortran/f95-lang.cc | 4 +
gcc/fortran/gfortran.h | 2 +
gcc/fortran/gfortran.texi | 31 ++++++
gcc/fortran/trans-decl.cc | 3 +
.../gfortran.dg/attr_target_clones-1.F90 | 30 +++++
6 files changed, 174 insertions(+)
create mode 100644 gcc/testsuite/gfortran.dg/attr_target_clones-1.F90
diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 0f9b2ced4c2..3a619dbdd34 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "options.h"
#include "tree.h"
+#include "fold-const.h"
#include "gfortran.h"
#include "stringpool.h"
#include "match.h"
@@ -11709,6 +11710,96 @@ gfc_match_final_decl (void)
return MATCH_YES;
}
+/* Internal helper to parse attribute argument list.
+ If REQUIRE_STRING is true, then require a string.
+ If ALLOW_MULTIPLE is true, allow more than one arg.
+ If multiple arguments are passed, require braces around them.
+ Returns a tree_list of arguments or NULL_TREE. */
+static tree
+gfc_match_gcc_attribute_args (bool require_string, bool allow_multiple)
+{
+ tree attr_args = NULL_TREE, attr_arg;
+ char name[GFC_MAX_SYMBOL_LEN + 1];
+ unsigned pos = 0;
+ gfc_char_t c;
+
+ /* When we get here, we already parsed
+ !GCC$ ATTRIBUTES ATTRIBUTE_NAME
+ Now parse the arguments. These could be one of
+ "single_string_literal"
+ ( "str_literal_1" , "str_literal_2" )
+ */
+
+ gfc_gobble_whitespace ();
+
+ if (allow_multiple && gfc_match_char ('(') != MATCH_YES)
+ {
+ gfc_error ("expected '(' at %C");
+ return NULL_TREE;
+ }
+
+ if (require_string)
+ {
+ do {
+ if (pos)
+ {
+ if (!allow_multiple)
+ {
+ gfc_error ("surplus argument at %C");
+ return NULL_TREE;
+ }
+ gfc_next_ascii_char (); /* Consume the comma. */
+ }
+ pos = 0;
+ gfc_gobble_whitespace ();
+ unsigned char num_quotes = 0;
+ do {
+ c = gfc_next_char_literal (NONSTRING);
+ if (c == '"')
+ {
+ num_quotes++;
+ continue; /* Skip the quote */
+ }
+ name[pos++] = c;
+ if (pos >= GFC_MAX_SYMBOL_LEN)
+ {
+ gfc_error ("attribute argument truncated at %C");
+ return NULL_TREE;
+ }
+ } while (num_quotes % 2 && gfc_match_eos () != MATCH_YES);
+ if (pos < 1)
+ {
+ gfc_error ("expected argument at %C");
+ return NULL_TREE;
+ }
+ if (num_quotes != 2)
+ {
+ gfc_error ("invalid string literal at %C");
+ return NULL_TREE;
+ }
+ name[pos] = '\0'; /* Redundant wrt build_string. */
+ tree str = build_string (pos, name);
+ /* Compare with c-family/c-common.cc: fix_string_type. */
+ tree i_type = build_index_type (size_int (pos));
+ tree a_type = build_array_type (char_type_node, i_type);
+ TREE_TYPE (str) = a_type;
+ TREE_READONLY (str) = 1;
+ TREE_STATIC (str) = 1;
+ attr_arg = build_tree_list (NULL_TREE, str);
+ attr_args = chainon (attr_args, attr_arg);
+
+ gfc_gobble_whitespace ();
+ } while (gfc_peek_ascii_char () == ',');
+ }
+
+ if (allow_multiple && gfc_match_char (')') != MATCH_YES)
+ {
+ gfc_error ("expected ')' at %C");
+ return NULL_TREE;
+ }
+
+ return attr_args;
+}
const ext_attr_t ext_attr_list[] = {
{ "dllimport", EXT_ATTR_DLLIMPORT, "dllimport" },
@@ -11718,6 +11809,7 @@ const ext_attr_t ext_attr_list[] = {
{ "fastcall", EXT_ATTR_FASTCALL, "fastcall" },
{ "no_arg_check", EXT_ATTR_NO_ARG_CHECK, NULL },
{ "deprecated", EXT_ATTR_DEPRECATED, NULL },
+ { "target_clones",EXT_ATTR_TARGET_CLONES,NULL },
{ NULL, EXT_ATTR_LAST, NULL }
};
@@ -11743,6 +11835,7 @@ gfc_match_gcc_attributes (void)
unsigned id;
gfc_symbol *sym;
match m;
+ tree attr_args = NULL_TREE;
gfc_clear_attr (&attr);
for(;;)
@@ -11761,6 +11854,15 @@ gfc_match_gcc_attributes (void)
gfc_error ("Unknown attribute in !GCC$ ATTRIBUTES statement at %C");
return MATCH_ERROR;
}
+ else if (id == EXT_ATTR_TARGET_CLONES)
+ {
+ attr_args
+ = gfc_match_gcc_attribute_args(true, true);
+ if (attr_args != NULL_TREE)
+ attr.ext_attr_args
+ = chainon (attr.ext_attr_args,
+ build_tree_list (get_identifier (name), attr_args));
+ }
if (!gfc_add_ext_attribute (&attr, (ext_attr_id_t)id, &gfc_current_locus))
return MATCH_ERROR;
@@ -11793,6 +11895,8 @@ gfc_match_gcc_attributes (void)
return MATCH_ERROR;
sym->attr.ext_attr |= attr.ext_attr;
+ sym->attr.ext_attr_args
+ = chainon (sym->attr.ext_attr_args, attr.ext_attr_args);
if (gfc_match_eos () == MATCH_YES)
break;
diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc
index a6750bea787..7154568aec5 100644
--- a/gcc/fortran/f95-lang.cc
+++ b/gcc/fortran/f95-lang.cc
@@ -97,6 +97,10 @@ static const struct attribute_spec gfc_attribute_table[] =
gfc_handle_omp_declare_target_attribute, NULL },
{ "oacc function", 0, -1, true, false, false, false,
gfc_handle_omp_declare_target_attribute, NULL },
+ { "target", 1, -1, true, false, false, false,
+ gfc_handle_omp_declare_target_attribute, NULL },
+ { "target_clones", 1, -1, true, false, false, false,
+ gfc_handle_omp_declare_target_attribute, NULL },
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
};
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 6bd8800ecf8..ce0cb61e647 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -838,6 +838,7 @@ typedef enum
EXT_ATTR_FASTCALL,
EXT_ATTR_NO_ARG_CHECK,
EXT_ATTR_DEPRECATED,
+ EXT_ATTR_TARGET_CLONES,
EXT_ATTR_LAST, EXT_ATTR_NUM = EXT_ATTR_LAST
}
ext_attr_id_t;
@@ -1009,6 +1010,7 @@ typedef struct
/* Attributes set by compiler extensions (!GCC$ ATTRIBUTES). */
unsigned ext_attr:EXT_ATTR_NUM;
+ tree ext_attr_args;
/* The namespace where the attribute has been set. */
struct gfc_namespace *volatile_ns, *asynchronous_ns;
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 4b4ecd528a7..06e4c8c00a1 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -3248,6 +3248,37 @@ deprecated procedure, variable or parameter; the warning can be suppressed
with @option{-Wno-deprecated-declarations}.
@end itemize
+@node target_clones (@var{options})
+
+Procedures can be annotated with a @code{target_clones} attribute to
+instruct the compiler to emit multiple versions of the procedure, each
+compiled with different target options in addition to those specified on
+the command line. The calling code remains exactly the same.
+Please refer to
+@ref{Top,,Common Function Attributes,gcc,Using the GNU Compiler Collection (GCC)}
+for details about the respective attribute.
+
+For example,
+
+@smallexample
+module mymod
+contains
+ subroutine sub1
+!GCC$ ATTRIBUTES target_clones("avx", "sse", "default") :: sub1
+ ! your code here
+ end
+end module mymod
+@end smallexample
+or,
+@smallexample
+module mymod
+contains
+ subroutine sub1
+!GCC$ ATTRIBUTES target_clones("power10","power9","power8","power7","default") :: sub1
+ ! your code here will be optimized for several PPC target architectures
+ end
+end module mymod
+@end smallexample
The attributes are specified using the syntax
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 63515b9072a..24cbd4cda28 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -1447,6 +1447,9 @@ add_attributes_to_decl (symbol_attribute sym_attr, tree list)
NULL_TREE);
list = chainon (list, attr);
}
+ /* Add attribute args. */
+ if (sym_attr.ext_attr_args != NULL_TREE)
+ list = chainon (list, sym_attr.ext_attr_args);
tree clauses = NULL_TREE;
diff --git a/gcc/testsuite/gfortran.dg/attr_target_clones-1.F90 b/gcc/testsuite/gfortran.dg/attr_target_clones-1.F90
new file mode 100644
index 00000000000..724e58021fa
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/attr_target_clones-1.F90
@@ -0,0 +1,30 @@
+! { dg-require-ifunc "" }
+! { dg-options "-O1" }
+! { dg-additional-options "-fdump-tree-optimized" }
+! It seems arch defines are not defined?!
+! See fortran.cpp FIXME: Pandora's Box
+! Ok, so enterprise-level bugfix:
+! { dg-additional-options "-D__i686__=1" { target { i?86-*-* } } }
+! { dg-additional-options "-D__x86_64__=1" { target { x86_64-*-* } } }
+! { dg-additional-options "-D__powerpc__=1" { target { powerpc*-*-* } } }
+! { dg-skip-if "test not yet implemented for target" { ! {i?86-*-* x86_64-*-* powerpc*-*-*} } }
+! Test __attribute__ ((target_clones ("foo", "bar")))
+!
+module m
+ implicit none
+contains
+ subroutine sub1()
+#if defined __i686__ || defined __x86_64__
+!GCC$ ATTRIBUTES target_clones("avx", "sse","default") :: sub1
+#elif defined __powerpc__
+!GCC$ ATTRIBUTES target_clones("power10", "power9","default") :: sub1
+#endif
+ print *, 4321
+ end
+end module m
+! { dg-final { scan-tree-dump-times {(?n)void \* __m_MOD_sub1\.resolver \(\)} 1 "optimized" } }
+! { dg-final { scan-tree-dump-times {(?n)void __m_MOD_sub1\.(?:avx|power10) \(\)} 1 "optimized" } }
+! { dg-final { scan-tree-dump-times {(?n)void __m_MOD_sub1\.(?:sse|power9) \(\)} 1 "optimized" } }
+! { dg-final { scan-tree-dump-times {(?n)void sub1 \(\)} 1 "optimized" } }
+!! and a non-assembly hint on the ifunc
+! { dg-final { scan-tree-dump-times {Function sub1 \(__m_MOD_sub1\.default,} 1 "optimized" } }
--
2.38.1
next prev parent reply other threads:[~2022-11-09 19:02 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-09 19:02 [PATCH 0/2] " Bernhard Reutner-Fischer
2022-11-09 19:02 ` [PATCH 1/2] symtab: also change RTL decl name Bernhard Reutner-Fischer
2022-11-17 8:02 ` Bernhard Reutner-Fischer
2022-11-21 18:24 ` Mikael Morin
2022-11-21 19:02 ` Jan Hubicka
2022-11-21 19:47 ` Bernhard Reutner-Fischer
2022-11-22 11:54 ` Jan Hubicka
2023-02-19 2:29 ` Bernhard Reutner-Fischer
2023-02-19 2:49 ` Bernhard Reutner-Fischer
2022-11-09 19:02 ` Bernhard Reutner-Fischer [this message]
2022-11-21 19:13 ` [PATCH 2/2] Fortran: add attribute target_clones Mikael Morin
2022-11-21 22:26 ` Bernhard Reutner-Fischer
2022-11-22 13:17 ` Mikael Morin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221109190225.96037-3-aldot@gcc.gnu.org \
--to=rep.dot.nop@gmail.com \
--cc=aldot@gcc.gnu.org \
--cc=fortran@gcc.gnu.org \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).