diff mbox series

[v4] LoongArch: Split loongarch_option_override_internal into smaller procedures

Message ID 20240330084313.827920-2-yangyujie@loongson.cn
State New
Headers show
Series [v4] LoongArch: Split loongarch_option_override_internal into smaller procedures | expand

Commit Message

Yang Yujie March 30, 2024, 8:43 a.m. UTC
gcc/ChangeLog:

	* config/loongarch/genopts/loongarch.opt.in: Mark -m[no-]recip as
	aliases to -mrecip={all,none}, respectively.
	* config/loongarch/loongarch.opt: Regenerate.
	* config/loongarch/loongarch-def.h (ABI_FPU_64): Rename to...
	(ABI_FPU64_P): ...this.
	(ABI_FPU_32): Rename to...
	(ABI_FPU32_P): ...this.
	(ABI_FPU_NONE): Rename to...
	(ABI_NOFPU_P): ...this.
	(ABI_LP64_P): Define.
	* config/loongarch/loongarch.cc (loongarch_init_print_operand_punct):
	Merged into loongarch_global_init.
	(loongarch_cpu_option_override): Renamed to
	loongarch_target_option_override.
	(loongarch_option_override_internal): Move the work after
	loongarch_config_target into loongarch_target_option_override.
	(loongarch_global_init): Define.
	(INIT_TARGET_FLAG): Move to loongarch-opts.cc.
	(loongarch_option_override): Call loongarch_global_init
	separately.
	* config/loongarch/loongarch-opts.cc (loongarch_parse_mrecip_scheme):
	Split the parsing of -mrecip=<string> from
	loongarch_option_override_internal.
	(loongarch_generate_mrecip_scheme): Define. Split from
	loongarch_option_override_internal.
	(loongarch_target_option_override): Define. Renamed from
	loongarch_cpu_option_override.
	(loongarch_init_misc_options): Define. Split from
	loongarch_option_override_internal.
	(INIT_TARGET_FLAG): Move from loongarch.cc.
	* config/loongarch/loongarch-opts.h (loongarch_target_option_override):
	New prototype.
	(loongarch_parse_mrecip_scheme): New prototype.
	(loongarch_init_misc_options): New prototype.
	(TARGET_ABI_LP64): Simplify with ABI_LP64_P.
	* config/loongarch/loongarch.h (TARGET_RECIP_DIV): Simplify.
	Do not reference specific CPU architecture (LA664).
	(TARGET_RECIP_SQRT): Same.
	(TARGET_RECIP_RSQRT): Same.
	(TARGET_RECIP_VEC_DIV): Same.
	(TARGET_RECIP_VEC_SQRT): Same.
	(TARGET_RECIP_VEC_RSQRT): Same.
---
 gcc/config/loongarch/genopts/loongarch.opt.in |   8 +-
 gcc/config/loongarch/loongarch-def.h          |  11 +-
 gcc/config/loongarch/loongarch-opts.cc        | 253 ++++++++++++++++++
 gcc/config/loongarch/loongarch-opts.h         |  27 +-
 gcc/config/loongarch/loongarch.cc             | 253 +++---------------
 gcc/config/loongarch/loongarch.h              |  18 +-
 gcc/config/loongarch/loongarch.opt            |   8 +-
 7 files changed, 342 insertions(+), 236 deletions(-)

Comments

Lulu Cheng April 1, 2024, 1:17 a.m. UTC | #1
Pushed to r14-9737.

在 2024/3/30 下午4:43, Yang Yujie 写道:
> gcc/ChangeLog:
>
> 	* config/loongarch/genopts/loongarch.opt.in: Mark -m[no-]recip as
> 	aliases to -mrecip={all,none}, respectively.
> 	* config/loongarch/loongarch.opt: Regenerate.
> 	* config/loongarch/loongarch-def.h (ABI_FPU_64): Rename to...
> 	(ABI_FPU64_P): ...this.
> 	(ABI_FPU_32): Rename to...
> 	(ABI_FPU32_P): ...this.
> 	(ABI_FPU_NONE): Rename to...
> 	(ABI_NOFPU_P): ...this.
> 	(ABI_LP64_P): Define.
> 	* config/loongarch/loongarch.cc (loongarch_init_print_operand_punct):
> 	Merged into loongarch_global_init.
> 	(loongarch_cpu_option_override): Renamed to
> 	loongarch_target_option_override.
> 	(loongarch_option_override_internal): Move the work after
> 	loongarch_config_target into loongarch_target_option_override.
> 	(loongarch_global_init): Define.
> 	(INIT_TARGET_FLAG): Move to loongarch-opts.cc.
> 	(loongarch_option_override): Call loongarch_global_init
> 	separately.
> 	* config/loongarch/loongarch-opts.cc (loongarch_parse_mrecip_scheme):
> 	Split the parsing of -mrecip=<string> from
> 	loongarch_option_override_internal.
> 	(loongarch_generate_mrecip_scheme): Define. Split from
> 	loongarch_option_override_internal.
> 	(loongarch_target_option_override): Define. Renamed from
> 	loongarch_cpu_option_override.
> 	(loongarch_init_misc_options): Define. Split from
> 	loongarch_option_override_internal.
> 	(INIT_TARGET_FLAG): Move from loongarch.cc.
> 	* config/loongarch/loongarch-opts.h (loongarch_target_option_override):
> 	New prototype.
> 	(loongarch_parse_mrecip_scheme): New prototype.
> 	(loongarch_init_misc_options): New prototype.
> 	(TARGET_ABI_LP64): Simplify with ABI_LP64_P.
> 	* config/loongarch/loongarch.h (TARGET_RECIP_DIV): Simplify.
> 	Do not reference specific CPU architecture (LA664).
> 	(TARGET_RECIP_SQRT): Same.
> 	(TARGET_RECIP_RSQRT): Same.
> 	(TARGET_RECIP_VEC_DIV): Same.
> 	(TARGET_RECIP_VEC_SQRT): Same.
> 	(TARGET_RECIP_VEC_RSQRT): Same.
> ---
>   gcc/config/loongarch/genopts/loongarch.opt.in |   8 +-
>   gcc/config/loongarch/loongarch-def.h          |  11 +-
>   gcc/config/loongarch/loongarch-opts.cc        | 253 ++++++++++++++++++
>   gcc/config/loongarch/loongarch-opts.h         |  27 +-
>   gcc/config/loongarch/loongarch.cc             | 253 +++---------------
>   gcc/config/loongarch/loongarch.h              |  18 +-
>   gcc/config/loongarch/loongarch.opt            |   8 +-
>   7 files changed, 342 insertions(+), 236 deletions(-)
>
> diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in b/gcc/config/loongarch/genopts/loongarch.opt.in
> index 02f918053f5..a77893d31d9 100644
> --- a/gcc/config/loongarch/genopts/loongarch.opt.in
> +++ b/gcc/config/loongarch/genopts/loongarch.opt.in
> @@ -197,14 +197,14 @@ mexplicit-relocs
>   Target Alias(mexplicit-relocs=, always, none)
>   Use %reloc() assembly operators (for backward compatibility).
>   
> -mrecip
> -Target RejectNegative Var(la_recip) Save
> -Generate approximate reciprocal divide and square root for better throughput.
> -
>   mrecip=
>   Target RejectNegative Joined Var(la_recip_name) Save
>   Control generation of reciprocal estimates.
>   
> +mrecip
> +Target Alias(mrecip=, all, none)
> +Generate approximate reciprocal divide and square root for better throughput.
> +
>   ; The code model option names for -mcmodel.
>   Enum
>   Name(cmodel) Type(int)
> diff --git a/gcc/config/loongarch/loongarch-def.h b/gcc/config/loongarch/loongarch-def.h
> index 2dbf006d013..0cbf9476690 100644
> --- a/gcc/config/loongarch/loongarch-def.h
> +++ b/gcc/config/loongarch/loongarch-def.h
> @@ -90,11 +90,16 @@ extern loongarch_def_array<const char *, N_ABI_BASE_TYPES>
>   
>   #define TO_LP64_ABI_BASE(C) (C)
>   
> -#define ABI_FPU_64(abi_base) \
> +#define ABI_LP64_P(abi_base) \
> +  (abi_base == ABI_BASE_LP64D \
> +   || abi_base == ABI_BASE_LP64F \
> +   || abi_base == ABI_BASE_LP64S)
> +
> +#define ABI_FPU64_P(abi_base) \
>     (abi_base == ABI_BASE_LP64D)
> -#define ABI_FPU_32(abi_base) \
> +#define ABI_FPU32_P(abi_base) \
>     (abi_base == ABI_BASE_LP64F)
> -#define ABI_FPU_NONE(abi_base) \
> +#define ABI_NOFPU_P(abi_base) \
>     (abi_base == ABI_BASE_LP64S)
>   
>   
> diff --git a/gcc/config/loongarch/loongarch-opts.cc b/gcc/config/loongarch/loongarch-opts.cc
> index 627f9148adf..e600f08f03b 100644
> --- a/gcc/config/loongarch/loongarch-opts.cc
> +++ b/gcc/config/loongarch/loongarch-opts.cc
> @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "coretypes.h"
>   #include "tm.h"
>   #include "obstack.h"
> +#include "opts.h"
>   #include "diagnostic-core.h"
>   
>   #include "loongarch-cpu.h"
> @@ -32,8 +33,12 @@ along with GCC; see the file COPYING3.  If not see
>   #include "loongarch-str.h"
>   #include "loongarch-def.h"
>   
> +/* Target configuration */
>   struct loongarch_target la_target;
>   
> +/* RTL cost information */
> +const struct loongarch_rtx_cost_data *loongarch_cost;
> +
>   /* ABI-related configuration.  */
>   #define ABI_COUNT (sizeof(abi_priority_list)/sizeof(struct loongarch_abi))
>   static const struct loongarch_abi
> @@ -795,3 +800,251 @@ loongarch_update_gcc_opt_status (struct loongarch_target *target,
>     /* ISA evolution features */
>     opts->x_la_isa_evolution = target->isa.evolution;
>   }
> +
> +/* -mrecip=<str> handling */
> +static struct
> +  {
> +    const char *string;	    /* option name.  */
> +    unsigned int mask;	    /* mask bits to set.  */
> +  }
> +const recip_options[] = {
> +      { "all",       RECIP_MASK_ALL },
> +      { "none",      RECIP_MASK_NONE },
> +      { "div",       RECIP_MASK_DIV },
> +      { "sqrt",      RECIP_MASK_SQRT },
> +      { "rsqrt",     RECIP_MASK_RSQRT },
> +      { "vec-div",   RECIP_MASK_VEC_DIV },
> +      { "vec-sqrt",  RECIP_MASK_VEC_SQRT },
> +      { "vec-rsqrt", RECIP_MASK_VEC_RSQRT },
> +};
> +
> +/* Parser for -mrecip=<recip_string>.  */
> +unsigned int
> +loongarch_parse_mrecip_scheme (const char *recip_string)
> +{
> +  unsigned int result_mask = RECIP_MASK_NONE;
> +
> +  if (recip_string)
> +    {
> +      char *p = ASTRDUP (recip_string);
> +      char *q;
> +      unsigned int mask, i;
> +      bool invert;
> +
> +      while ((q = strtok (p, ",")) != NULL)
> +	{
> +	  p = NULL;
> +	  if (*q == '!')
> +	    {
> +	      invert = true;
> +	      q++;
> +	    }
> +	  else
> +	    invert = false;
> +
> +	  if (!strcmp (q, "default"))
> +	    mask = RECIP_MASK_ALL;
> +	  else
> +	    {
> +	      for (i = 0; i < ARRAY_SIZE (recip_options); i++)
> +		if (!strcmp (q, recip_options[i].string))
> +		  {
> +		    mask = recip_options[i].mask;
> +		    break;
> +		  }
> +
> +	      if (i == ARRAY_SIZE (recip_options))
> +		{
> +		  error ("unknown option for %<-mrecip=%s%>", q);
> +		  invert = false;
> +		  mask = RECIP_MASK_NONE;
> +		}
> +	    }
> +
> +	  if (invert)
> +	    result_mask &= ~mask;
> +	  else
> +	    result_mask |= mask;
> +	}
> +    }
> +  return result_mask;
> +}
> +
> +/* Generate -mrecip= argument based on the mask.  */
> +const char*
> +loongarch_generate_mrecip_scheme (unsigned int mask)
> +{
> +  static char recip_scheme_str[128];
> +  int p = 0, tmp;
> +
> +  switch (mask)
> +    {
> +      case RECIP_MASK_ALL:
> +	return "all";
> +
> +      case RECIP_MASK_NONE:
> +	return "none";
> +    }
> +
> +  for (unsigned long i = 2; i < ARRAY_SIZE (recip_options); i++)
> +    {
> +      if (mask & recip_options[i].mask)
> +	{
> +	  if ((tmp = strlen (recip_options[i].string) + 1) >= 127 - p)
> +	    gcc_unreachable ();
> +
> +	  recip_scheme_str[p] = ',';
> +	  strcpy (recip_scheme_str + p + 1, recip_options[i].string);
> +	  p += tmp;
> +	}
> +    }
> +  recip_scheme_str[p] = '\0';
> +  return recip_scheme_str + 1;
> +}
> +
> +
> +
> +/* Refresh the switches acccording to the resolved loongarch_target struct.  */
> +void
> +loongarch_target_option_override (struct loongarch_target *target,
> +				  struct gcc_options *opts,
> +				  struct gcc_options *opts_set)
> +{
> +  loongarch_update_gcc_opt_status (target, opts, opts_set);
> +
> +  /* alignments */
> +  if (opts->x_flag_align_functions && !opts->x_str_align_functions)
> +    opts->x_str_align_functions
> +      = loongarch_cpu_align[target->cpu_tune].function;
> +
> +  if (opts->x_flag_align_labels && !opts->x_str_align_labels)
> +    opts->x_str_align_labels = loongarch_cpu_align[target->cpu_tune].label;
> +
> +  /* Set up parameters to be used in prefetching algorithm.  */
> +  int simultaneous_prefetches
> +    = loongarch_cpu_cache[target->cpu_tune].simultaneous_prefetches;
> +
> +  SET_OPTION_IF_UNSET (opts, opts_set, param_simultaneous_prefetches,
> +		       simultaneous_prefetches);
> +
> +  SET_OPTION_IF_UNSET (opts, opts_set, param_l1_cache_line_size,
> +		       loongarch_cpu_cache[target->cpu_tune].l1d_line_size);
> +
> +  SET_OPTION_IF_UNSET (opts, opts_set, param_l1_cache_size,
> +		       loongarch_cpu_cache[target->cpu_tune].l1d_size);
> +
> +  SET_OPTION_IF_UNSET (opts, opts_set, param_l2_cache_size,
> +		       loongarch_cpu_cache[target->cpu_tune].l2d_size);
> +
> +  /* Other arch-specific overrides.  */
> +  switch (target->cpu_arch)
> +    {
> +      case CPU_LA664:
> +	/* Enable -mrecipe=all for LA664 by default.  */
> +	if (!opts_set->x_recip_mask)
> +	  {
> +	    opts->x_recip_mask = RECIP_MASK_ALL;
> +	    opts_set->x_recip_mask = 1;
> +	  }
> +    }
> +
> +  /* -mrecip= */
> +  opts->x_la_recip_name
> +    = loongarch_generate_mrecip_scheme (opts->x_recip_mask);
> +
> +  /* Decide which rtx_costs structure to use.  */
> +  if (opts->x_optimize_size)
> +    loongarch_cost = &loongarch_rtx_cost_optimize_size;
> +  else
> +    loongarch_cost = &loongarch_cpu_rtx_cost_data[target->cpu_tune];
> +
> +  /* If the user hasn't specified a branch cost, use the processor's
> +     default.  */
> +  if (!opts_set->x_la_branch_cost)
> +    opts->x_la_branch_cost = loongarch_cost->branch_cost;
> +
> +  /* other stuff */
> +  if (ABI_LP64_P (target->abi.base))
> +    opts->x_flag_pcc_struct_return = 0;
> +
> +  switch (target->cmodel)
> +    {
> +      case CMODEL_EXTREME:
> +	if (opts->x_flag_plt)
> +	  {
> +	    if (opts_set->x_flag_plt)
> +	      error ("code model %qs is not compatible with %s",
> +		     "extreme", "-fplt");
> +	    opts->x_flag_plt = 0;
> +	  }
> +	break;
> +
> +      case CMODEL_TINY_STATIC:
> +      case CMODEL_MEDIUM:
> +      case CMODEL_NORMAL:
> +      case CMODEL_TINY:
> +      case CMODEL_LARGE:
> +	break;
> +
> +      default:
> +	gcc_unreachable ();
> +    }
> +}
> +
> +
> +/* Resolve options that's not covered by la_target.  */
> +void
> +loongarch_init_misc_options (struct gcc_options *opts,
> +			     struct gcc_options *opts_set)
> +{
> +  if (opts->x_flag_pic)
> +    opts->x_g_switch_value = 0;
> +
> +  /* -mrecip options.  */
> +  opts->x_recip_mask = loongarch_parse_mrecip_scheme (opts->x_la_recip_name);
> +
> +#define INIT_TARGET_FLAG(NAME, INIT) \
> +  { \
> +    if (!(opts_set->x_target_flags & MASK_##NAME)) \
> +      { \
> +	if (INIT) \
> +	  opts->x_target_flags |= MASK_##NAME; \
> +	else \
> +	  opts->x_target_flags &= ~MASK_##NAME; \
> +      } \
> +  }
> +
> +  /* Enable conditional moves for int and float by default.  */
> +  INIT_TARGET_FLAG (COND_MOVE_INT, 1)
> +  INIT_TARGET_FLAG (COND_MOVE_FLOAT, 1)
> +
> +  /* Set mrelax default.  */
> +  INIT_TARGET_FLAG (LINKER_RELAXATION,
> +		    HAVE_AS_MRELAX_OPTION && HAVE_AS_COND_BRANCH_RELAXATION)
> +
> +#undef INIT_TARGET_FLAG
> +
> +  /* Set mexplicit-relocs default.  */
> +  if (opts->x_la_opt_explicit_relocs == M_OPT_UNSET)
> +    opts->x_la_opt_explicit_relocs = (HAVE_AS_EXPLICIT_RELOCS
> +				      ? (TARGET_LINKER_RELAXATION
> +					 ? EXPLICIT_RELOCS_AUTO
> +					 : EXPLICIT_RELOCS_ALWAYS)
> +				      : EXPLICIT_RELOCS_NONE);
> +
> +  /* Enable sw prefetching at -O3 and higher.  */
> +  if (opts->x_flag_prefetch_loop_arrays < 0
> +      && (opts->x_optimize >= 3 || opts->x_flag_profile_use)
> +      && !opts->x_optimize_size)
> +    opts->x_flag_prefetch_loop_arrays = 1;
> +
> +  if (TARGET_DIRECT_EXTERN_ACCESS_OPTS_P (opts) && opts->x_flag_shlib)
> +    error ("%qs cannot be used for compiling a shared library",
> +	   "-mdirect-extern-access");
> +
> +  /* Enforce that interval is the same size as size so the mid-end does the
> +     right thing.  */
> +  SET_OPTION_IF_UNSET (opts, opts_set,
> +		       param_stack_clash_protection_probe_interval,
> +		       param_stack_clash_protection_guard_size);
> +}
> diff --git a/gcc/config/loongarch/loongarch-opts.h b/gcc/config/loongarch/loongarch-opts.h
> index 586e67e65ee..2d9f59296e7 100644
> --- a/gcc/config/loongarch/loongarch-opts.h
> +++ b/gcc/config/loongarch/loongarch-opts.h
> @@ -30,6 +30,10 @@ along with GCC; see the file COPYING3.  If not see
>   /* Target configuration */
>   extern struct loongarch_target la_target;
>   
> +/* RTL cost information */
> +extern const struct loongarch_rtx_cost_data *loongarch_cost;
> +
> +
>   /* Initialize loongarch_target from separate option variables.  */
>   void
>   loongarch_init_target (struct loongarch_target *target,
> @@ -46,11 +50,30 @@ loongarch_config_target (struct loongarch_target *target,
>   			 struct loongarch_flags *flags,
>   			 int follow_multilib_list_p);
>   
> +
> +/* Refresh the switches acccording to the resolved loongarch_target struct.  */
> +void
> +loongarch_target_option_override (struct loongarch_target *target,
> +				  struct gcc_options *opts,
> +				  struct gcc_options *opts_set);
> +
> +
>   /* option status feedback for "gcc --help=target -Q" */
>   void
>   loongarch_update_gcc_opt_status (struct loongarch_target *target,
>   				 struct gcc_options *opts,
>   				 struct gcc_options *opts_set);
> +
> +
> +/* Parser for -mrecip=<recip_string>.  */
> +unsigned int
> +loongarch_parse_mrecip_scheme (const char *recip_string);
> +
> +
> +/* Resolve options that's not covered by la_target.  */
> +void
> +loongarch_init_misc_options (struct gcc_options *opts,
> +			     struct gcc_options *opts_set);
>   #endif
>   
>   /* Flag status */
> @@ -80,9 +103,7 @@ struct loongarch_flags {
>   #define TARGET_DOUBLE_FLOAT_ABI	  (la_target.abi.base == ABI_BASE_LP64D)
>   
>   #define TARGET_64BIT		  (la_target.isa.base == ISA_BASE_LA64)
> -#define TARGET_ABI_LP64		  (la_target.abi.base == ABI_BASE_LP64D	\
> -				   || la_target.abi.base == ABI_BASE_LP64F \
> -				   || la_target.abi.base == ABI_BASE_LP64S)
> +#define TARGET_ABI_LP64		  ABI_LP64_P(la_target.abi.base)
>   
>   #define ISA_HAS_LSX \
>     (la_target.isa.simd == ISA_EXT_SIMD_LSX \
> diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
> index 030957db4e7..a69a203fbe6 100644
> --- a/gcc/config/loongarch/loongarch.cc
> +++ b/gcc/config/loongarch/loongarch.cc
> @@ -208,9 +208,6 @@ const enum reg_class loongarch_regno_to_class[FIRST_PSEUDO_REGISTER] = {
>       FRAME_REGS,	FRAME_REGS
>   };
>   
> -/* Which cost information to use.  */
> -static const struct loongarch_rtx_cost_data *loongarch_cost;
> -
>   /* Information about a single argument.  */
>   struct loongarch_arg_info
>   {
> @@ -5911,17 +5908,6 @@ loongarch_print_operand_punctuation (FILE *file, int ch)
>       }
>   }
>   
> -/* Initialize loongarch_print_operand_punct.  */
> -
> -static void
> -loongarch_init_print_operand_punct (void)
> -{
> -  const char *p;
> -
> -  for (p = ".$"; *p; p++)
> -    loongarch_print_operand_punct[(unsigned char) *p] = true;
> -}
> -
>   /* PRINT_OPERAND prefix LETTER refers to the integer branch instruction
>      associated with condition CODE.  Print the condition part of the
>      opcode to FILE.  */
> @@ -7625,118 +7611,15 @@ loongarch_init_machine_status (void)
>   }
>   
>   static void
> -loongarch_cpu_option_override (struct loongarch_target *target,
> -			       struct gcc_options *opts,
> -			       struct gcc_options *opts_set)
> -{
> -  /* alignments */
> -  if (opts->x_flag_align_functions && !opts->x_str_align_functions)
> -    opts->x_str_align_functions
> -      = loongarch_cpu_align[target->cpu_tune].function;
> -
> -  if (opts->x_flag_align_labels && !opts->x_str_align_labels)
> -    opts->x_str_align_labels = loongarch_cpu_align[target->cpu_tune].label;
> -
> -  /* Set up parameters to be used in prefetching algorithm.  */
> -  int simultaneous_prefetches
> -    = loongarch_cpu_cache[target->cpu_tune].simultaneous_prefetches;
> -
> -  SET_OPTION_IF_UNSET (opts, opts_set, param_simultaneous_prefetches,
> -		       simultaneous_prefetches);
> -
> -  SET_OPTION_IF_UNSET (opts, opts_set, param_l1_cache_line_size,
> -		       loongarch_cpu_cache[target->cpu_tune].l1d_line_size);
> -
> -  SET_OPTION_IF_UNSET (opts, opts_set, param_l1_cache_size,
> -		       loongarch_cpu_cache[target->cpu_tune].l1d_size);
> -
> -  SET_OPTION_IF_UNSET (opts, opts_set, param_l2_cache_size,
> -		       loongarch_cpu_cache[target->cpu_tune].l2d_size);
> -}
> -
> -static void
> -loongarch_option_override_internal (struct gcc_options *opts,
> -				    struct gcc_options *opts_set)
> +loongarch_global_init (void)
>   {
> -  int i, regno, mode;
> -
> -  if (flag_pic)
> -    g_switch_value = 0;
> -
> -  loongarch_init_target (&la_target,
> -			 la_opt_cpu_arch, la_opt_cpu_tune, la_opt_fpu,
> -			 la_opt_simd, la_opt_abi_base, la_opt_abi_ext,
> -			 la_opt_cmodel, opts->x_la_isa_evolution,
> -			 opts_set->x_la_isa_evolution);
> -
> -  /* Handle target-specific options: compute defaults/conflicts etc.  */
> -  loongarch_config_target (&la_target, NULL, 0);
> -
> -  loongarch_update_gcc_opt_status (&la_target, opts, opts_set);
> -  loongarch_cpu_option_override (&la_target, opts, opts_set);
> -
> -  if (TARGET_ABI_LP64)
> -    flag_pcc_struct_return = 0;
> -
> -  /* Decide which rtx_costs structure to use.  */
> -  if (optimize_size)
> -    loongarch_cost = &loongarch_rtx_cost_optimize_size;
> -  else
> -    loongarch_cost = &loongarch_cpu_rtx_cost_data[la_target.cpu_tune];
> -
> -  /* If the user hasn't specified a branch cost, use the processor's
> -     default.  */
> -  if (la_branch_cost == 0)
> -    la_branch_cost = loongarch_cost->branch_cost;
> -
> -  /* Enable sw prefetching at -O3 and higher.  */
> -  if (opts->x_flag_prefetch_loop_arrays < 0
> -      && (opts->x_optimize >= 3 || opts->x_flag_profile_use)
> -      && !opts->x_optimize_size)
> -    opts->x_flag_prefetch_loop_arrays = 1;
> -
> -  if (TARGET_DIRECT_EXTERN_ACCESS && flag_shlib)
> -    error ("%qs cannot be used for compiling a shared library",
> -	   "-mdirect-extern-access");
> -
> -  switch (la_target.cmodel)
> -    {
> -      case CMODEL_EXTREME:
> -	if (opts->x_flag_plt)
> -	  {
> -	    if (global_options_set.x_flag_plt)
> -	      error ("code model %qs is not compatible with %s",
> -		     "extreme", "-fplt");
> -	    opts->x_flag_plt = 0;
> -	  }
> -	break;
> -
> -      case CMODEL_TINY_STATIC:
> -      case CMODEL_MEDIUM:
> -      case CMODEL_NORMAL:
> -      case CMODEL_TINY:
> -      case CMODEL_LARGE:
> -	break;
> -
> -      default:
> -	gcc_unreachable ();
> -    }
> -
> -  /* Validate the guard size.  */
> -  int guard_size = param_stack_clash_protection_guard_size;
> -
> -  /* Enforce that interval is the same size as size so the mid-end does the
> -     right thing.  */
> -  SET_OPTION_IF_UNSET (opts, &global_options_set,
> -		       param_stack_clash_protection_probe_interval,
> -		       guard_size);
> -
> -  loongarch_init_print_operand_punct ();
> +  /* Initialize loongarch_print_operand_punct.  */
> +  for (const char *p = ".$"; *p; p++)
> +    loongarch_print_operand_punct[(unsigned char) *p] = true;
>   
>     /* Set up array to map GCC register number to debug register number.
>        Ignore the special purpose register numbers.  */
> -
> -  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> +  for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
>       {
>         if (GP_REG_P (i) || FP_REG_P (i))
>   	loongarch_dwarf_regno[i] = i;
> @@ -7745,115 +7628,53 @@ loongarch_option_override_internal (struct gcc_options *opts,
>       }
>   
>     /* Set up loongarch_hard_regno_mode_ok.  */
> -  for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
> -    for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
> +  for (int mode = 0; mode < MAX_MACHINE_MODE; mode++)
> +    for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
>         loongarch_hard_regno_mode_ok_p[mode][regno]
>   	= loongarch_hard_regno_mode_ok_uncached (regno, (machine_mode) mode);
>   
>     /* Function to allocate machine-dependent function status.  */
>     init_machine_status = &loongarch_init_machine_status;
> +};
>   
> -  /* -mrecip options.  */
> -  static struct
> -    {
> -      const char *string;	    /* option name.  */
> -      unsigned int mask;	    /* mask bits to set.  */
> -    }
> -  const recip_options[] = {
> -	{ "all",       RECIP_MASK_ALL },
> -	{ "none",      RECIP_MASK_NONE },
> -	{ "div",       RECIP_MASK_DIV },
> -	{ "sqrt",      RECIP_MASK_SQRT },
> -	{ "rsqrt",     RECIP_MASK_RSQRT },
> -	{ "vec-div",   RECIP_MASK_VEC_DIV },
> -	{ "vec-sqrt",  RECIP_MASK_VEC_SQRT },
> -	{ "vec-rsqrt", RECIP_MASK_VEC_RSQRT },
> -  };
> -
> -  if (la_recip_name)
> -    {
> -      char *p = ASTRDUP (la_recip_name);
> -      char *q;
> -      unsigned int mask, i;
> -      bool invert;
> -
> -      while ((q = strtok (p, ",")) != NULL)
> -	{
> -	  p = NULL;
> -	  if (*q == '!')
> -	    {
> -	      invert = true;
> -	      q++;
> -	    }
> -	  else
> -	    invert = false;
> -
> -	  if (!strcmp (q, "default"))
> -	    mask = RECIP_MASK_ALL;
> -	  else
> -	    {
> -	      for (i = 0; i < ARRAY_SIZE (recip_options); i++)
> -		if (!strcmp (q, recip_options[i].string))
> -		  {
> -		    mask = recip_options[i].mask;
> -		    break;
> -		  }
> -
> -	      if (i == ARRAY_SIZE (recip_options))
> -		{
> -		  error ("unknown option for %<-mrecip=%s%>", q);
> -		  invert = false;
> -		  mask = RECIP_MASK_NONE;
> -		}
> -	    }
> -
> -	  if (invert)
> -	    recip_mask &= ~mask;
> -	  else
> -	    recip_mask |= mask;
> -	}
> -    }
> -  if (la_recip)
> -    recip_mask |= RECIP_MASK_ALL;
> -  if (!ISA_HAS_FRECIPE)
> -    recip_mask = RECIP_MASK_NONE;
> -
> -#define INIT_TARGET_FLAG(NAME, INIT) \
> -  { \
> -    if (!(target_flags_explicit & MASK_##NAME)) \
> -      { \
> -	if (INIT) \
> -	  target_flags |= MASK_##NAME; \
> -	else \
> -	  target_flags &= ~MASK_##NAME; \
> -      } \
> -  }
> -
> -  /* Enable conditional moves for int and float by default.  */
> -  INIT_TARGET_FLAG (COND_MOVE_INT, 1)
> -  INIT_TARGET_FLAG (COND_MOVE_FLOAT, 1)
> -
> -  /* Set mrelax default.  */
> -  INIT_TARGET_FLAG (LINKER_RELAXATION,
> -		    HAVE_AS_MRELAX_OPTION && HAVE_AS_COND_BRANCH_RELAXATION)
> +static void
> +loongarch_option_override_internal (struct loongarch_target *target,
> +				    struct gcc_options *opts,
> +				    struct gcc_options *opts_set)
> +{
> +  /* Handle options not covered by struct loongarch_target.  */
> +  loongarch_init_misc_options (opts, opts_set);
> +
> +  /* Resolve the target struct.  */
> +  loongarch_init_target (target,
> +			 opts->x_la_opt_cpu_arch,
> +			 opts->x_la_opt_cpu_tune,
> +			 opts->x_la_opt_fpu,
> +			 opts->x_la_opt_simd,
> +			 opts->x_la_opt_abi_base,
> +			 opts->x_la_opt_abi_ext,
> +			 opts->x_la_opt_cmodel,
> +			 opts->x_la_isa_evolution,
> +			 opts_set->x_la_isa_evolution);
>   
> -#undef INIT_TARGET_FLAG
> +  loongarch_config_target (target, NULL, 0);
>   
> -  if (la_opt_explicit_relocs == M_OPT_UNSET)
> -    la_opt_explicit_relocs = (HAVE_AS_EXPLICIT_RELOCS
> -			      ? (TARGET_LINKER_RELAXATION
> -				 ? EXPLICIT_RELOCS_AUTO
> -				 : EXPLICIT_RELOCS_ALWAYS)
> -			      : EXPLICIT_RELOCS_NONE);
> +  /* Override some options according to the resolved target.  */
> +  loongarch_target_option_override (target, opts, opts_set);
>   }
>   
> -
>   /* Implement TARGET_OPTION_OVERRIDE.  */
>   
>   static void
>   loongarch_option_override (void)
>   {
> -  loongarch_option_override_internal (&global_options, &global_options_set);
> +  /* Setting up the target configuration.  */
> +  loongarch_option_override_internal (&la_target,
> +				      &global_options,
> +				      &global_options_set);
> +
> +  /* Global initializations.  */
> +  loongarch_global_init ();
>   }
>   
>   /* Implement TARGET_OPTION_SAVE.  */
> diff --git a/gcc/config/loongarch/loongarch.h b/gcc/config/loongarch/loongarch.h
> index 888a633961d..23bb3254883 100644
> --- a/gcc/config/loongarch/loongarch.h
> +++ b/gcc/config/loongarch/loongarch.h
> @@ -710,12 +710,18 @@ enum reg_class
>   			| RECIP_MASK_RSQRT | RECIP_MASK_VEC_SQRT \
>   			| RECIP_MASK_VEC_DIV | RECIP_MASK_VEC_RSQRT)
>   
> -#define TARGET_RECIP_DIV        ((recip_mask & RECIP_MASK_DIV) != 0 || TARGET_uARCH_LA664)
> -#define TARGET_RECIP_SQRT       ((recip_mask & RECIP_MASK_SQRT) != 0 || TARGET_uARCH_LA664)
> -#define TARGET_RECIP_RSQRT      ((recip_mask & RECIP_MASK_RSQRT) != 0 || TARGET_uARCH_LA664)
> -#define TARGET_RECIP_VEC_DIV    ((recip_mask & RECIP_MASK_VEC_DIV) != 0 || TARGET_uARCH_LA664)
> -#define TARGET_RECIP_VEC_SQRT   ((recip_mask & RECIP_MASK_VEC_SQRT) != 0 || TARGET_uARCH_LA664)
> -#define TARGET_RECIP_VEC_RSQRT  ((recip_mask & RECIP_MASK_VEC_RSQRT) != 0 || TARGET_uARCH_LA664)
> +#define TARGET_RECIP_DIV \
> +  ((recip_mask & RECIP_MASK_DIV) != 0 && ISA_HAS_FRECIPE)
> +#define TARGET_RECIP_SQRT \
> +  ((recip_mask & RECIP_MASK_SQRT) != 0 && ISA_HAS_FRECIPE)
> +#define TARGET_RECIP_RSQRT \
> +  ((recip_mask & RECIP_MASK_RSQRT) != 0 && ISA_HAS_FRECIPE)
> +#define TARGET_RECIP_VEC_DIV \
> +  ((recip_mask & RECIP_MASK_VEC_DIV) != 0 && ISA_HAS_FRECIPE)
> +#define TARGET_RECIP_VEC_SQRT \
> +  ((recip_mask & RECIP_MASK_VEC_SQRT) != 0 && ISA_HAS_FRECIPE)
> +#define TARGET_RECIP_VEC_RSQRT \
> +  ((recip_mask & RECIP_MASK_VEC_RSQRT) != 0 && ISA_HAS_FRECIPE)
>   
>   /* 1 if N is a possible register number for function argument passing.
>      We have no FP argument registers when soft-float.  */
> diff --git a/gcc/config/loongarch/loongarch.opt b/gcc/config/loongarch/loongarch.opt
> index f10fcdd968c..317cd11a67c 100644
> --- a/gcc/config/loongarch/loongarch.opt
> +++ b/gcc/config/loongarch/loongarch.opt
> @@ -205,14 +205,14 @@ mexplicit-relocs
>   Target Alias(mexplicit-relocs=, always, none)
>   Use %reloc() assembly operators (for backward compatibility).
>   
> -mrecip
> -Target RejectNegative Var(la_recip) Save
> -Generate approximate reciprocal divide and square root for better throughput.
> -
>   mrecip=
>   Target RejectNegative Joined Var(la_recip_name) Save
>   Control generation of reciprocal estimates.
>   
> +mrecip
> +Target Alias(mrecip=, all, none)
> +Generate approximate reciprocal divide and square root for better throughput.
> +
>   ; The code model option names for -mcmodel.
>   Enum
>   Name(cmodel) Type(int)
diff mbox series

Patch

diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in b/gcc/config/loongarch/genopts/loongarch.opt.in
index 02f918053f5..a77893d31d9 100644
--- a/gcc/config/loongarch/genopts/loongarch.opt.in
+++ b/gcc/config/loongarch/genopts/loongarch.opt.in
@@ -197,14 +197,14 @@  mexplicit-relocs
 Target Alias(mexplicit-relocs=, always, none)
 Use %reloc() assembly operators (for backward compatibility).
 
-mrecip
-Target RejectNegative Var(la_recip) Save
-Generate approximate reciprocal divide and square root for better throughput.
-
 mrecip=
 Target RejectNegative Joined Var(la_recip_name) Save
 Control generation of reciprocal estimates.
 
+mrecip
+Target Alias(mrecip=, all, none)
+Generate approximate reciprocal divide and square root for better throughput.
+
 ; The code model option names for -mcmodel.
 Enum
 Name(cmodel) Type(int)
diff --git a/gcc/config/loongarch/loongarch-def.h b/gcc/config/loongarch/loongarch-def.h
index 2dbf006d013..0cbf9476690 100644
--- a/gcc/config/loongarch/loongarch-def.h
+++ b/gcc/config/loongarch/loongarch-def.h
@@ -90,11 +90,16 @@  extern loongarch_def_array<const char *, N_ABI_BASE_TYPES>
 
 #define TO_LP64_ABI_BASE(C) (C)
 
-#define ABI_FPU_64(abi_base) \
+#define ABI_LP64_P(abi_base) \
+  (abi_base == ABI_BASE_LP64D \
+   || abi_base == ABI_BASE_LP64F \
+   || abi_base == ABI_BASE_LP64S)
+
+#define ABI_FPU64_P(abi_base) \
   (abi_base == ABI_BASE_LP64D)
-#define ABI_FPU_32(abi_base) \
+#define ABI_FPU32_P(abi_base) \
   (abi_base == ABI_BASE_LP64F)
-#define ABI_FPU_NONE(abi_base) \
+#define ABI_NOFPU_P(abi_base) \
   (abi_base == ABI_BASE_LP64S)
 
 
diff --git a/gcc/config/loongarch/loongarch-opts.cc b/gcc/config/loongarch/loongarch-opts.cc
index 627f9148adf..e600f08f03b 100644
--- a/gcc/config/loongarch/loongarch-opts.cc
+++ b/gcc/config/loongarch/loongarch-opts.cc
@@ -25,6 +25,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "obstack.h"
+#include "opts.h"
 #include "diagnostic-core.h"
 
 #include "loongarch-cpu.h"
@@ -32,8 +33,12 @@  along with GCC; see the file COPYING3.  If not see
 #include "loongarch-str.h"
 #include "loongarch-def.h"
 
+/* Target configuration */
 struct loongarch_target la_target;
 
+/* RTL cost information */
+const struct loongarch_rtx_cost_data *loongarch_cost;
+
 /* ABI-related configuration.  */
 #define ABI_COUNT (sizeof(abi_priority_list)/sizeof(struct loongarch_abi))
 static const struct loongarch_abi
@@ -795,3 +800,251 @@  loongarch_update_gcc_opt_status (struct loongarch_target *target,
   /* ISA evolution features */
   opts->x_la_isa_evolution = target->isa.evolution;
 }
+
+/* -mrecip=<str> handling */
+static struct
+  {
+    const char *string;	    /* option name.  */
+    unsigned int mask;	    /* mask bits to set.  */
+  }
+const recip_options[] = {
+      { "all",       RECIP_MASK_ALL },
+      { "none",      RECIP_MASK_NONE },
+      { "div",       RECIP_MASK_DIV },
+      { "sqrt",      RECIP_MASK_SQRT },
+      { "rsqrt",     RECIP_MASK_RSQRT },
+      { "vec-div",   RECIP_MASK_VEC_DIV },
+      { "vec-sqrt",  RECIP_MASK_VEC_SQRT },
+      { "vec-rsqrt", RECIP_MASK_VEC_RSQRT },
+};
+
+/* Parser for -mrecip=<recip_string>.  */
+unsigned int
+loongarch_parse_mrecip_scheme (const char *recip_string)
+{
+  unsigned int result_mask = RECIP_MASK_NONE;
+
+  if (recip_string)
+    {
+      char *p = ASTRDUP (recip_string);
+      char *q;
+      unsigned int mask, i;
+      bool invert;
+
+      while ((q = strtok (p, ",")) != NULL)
+	{
+	  p = NULL;
+	  if (*q == '!')
+	    {
+	      invert = true;
+	      q++;
+	    }
+	  else
+	    invert = false;
+
+	  if (!strcmp (q, "default"))
+	    mask = RECIP_MASK_ALL;
+	  else
+	    {
+	      for (i = 0; i < ARRAY_SIZE (recip_options); i++)
+		if (!strcmp (q, recip_options[i].string))
+		  {
+		    mask = recip_options[i].mask;
+		    break;
+		  }
+
+	      if (i == ARRAY_SIZE (recip_options))
+		{
+		  error ("unknown option for %<-mrecip=%s%>", q);
+		  invert = false;
+		  mask = RECIP_MASK_NONE;
+		}
+	    }
+
+	  if (invert)
+	    result_mask &= ~mask;
+	  else
+	    result_mask |= mask;
+	}
+    }
+  return result_mask;
+}
+
+/* Generate -mrecip= argument based on the mask.  */
+const char*
+loongarch_generate_mrecip_scheme (unsigned int mask)
+{
+  static char recip_scheme_str[128];
+  int p = 0, tmp;
+
+  switch (mask)
+    {
+      case RECIP_MASK_ALL:
+	return "all";
+
+      case RECIP_MASK_NONE:
+	return "none";
+    }
+
+  for (unsigned long i = 2; i < ARRAY_SIZE (recip_options); i++)
+    {
+      if (mask & recip_options[i].mask)
+	{
+	  if ((tmp = strlen (recip_options[i].string) + 1) >= 127 - p)
+	    gcc_unreachable ();
+
+	  recip_scheme_str[p] = ',';
+	  strcpy (recip_scheme_str + p + 1, recip_options[i].string);
+	  p += tmp;
+	}
+    }
+  recip_scheme_str[p] = '\0';
+  return recip_scheme_str + 1;
+}
+
+
+
+/* Refresh the switches acccording to the resolved loongarch_target struct.  */
+void
+loongarch_target_option_override (struct loongarch_target *target,
+				  struct gcc_options *opts,
+				  struct gcc_options *opts_set)
+{
+  loongarch_update_gcc_opt_status (target, opts, opts_set);
+
+  /* alignments */
+  if (opts->x_flag_align_functions && !opts->x_str_align_functions)
+    opts->x_str_align_functions
+      = loongarch_cpu_align[target->cpu_tune].function;
+
+  if (opts->x_flag_align_labels && !opts->x_str_align_labels)
+    opts->x_str_align_labels = loongarch_cpu_align[target->cpu_tune].label;
+
+  /* Set up parameters to be used in prefetching algorithm.  */
+  int simultaneous_prefetches
+    = loongarch_cpu_cache[target->cpu_tune].simultaneous_prefetches;
+
+  SET_OPTION_IF_UNSET (opts, opts_set, param_simultaneous_prefetches,
+		       simultaneous_prefetches);
+
+  SET_OPTION_IF_UNSET (opts, opts_set, param_l1_cache_line_size,
+		       loongarch_cpu_cache[target->cpu_tune].l1d_line_size);
+
+  SET_OPTION_IF_UNSET (opts, opts_set, param_l1_cache_size,
+		       loongarch_cpu_cache[target->cpu_tune].l1d_size);
+
+  SET_OPTION_IF_UNSET (opts, opts_set, param_l2_cache_size,
+		       loongarch_cpu_cache[target->cpu_tune].l2d_size);
+
+  /* Other arch-specific overrides.  */
+  switch (target->cpu_arch)
+    {
+      case CPU_LA664:
+	/* Enable -mrecipe=all for LA664 by default.  */
+	if (!opts_set->x_recip_mask)
+	  {
+	    opts->x_recip_mask = RECIP_MASK_ALL;
+	    opts_set->x_recip_mask = 1;
+	  }
+    }
+
+  /* -mrecip= */
+  opts->x_la_recip_name
+    = loongarch_generate_mrecip_scheme (opts->x_recip_mask);
+
+  /* Decide which rtx_costs structure to use.  */
+  if (opts->x_optimize_size)
+    loongarch_cost = &loongarch_rtx_cost_optimize_size;
+  else
+    loongarch_cost = &loongarch_cpu_rtx_cost_data[target->cpu_tune];
+
+  /* If the user hasn't specified a branch cost, use the processor's
+     default.  */
+  if (!opts_set->x_la_branch_cost)
+    opts->x_la_branch_cost = loongarch_cost->branch_cost;
+
+  /* other stuff */
+  if (ABI_LP64_P (target->abi.base))
+    opts->x_flag_pcc_struct_return = 0;
+
+  switch (target->cmodel)
+    {
+      case CMODEL_EXTREME:
+	if (opts->x_flag_plt)
+	  {
+	    if (opts_set->x_flag_plt)
+	      error ("code model %qs is not compatible with %s",
+		     "extreme", "-fplt");
+	    opts->x_flag_plt = 0;
+	  }
+	break;
+
+      case CMODEL_TINY_STATIC:
+      case CMODEL_MEDIUM:
+      case CMODEL_NORMAL:
+      case CMODEL_TINY:
+      case CMODEL_LARGE:
+	break;
+
+      default:
+	gcc_unreachable ();
+    }
+}
+
+
+/* Resolve options that's not covered by la_target.  */
+void
+loongarch_init_misc_options (struct gcc_options *opts,
+			     struct gcc_options *opts_set)
+{
+  if (opts->x_flag_pic)
+    opts->x_g_switch_value = 0;
+
+  /* -mrecip options.  */
+  opts->x_recip_mask = loongarch_parse_mrecip_scheme (opts->x_la_recip_name);
+
+#define INIT_TARGET_FLAG(NAME, INIT) \
+  { \
+    if (!(opts_set->x_target_flags & MASK_##NAME)) \
+      { \
+	if (INIT) \
+	  opts->x_target_flags |= MASK_##NAME; \
+	else \
+	  opts->x_target_flags &= ~MASK_##NAME; \
+      } \
+  }
+
+  /* Enable conditional moves for int and float by default.  */
+  INIT_TARGET_FLAG (COND_MOVE_INT, 1)
+  INIT_TARGET_FLAG (COND_MOVE_FLOAT, 1)
+
+  /* Set mrelax default.  */
+  INIT_TARGET_FLAG (LINKER_RELAXATION,
+		    HAVE_AS_MRELAX_OPTION && HAVE_AS_COND_BRANCH_RELAXATION)
+
+#undef INIT_TARGET_FLAG
+
+  /* Set mexplicit-relocs default.  */
+  if (opts->x_la_opt_explicit_relocs == M_OPT_UNSET)
+    opts->x_la_opt_explicit_relocs = (HAVE_AS_EXPLICIT_RELOCS
+				      ? (TARGET_LINKER_RELAXATION
+					 ? EXPLICIT_RELOCS_AUTO
+					 : EXPLICIT_RELOCS_ALWAYS)
+				      : EXPLICIT_RELOCS_NONE);
+
+  /* Enable sw prefetching at -O3 and higher.  */
+  if (opts->x_flag_prefetch_loop_arrays < 0
+      && (opts->x_optimize >= 3 || opts->x_flag_profile_use)
+      && !opts->x_optimize_size)
+    opts->x_flag_prefetch_loop_arrays = 1;
+
+  if (TARGET_DIRECT_EXTERN_ACCESS_OPTS_P (opts) && opts->x_flag_shlib)
+    error ("%qs cannot be used for compiling a shared library",
+	   "-mdirect-extern-access");
+
+  /* Enforce that interval is the same size as size so the mid-end does the
+     right thing.  */
+  SET_OPTION_IF_UNSET (opts, opts_set,
+		       param_stack_clash_protection_probe_interval,
+		       param_stack_clash_protection_guard_size);
+}
diff --git a/gcc/config/loongarch/loongarch-opts.h b/gcc/config/loongarch/loongarch-opts.h
index 586e67e65ee..2d9f59296e7 100644
--- a/gcc/config/loongarch/loongarch-opts.h
+++ b/gcc/config/loongarch/loongarch-opts.h
@@ -30,6 +30,10 @@  along with GCC; see the file COPYING3.  If not see
 /* Target configuration */
 extern struct loongarch_target la_target;
 
+/* RTL cost information */
+extern const struct loongarch_rtx_cost_data *loongarch_cost;
+
+
 /* Initialize loongarch_target from separate option variables.  */
 void
 loongarch_init_target (struct loongarch_target *target,
@@ -46,11 +50,30 @@  loongarch_config_target (struct loongarch_target *target,
 			 struct loongarch_flags *flags,
 			 int follow_multilib_list_p);
 
+
+/* Refresh the switches acccording to the resolved loongarch_target struct.  */
+void
+loongarch_target_option_override (struct loongarch_target *target,
+				  struct gcc_options *opts,
+				  struct gcc_options *opts_set);
+
+
 /* option status feedback for "gcc --help=target -Q" */
 void
 loongarch_update_gcc_opt_status (struct loongarch_target *target,
 				 struct gcc_options *opts,
 				 struct gcc_options *opts_set);
+
+
+/* Parser for -mrecip=<recip_string>.  */
+unsigned int
+loongarch_parse_mrecip_scheme (const char *recip_string);
+
+
+/* Resolve options that's not covered by la_target.  */
+void
+loongarch_init_misc_options (struct gcc_options *opts,
+			     struct gcc_options *opts_set);
 #endif
 
 /* Flag status */
@@ -80,9 +103,7 @@  struct loongarch_flags {
 #define TARGET_DOUBLE_FLOAT_ABI	  (la_target.abi.base == ABI_BASE_LP64D)
 
 #define TARGET_64BIT		  (la_target.isa.base == ISA_BASE_LA64)
-#define TARGET_ABI_LP64		  (la_target.abi.base == ABI_BASE_LP64D	\
-				   || la_target.abi.base == ABI_BASE_LP64F \
-				   || la_target.abi.base == ABI_BASE_LP64S)
+#define TARGET_ABI_LP64		  ABI_LP64_P(la_target.abi.base)
 
 #define ISA_HAS_LSX \
   (la_target.isa.simd == ISA_EXT_SIMD_LSX \
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index 030957db4e7..a69a203fbe6 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -208,9 +208,6 @@  const enum reg_class loongarch_regno_to_class[FIRST_PSEUDO_REGISTER] = {
     FRAME_REGS,	FRAME_REGS
 };
 
-/* Which cost information to use.  */
-static const struct loongarch_rtx_cost_data *loongarch_cost;
-
 /* Information about a single argument.  */
 struct loongarch_arg_info
 {
@@ -5911,17 +5908,6 @@  loongarch_print_operand_punctuation (FILE *file, int ch)
     }
 }
 
-/* Initialize loongarch_print_operand_punct.  */
-
-static void
-loongarch_init_print_operand_punct (void)
-{
-  const char *p;
-
-  for (p = ".$"; *p; p++)
-    loongarch_print_operand_punct[(unsigned char) *p] = true;
-}
-
 /* PRINT_OPERAND prefix LETTER refers to the integer branch instruction
    associated with condition CODE.  Print the condition part of the
    opcode to FILE.  */
@@ -7625,118 +7611,15 @@  loongarch_init_machine_status (void)
 }
 
 static void
-loongarch_cpu_option_override (struct loongarch_target *target,
-			       struct gcc_options *opts,
-			       struct gcc_options *opts_set)
-{
-  /* alignments */
-  if (opts->x_flag_align_functions && !opts->x_str_align_functions)
-    opts->x_str_align_functions
-      = loongarch_cpu_align[target->cpu_tune].function;
-
-  if (opts->x_flag_align_labels && !opts->x_str_align_labels)
-    opts->x_str_align_labels = loongarch_cpu_align[target->cpu_tune].label;
-
-  /* Set up parameters to be used in prefetching algorithm.  */
-  int simultaneous_prefetches
-    = loongarch_cpu_cache[target->cpu_tune].simultaneous_prefetches;
-
-  SET_OPTION_IF_UNSET (opts, opts_set, param_simultaneous_prefetches,
-		       simultaneous_prefetches);
-
-  SET_OPTION_IF_UNSET (opts, opts_set, param_l1_cache_line_size,
-		       loongarch_cpu_cache[target->cpu_tune].l1d_line_size);
-
-  SET_OPTION_IF_UNSET (opts, opts_set, param_l1_cache_size,
-		       loongarch_cpu_cache[target->cpu_tune].l1d_size);
-
-  SET_OPTION_IF_UNSET (opts, opts_set, param_l2_cache_size,
-		       loongarch_cpu_cache[target->cpu_tune].l2d_size);
-}
-
-static void
-loongarch_option_override_internal (struct gcc_options *opts,
-				    struct gcc_options *opts_set)
+loongarch_global_init (void)
 {
-  int i, regno, mode;
-
-  if (flag_pic)
-    g_switch_value = 0;
-
-  loongarch_init_target (&la_target,
-			 la_opt_cpu_arch, la_opt_cpu_tune, la_opt_fpu,
-			 la_opt_simd, la_opt_abi_base, la_opt_abi_ext,
-			 la_opt_cmodel, opts->x_la_isa_evolution,
-			 opts_set->x_la_isa_evolution);
-
-  /* Handle target-specific options: compute defaults/conflicts etc.  */
-  loongarch_config_target (&la_target, NULL, 0);
-
-  loongarch_update_gcc_opt_status (&la_target, opts, opts_set);
-  loongarch_cpu_option_override (&la_target, opts, opts_set);
-
-  if (TARGET_ABI_LP64)
-    flag_pcc_struct_return = 0;
-
-  /* Decide which rtx_costs structure to use.  */
-  if (optimize_size)
-    loongarch_cost = &loongarch_rtx_cost_optimize_size;
-  else
-    loongarch_cost = &loongarch_cpu_rtx_cost_data[la_target.cpu_tune];
-
-  /* If the user hasn't specified a branch cost, use the processor's
-     default.  */
-  if (la_branch_cost == 0)
-    la_branch_cost = loongarch_cost->branch_cost;
-
-  /* Enable sw prefetching at -O3 and higher.  */
-  if (opts->x_flag_prefetch_loop_arrays < 0
-      && (opts->x_optimize >= 3 || opts->x_flag_profile_use)
-      && !opts->x_optimize_size)
-    opts->x_flag_prefetch_loop_arrays = 1;
-
-  if (TARGET_DIRECT_EXTERN_ACCESS && flag_shlib)
-    error ("%qs cannot be used for compiling a shared library",
-	   "-mdirect-extern-access");
-
-  switch (la_target.cmodel)
-    {
-      case CMODEL_EXTREME:
-	if (opts->x_flag_plt)
-	  {
-	    if (global_options_set.x_flag_plt)
-	      error ("code model %qs is not compatible with %s",
-		     "extreme", "-fplt");
-	    opts->x_flag_plt = 0;
-	  }
-	break;
-
-      case CMODEL_TINY_STATIC:
-      case CMODEL_MEDIUM:
-      case CMODEL_NORMAL:
-      case CMODEL_TINY:
-      case CMODEL_LARGE:
-	break;
-
-      default:
-	gcc_unreachable ();
-    }
-
-  /* Validate the guard size.  */
-  int guard_size = param_stack_clash_protection_guard_size;
-
-  /* Enforce that interval is the same size as size so the mid-end does the
-     right thing.  */
-  SET_OPTION_IF_UNSET (opts, &global_options_set,
-		       param_stack_clash_protection_probe_interval,
-		       guard_size);
-
-  loongarch_init_print_operand_punct ();
+  /* Initialize loongarch_print_operand_punct.  */
+  for (const char *p = ".$"; *p; p++)
+    loongarch_print_operand_punct[(unsigned char) *p] = true;
 
   /* Set up array to map GCC register number to debug register number.
      Ignore the special purpose register numbers.  */
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
       if (GP_REG_P (i) || FP_REG_P (i))
 	loongarch_dwarf_regno[i] = i;
@@ -7745,115 +7628,53 @@  loongarch_option_override_internal (struct gcc_options *opts,
     }
 
   /* Set up loongarch_hard_regno_mode_ok.  */
-  for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
-    for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+  for (int mode = 0; mode < MAX_MACHINE_MODE; mode++)
+    for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
       loongarch_hard_regno_mode_ok_p[mode][regno]
 	= loongarch_hard_regno_mode_ok_uncached (regno, (machine_mode) mode);
 
   /* Function to allocate machine-dependent function status.  */
   init_machine_status = &loongarch_init_machine_status;
+};
 
-  /* -mrecip options.  */
-  static struct
-    {
-      const char *string;	    /* option name.  */
-      unsigned int mask;	    /* mask bits to set.  */
-    }
-  const recip_options[] = {
-	{ "all",       RECIP_MASK_ALL },
-	{ "none",      RECIP_MASK_NONE },
-	{ "div",       RECIP_MASK_DIV },
-	{ "sqrt",      RECIP_MASK_SQRT },
-	{ "rsqrt",     RECIP_MASK_RSQRT },
-	{ "vec-div",   RECIP_MASK_VEC_DIV },
-	{ "vec-sqrt",  RECIP_MASK_VEC_SQRT },
-	{ "vec-rsqrt", RECIP_MASK_VEC_RSQRT },
-  };
-
-  if (la_recip_name)
-    {
-      char *p = ASTRDUP (la_recip_name);
-      char *q;
-      unsigned int mask, i;
-      bool invert;
-
-      while ((q = strtok (p, ",")) != NULL)
-	{
-	  p = NULL;
-	  if (*q == '!')
-	    {
-	      invert = true;
-	      q++;
-	    }
-	  else
-	    invert = false;
-
-	  if (!strcmp (q, "default"))
-	    mask = RECIP_MASK_ALL;
-	  else
-	    {
-	      for (i = 0; i < ARRAY_SIZE (recip_options); i++)
-		if (!strcmp (q, recip_options[i].string))
-		  {
-		    mask = recip_options[i].mask;
-		    break;
-		  }
-
-	      if (i == ARRAY_SIZE (recip_options))
-		{
-		  error ("unknown option for %<-mrecip=%s%>", q);
-		  invert = false;
-		  mask = RECIP_MASK_NONE;
-		}
-	    }
-
-	  if (invert)
-	    recip_mask &= ~mask;
-	  else
-	    recip_mask |= mask;
-	}
-    }
-  if (la_recip)
-    recip_mask |= RECIP_MASK_ALL;
-  if (!ISA_HAS_FRECIPE)
-    recip_mask = RECIP_MASK_NONE;
-
-#define INIT_TARGET_FLAG(NAME, INIT) \
-  { \
-    if (!(target_flags_explicit & MASK_##NAME)) \
-      { \
-	if (INIT) \
-	  target_flags |= MASK_##NAME; \
-	else \
-	  target_flags &= ~MASK_##NAME; \
-      } \
-  }
-
-  /* Enable conditional moves for int and float by default.  */
-  INIT_TARGET_FLAG (COND_MOVE_INT, 1)
-  INIT_TARGET_FLAG (COND_MOVE_FLOAT, 1)
-
-  /* Set mrelax default.  */
-  INIT_TARGET_FLAG (LINKER_RELAXATION,
-		    HAVE_AS_MRELAX_OPTION && HAVE_AS_COND_BRANCH_RELAXATION)
+static void
+loongarch_option_override_internal (struct loongarch_target *target,
+				    struct gcc_options *opts,
+				    struct gcc_options *opts_set)
+{
+  /* Handle options not covered by struct loongarch_target.  */
+  loongarch_init_misc_options (opts, opts_set);
+
+  /* Resolve the target struct.  */
+  loongarch_init_target (target,
+			 opts->x_la_opt_cpu_arch,
+			 opts->x_la_opt_cpu_tune,
+			 opts->x_la_opt_fpu,
+			 opts->x_la_opt_simd,
+			 opts->x_la_opt_abi_base,
+			 opts->x_la_opt_abi_ext,
+			 opts->x_la_opt_cmodel,
+			 opts->x_la_isa_evolution,
+			 opts_set->x_la_isa_evolution);
 
-#undef INIT_TARGET_FLAG
+  loongarch_config_target (target, NULL, 0);
 
-  if (la_opt_explicit_relocs == M_OPT_UNSET)
-    la_opt_explicit_relocs = (HAVE_AS_EXPLICIT_RELOCS
-			      ? (TARGET_LINKER_RELAXATION
-				 ? EXPLICIT_RELOCS_AUTO
-				 : EXPLICIT_RELOCS_ALWAYS)
-			      : EXPLICIT_RELOCS_NONE);
+  /* Override some options according to the resolved target.  */
+  loongarch_target_option_override (target, opts, opts_set);
 }
 
-
 /* Implement TARGET_OPTION_OVERRIDE.  */
 
 static void
 loongarch_option_override (void)
 {
-  loongarch_option_override_internal (&global_options, &global_options_set);
+  /* Setting up the target configuration.  */
+  loongarch_option_override_internal (&la_target,
+				      &global_options,
+				      &global_options_set);
+
+  /* Global initializations.  */
+  loongarch_global_init ();
 }
 
 /* Implement TARGET_OPTION_SAVE.  */
diff --git a/gcc/config/loongarch/loongarch.h b/gcc/config/loongarch/loongarch.h
index 888a633961d..23bb3254883 100644
--- a/gcc/config/loongarch/loongarch.h
+++ b/gcc/config/loongarch/loongarch.h
@@ -710,12 +710,18 @@  enum reg_class
 			| RECIP_MASK_RSQRT | RECIP_MASK_VEC_SQRT \
 			| RECIP_MASK_VEC_DIV | RECIP_MASK_VEC_RSQRT)
 
-#define TARGET_RECIP_DIV        ((recip_mask & RECIP_MASK_DIV) != 0 || TARGET_uARCH_LA664)
-#define TARGET_RECIP_SQRT       ((recip_mask & RECIP_MASK_SQRT) != 0 || TARGET_uARCH_LA664)
-#define TARGET_RECIP_RSQRT      ((recip_mask & RECIP_MASK_RSQRT) != 0 || TARGET_uARCH_LA664)
-#define TARGET_RECIP_VEC_DIV    ((recip_mask & RECIP_MASK_VEC_DIV) != 0 || TARGET_uARCH_LA664)
-#define TARGET_RECIP_VEC_SQRT   ((recip_mask & RECIP_MASK_VEC_SQRT) != 0 || TARGET_uARCH_LA664)
-#define TARGET_RECIP_VEC_RSQRT  ((recip_mask & RECIP_MASK_VEC_RSQRT) != 0 || TARGET_uARCH_LA664)
+#define TARGET_RECIP_DIV \
+  ((recip_mask & RECIP_MASK_DIV) != 0 && ISA_HAS_FRECIPE)
+#define TARGET_RECIP_SQRT \
+  ((recip_mask & RECIP_MASK_SQRT) != 0 && ISA_HAS_FRECIPE)
+#define TARGET_RECIP_RSQRT \
+  ((recip_mask & RECIP_MASK_RSQRT) != 0 && ISA_HAS_FRECIPE)
+#define TARGET_RECIP_VEC_DIV \
+  ((recip_mask & RECIP_MASK_VEC_DIV) != 0 && ISA_HAS_FRECIPE)
+#define TARGET_RECIP_VEC_SQRT \
+  ((recip_mask & RECIP_MASK_VEC_SQRT) != 0 && ISA_HAS_FRECIPE)
+#define TARGET_RECIP_VEC_RSQRT \
+  ((recip_mask & RECIP_MASK_VEC_RSQRT) != 0 && ISA_HAS_FRECIPE)
 
 /* 1 if N is a possible register number for function argument passing.
    We have no FP argument registers when soft-float.  */
diff --git a/gcc/config/loongarch/loongarch.opt b/gcc/config/loongarch/loongarch.opt
index f10fcdd968c..317cd11a67c 100644
--- a/gcc/config/loongarch/loongarch.opt
+++ b/gcc/config/loongarch/loongarch.opt
@@ -205,14 +205,14 @@  mexplicit-relocs
 Target Alias(mexplicit-relocs=, always, none)
 Use %reloc() assembly operators (for backward compatibility).
 
-mrecip
-Target RejectNegative Var(la_recip) Save
-Generate approximate reciprocal divide and square root for better throughput.
-
 mrecip=
 Target RejectNegative Joined Var(la_recip_name) Save
 Control generation of reciprocal estimates.
 
+mrecip
+Target Alias(mrecip=, all, none)
+Generate approximate reciprocal divide and square root for better throughput.
+
 ; The code model option names for -mcmodel.
 Enum
 Name(cmodel) Type(int)