Hi. I'm CCing gcc-patches ML and Jakub, who significantly helped me yesterday. The idea now is to have a driver search for the math header file. When it exists, Fortran FE loads the file (via new -fpre-include option).
I can confirm that e.g. roms_r CPU2017 benchmark utilizes couple of simd clones: $ grep simd *.optimized analytical.fppized.f90.229t.optimized: vect__77.555_90 = exp.simdclone.12 (vect__76.554_94); analytical.fppized.f90.229t.optimized: vect__322.866_1061 = sin.simdclone.4 (vect__321.865_1062); bulk_flux.fppized.f90.229t.optimized: vect__506.784_1887 = pow.simdclone.2 (vect__1057.783_1889, { 1.939999999999999946709294817992486059665679931640625e+0, 1.939999999999999946709294817992486059665679931640625e+0 }); gasdev.fppized.f90.229t.optimized: vect__66.139_93 = log.simdclone.0 (vect__65.138_94); lmd_swfrac.fppized.f90.229t.optimized: vect__84.60_182 = exp.simdclone.0 (vect__83.59_183); lmd_swfrac.fppized.f90.229t.optimized: vect__89.69_161 = exp.simdclone.0 (vect__88.68_162); marxin@marxinbox:~/Programming/cpu2017/benchspec/CPU/554.roms_r/build/build_peak_gcc7-m64.0000> grep simd *.optimized analytical.fppized.f90.229t.optimized: vect__77.555_90 = exp.simdclone.12 (vect__76.554_94); analytical.fppized.f90.229t.optimized: vect__322.866_1061 = sin.simdclone.4 (vect__321.865_1062); bulk_flux.fppized.f90.229t.optimized: vect__506.784_1887 = pow.simdclone.2 (vect__1057.783_1889, { 1.939999999999999946709294817992486059665679931640625e+0, 1.939999999999999946709294817992486059665679931640625e+0 }); gasdev.fppized.f90.229t.optimized: vect__66.139_93 = log.simdclone.0 (vect__65.138_94); lmd_swfrac.fppized.f90.229t.optimized: vect__84.60_182 = exp.simdclone.0 (vect__83.59_183); lmd_swfrac.fppized.f90.229t.optimized: vect__89.69_161 = exp.simdclone.0 (vect__88.68_162); and it also finishes successfully. Question I have is about default search locations for the header file. On my machine I can see: access("/home/marxin/bin/gcc2/lib64/gcc/x86_64-pc-linux-gnu/9.0.0/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/home/marxin/bin/gcc2/lib64/gcc/x86_64-pc-linux-gnu/9.0.0/../../../../x86_64-pc-linux-gnu/lib/x86_64-pc-linux-gnu/9.0.0/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/home/marxin/bin/gcc2/lib64/gcc/x86_64-pc-linux-gnu/9.0.0/../../../../x86_64-pc-linux-gnu/lib/../lib64/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/home/marxin/bin/gcc2/lib64/gcc/x86_64-pc-linux-gnu/9.0.0/../../../x86_64-pc-linux-gnu/9.0.0/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/home/marxin/bin/gcc2/lib64/gcc/x86_64-pc-linux-gnu/9.0.0/../../../../lib64/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/lib/x86_64-pc-linux-gnu/9.0.0/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/lib/../lib64/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/usr/lib/x86_64-pc-linux-gnu/9.0.0/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/usr/lib/../lib64/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/home/marxin/bin/gcc2/lib64/gcc/x86_64-pc-linux-gnu/9.0.0/../../../../x86_64-pc-linux-gnu/lib/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/home/marxin/bin/gcc2/lib64/gcc/x86_64-pc-linux-gnu/9.0.0/../../../math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/lib/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) access("/usr/lib/math-vector-fortran.h", R_OK) = -1 ENOENT (No such file or directory) Aren't these locations desired for libraries, instead of include locations? Thoughts? Thanks, Martin
>From 53579915be2f2566d2bbf8ba52175762b8cea7ec 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-14 Martin Liska <mli...@suse.cz> Jakub Jelinek <ja...@redhat.com> * config/gnu-user.h (TARGET_F951_NOSTDINC_OPTIONS): Define new macro. * gcc.c (find_fortran_header_file): New function. gcc/fortran/ChangeLog: 2018-11-14 Martin Liska <mli...@suse.cz> Jakub Jelinek <ja...@redhat.com> * decl.c (gfc_match_gcc_builtin): New function to find new !GCC attribute directive. * gfortran.h (gfc_adjust_builtins): Declre. * match.h (gfc_match_gcc_builtin): New function. * parse.c (decode_gcc_attribute): Parse "builtin" in GCC attributes. (parse_progunit): Modify builtins based on result of GCC builtin parsing. * scanner.c (load_file): Preinclude header if set by the flag_pre_include flag. * trans-intrinsic.c (add_simd_flag_for_built_in): New. (gfc_adjust_builtins): New. --- gcc/config/gnu-user.h | 3 +++ gcc/fortran/decl.c | 33 +++++++++++++++++++++++++ gcc/fortran/gfortran.h | 2 ++ gcc/fortran/lang-specs.h | 8 +++++- gcc/fortran/lang.opt | 4 +++ gcc/fortran/match.h | 1 + gcc/fortran/parse.c | 3 +++ gcc/fortran/scanner.c | 10 ++++++++ gcc/fortran/trans-intrinsic.c | 46 +++++++++++++++++++++++++++++++++++ gcc/gcc.c | 19 +++++++++++++++ 10 files changed, 128 insertions(+), 1 deletion(-) diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h index 5b48fb21514..f3ad7cf05fd 100644 --- 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)" diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 2b77d950abb..938c35c508f 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<const char *> 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 flags form: + + The parameter b is name of a middle-end built-in. + Flags are one of: + - omp-simd-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_name (builtin) != MATCH_YES) + return MATCH_ERROR; + + gfc_gobble_whitespace (); + if (gfc_match ("attributes") != MATCH_YES) + return MATCH_ERROR; + + gfc_gobble_whitespace (); + if (gfc_match ("omp_simd_notinbranch") != MATCH_YES) + return MATCH_ERROR; + + char *r = XNEWVEC (char, strlen (builtin) + 32); + sprintf (r, "__builtin_%s", builtin); + vectorized_builtins.safe_push (r); + + return MATCH_YES; +} diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index d8ef35d9d6c..bb7f4dd0c4b 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2763,6 +2763,7 @@ gfc_finalizer; bool gfc_in_match_data (void); match gfc_match_char_spec (gfc_typespec *); extern int directive_unroll; +extern vec<const char *> vectorized_builtins; /* Handling Parameterized Derived Types */ bool gfc_insert_kind_parameter_exprs (gfc_expr *); @@ -3501,5 +3502,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..6f940755801 100644 --- a/gcc/fortran/lang-specs.h +++ b/gcc/fortran/lang-specs.h @@ -32,8 +32,14 @@ #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_NOSTDINC_OPTIONS +#define TARGET_F951_NOSTDINC_OPTIONS +#endif + #define F951_OPTIONS "%(cc1_options) %{J*} \ - %{!nostdinc:-fintrinsic-modules-path finclude%s}\ + %{!nostdinc:-fintrinsic-modules-path finclude%s " \ + TARGET_F951_NOSTDINC_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..a9eb58cbf23 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 JoinedOrMissing 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..cf56a675a08 100644 --- a/gcc/fortran/scanner.c +++ b/gcc/fortran/scanner.c @@ -2365,6 +2365,16 @@ load_file (const char *realfilename, const char *displayedname, bool initial) } } + /* Make a guard to prevent recursive inclusion. */ + static bool preinclude_done = false; + if (!preinclude_done) + { + preinclude_done = true; + if (flag_pre_include != NULL && !load_file (flag_pre_include, NULL, + false)) + exit (FATAL_EXIT_CODE); + } + /* Preprocessed files have preprocessor lines added before the byte order mark, so first_line is not about the first line of the file but the first line that's not a preprocessor line. */ diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 4ae2b3252b5..40ff66663eb 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -597,7 +597,53 @@ 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. */ +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) == 0) + { + tree omp_clause = build_omp_clause (UNKNOWN_LOCATION, + OMP_CLAUSE_NOTINBRANCH); + DECL_ATTRIBUTES (fndecl) + = tree_cons (get_identifier ("omp declare simd"), + build_tree_list (NULL_TREE, omp_clause), + DECL_ATTRIBUTES (fndecl)); + return; + } +} + +/* 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..1b9370be1d4 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_header_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-header-file", find_fortran_header_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_header_file (int argc, const char **argv) +{ + if (argc != 2) + return NULL; + + const char *path = find_file (argv[1]); + if (path != argv[1]) + 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. -- 2.19.1