From patchwork Mon Aug 3 15:20:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kyrylo Tkachov X-Patchwork-Id: 503225 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 0E0191402D6 for ; Tue, 4 Aug 2015 01:20:32 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=K0eYwYm6; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=ywB2wBQ0tKOgnjnbL DW0SNZXpmlwhfc+6DFDhxgZIFsLrKdxu2bZaYcWAjwOhzZKkXBpW5KEtV/rX0NKD sRgRE946vB1wh40mBzzr9lZEF3pb4RyjRccd1GpCu0LREKnG5zQwKM9ok7/kdlcY 23TXKzdRKFrsoPHPI2+by1B32Y= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=xsUlo704YPCirGWue6IOOH3 MSaM=; b=K0eYwYm6HcFmHuDoGTTNN6lBMZeFl6JD4UdcttD45OMhNrCfYIqkTFg stBypbHYRO43mUL5ZXFrPz99+0rtfAmmEPRg9QYJE/WxCPqku/TuBS5F7apDCeQ6 85R36Oty9U6nhMCXKYUF25N5/bsKqWm9ZYJaBkn230/jz88u28T8= Received: (qmail 99131 invoked by alias); 3 Aug 2015 15:20:23 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 99120 invoked by uid 89); 3 Aug 2015 15:20:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.0 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, SPF_PASS autolearn=no version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Received: from eu-smtp-delivery-143.mimecast.com (HELO eu-smtp-delivery-143.mimecast.com) (207.82.80.143) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 03 Aug 2015 15:20:18 +0000 Received: from cam-owa2.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-32-Imv-JzoZTX-0LpJ63FCxkA-1; Mon, 03 Aug 2015 16:20:14 +0100 Received: from [10.2.207.50] ([10.1.2.79]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 3 Aug 2015 16:20:13 +0100 Message-ID: <55BF86AD.2020701@arm.com> Date: Mon, 03 Aug 2015 16:20:13 +0100 From: Kyrill Tkachov User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 MIME-Version: 1.0 To: James Greenhalgh CC: GCC Patches , Marcus Shawcroft , Richard Earnshaw Subject: Re: [PATCH][AArch64][8/14] Implement TARGET_OPTION_VALID_ATTRIBUTE_P References: <55A7CBDB.9020908@arm.com> <20150721153733.GA13935@arm.com> <55B216D4.5010604@arm.com> <20150803105246.GA10382@arm.com> In-Reply-To: <20150803105246.GA10382@arm.com> X-MC-Unique: Imv-JzoZTX-0LpJ63FCxkA-1 X-IsSubscribed: yes 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; >> + > <> > >> + 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 * 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 > commit 48f8c09d7841c2591714c7ca90fb2894fc9186b1 Author: Kyrylo Tkachov 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