diff -Nurp a/gcc/common.opt b/gcc/common.opt --- a/gcc/common.opt 2021-02-18 21:22:07.216000000 +0800 +++ b/gcc/common.opt 2021-02-19 16:04:17.876000000 +0800 @@ -1506,6 +1506,32 @@ ffp-int-builtin-inexact Common Report Var(flag_fp_int_builtin_inexact) Init(1) Optimization Allow built-in functions ceil, floor, round, trunc to raise \"inexact\" exceptions. +fftz +Common Report Var(flag_ftz) Optimization +Control fpcr register for flush to zero. + +fp-model= +Common Joined RejectNegative Enum(fp_model) Var(flag_fp_model) Init(FP_MODEL_NORMAL) Optimization +-fp-model=[normal|fast|precise|except|strict] Perform floating-point precision control. + +Enum +Name(fp_model) Type(enum fp_model) UnknownError(unknown floating point precision model %qs) + +EnumValue +Enum(fp_model) String(normal) Value(FP_MODEL_NORMAL) + +EnumValue +Enum(fp_model) String(fast) Value(FP_MODEL_FAST) + +EnumValue +Enum(fp_model) String(precise) Value(FP_MODEL_PRECISE) + +EnumValue +Enum(fp_model) String(except) Value(FP_MODEL_EXCEPT) + +EnumValue +Enum(fp_model) String(strict) Value(FP_MODEL_STRICT) + ; Nonzero means don't put addresses of constant functions in registers. ; Used for compiling the Unix kernel, where strange substitutions are ; done on the assembly output. diff -Nurp a/gcc/config/aarch64/aarch64-linux.h b/gcc/config/aarch64/aarch64-linux.h --- a/gcc/config/aarch64/aarch64-linux.h 2021-02-18 21:22:07.220000000 +0800 +++ b/gcc/config/aarch64/aarch64-linux.h 2021-02-18 21:23:55.932000000 +0800 @@ -50,7 +50,8 @@ #define LINK_SPEC LINUX_TARGET_LINK_SPEC AARCH64_ERRATA_LINK_SPEC #define GNU_USER_TARGET_MATHFILE_SPEC \ - "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s}" + "%{Ofast|ffast-math|funsafe-math-optimizations|fp-model=fast|fftz:\ + %{!fno-ftz:crtfastmath.o%s}}" #undef ENDFILE_SPEC #define ENDFILE_SPEC \ diff -Nurp a/gcc/flag-types.h b/gcc/flag-types.h --- a/gcc/flag-types.h 2020-03-12 19:07:21.000000000 +0800 +++ b/gcc/flag-types.h 2021-02-18 21:23:55.932000000 +0800 @@ -207,6 +207,15 @@ enum fp_contract_mode { FP_CONTRACT_FAST = 2 }; +/* Floating-point precision mode. */ +enum fp_model { + FP_MODEL_NORMAL = 0, + FP_MODEL_FAST = 1, + FP_MODEL_PRECISE = 2, + FP_MODEL_EXCEPT = 3, + FP_MODEL_STRICT = 4 +}; + /* Scalar storage order kind. */ enum scalar_storage_order_kind { SSO_NATIVE = 0, diff -Nurp a/gcc/fortran/options.c b/gcc/fortran/options.c --- a/gcc/fortran/options.c 2020-03-12 19:07:21.000000000 +0800 +++ b/gcc/fortran/options.c 2021-02-18 21:23:55.932000000 +0800 @@ -247,6 +247,7 @@ form_from_filename (const char *filename return f_form; } +static void gfc_handle_fpe_option (const char *arg, bool trap); /* Finalize commandline options. */ @@ -274,6 +275,13 @@ gfc_post_options (const char **pfilename if (flag_protect_parens == -1) flag_protect_parens = !optimize_fast; + /* If fp-model=precise/strict, turn on all ffpe-trap and ffpe-summary. */ + if (flag_fp_model == FP_MODEL_EXCEPT || flag_fp_model == FP_MODEL_STRICT) + { + gfc_handle_fpe_option ("all", false); + gfc_handle_fpe_option ("invalid,zero,overflow,underflow", true); + } + /* -Ofast sets implies -fstack-arrays unless an explicit size is set for stack arrays. */ if (flag_stack_arrays == -1 && flag_max_stack_var_size == -2) diff -Nurp a/gcc/opts.c b/gcc/opts.c --- a/gcc/opts.c 2021-02-18 21:22:07.424000000 +0800 +++ b/gcc/opts.c 2021-02-19 16:00:08.628000000 +0800 @@ -196,6 +196,7 @@ static void set_debug_level (enum debug_ struct gcc_options *opts_set, location_t loc); static void set_fast_math_flags (struct gcc_options *opts, int set); +static void set_fp_model_flags (struct gcc_options *opts, int set); static void decode_d_option (const char *arg, struct gcc_options *opts, location_t loc, diagnostic_context *dc); static void set_unsafe_math_optimizations_flags (struct gcc_options *opts, @@ -2433,6 +2434,10 @@ common_handle_option (struct gcc_options set_fast_math_flags (opts, value); break; + case OPT_fp_model_: + set_fp_model_flags (opts, value); + break; + case OPT_funsafe_math_optimizations: set_unsafe_math_optimizations_flags (opts, value); break; @@ -2905,6 +2910,69 @@ set_fast_math_flags (struct gcc_options } } +/* Handle fp-model options. */ +static void +set_fp_model_flags (struct gcc_options *opts, int set) +{ + enum fp_model model = (enum fp_model) set; + switch (model) + { + case FP_MODEL_FAST: + /* Equivalent to open ffast-math. */ + set_fast_math_flags (opts, 1); + break; + + case FP_MODEL_PRECISE: + /* Equivalent to close ffast-math. */ + set_fast_math_flags (opts, 0); + /* Turn on -frounding-math -fsignaling-nans. */ + if (!opts->frontend_set_flag_signaling_nans) + opts->x_flag_signaling_nans = 1; + if (!opts->frontend_set_flag_rounding_math) + opts->x_flag_rounding_math = 1; + opts->x_flag_expensive_optimizations = 0; + opts->x_flag_code_hoisting = 0; + opts->x_flag_predictive_commoning = 0; + opts->x_flag_fp_contract_mode = FP_CONTRACT_OFF; + break; + + case FP_MODEL_EXCEPT: + if (!opts->frontend_set_flag_signaling_nans) + opts->x_flag_signaling_nans = 1; + if (!opts->frontend_set_flag_errno_math) + opts->x_flag_errno_math = 1; + if (!opts->frontend_set_flag_trapping_math) + opts->x_flag_trapping_math = 1; + opts->x_flag_fp_int_builtin_inexact = 1; + /* Also turn on ffpe-trap in fortran. */ + break; + + case FP_MODEL_STRICT: + /* Turn on both precise and except. */ + if (!opts->frontend_set_flag_signaling_nans) + opts->x_flag_signaling_nans = 1; + if (!opts->frontend_set_flag_rounding_math) + opts->x_flag_rounding_math = 1; + opts->x_flag_expensive_optimizations = 0; + opts->x_flag_code_hoisting = 0; + opts->x_flag_predictive_commoning = 0; + if (!opts->frontend_set_flag_errno_math) + opts->x_flag_errno_math = 1; + if (!opts->frontend_set_flag_trapping_math) + opts->x_flag_trapping_math = 1; + opts->x_flag_fp_int_builtin_inexact = 1; + opts->x_flag_fp_contract_mode = FP_CONTRACT_OFF; + break; + + case FP_MODEL_NORMAL: + /* Do nothing. */ + break; + + default: + gcc_unreachable (); + } +} + /* When -funsafe-math-optimizations is set the following flags are set as well. */ static void diff -Nurp a/gcc/opts-common.c b/gcc/opts-common.c --- a/gcc/opts-common.c 2020-03-12 19:07:21.000000000 +0800 +++ b/gcc/opts-common.c 2021-02-19 09:49:18.880000000 +0800 @@ -26,7 +26,8 @@ along with GCC; see the file COPYING3. #include "diagnostic.h" #include "spellcheck.h" -static void prune_options (struct cl_decoded_option **, unsigned int *); +static void prune_options (struct cl_decoded_option **, unsigned int *, + unsigned int); /* An option that is undocumented, that takes a joined argument, and that doesn't fit any of the classes of uses (language/common, @@ -968,7 +969,7 @@ decode_cmdline_options_to_array (unsigne *decoded_options = opt_array; *decoded_options_count = num_decoded_options; - prune_options (decoded_options, decoded_options_count); + prune_options (decoded_options, decoded_options_count, lang_mask); } /* Return true if NEXT_OPT_IDX cancels OPT_IDX. Return false if the @@ -989,11 +990,108 @@ cancel_option (int opt_idx, int next_opt return false; } +/* Check whether opt_idx exists in decoded_options array bewteen index + start and end. If found, return its index in decoded_options, + else return end. */ +static unsigned int +find_opt_idx (struct cl_decoded_option *decoded_options, + unsigned int decoded_options_count, + unsigned int start, unsigned int end, unsigned int opt_idx) +{ + gcc_assert (end <= decoded_options_count); + gcc_assert (opt_idx < cl_options_count); + unsigned int k; + for (k = start; k < end; k++) + { + if (decoded_options[k].opt_index == opt_idx) + { + return k; + } + } + return k; +} + +/* remove the opt_index element from decoded_options array. */ +static unsigned int +remove_option (struct cl_decoded_option *decoded_options, + unsigned int decoded_options_count, + unsigned int opt_index) +{ + gcc_assert (opt_index < decoded_options_count); + unsigned int i; + for (i = opt_index; i < decoded_options_count - 1; i++) + { + decoded_options[i] = decoded_options[i + 1]; + } + return decoded_options_count - 1; +} + +/* Handle the priority between fp-model, Ofast, and + ffast-math. */ +static unsigned int +handle_fp_model_driver (struct cl_decoded_option *decoded_options, + unsigned int decoded_options_count, + unsigned int fp_model_index, + unsigned int lang_mask) +{ + struct cl_decoded_option fp_model_opt = decoded_options[fp_model_index]; + enum fp_model model = (enum fp_model) fp_model_opt.value; + if (model == FP_MODEL_PRECISE || model == FP_MODEL_STRICT) + { + /* If found Ofast, override Ofast with O3. */ + unsigned int Ofast_index; + Ofast_index = find_opt_idx (decoded_options, decoded_options_count, + 0, decoded_options_count, OPT_Ofast); + while (Ofast_index != decoded_options_count) + { + const char *tmp_argv = "-O3"; + decode_cmdline_option (&tmp_argv, lang_mask, + &decoded_options[Ofast_index]); + warning (0, "'-Ofast' is degraded to '-O3' due to %qs", + fp_model_opt.orig_option_with_args_text); + Ofast_index = find_opt_idx (decoded_options, decoded_options_count, + 0, decoded_options_count, OPT_Ofast); + } + /* If found ffast-math before fp-model=precise/strict + it, cancel it. */ + unsigned int ffast_math_index; + ffast_math_index + = find_opt_idx (decoded_options, decoded_options_count, 0, + fp_model_index, OPT_ffast_math); + if (ffast_math_index != fp_model_index) + { + decoded_options_count + = remove_option (decoded_options, decoded_options_count, + ffast_math_index); + warning (0, "'-ffast-math' before %qs is canceled", + fp_model_opt.orig_option_with_args_text); + } + } + if (model == FP_MODEL_FAST) + { + /* If found -fno-fast-math after fp-model=fast, cancel this one. */ + unsigned int fno_fast_math_index; + fno_fast_math_index + = find_opt_idx (decoded_options, decoded_options_count, fp_model_index, + decoded_options_count, OPT_ffast_math); + if (fno_fast_math_index != decoded_options_count + && decoded_options[fno_fast_math_index].value == 0) + { + decoded_options_count + = remove_option (decoded_options, decoded_options_count, + fp_model_index); + warning (0, "'-fp-model=fast' before '-fno-fast-math' is canceled"); + } + } + return decoded_options_count; +} + /* Filter out options canceled by the ones after them. */ static void prune_options (struct cl_decoded_option **decoded_options, - unsigned int *decoded_options_count) + unsigned int *decoded_options_count, + unsigned int lang_mask) { unsigned int old_decoded_options_count = *decoded_options_count; struct cl_decoded_option *old_decoded_options = *decoded_options; @@ -1005,6 +1103,8 @@ prune_options (struct cl_decoded_option unsigned int fdiagnostics_color_idx = 0; /* Remove arguments which are negated by others after them. */ + + unsigned int fp_model_index = old_decoded_options_count; new_decoded_options_count = 0; for (i = 0; i < old_decoded_options_count; i++) { @@ -1028,6 +1128,34 @@ prune_options (struct cl_decoded_option fdiagnostics_color_idx = i; continue; + case OPT_fp_model_: + /* Only the last fp-model option will take effect. */ + unsigned int next_fp_model_idx; + next_fp_model_idx = find_opt_idx (old_decoded_options, + old_decoded_options_count, + i + 1, + old_decoded_options_count, + OPT_fp_model_); + if (next_fp_model_idx != old_decoded_options_count) + { + /* Found more than one fp-model, cancel this one. */ + if (old_decoded_options[i].value + != old_decoded_options[next_fp_model_idx].value) + { + warning (0, "%qs is overrided by %qs", + old_decoded_options[i]. + orig_option_with_args_text, + old_decoded_options[next_fp_model_idx]. + orig_option_with_args_text); + } + break; + } + else + { + /* Found the last fp-model option. */ + fp_model_index = new_decoded_options_count; + } + /* FALLTHRU. */ default: gcc_assert (opt_idx < cl_options_count); option = &cl_options[opt_idx]; @@ -1067,6 +1195,14 @@ keep: break; } } + if (fp_model_index < new_decoded_options_count) + { + new_decoded_options_count + = handle_fp_model_driver (new_decoded_options, + new_decoded_options_count, + fp_model_index, + lang_mask); + } if (fdiagnostics_color_idx >= 1) {