diff mbox

[AArch64,8/14] Implement TARGET_OPTION_VALID_ATTRIBUTE_P

Message ID 55BF86AD.2020701@arm.com
State New
Headers show

Commit Message

Kyrylo Tkachov Aug. 3, 2015, 3:20 p.m. UTC
On 03/08/15 11:52, James Greenhalgh wrote:
> On Fri, Jul 24, 2015 at 11:43:32AM +0100, Kyrill Tkachov wrote:
>> On 21/07/15 16:37, James Greenhalgh wrote:
>>> On Thu, Jul 16, 2015 at 04:20:59PM +0100, Kyrill Tkachov wrote:
>>>> Hi all,
>>>>
>>>> This patch implements target attribute support via the TARGET_OPTION_VALID_ATTRIBUTE_P hook.
>>>> The aarch64_handle_option function in common/config/aarch64/aarch64-common.c is exported to the
>>>> backend and beefed up a bit.
>>>>
>>>> The target attributes supported by this patch reflect the command-line options that we specified as Save
>>>> earlier in the series.  Explicitly, the target attributes supported are:
>>>>     - "general-regs-only"
>>>>     - "fix-cortex-a53-835769" and "no-fix-cortex-a53-835769"
>>>>     - "cmodel="
>>>>     - "strict-align"
>>>>     - "omit-leaf-frame-pointer" and "no-omit-leaf-frame-pointer"
>>>>     - "tls-dialect"
>>>>     - "arch="
>>>>     - "cpu="
>>>>     - "tune="
>>>>
>>>> These correspond to equivalent command-line options when prefixed with a '-m'.
>>>> Additionally, this patch supports specifying architectural features, as in the -march and -mcpu options
>>>> by themselves. So, for example we can write:
>>>> __attribute__((target("+simd+crypto")))
>>>> to enable 'simd' and 'crypto' on a per-function basis.
>>>>
>>>> The documentation and tests for this come as a separate patch later after the target pragma support and
>>>> the inlining rules are implemented.
>>>>
>>>> Bootstrapped and tested on aarch64.
>>>>
>>> In addition to the comments below, you may want to run
>>> contrib/check_GNU_style.sh on this patch, it shows a number of other
>>> issues that would be nice to fix.
>> Thanks, here's the updated patch.
>> I used alloca for memory allocation to keep consistent with the rest of aarch64.c,
>> fixed the error message issues, spacing and control flow issues you pointed out.
>>
>> How's this?
>> +static bool
>> +aarch64_process_one_target_attr (char *arg_str, const char* pragma_or_attr)
>> +{
>> +  bool ret;
>> +  bool invert = false;
>> +
> <<snip>>
>
>> +  ret = false;
> I don't think this variable is exactly what you want. Surely as soon
> as we see a failure case, we want to return false. Otherwise we could
> see junk,junk,ok_stuff and return true.
>
> So I would drop "ret" and rewrite this to bail out as soon as we see an
> error. The downside is we won't catch multiple errors that way.
>
> The other thing to do would be to invert the sense of your flag to something
> like "failed" and only set it where we fail. It depends what behaviour
> you're looking for.
>
>> +  for (p_attr = aarch64_attributes; !ret && p_attr->name; p_attr++)
>> +    {
>> +      /* If the names don't match up, or the user has given an argument
>> +	 to an attribute that doesn't accept one, or didn't give an argument
>> +	 to an attribute that expects one, fail to match.  */
>> +      if (strcmp (str_to_check, p_attr->name) != 0)
>> +	continue;
>> +
>> +      bool attr_need_arg_p = p_attr->attr_type == aarch64_attr_custom
>> +			      || p_attr->attr_type == aarch64_attr_enum;
>> +
>> +      if (attr_need_arg_p ^ (arg != NULL))
>> +	{
>> +	  error ("target %s %qs does not accept an argument",
>> +		  pragma_or_attr, str_to_check);
>> +	  return false;
>> +	}
>> +
>> +      /* If the name matches but the attribute does not allow "no-" versions
>> +	 then we can't match.  */
>> +      if (invert && !p_attr->allow_neg)
>> +	{
>> +	  error ("target %s %qs does not allow a negated form",
>> +		  pragma_or_attr, str_to_check);
>> +	  return false;
>> +	}
>> +
>> +      switch (p_attr->attr_type)
>> +	{
>> +	/* Has a custom handler registered.
>> +	   For example, cpu=, arch=, tune=.  */
>> +	  case aarch64_attr_custom:
>> +	    gcc_assert (p_attr->handler);
>> +	    ret = p_attr->handler (arg, pragma_or_attr);
>> +	    break;
>> +
>> +	  /* Either set or unset a boolean option.  */
>> +	  case aarch64_attr_bool:
>> +	    {
>> +	      struct cl_decoded_option decoded;
>> +
>> +	      generate_option (p_attr->opt_num, NULL, !invert,
>> +			       CL_TARGET, &decoded);
>> +	      aarch64_handle_option (&global_options, &global_options_set,
>> +				      &decoded, input_location);
>> +	      ret = true;
>> +	      break;
>> +	    }
>> +	  /* Set or unset a bit in the target_flags.  aarch64_handle_option
>> +	     should know what mask to apply given the option number.  */
>> +	  case aarch64_attr_mask:
>> +	    {
>> +	      struct cl_decoded_option decoded;
>> +	      /* We only need to specify the option number.
>> +		 aarch64_handle_option will know which mask to apply.  */
>> +	      decoded.opt_index = p_attr->opt_num;
>> +	      decoded.value = !invert;
>> +	      aarch64_handle_option (&global_options, &global_options_set,
>> +				      &decoded, input_location);
>> +	      ret = true;
>> +	      break;
>> +	    }
>> +	  /* Use the option setting machinery to set an option to an enum.  */
>> +	  case aarch64_attr_enum:
>> +	    {
>> +	      gcc_assert (arg);
>> +	      bool valid;
>> +	      int value;
>> +	      valid = opt_enum_arg_to_value (p_attr->opt_num, arg,
>> +					      &value, CL_TARGET);
>> +	      if (valid)
>> +		{
>> +		  set_option (&global_options, NULL, p_attr->opt_num, value,
>> +			      NULL, DK_UNSPECIFIED, input_location,
>> +			      global_dc);
>> +		  ret = true;
>> +		}
>> +	      else
>> +		{
>> +		  error ("target %s %s=%s is not valid",
>> +			 pragma_or_attr, str_to_check, arg);
>> +		  ret = false;
>> +		}
>> +	      break;
>> +	    }
>> +	  default:
>> +	    gcc_unreachable ();
>> +	}
>> +    }
>> +
>> +  return ret;
>> +}
>> +
>> +/* Parse the tree in ARGS that contains the target attribute information
>> +   and update the global target options space.  PRAGMA_OR_ATTR is a string
>> +   to be used in error messages, specifying whether this is processing
>> +   a target attribute or a target pragma.  */
>> +
>> +bool
>> +aarch64_process_target_attr (tree args, const char* pragma_or_attr)
>> +{
>> +  bool ret = true;
> Same comment again...
>
>> +  if (TREE_CODE (args) == TREE_LIST)
>> +    {
>> +      do
>> +	{
>> +	  tree head = TREE_VALUE (args);
>> +	  if (head)
>> +	    {
>> +	      if (!aarch64_process_target_attr (head, pragma_or_attr))
>> +		ret = false;
>> +	    }
>> +	  args = TREE_CHAIN (args);
>> +	} while (args);
>> +
>> +      return ret;
>> +    }
>> +  /* We expect to find a string to parse.  */
>> +  gcc_assert (TREE_CODE (args) == STRING_CST);
>> +
>> +  size_t len = strlen (TREE_STRING_POINTER (args));
>> +  char *str_to_check = (char *) alloca (len + 1);
>> +  strcpy (str_to_check, TREE_STRING_POINTER (args));
>> +
>> +  if (len == 0)
>> +    {
>> +      error ("malformed target %s value", pragma_or_attr);
>> +      return false;
>> +    }
>> +
>> +  /* Used to catch empty spaces between commas i.e.
>> +     attribute ((target ("attr1,,attr2"))).  */
>> +  unsigned int num_commas = num_occurences_in_str (',', str_to_check);
>> +
>> +  /* Handle multiple target attributes separated by ','.  */
>> +  char *token = strtok (str_to_check, ",");
>> +
>> +  unsigned int num_attrs = 0;
>> +  while (token)
>> +    {
>> +      num_attrs++;
>> +      if (!aarch64_process_one_target_attr (token, pragma_or_attr))
>> +	{
>> +	  error ("target %s %qs is invalid", pragma_or_attr, token);
>> +	  ret = false;
>> +	}
>> +
>> +      token = strtok (NULL, ",");
>> +    }
>> +
>> +  if (num_attrs != num_commas + 1)
>> +    {
>> +      error ("malformed target %s list %qs",
>> +	      pragma_or_attr, TREE_STRING_POINTER (args));
>> +      ret = false;
>> +    }
>> +
>> +  return ret;
>> +}
>> +
>> +/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P.  This is used to
>> +   process attribute ((target ("..."))).  */
>> +
>> +static bool
>> +aarch64_option_valid_attribute_p (tree fndecl, tree, tree args, int)
>> +{
>> +  struct cl_target_option cur_target;
>> +  bool ret;
>> +  tree old_optimize;
>> +  tree new_target, new_optimize;
>> +  tree existing_target = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
>> +  tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
>> +
>> +  old_optimize = build_optimization_node (&global_options);
>> +  func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
>> +
>> +  /* If the function changed the optimization levels as well as setting
>> +     target options, start with the optimizations specified.  */
>> +  if (func_optimize && func_optimize != old_optimize)
>> +    cl_optimization_restore (&global_options,
>> +			     TREE_OPTIMIZATION (func_optimize));
>> +
>> +  /* Save the current target options to restore at the end.  */
>> +  cl_target_option_save (&cur_target, &global_options);
>> +
>> +  /* If fndecl already has some target attributes applied to it, unpack
>> +     them so that we add this attribute on top of them, rather than
>> +     overwriting them.  */
>> +  if (existing_target)
>> +    {
>> +      struct cl_target_option *existing_options
>> +	= TREE_TARGET_OPTION (existing_target);
>> +
>> +      if (existing_options)
>> +	cl_target_option_restore (&global_options, existing_options);
>> +    }
>> +  else
>> +    cl_target_option_restore (&global_options,
>> +			TREE_TARGET_OPTION (target_option_current_node));
>> +
>> +
>> +  ret = aarch64_process_target_attr (args, "attribute");
>> +
>> +  /* Set up any additional state.  */
>> +  if (ret)
>> +    {
>> +      aarch64_override_options_internal (&global_options);
>> +      new_target = build_target_option_node (&global_options);
>> +    }
>> +  else
>> +    new_target = NULL;
>> +
>> +  new_optimize = build_optimization_node (&global_options);
>> +
>> +  if (!new_target)
>> +    ret = false;
>> +
> Misleading newline, and another use of a "ret" variable.

Ok, I've removed usages of 'ret' in favor of returning when appropriate.
In this last one I left the ret (but cleaned up the control flow a bit)
because if the processing fails we need to clean up a bit of state before
returning.

Thanks,
Kyrill

2015-08-03  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

      * common/config/aarch64/aarch64-common.c (aarch64_handle_option):
      Remove static.  Handle OPT_mgeneral_regs_only,
      OPT_mfix_cortex_a53_835769, OPT_mstrict_align,
      OPT_momit_leaf_frame_pointer.
      * config/aarch64/aarch64.c: Include opts.h and diagnostic.h
      (aarch64_attr_opt_type): New enum.
      (aarch64_attribute_info): New struct.
      (aarch64_handle_attr_arch): New function.
      (aarch64_handle_attr_cpu): Likewise.
      (aarch64_handle_attr_tune): Likewise.
      (aarch64_handle_attr_isa_flags): Likewise.
      (aarch64_attributes): New table.
      (aarch64_process_one_target_attr): New function.
      (num_occurences_in_str): Likewise.
      (aarch64_process_target_attr): Likewise.
      (aarch64_option_valid_attribute_p): Likewise.
      (TARGET_OPTION_VALID_ATTRIBUTE_P): Define.
      * config/aarch64/aarch64-protos.h: Include input.h
      (aarch64_handle_option): Declare prototype.



>
> Thanks,
> James
>

Comments

James Greenhalgh Aug. 4, 2015, 8:53 a.m. UTC | #1
On Mon, Aug 03, 2015 at 04:20:13PM +0100, Kyrill Tkachov wrote:
> Ok, I've removed usages of 'ret' in favor of returning when appropriate.
> In this last one I left the ret (but cleaned up the control flow a bit)
> because if the processing fails we need to clean up a bit of state before
> returning.

This is OK with the changes below fixed, or commented on as justification.

> diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
> index fc1cec7..3a5482d 100644
> --- a/gcc/config/aarch64/aarch64-protos.h
> +++ b/gcc/config/aarch64/aarch64-protos.h
> @@ -376,6 +378,8 @@ extern bool aarch64_madd_needs_nop (rtx_insn *);
>  extern void aarch64_final_prescan_insn (rtx_insn *);
>  extern bool
>  aarch64_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel);
> +bool aarch64_handle_option (struct gcc_options *, struct gcc_options *,
> +			     const struct cl_decoded_option *, location_t);

Please try to keep this file in alphabetical order, first by return type,
then by function name.

>  void aarch64_atomic_assign_expand_fenv (tree *, tree *, tree *);
>  int aarch64_ccmp_mode_to_code (enum machine_mode mode);
>  
> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
> index d0d62e7..7a369fd 100644
> --- a/gcc/config/aarch64/aarch64.c
> +++ b/gcc/config/aarch64/aarch64.c

> +static bool
> +aarch64_handle_attr_arch (const char *str, const char *pragma_or_attr)
> +{
> +  const struct processor *tmp_arch = NULL;
> +  enum aarch64_parse_opt_result parse_res
> +    = aarch64_parse_arch (str, &tmp_arch, &aarch64_isa_flags);
> +
> +  if (parse_res == AARCH64_PARSE_OK)
> +    {
> +      gcc_assert (tmp_arch);
> +      selected_arch = tmp_arch;
> +      explicit_arch = selected_arch->arch;
> +      return true;
> +    }

Why not pull this in to the switch case below?

> +
> +  switch (parse_res)
> +    {
> +      case AARCH64_PARSE_MISSING_ARG:
> +	error ("missing architecture name in 'arch' target %s", pragma_or_attr);
> +	break;
> +      case AARCH64_PARSE_INVALID_ARG:
> +	error ("unknown value %qs for 'arch' target %s", str, pragma_or_attr);
> +	break;
> +      case AARCH64_PARSE_INVALID_FEATURE:
> +	error ("invalid feature modifier %qs for 'arch' target %s",
> +	       str, pragma_or_attr);
> +	break;
> +      default:
> +	gcc_unreachable ();
> +    }
> +
> +  return false;
> +}
> +
> +/* Handle the argument CPU_STR to the cpu= target attribute.
> +   PRAGMA_OR_ATTR is used in potential error messages.  */
> +
> +static bool
> +aarch64_handle_attr_cpu (const char *str, const char *pragma_or_attr)
> +{
> +  const struct processor *tmp_cpu = NULL;
> +  enum aarch64_parse_opt_result parse_res
> +    = aarch64_parse_cpu (str, &tmp_cpu, &aarch64_isa_flags);
> +
> +  if (parse_res == AARCH64_PARSE_OK)
> +    {
> +      gcc_assert (tmp_cpu);
> +      selected_tune = tmp_cpu;
> +      explicit_tune_core = selected_tune->ident;
> +
> +      selected_arch = &all_architectures[tmp_cpu->arch];
> +      explicit_arch = selected_arch->arch;
> +      return true;
> +    }

Likewise here.

> +
> +  switch (parse_res)
> +    {
> +      case AARCH64_PARSE_MISSING_ARG:
> +	error ("missing cpu name in 'cpu' target %s", pragma_or_attr);
> +	break;
> +      case AARCH64_PARSE_INVALID_ARG:
> +	error ("unknown value %qs for 'cpu' target %s", str, pragma_or_attr);
> +	break;
> +      case AARCH64_PARSE_INVALID_FEATURE:
> +	error ("invalid feature modifier %qs for 'cpu' target %s",
> +	       str, pragma_or_attr);
> +	break;
> +      default:
> +	gcc_unreachable ();
> +    }
> +
> +  return false;
> +}
> +
> +/* Handle the argument STR to the tune= target attribute.
> +   PRAGMA_OR_ATTR is used in potential error messages.  */
> +
> +static bool
> +aarch64_handle_attr_tune (const char *str, const char *pragma_or_attr)
> +{
> +  const struct processor *tmp_tune = NULL;
> +  enum aarch64_parse_opt_result parse_res
> +    = aarch64_parse_tune (str, &tmp_tune);
> +
> +  if (parse_res == AARCH64_PARSE_OK)
> +    {
> +      gcc_assert (tmp_tune);
> +      selected_tune = tmp_tune;
> +      explicit_tune_core = selected_tune->ident;
> +      return true;
> +    }
> +

And likewise here.

> +  switch (parse_res)
> +    {
> +      case AARCH64_PARSE_INVALID_ARG:
> +	error ("unknown value %qs for 'tune' target %s", str, pragma_or_attr);
> +	break;
> +      default:
> +	gcc_unreachable ();
> +    }
> +
> +  return false;
> +}
> +
> +/* Parse an architecture extensions target attribute string specified in STR.
> +   For example "+fp+nosimd".  Show any errors if needed.  Return TRUE
> +   if successful.  Update aarch64_isa_flags to reflect the ISA features
> +   modified.
> +   PRAGMA_OR_ATTR is used in potential error messages.  */
> +
> +static bool
> +aarch64_handle_attr_isa_flags (char *str, const char *pragma_or_attr)
> +{
> +  enum aarch64_parse_opt_result parse_res;
> +  unsigned long isa_flags = aarch64_isa_flags;
> +
> +  parse_res = aarch64_parse_extension (str, &isa_flags);
> +
> +  if (parse_res == AARCH64_PARSE_OK)
> +    {
> +      aarch64_isa_flags = isa_flags;
> +      return true;
> +    }
> +

And again here.

> +  switch (parse_res)
> +    {
> +      case AARCH64_PARSE_MISSING_ARG:
> +	error ("missing feature modifier in target %s %qs",
> +	       pragma_or_attr, str);
> +	break;
> +
> +      case AARCH64_PARSE_INVALID_FEATURE:
> +	error ("invalid feature modifier in target %s %qs",
> +	       pragma_or_attr, str);
> +	break;
> +
> +      default:
> +	gcc_unreachable ();
> +    }
> +
> + return false;
> +}
> +

Thanks,
James
Kyrylo Tkachov Aug. 4, 2015, 8:58 a.m. UTC | #2
On 04/08/15 09:53, James Greenhalgh wrote:
> On Mon, Aug 03, 2015 at 04:20:13PM +0100, Kyrill Tkachov wrote:
>> Ok, I've removed usages of 'ret' in favor of returning when appropriate.
>> In this last one I left the ret (but cleaned up the control flow a bit)
>> because if the processing fails we need to clean up a bit of state before
>> returning.
> This is OK with the changes below fixed, or commented on as justification.
>
>> diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
>> index fc1cec7..3a5482d 100644
>> --- a/gcc/config/aarch64/aarch64-protos.h
>> +++ b/gcc/config/aarch64/aarch64-protos.h
>> @@ -376,6 +378,8 @@ extern bool aarch64_madd_needs_nop (rtx_insn *);
>>   extern void aarch64_final_prescan_insn (rtx_insn *);
>>   extern bool
>>   aarch64_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel);
>> +bool aarch64_handle_option (struct gcc_options *, struct gcc_options *,
>> +			     const struct cl_decoded_option *, location_t);
> Please try to keep this file in alphabetical order, first by return type,
> then by function name.

Ok, will do.

>
>>   void aarch64_atomic_assign_expand_fenv (tree *, tree *, tree *);
>>   int aarch64_ccmp_mode_to_code (enum machine_mode mode);
>>   
>> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
>> index d0d62e7..7a369fd 100644
>> --- a/gcc/config/aarch64/aarch64.c
>> +++ b/gcc/config/aarch64/aarch64.c
>> +static bool
>> +aarch64_handle_attr_arch (const char *str, const char *pragma_or_attr)
>> +{
>> +  const struct processor *tmp_arch = NULL;
>> +  enum aarch64_parse_opt_result parse_res
>> +    = aarch64_parse_arch (str, &tmp_arch, &aarch64_isa_flags);
>> +
>> +  if (parse_res == AARCH64_PARSE_OK)
>> +    {
>> +      gcc_assert (tmp_arch);
>> +      selected_arch = tmp_arch;
>> +      explicit_arch = selected_arch->arch;
>> +      return true;
>> +    }
> Why not pull this in to the switch case below?

I chose to keep the success case separate from error handling and reporting as it made it
easier to find it (and it is the more interesting case in these functions). I can add a comment
to that effect there if you'd like.

Thanks,
Kyrill

>
>> +
>> +  switch (parse_res)
>> +    {
>> +      case AARCH64_PARSE_MISSING_ARG:
>> +	error ("missing architecture name in 'arch' target %s", pragma_or_attr);
>> +	break;
>> +      case AARCH64_PARSE_INVALID_ARG:
>> +	error ("unknown value %qs for 'arch' target %s", str, pragma_or_attr);
>> +	break;
>> +      case AARCH64_PARSE_INVALID_FEATURE:
>> +	error ("invalid feature modifier %qs for 'arch' target %s",
>> +	       str, pragma_or_attr);
>> +	break;
>> +      default:
>> +	gcc_unreachable ();
>> +    }
>> +
>> +  return false;
>> +}
>> +
>> +/* Handle the argument CPU_STR to the cpu= target attribute.
>> +   PRAGMA_OR_ATTR is used in potential error messages.  */
>> +
>> +static bool
>> +aarch64_handle_attr_cpu (const char *str, const char *pragma_or_attr)
>> +{
>> +  const struct processor *tmp_cpu = NULL;
>> +  enum aarch64_parse_opt_result parse_res
>> +    = aarch64_parse_cpu (str, &tmp_cpu, &aarch64_isa_flags);
>> +
>> +  if (parse_res == AARCH64_PARSE_OK)
>> +    {
>> +      gcc_assert (tmp_cpu);
>> +      selected_tune = tmp_cpu;
>> +      explicit_tune_core = selected_tune->ident;
>> +
>> +      selected_arch = &all_architectures[tmp_cpu->arch];
>> +      explicit_arch = selected_arch->arch;
>> +      return true;
>> +    }
> Likewise here.
>
>> +
>> +  switch (parse_res)
>> +    {
>> +      case AARCH64_PARSE_MISSING_ARG:
>> +	error ("missing cpu name in 'cpu' target %s", pragma_or_attr);
>> +	break;
>> +      case AARCH64_PARSE_INVALID_ARG:
>> +	error ("unknown value %qs for 'cpu' target %s", str, pragma_or_attr);
>> +	break;
>> +      case AARCH64_PARSE_INVALID_FEATURE:
>> +	error ("invalid feature modifier %qs for 'cpu' target %s",
>> +	       str, pragma_or_attr);
>> +	break;
>> +      default:
>> +	gcc_unreachable ();
>> +    }
>> +
>> +  return false;
>> +}
>> +
>> +/* Handle the argument STR to the tune= target attribute.
>> +   PRAGMA_OR_ATTR is used in potential error messages.  */
>> +
>> +static bool
>> +aarch64_handle_attr_tune (const char *str, const char *pragma_or_attr)
>> +{
>> +  const struct processor *tmp_tune = NULL;
>> +  enum aarch64_parse_opt_result parse_res
>> +    = aarch64_parse_tune (str, &tmp_tune);
>> +
>> +  if (parse_res == AARCH64_PARSE_OK)
>> +    {
>> +      gcc_assert (tmp_tune);
>> +      selected_tune = tmp_tune;
>> +      explicit_tune_core = selected_tune->ident;
>> +      return true;
>> +    }
>> +
> And likewise here.
>
>> +  switch (parse_res)
>> +    {
>> +      case AARCH64_PARSE_INVALID_ARG:
>> +	error ("unknown value %qs for 'tune' target %s", str, pragma_or_attr);
>> +	break;
>> +      default:
>> +	gcc_unreachable ();
>> +    }
>> +
>> +  return false;
>> +}
>> +
>> +/* Parse an architecture extensions target attribute string specified in STR.
>> +   For example "+fp+nosimd".  Show any errors if needed.  Return TRUE
>> +   if successful.  Update aarch64_isa_flags to reflect the ISA features
>> +   modified.
>> +   PRAGMA_OR_ATTR is used in potential error messages.  */
>> +
>> +static bool
>> +aarch64_handle_attr_isa_flags (char *str, const char *pragma_or_attr)
>> +{
>> +  enum aarch64_parse_opt_result parse_res;
>> +  unsigned long isa_flags = aarch64_isa_flags;
>> +
>> +  parse_res = aarch64_parse_extension (str, &isa_flags);
>> +
>> +  if (parse_res == AARCH64_PARSE_OK)
>> +    {
>> +      aarch64_isa_flags = isa_flags;
>> +      return true;
>> +    }
>> +
> And again here.
>
>> +  switch (parse_res)
>> +    {
>> +      case AARCH64_PARSE_MISSING_ARG:
>> +	error ("missing feature modifier in target %s %qs",
>> +	       pragma_or_attr, str);
>> +	break;
>> +
>> +      case AARCH64_PARSE_INVALID_FEATURE:
>> +	error ("invalid feature modifier in target %s %qs",
>> +	       pragma_or_attr, str);
>> +	break;
>> +
>> +      default:
>> +	gcc_unreachable ();
>> +    }
>> +
>> + return false;
>> +}
>> +
> Thanks,
> James
>
James Greenhalgh Aug. 4, 2015, 9:02 a.m. UTC | #3
On Tue, Aug 04, 2015 at 09:58:37AM +0100, Kyrill Tkachov wrote:
> 
> On 04/08/15 09:53, James Greenhalgh wrote:
> > On Mon, Aug 03, 2015 at 04:20:13PM +0100, Kyrill Tkachov wrote:
> >> Ok, I've removed usages of 'ret' in favor of returning when appropriate.
> >> In this last one I left the ret (but cleaned up the control flow a bit)
> >> because if the processing fails we need to clean up a bit of state before
> >> returning.
> > This is OK with the changes below fixed, or commented on as justification.
> >
> >> diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
> >> index fc1cec7..3a5482d 100644
> >> --- a/gcc/config/aarch64/aarch64-protos.h
> >> +++ b/gcc/config/aarch64/aarch64-protos.h
> >> @@ -376,6 +378,8 @@ extern bool aarch64_madd_needs_nop (rtx_insn *);
> >>   extern void aarch64_final_prescan_insn (rtx_insn *);
> >>   extern bool
> >>   aarch64_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel);
> >> +bool aarch64_handle_option (struct gcc_options *, struct gcc_options *,
> >> +			     const struct cl_decoded_option *, location_t);
> > Please try to keep this file in alphabetical order, first by return type,
> > then by function name.
> 
> Ok, will do.
> 
> >
> >>   void aarch64_atomic_assign_expand_fenv (tree *, tree *, tree *);
> >>   int aarch64_ccmp_mode_to_code (enum machine_mode mode);
> >>   
> >> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
> >> index d0d62e7..7a369fd 100644
> >> --- a/gcc/config/aarch64/aarch64.c
> >> +++ b/gcc/config/aarch64/aarch64.c
> >> +static bool
> >> +aarch64_handle_attr_arch (const char *str, const char *pragma_or_attr)
> >> +{
> >> +  const struct processor *tmp_arch = NULL;
> >> +  enum aarch64_parse_opt_result parse_res
> >> +    = aarch64_parse_arch (str, &tmp_arch, &aarch64_isa_flags);
> >> +
> >> +  if (parse_res == AARCH64_PARSE_OK)
> >> +    {
> >> +      gcc_assert (tmp_arch);
> >> +      selected_arch = tmp_arch;
> >> +      explicit_arch = selected_arch->arch;
> >> +      return true;
> >> +    }
> > Why not pull this in to the switch case below?
> 
> I chose to keep the success case separate from error handling and reporting as it made it
> easier to find it (and it is the more interesting case in these functions). I can add a comment
> to that effect there if you'd like.

I thought that might be it. It looks unusual to me, but I don't have
strong feelings against it, so I'm happy for you to leave it as is if
that is your preference.

Thanks,
James
diff mbox

Patch

commit 48f8c09d7841c2591714c7ca90fb2894fc9186b1
Author: Kyrylo Tkachov <kyrylo.tkachov@arm.com>
Date:   Fri May 8 12:06:24 2015 +0100

    [AArch64][8/N] Implement TARGET_OPTION_VALID_ATTRIBUTE_P

diff --git a/gcc/common/config/aarch64/aarch64-common.c b/gcc/common/config/aarch64/aarch64-common.c
index b3fd9dc..726c625 100644
--- a/gcc/common/config/aarch64/aarch64-common.c
+++ b/gcc/common/config/aarch64/aarch64-common.c
@@ -60,7 +60,7 @@  static const struct default_options aarch_option_optimization_table[] =
    respective component of -mcpu.  This logic is implemented
    in config/aarch64/aarch64.c:aarch64_override_options.  */
 
-static bool
+bool
 aarch64_handle_option (struct gcc_options *opts,
 		       struct gcc_options *opts_set ATTRIBUTE_UNUSED,
 		       const struct cl_decoded_option *decoded,
@@ -68,6 +68,7 @@  aarch64_handle_option (struct gcc_options *opts,
 {
   size_t code = decoded->opt_index;
   const char *arg = decoded->arg;
+  int val = decoded->value;
 
   switch (code)
     {
@@ -83,6 +84,22 @@  aarch64_handle_option (struct gcc_options *opts,
       opts->x_aarch64_tune_string = arg;
       return true;
 
+    case OPT_mgeneral_regs_only:
+      opts->x_target_flags |= MASK_GENERAL_REGS_ONLY;
+      return true;
+
+    case OPT_mfix_cortex_a53_835769:
+      opts->x_aarch64_fix_a53_err835769 = val;
+      return true;
+
+    case OPT_mstrict_align:
+      opts->x_target_flags |= MASK_STRICT_ALIGN;
+      return true;
+
+    case OPT_momit_leaf_frame_pointer:
+      opts->x_flag_omit_frame_pointer = val;
+      return true;
+
     default:
       return true;
     }
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index fc1cec7..3a5482d 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -22,6 +22,8 @@ 
 #ifndef GCC_AARCH64_PROTOS_H
 #define GCC_AARCH64_PROTOS_H
 
+#include "input.h"
+
 /*
   SYMBOL_CONTEXT_ADR
   The symbol is used in a load-address operation.
@@ -376,6 +378,8 @@  extern bool aarch64_madd_needs_nop (rtx_insn *);
 extern void aarch64_final_prescan_insn (rtx_insn *);
 extern bool
 aarch64_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel);
+bool aarch64_handle_option (struct gcc_options *, struct gcc_options *,
+			     const struct cl_decoded_option *, location_t);
 void aarch64_atomic_assign_expand_fenv (tree *, tree *, tree *);
 int aarch64_ccmp_mode_to_code (enum machine_mode mode);
 
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index d0d62e7..7a369fd 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -57,6 +57,8 @@ 
 #include "tm_p.h"
 #include "recog.h"
 #include "langhooks.h"
+#include "opts.h"
+#include "diagnostic.h"
 #include "diagnostic-core.h"
 #include "internal-fn.h"
 #include "gimple-fold.h"
@@ -7964,6 +7966,499 @@  aarch64_set_current_function (tree fndecl)
     }
 }
 
+/* Enum describing the various ways we can handle attributes.
+   In many cases we can reuse the generic option handling machinery.  */
+
+enum aarch64_attr_opt_type
+{
+  aarch64_attr_mask,	/* Attribute should set a bit in target_flags.  */
+  aarch64_attr_bool,	/* Attribute sets or unsets a boolean variable.  */
+  aarch64_attr_enum,	/* Attribute sets an enum variable.  */
+  aarch64_attr_custom	/* Attribute requires a custom handling function.  */
+};
+
+/* All the information needed to handle a target attribute.
+   NAME is the name of the attribute.
+   ATTR_TYPE specifies the type of behaviour of the attribute as described
+   in the definition of enum aarch64_attr_opt_type.
+   ALLOW_NEG is true if the attribute supports a "no-" form.
+   HANDLER is the function that takes the attribute string and whether
+   it is a pragma or attribute and handles the option.  It is needed only
+   when the ATTR_TYPE is aarch64_attr_custom.
+   OPT_NUM is the enum specifying the option that the attribute modifies.
+   This is needed for attributes that mirror the behaviour of a command-line
+   option, that is it has ATTR_TYPE aarch64_attr_mask, aarch64_attr_bool or
+   aarch64_attr_enum.  */
+
+struct aarch64_attribute_info
+{
+  const char *name;
+  enum aarch64_attr_opt_type attr_type;
+  bool allow_neg;
+  bool (*handler) (const char *, const char *);
+  enum opt_code opt_num;
+};
+
+/* Handle the ARCH_STR argument to the arch= target attribute.
+   PRAGMA_OR_ATTR is used in potential error messages.  */
+
+static bool
+aarch64_handle_attr_arch (const char *str, const char *pragma_or_attr)
+{
+  const struct processor *tmp_arch = NULL;
+  enum aarch64_parse_opt_result parse_res
+    = aarch64_parse_arch (str, &tmp_arch, &aarch64_isa_flags);
+
+  if (parse_res == AARCH64_PARSE_OK)
+    {
+      gcc_assert (tmp_arch);
+      selected_arch = tmp_arch;
+      explicit_arch = selected_arch->arch;
+      return true;
+    }
+
+  switch (parse_res)
+    {
+      case AARCH64_PARSE_MISSING_ARG:
+	error ("missing architecture name in 'arch' target %s", pragma_or_attr);
+	break;
+      case AARCH64_PARSE_INVALID_ARG:
+	error ("unknown value %qs for 'arch' target %s", str, pragma_or_attr);
+	break;
+      case AARCH64_PARSE_INVALID_FEATURE:
+	error ("invalid feature modifier %qs for 'arch' target %s",
+	       str, pragma_or_attr);
+	break;
+      default:
+	gcc_unreachable ();
+    }
+
+  return false;
+}
+
+/* Handle the argument CPU_STR to the cpu= target attribute.
+   PRAGMA_OR_ATTR is used in potential error messages.  */
+
+static bool
+aarch64_handle_attr_cpu (const char *str, const char *pragma_or_attr)
+{
+  const struct processor *tmp_cpu = NULL;
+  enum aarch64_parse_opt_result parse_res
+    = aarch64_parse_cpu (str, &tmp_cpu, &aarch64_isa_flags);
+
+  if (parse_res == AARCH64_PARSE_OK)
+    {
+      gcc_assert (tmp_cpu);
+      selected_tune = tmp_cpu;
+      explicit_tune_core = selected_tune->ident;
+
+      selected_arch = &all_architectures[tmp_cpu->arch];
+      explicit_arch = selected_arch->arch;
+      return true;
+    }
+
+  switch (parse_res)
+    {
+      case AARCH64_PARSE_MISSING_ARG:
+	error ("missing cpu name in 'cpu' target %s", pragma_or_attr);
+	break;
+      case AARCH64_PARSE_INVALID_ARG:
+	error ("unknown value %qs for 'cpu' target %s", str, pragma_or_attr);
+	break;
+      case AARCH64_PARSE_INVALID_FEATURE:
+	error ("invalid feature modifier %qs for 'cpu' target %s",
+	       str, pragma_or_attr);
+	break;
+      default:
+	gcc_unreachable ();
+    }
+
+  return false;
+}
+
+/* Handle the argument STR to the tune= target attribute.
+   PRAGMA_OR_ATTR is used in potential error messages.  */
+
+static bool
+aarch64_handle_attr_tune (const char *str, const char *pragma_or_attr)
+{
+  const struct processor *tmp_tune = NULL;
+  enum aarch64_parse_opt_result parse_res
+    = aarch64_parse_tune (str, &tmp_tune);
+
+  if (parse_res == AARCH64_PARSE_OK)
+    {
+      gcc_assert (tmp_tune);
+      selected_tune = tmp_tune;
+      explicit_tune_core = selected_tune->ident;
+      return true;
+    }
+
+  switch (parse_res)
+    {
+      case AARCH64_PARSE_INVALID_ARG:
+	error ("unknown value %qs for 'tune' target %s", str, pragma_or_attr);
+	break;
+      default:
+	gcc_unreachable ();
+    }
+
+  return false;
+}
+
+/* Parse an architecture extensions target attribute string specified in STR.
+   For example "+fp+nosimd".  Show any errors if needed.  Return TRUE
+   if successful.  Update aarch64_isa_flags to reflect the ISA features
+   modified.
+   PRAGMA_OR_ATTR is used in potential error messages.  */
+
+static bool
+aarch64_handle_attr_isa_flags (char *str, const char *pragma_or_attr)
+{
+  enum aarch64_parse_opt_result parse_res;
+  unsigned long isa_flags = aarch64_isa_flags;
+
+  parse_res = aarch64_parse_extension (str, &isa_flags);
+
+  if (parse_res == AARCH64_PARSE_OK)
+    {
+      aarch64_isa_flags = isa_flags;
+      return true;
+    }
+
+  switch (parse_res)
+    {
+      case AARCH64_PARSE_MISSING_ARG:
+	error ("missing feature modifier in target %s %qs",
+	       pragma_or_attr, str);
+	break;
+
+      case AARCH64_PARSE_INVALID_FEATURE:
+	error ("invalid feature modifier in target %s %qs",
+	       pragma_or_attr, str);
+	break;
+
+      default:
+	gcc_unreachable ();
+    }
+
+ return false;
+}
+
+/* The target attributes that we support.  On top of these we also support just
+   ISA extensions, like  __attribute__ ((target ("+crc"))), but that case is
+   handled explicitly in aarch64_process_one_target_attr.  */
+
+static const struct aarch64_attribute_info aarch64_attributes[] =
+{
+  { "general-regs-only", aarch64_attr_mask, false, NULL,
+     OPT_mgeneral_regs_only },
+  { "fix-cortex-a53-835769", aarch64_attr_bool, true, NULL,
+     OPT_mfix_cortex_a53_835769 },
+  { "cmodel", aarch64_attr_enum, false, NULL, OPT_mcmodel_ },
+  { "strict-align", aarch64_attr_mask, false, NULL, OPT_mstrict_align },
+  { "omit-leaf-frame-pointer", aarch64_attr_bool, true, NULL,
+     OPT_momit_leaf_frame_pointer },
+  { "tls-dialect", aarch64_attr_enum, false, NULL, OPT_mtls_dialect_ },
+  { "arch", aarch64_attr_custom, false, aarch64_handle_attr_arch,
+     OPT_march_ },
+  { "cpu", aarch64_attr_custom, false, aarch64_handle_attr_cpu, OPT_mcpu_ },
+  { "tune", aarch64_attr_custom, false, aarch64_handle_attr_tune,
+     OPT_mtune_ },
+  { NULL, aarch64_attr_custom, false, NULL, OPT____ }
+};
+
+/* Parse ARG_STR which contains the definition of one target attribute.
+   Show appropriate errors if any or return true if the attribute is valid.
+   PRAGMA_OR_ATTR holds the string to use in error messages about whether
+   we're processing a target attribute or pragma.  */
+
+static bool
+aarch64_process_one_target_attr (char *arg_str, const char* pragma_or_attr)
+{
+  bool invert = false;
+
+  size_t len = strlen (arg_str);
+
+  if (len == 0)
+    {
+      error ("malformed target %s", pragma_or_attr);
+      return false;
+    }
+
+  char *str_to_check = (char *) alloca (len + 1);
+  strcpy (str_to_check, arg_str);
+
+  /* Skip leading whitespace.  */
+  while (*str_to_check == ' ' || *str_to_check == '\t')
+    str_to_check++;
+
+  /* We have something like __attribute__ ((target ("+fp+nosimd"))).
+     It is easier to detect and handle it explicitly here rather than going
+     through the machinery for the rest of the target attributes in this
+     function.  */
+  if (*str_to_check == '+')
+    return aarch64_handle_attr_isa_flags (str_to_check, pragma_or_attr);
+
+  if (len > 3 && strncmp (str_to_check, "no-", 3) == 0)
+    {
+      invert = true;
+      str_to_check += 3;
+    }
+  char *arg = strchr (str_to_check, '=');
+
+  /* If we found opt=foo then terminate STR_TO_CHECK at the '='
+     and point ARG to "foo".  */
+  if (arg)
+    {
+      *arg = '\0';
+      arg++;
+    }
+  const struct aarch64_attribute_info *p_attr;
+  for (p_attr = aarch64_attributes; p_attr->name; p_attr++)
+    {
+      /* If the names don't match up, or the user has given an argument
+	 to an attribute that doesn't accept one, or didn't give an argument
+	 to an attribute that expects one, fail to match.  */
+      if (strcmp (str_to_check, p_attr->name) != 0)
+	continue;
+
+      bool attr_need_arg_p = p_attr->attr_type == aarch64_attr_custom
+			      || p_attr->attr_type == aarch64_attr_enum;
+
+      if (attr_need_arg_p ^ (arg != NULL))
+	{
+	  error ("target %s %qs does not accept an argument",
+		  pragma_or_attr, str_to_check);
+	  return false;
+	}
+
+      /* If the name matches but the attribute does not allow "no-" versions
+	 then we can't match.  */
+      if (invert && !p_attr->allow_neg)
+	{
+	  error ("target %s %qs does not allow a negated form",
+		  pragma_or_attr, str_to_check);
+	  return false;
+	}
+
+      switch (p_attr->attr_type)
+	{
+	/* Has a custom handler registered.
+	   For example, cpu=, arch=, tune=.  */
+	  case aarch64_attr_custom:
+	    gcc_assert (p_attr->handler);
+	    if (!p_attr->handler (arg, pragma_or_attr))
+	      return false;
+	    break;
+
+	  /* Either set or unset a boolean option.  */
+	  case aarch64_attr_bool:
+	    {
+	      struct cl_decoded_option decoded;
+
+	      generate_option (p_attr->opt_num, NULL, !invert,
+			       CL_TARGET, &decoded);
+	      aarch64_handle_option (&global_options, &global_options_set,
+				      &decoded, input_location);
+	      break;
+	    }
+	  /* Set or unset a bit in the target_flags.  aarch64_handle_option
+	     should know what mask to apply given the option number.  */
+	  case aarch64_attr_mask:
+	    {
+	      struct cl_decoded_option decoded;
+	      /* We only need to specify the option number.
+		 aarch64_handle_option will know which mask to apply.  */
+	      decoded.opt_index = p_attr->opt_num;
+	      decoded.value = !invert;
+	      aarch64_handle_option (&global_options, &global_options_set,
+				      &decoded, input_location);
+	      break;
+	    }
+	  /* Use the option setting machinery to set an option to an enum.  */
+	  case aarch64_attr_enum:
+	    {
+	      gcc_assert (arg);
+	      bool valid;
+	      int value;
+	      valid = opt_enum_arg_to_value (p_attr->opt_num, arg,
+					      &value, CL_TARGET);
+	      if (valid)
+		{
+		  set_option (&global_options, NULL, p_attr->opt_num, value,
+			      NULL, DK_UNSPECIFIED, input_location,
+			      global_dc);
+		}
+	      else
+		{
+		  error ("target %s %s=%s is not valid",
+			 pragma_or_attr, str_to_check, arg);
+		}
+	      break;
+	    }
+	  default:
+	    gcc_unreachable ();
+	}
+    }
+
+  return true;
+}
+
+/* Count how many times the character C appears in
+   NULL-terminated string STR.  */
+
+static unsigned int
+num_occurences_in_str (char c, char *str)
+{
+  unsigned int res = 0;
+  while (*str != '\0')
+    {
+      if (*str == c)
+	res++;
+
+      str++;
+    }
+
+  return res;
+}
+
+/* Parse the tree in ARGS that contains the target attribute information
+   and update the global target options space.  PRAGMA_OR_ATTR is a string
+   to be used in error messages, specifying whether this is processing
+   a target attribute or a target pragma.  */
+
+bool
+aarch64_process_target_attr (tree args, const char* pragma_or_attr)
+{
+  if (TREE_CODE (args) == TREE_LIST)
+    {
+      do
+	{
+	  tree head = TREE_VALUE (args);
+	  if (head)
+	    {
+	      if (!aarch64_process_target_attr (head, pragma_or_attr))
+		return false;
+	    }
+	  args = TREE_CHAIN (args);
+	} while (args);
+
+      return true;
+    }
+  /* We expect to find a string to parse.  */
+  gcc_assert (TREE_CODE (args) == STRING_CST);
+
+  size_t len = strlen (TREE_STRING_POINTER (args));
+  char *str_to_check = (char *) alloca (len + 1);
+  strcpy (str_to_check, TREE_STRING_POINTER (args));
+
+  if (len == 0)
+    {
+      error ("malformed target %s value", pragma_or_attr);
+      return false;
+    }
+
+  /* Used to catch empty spaces between commas i.e.
+     attribute ((target ("attr1,,attr2"))).  */
+  unsigned int num_commas = num_occurences_in_str (',', str_to_check);
+
+  /* Handle multiple target attributes separated by ','.  */
+  char *token = strtok (str_to_check, ",");
+
+  unsigned int num_attrs = 0;
+  while (token)
+    {
+      num_attrs++;
+      if (!aarch64_process_one_target_attr (token, pragma_or_attr))
+	{
+	  error ("target %s %qs is invalid", pragma_or_attr, token);
+	  return false;
+	}
+
+      token = strtok (NULL, ",");
+    }
+
+  if (num_attrs != num_commas + 1)
+    {
+      error ("malformed target %s list %qs",
+	      pragma_or_attr, TREE_STRING_POINTER (args));
+      return false;
+    }
+
+  return true;
+}
+
+/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P.  This is used to
+   process attribute ((target ("..."))).  */
+
+static bool
+aarch64_option_valid_attribute_p (tree fndecl, tree, tree args, int)
+{
+  struct cl_target_option cur_target;
+  bool ret;
+  tree old_optimize;
+  tree new_target, new_optimize;
+  tree existing_target = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
+  tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+
+  old_optimize = build_optimization_node (&global_options);
+  func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+
+  /* If the function changed the optimization levels as well as setting
+     target options, start with the optimizations specified.  */
+  if (func_optimize && func_optimize != old_optimize)
+    cl_optimization_restore (&global_options,
+			     TREE_OPTIMIZATION (func_optimize));
+
+  /* Save the current target options to restore at the end.  */
+  cl_target_option_save (&cur_target, &global_options);
+
+  /* If fndecl already has some target attributes applied to it, unpack
+     them so that we add this attribute on top of them, rather than
+     overwriting them.  */
+  if (existing_target)
+    {
+      struct cl_target_option *existing_options
+	= TREE_TARGET_OPTION (existing_target);
+
+      if (existing_options)
+	cl_target_option_restore (&global_options, existing_options);
+    }
+  else
+    cl_target_option_restore (&global_options,
+			TREE_TARGET_OPTION (target_option_current_node));
+
+
+  ret = aarch64_process_target_attr (args, "attribute");
+
+  /* Set up any additional state.  */
+  if (ret)
+    {
+      aarch64_override_options_internal (&global_options);
+      new_target = build_target_option_node (&global_options);
+    }
+  else
+    new_target = NULL;
+
+  new_optimize = build_optimization_node (&global_options);
+
+  if (fndecl && ret)
+    {
+      DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
+
+      if (old_optimize != new_optimize)
+	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
+    }
+
+  cl_target_option_restore (&global_options, &cur_target);
+
+  if (old_optimize != new_optimize)
+    cl_optimization_restore (&global_options,
+			     TREE_OPTIMIZATION (old_optimize));
+  return ret;
+}
+
 /* Return true if SYMBOL_REF X binds locally.  */
 
 static bool
@@ -12478,6 +12973,9 @@  aarch64_promoted_type (const_tree t)
 #undef TARGET_OPTION_PRINT
 #define TARGET_OPTION_PRINT aarch64_option_print
 
+#undef TARGET_OPTION_VALID_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_ATTRIBUTE_P aarch64_option_valid_attribute_p
+
 #undef TARGET_SET_CURRENT_FUNCTION
 #define TARGET_SET_CURRENT_FUNCTION aarch64_set_current_function