On 11/15/18 9:54 PM, Jakub Jelinek wrote: > On Thu, Nov 15, 2018 at 08:40:13PM +0100, Bernhard Reutner-Fischer wrote: >> On 14 November 2018 12:35:27 CET, Jakub Jelinek <ja...@redhat.com> wrote: >> >>>> --- a/gcc/config/gnu-user.h >>>> +++ b/gcc/config/gnu-user.h >>>> @@ -170,3 +170,6 @@ see the files COPYING3 and COPYING.RUNTIME >>> respectively. If not, see >>>> LD_STATIC_OPTION " --whole-archive -llsan --no-whole-archive " \ >>>> LD_DYNAMIC_OPTION "}}%{!static-liblsan:-llsan}" >>>> #endif >>>> + >>>> +#undef TARGET_F951_NOSTDINC_OPTIONS >>>> +#define TARGET_F951_NOSTDINC_OPTIONS >>> "%:fortran-header-file(-fpre-include= math-vector-fortran.h)" >>> >>> Too long line, use some \s to split it up. >>> >> >> Can we use plain -include like in C? > > Wouldn't that be confusing whether it is included in preprocessor only or if > it is included as a magic fortran include line at the beginning? > > Jakub >
Agree with that, I'm sending updated version of the patch. It's tested on x86_64-linux-gnu, where it survives regression tests and bootstraps. I hope I addressed all notes that Jakub provided. Thanks, Martin
>From 958b29507153e923e08f79e754ed3e2e95bbec91 Mon Sep 17 00:00:00 2001 From: marxin <mli...@suse.cz> Date: Wed, 7 Nov 2018 12:41:19 +0100 Subject: [PATCH] Support simd function declarations via a pre-include. gcc/ChangeLog: 2018-11-15 Martin Liska <mli...@suse.cz> * config/gnu-user.h (TARGET_F951_OPTIONS): New. * gcc.c (find_fortran_preinclude_file): New function to handle Fortran pre-include. gcc/fortran/ChangeLog: 2018-11-15 Martin Liska <mli...@suse.cz> * decl.c (gfc_match_gcc_builtin): New function. * gfortran.h (struct vect_builtin_tuple): New. (gfc_adjust_builtins): Likewise. * lang-specs.h (TARGET_F951_OPTIONS): New. (F951_OPTIONS): Use it. * lang.opt: Add new option -fpre-include. * match.h (gfc_match_gcc_builtin): Declare new function. * parse.c (decode_gcc_attribute): Handle builtin. (parse_progunit): Call gfc_adjust_builtins. * scanner.c (gfc_new_file): Load pre-included header file when provided. * trans-intrinsic.c (add_simd_flag_for_built_in): New. (gfc_adjust_builtins): Likewise. gcc/testsuite/ChangeLog: 2018-11-15 Martin Liska <mli...@suse.cz> * gfortran.dg/simd-builtins-1.f90: New test. * gfortran.dg/simd-builtins-1.h: New test. * gfortran.dg/simd-builtins-2.f90: New test. --- gcc/config/gnu-user.h | 4 ++ gcc/fortran/decl.c | 33 ++++++++++++ gcc/fortran/gfortran.h | 13 +++++ gcc/fortran/lang-specs.h | 10 +++- gcc/fortran/lang.opt | 4 ++ gcc/fortran/match.h | 1 + gcc/fortran/parse.c | 3 ++ gcc/fortran/scanner.c | 4 ++ gcc/fortran/trans-intrinsic.c | 54 +++++++++++++++++++ gcc/gcc.c | 19 +++++++ gcc/testsuite/gfortran.dg/simd-builtins-1.f90 | 19 +++++++ gcc/testsuite/gfortran.dg/simd-builtins-1.h | 4 ++ gcc/testsuite/gfortran.dg/simd-builtins-2.f90 | 20 +++++++ 13 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/simd-builtins-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/simd-builtins-1.h create mode 100644 gcc/testsuite/gfortran.dg/simd-builtins-2.f90 diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h index 5b48fb21514..d0acfed5116 100644 --- a/gcc/config/gnu-user.h +++ b/gcc/config/gnu-user.h @@ -170,3 +170,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see LD_STATIC_OPTION " --whole-archive -llsan --no-whole-archive " \ LD_DYNAMIC_OPTION "}}%{!static-liblsan:-llsan}" #endif + +#undef TARGET_F951_OPTIONS +#define TARGET_F951_OPTIONS "%{!nostdinc:\ + %:fortran-preinclude-file(-fpre-include= math-vector-fortran.h)}" diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 2b77d950abb..caac9d65b9f 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -98,6 +98,9 @@ bool gfc_matching_function; /* Set upon parsing a !GCC$ unroll n directive for use in the next loop. */ int directive_unroll = -1; +/* List middle-end built-ins that should be vectorized. */ +vec<vect_builtin_tuple> vectorized_builtins; + /* If a kind expression of a component of a parameterized derived type is parameterized, temporarily store the expression here. */ static gfc_expr *saved_kind_expr = NULL; @@ -11243,3 +11246,33 @@ gfc_match_gcc_unroll (void) gfc_error ("Syntax error in !GCC$ UNROLL directive at %C"); return MATCH_ERROR; } + +/* Match a !GCC$ builtin (b) attributes simd flags form: + + The parameter b is name of a middle-end built-in. + Flags are one of: + - (empty) + - inbranch + - notinbranch + + When we come here, we have already matched the !GCC$ builtin string. */ +match +gfc_match_gcc_builtin (void) +{ + char builtin[GFC_MAX_SYMBOL_LEN + 1]; + + if (gfc_match (" (%n) attributes simd", builtin) != MATCH_YES) + return MATCH_ERROR; + + int builtin_kind = 0; + if (gfc_match (" (notinbranch)") == MATCH_YES) + builtin_kind = -1; + else if (gfc_match (" (inbranch)") == MATCH_YES) + builtin_kind = 1; + + char *r = XNEWVEC (char, strlen (builtin) + 32); + sprintf (r, "__builtin_%s", builtin); + vectorized_builtins.safe_push (vect_builtin_tuple (r, builtin_kind)); + + return MATCH_YES; +} diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index d8ef35d9d6c..093bb6d1a64 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2764,6 +2764,18 @@ bool gfc_in_match_data (void); match gfc_match_char_spec (gfc_typespec *); extern int directive_unroll; +/* Tuple for parsing of vectorized built-ins. */ +struct vect_builtin_tuple +{ + vect_builtin_tuple (const char *n, int t): name (n), simd_type (t) + {} + + const char *name; + int simd_type; +}; + +extern vec<vect_builtin_tuple> vectorized_builtins; + /* Handling Parameterized Derived Types */ bool gfc_insert_kind_parameter_exprs (gfc_expr *); bool gfc_insert_parameter_exprs (gfc_expr *, gfc_actual_arglist *); @@ -3501,5 +3513,6 @@ bool gfc_is_reallocatable_lhs (gfc_expr *); /* trans-decl.c */ void finish_oacc_declare (gfc_namespace *, gfc_symbol *, bool); +void gfc_adjust_builtins (void); #endif /* GCC_GFORTRAN_H */ diff --git a/gcc/fortran/lang-specs.h b/gcc/fortran/lang-specs.h index c3ab9700ea7..61a9118d531 100644 --- a/gcc/fortran/lang-specs.h +++ b/gcc/fortran/lang-specs.h @@ -32,9 +32,15 @@ #define F951_CPP_OPTIONS "%{!nocpp: -cpp=%g.f90 %{E} %(cpp_unique_options) \ %{E|M|MM:%(cpp_debug_options) " CPP_ONLY_OPTIONS \ " -fsyntax-only};: " CPP_FORWARD_OPTIONS "}" + +#ifndef TARGET_F951_OPTIONS +#define TARGET_F951_OPTIONS +#endif + #define F951_OPTIONS "%(cc1_options) %{J*} \ - %{!nostdinc:-fintrinsic-modules-path finclude%s}\ - %{!fsyntax-only:%(invoke_as)}" + %{!nostdinc:-fintrinsic-modules-path finclude%s}" \ + TARGET_F951_OPTIONS \ + "%{!fsyntax-only:%(invoke_as)}" #define F951_SOURCE_FORM "%{!ffree-form:-ffixed-form}" diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt index 2b7f2903761..c86b2623fac 100644 --- a/gcc/fortran/lang.opt +++ b/gcc/fortran/lang.opt @@ -662,6 +662,10 @@ fprotect-parens Fortran Var(flag_protect_parens) Init(-1) Protect parentheses in expressions. +fpre-include= +Fortran RejectNegative Joined Var(flag_pre_include) Undocumented +Path to header file that should be pre-included before each compilation unit. + frange-check Fortran Var(flag_range_check) Init(1) Enable range checking during compilation. diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h index 418542bd5a6..f25ed860c06 100644 --- a/gcc/fortran/match.h +++ b/gcc/fortran/match.h @@ -247,6 +247,7 @@ match gfc_match_dimension (void); match gfc_match_external (void); match gfc_match_gcc_attributes (void); match gfc_match_gcc_unroll (void); +match gfc_match_gcc_builtin (void); match gfc_match_import (void); match gfc_match_intent (void); match gfc_match_intrinsic (void); diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 13cc6f5fccd..56d0d050bc3 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -1072,6 +1072,7 @@ decode_gcc_attribute (void) match ("attributes", gfc_match_gcc_attributes, ST_ATTR_DECL); match ("unroll", gfc_match_gcc_unroll, ST_NONE); + match ("builtin", gfc_match_gcc_builtin, ST_NONE); /* All else has failed, so give up. See if any of the matchers has stored an error message of some sort. */ @@ -5663,6 +5664,8 @@ parse_progunit (gfc_statement st) gfc_state_data *p; int n; + gfc_adjust_builtins (); + if (gfc_new_block && gfc_new_block->abr_modproc_decl && gfc_new_block->attr.function) diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c index 55d6dafdb5d..4e500f88174 100644 --- a/gcc/fortran/scanner.c +++ b/gcc/fortran/scanner.c @@ -2428,6 +2428,10 @@ gfc_new_file (void) { bool result; + if (flag_pre_include != NULL + && !load_file (flag_pre_include, NULL, false)) + exit (FATAL_EXIT_CODE); + if (gfc_cpp_enabled ()) { result = gfc_cpp_preprocess (gfc_source_file); diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 4ae2b3252b5..b307a7db1ed 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -597,7 +597,61 @@ define_quad_builtin (const char *name, tree type, bool is_const) return fndecl; } +/* Add SIMD attribute for FNDECL built-in if the built-in + name is in VECTORIZED_BUILTINS. */ +#include "print-tree.h" +static void +add_simd_flag_for_built_in (tree fndecl) +{ + if (fndecl == NULL_TREE) + return; + + const char *name = IDENTIFIER_POINTER (DECL_NAME (fndecl)); + for (unsigned i = 0; i < vectorized_builtins.length (); i++) + if (strcmp (vectorized_builtins[i].name, name) == 0) + { + int simd_type = vectorized_builtins[i].simd_type; + tree omp_clause = NULL_TREE; + if (simd_type == 0) + ; /* No SIMD clause. */ + else + { + omp_clause_code code + = (simd_type == 1 ? OMP_CLAUSE_INBRANCH : OMP_CLAUSE_NOTINBRANCH); + omp_clause = build_omp_clause (UNKNOWN_LOCATION, code); + omp_clause = build_tree_list (NULL_TREE, omp_clause); + } + + DECL_ATTRIBUTES (fndecl) + = tree_cons (get_identifier ("omp declare simd"), omp_clause, + DECL_ATTRIBUTES (fndecl)); + } +} +/* Set SIMD attribute to all built-in functions that are mentioned + in vectorized_builtins vector. */ + +void +gfc_adjust_builtins (void) +{ + gfc_intrinsic_map_t *m; + for (m = gfc_intrinsic_map; + m->id != GFC_ISYM_NONE || m->double_built_in != END_BUILTINS; m++) + { + add_simd_flag_for_built_in (m->real4_decl); + add_simd_flag_for_built_in (m->complex4_decl); + add_simd_flag_for_built_in (m->real8_decl); + add_simd_flag_for_built_in (m->complex8_decl); + add_simd_flag_for_built_in (m->real10_decl); + add_simd_flag_for_built_in (m->complex10_decl); + add_simd_flag_for_built_in (m->real16_decl); + add_simd_flag_for_built_in (m->complex16_decl); + add_simd_flag_for_built_in (m->real16_decl); + add_simd_flag_for_built_in (m->complex16_decl); + } + + vectorized_builtins.truncate (0); +} /* Initialize function decls for library functions. The external functions are created as required. Builtin functions are added here. */ diff --git a/gcc/gcc.c b/gcc/gcc.c index c0d17eb4f1b..911dc49cdd2 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -408,6 +408,7 @@ static const char *pass_through_libs_spec_func (int, const char **); static const char *replace_extension_spec_func (int, const char **); static const char *greater_than_spec_func (int, const char **); static const char *debug_level_greater_than_spec_func (int, const char **); +static const char *find_fortran_preinclude_file (int, const char **); static char *convert_white_space (char *); /* The Specs Language @@ -1647,6 +1648,7 @@ static const struct spec_function static_spec_functions[] = { "replace-extension", replace_extension_spec_func }, { "gt", greater_than_spec_func }, { "debug-level-gt", debug_level_greater_than_spec_func }, + { "fortran-preinclude-file", find_fortran_preinclude_file}, #ifdef EXTRA_SPEC_FUNCTIONS EXTRA_SPEC_FUNCTIONS #endif @@ -9889,6 +9891,23 @@ debug_level_greater_than_spec_func (int argc, const char **argv) return NULL; } +/* The function takes 2 arguments: OPTION name and file name. + When the FILE is found by find_file, return OPTION=path_to_file. */ + +static const char * +find_fortran_preinclude_file (int argc, const char **argv) +{ + if (argc != 2) + return NULL; + + const char *path = find_a_file (&include_prefixes, argv[1], R_OK, true); + if (path != NULL) + return concat (argv[0], path, NULL); + + return NULL; +} + + /* Insert backslash before spaces in ORIG (usually a file path), to avoid being broken by spec parser. diff --git a/gcc/testsuite/gfortran.dg/simd-builtins-1.f90 b/gcc/testsuite/gfortran.dg/simd-builtins-1.f90 new file mode 100644 index 00000000000..e52f8a2db1a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/simd-builtins-1.f90 @@ -0,0 +1,19 @@ +! { dg-do compile { target x86_64-*-linux* } } +! { dg-additional-options "-nostdinc -Ofast -fpre-include=simd-builtins-1.h -fdump-tree-optimized" } + +program test_overloaded_intrinsic + real(4) :: x4(3200), y4(3200) + real(8) :: x8(3200), y8(3200) + + ! this should be using simd clone + y4 = sin(x4) + print *, y4 + + ! this should not be using simd clone + y4 = sin(x8) + print *, y8 +end + +! { dg-final { scan-tree-dump "sinf.simdclone" "optimized" } } */ +! { dg-final { scan-tree-dump "__builtin_sin" "optimized" } } */ +! { dg-final { scan-assembler "call.*_ZGVbN4v_sinf" } } diff --git a/gcc/testsuite/gfortran.dg/simd-builtins-1.h b/gcc/testsuite/gfortran.dg/simd-builtins-1.h new file mode 100644 index 00000000000..c1b9f46b9ba --- /dev/null +++ b/gcc/testsuite/gfortran.dg/simd-builtins-1.h @@ -0,0 +1,4 @@ +!GCC$ builtin (sinf) attributes simd +!GCC$ builtin (sinf) attributes simd (inbranch) +!GCC$ builtin (sinf) attributes simd (notinbranch) +!GCC$ builtin (cosf) attributes simd (notinbranch) diff --git a/gcc/testsuite/gfortran.dg/simd-builtins-2.f90 b/gcc/testsuite/gfortran.dg/simd-builtins-2.f90 new file mode 100644 index 00000000000..bca0ce4be94 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/simd-builtins-2.f90 @@ -0,0 +1,20 @@ +! { dg-do compile { target x86_64-*-linux* } } +! { dg-additional-options "-nostdinc -Ofast -fdump-tree-optimized" } + +program test_overloaded_intrinsic + real(4) :: x4(3200), y4(3200) + real(8) :: x8(3200), y8(3200) + + ! this should be using simd clone + y4 = sin(x4) + print *, y4 + + ! this should not be using simd clone + y4 = sin(x8) + print *, y8 +end + +! { dg-final { scan-tree-dump "__builtin_sinf" "optimized" } } */ +! { dg-final { scan-tree-dump "__builtin_sin" "optimized" } } */ +! { dg-final { scan-tree-dump-not "simdclone" "optimized" } } */ +! { dg-final { scan-assembler-not "call.*_ZGVbN4v_sinf" } } -- 2.19.1