From patchwork Fri Jun 9 12:53:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Richard Earnshaw \(lists\)" X-Patchwork-Id: 103505 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp199275qgd; Fri, 9 Jun 2017 06:06:18 -0700 (PDT) X-Received: by 10.101.85.14 with SMTP id f14mr43255800pgr.112.1497013578181; Fri, 09 Jun 2017 06:06:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497013578; cv=none; d=google.com; s=arc-20160816; b=YhUTWgbVmcYGlkxjVs0mKggtCTdvXVK/K8oNz/2Z4XQSV3whsV4gjPXdk64zM/cB4q t9C9F0o9lIcVBkJMY7V7NvX85r0TiE+VtSrwMEDHgdvMQzAh0GiOa5q8LBqpsOCd7+2q QuzyYRC15I406qs2d1nKf7nVUmekjU9TdFzacw6cqpd/4jEw/RlOV4g6TLvUK1bLJ6bu TCdIorLwU6+AqQlgq0o/btyJlsS92Bp52UVPWg7sn7dRNxbKCAOkdLQPGiTs4vpRSI9x SDD+gnrHQSl0CyfZJLmIf1EgWqlTK+UOvmu4nm70S7f6CzLq7pKyknwO9wIeXPEFvd9v X2Kg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=mime-version:references:in-reply-to:references:in-reply-to :message-id:date:subject:cc:to:from:delivered-to:sender:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence :mailing-list:dkim-signature:domainkey-signature :arc-authentication-results; bh=evm+iQTW7zjH6gsOpGqQ6raoL/2o8lhBTQFxBfmXiBM=; b=iVNetHUo4O3NyQ9S4ATwD9GvRiMteicuqC7szjCxnUD1/U+KPvJERPC50JuM7cMh1+ l9vdN0vjDh0ezO5RMB7v6HG5v0TetPIBAaDY4QEUSVjFIL7IXf/w9nA9xZh2D4OCdoDe sZkNgPlSH5FmXCTAg4PUpqUxubyBrbeIpE+GNnE/NvlQm7FZnTqsDSSPPmu3BRofigt/ WlQViJToLazvwk//6rBuMyz3oFi5Ic0JPybIXT48rLv0YdvLtzSNrzSP97KZJQaSvXRX wzD4sfhSNgkyMd7xqzshK5nEUAfrW6qAJyXnAjuYm81zZn8tNrm3zoS8XUWy/fqWYf6f aQtA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-455549-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-455549-patch=linaro.org@gcc.gnu.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id 64si932067pft.234.2017.06.09.06.06.17 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 09 Jun 2017 06:06:18 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-455549-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-455549-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-455549-patch=linaro.org@gcc.gnu.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references:mime-version:content-type; q=dns; s= default; b=DkE7lRvLDGTFlTq/XJ4AYpTWBXZ2cdsmhwR7qgTLVJpkAvabe5lWQ mRNB8nK2QhjivslKalUPLobky2pyhphh5jlkMq/HNs3i8zu6e7Eo9d6p/SU/41lF 6KhyufXG7B8AQvkw5RYo/M2Blwxj1bmPTmupFuhNjKRg3PEZ+G3Wc0= 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:from :to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references:mime-version:content-type; s=default; bh=74Q5xwlN0CppnEzet6neMXp3Tn4=; b=b+DyJ+84GBd2LP7tTjMtrH82m05t EAFPVSk9NeQfaegTfiAE9U9VqNit3z5usc1bM/2MkGCeLqNPK9+b93aTrfTgVMAI MbmmayjKT2nrt5q1GrmtKoB29gSyrhbxwuCEa1oB8eB/yWelQnS08MvF5/CgEPIP +h/6MbDGUi3pinQ= Received: (qmail 109764 invoked by alias); 9 Jun 2017 12:55:18 -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 97344 invoked by uid 89); 9 Jun 2017 12:54:56 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_SOFTFAIL autolearn=ham version=3.3.2 spammy=badly, relate, aids X-HELO: eggs.gnu.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (208.118.235.92) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 09 Jun 2017 12:54:46 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dJJQh-0007aL-OP for gcc-patches@gcc.gnu.org; Fri, 09 Jun 2017 08:54:22 -0400 Received: from foss.arm.com ([217.140.101.70]:47128) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dJJQh-0007Te-Di for gcc-patches@gcc.gnu.org; Fri, 09 Jun 2017 08:54:19 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 223551610; Fri, 9 Jun 2017 05:54:19 -0700 (PDT) Received: from e105689-lin.cambridge.arm.com (e105689-lin.cambridge.arm.com [10.2.207.32]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9E7603F3E1; Fri, 9 Jun 2017 05:54:18 -0700 (PDT) From: Richard Earnshaw To: gcc-patches@gcc.gnu.org Cc: Richard Earnshaw Subject: [PATCH 14/30] [arm] Generate a canonical form for -march Date: Fri, 9 Jun 2017 13:53:43 +0100 Message-Id: In-Reply-To: References: In-Reply-To: References: MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 217.140.101.70 This patch uses the driver and some spec rewrite rules to generate a canonicalized form of the -march= option. We want to do this for several reasons, all relating to making multi-lib selection sane. 1) It can remove redundant extension options to produce a minimal list. 2) The general syntax of the option permits a plethora of features, these are permitted in any order. Canonicalization ensures that there is a single ordering of the options that are needed. 3) It can use additional options to remove extensions that aren't relevant, such as removing all features that relate to the FPU when use of that is disabled. Once we have this information in a sensible form the multilib rules can be vastly simplified making for much more understandable Makefile fragments. * common/config/arm/arm-common.c: Define INCLUDE_LIST. (configargs.h): Include it. (arm_print_hint_for_fpu_option): New function. (arm_parse_fpu_option): New function. (candidate_extension): New class. (arm_canon_for_multilib): New function. * config/arm/arm.h (CANON_ARCH_SPEC_FUNCTION): New macro. (EXTRA_SPEC_FUNCTIONS): Add CANON_ARCH_SPEC_FUNCTION. (ARCH_CANONICAL_SPECS): New macro. (DRIVER_SELF_SPECS): Add ARCH_CANONICAL_SPECS. --- gcc/common/config/arm/arm-common.c | 354 +++++++++++++++++++++++++++++++++++++ gcc/config/arm/arm.h | 19 +- 2 files changed, 372 insertions(+), 1 deletion(-) diff --git a/gcc/common/config/arm/arm-common.c b/gcc/common/config/arm/arm-common.c index 930cfb0..c4ab482 100644 --- a/gcc/common/config/arm/arm-common.c +++ b/gcc/common/config/arm/arm-common.c @@ -17,6 +17,7 @@ along with GCC; see the file COPYING3. If not see . */ +#define INCLUDE_LIST #include "config.h" #include "system.h" #include "coretypes.h" @@ -305,6 +306,41 @@ arm_parse_arch_option_name (const arch_option *list, const char *optname, return NULL; } +/* List the premitted architecture option names. If TARGET is a near + miss for an entry, print out the suggested alternative. */ +static void +arm_print_hint_for_fpu_option (const char *target) +{ + auto_vec candidates; + for (int i = 0; i < TARGET_FPU_auto; i++) + candidates.safe_push (all_fpus[i].name); + char *s; + const char *hint = candidates_list_and_hint (target, s, candidates); + if (hint) + inform (input_location, "valid arguments are: %s; did you mean %qs?", + s, hint); + else + inform (input_location, "valid arguments are: %s", s); + + XDELETEVEC (s); +} + +static const arm_fpu_desc * +arm_parse_fpu_option (const char *opt) +{ + int i; + + for (i = 0; i < TARGET_FPU_auto; i++) + { + if (strcmp (all_fpus[i].name, opt) == 0) + return all_fpus + i; + } + + error_at (input_location, "unrecognized -mfpu target: %s", opt); + arm_print_hint_for_fpu_option (opt); + return NULL; +} + /* Convert a static initializer array of feature bits to sbitmap representation. */ void @@ -405,6 +441,324 @@ arm_parse_option_features (sbitmap isa, const cpu_arch_option *target, } } +class candidate_extension +{ +public: + const cpu_arch_extension *extension; + sbitmap isa_bits; + bool required; + + candidate_extension (const cpu_arch_extension *ext, sbitmap bits) + : extension (ext), isa_bits (bits), required (true) + {} + ~candidate_extension () + { + sbitmap_free (isa_bits); + } +}; + +/* Generate a canonical representation of the -march option from the + current -march string (if given) and other options on the command + line that might affect the architecture. This aids multilib selection + by ensuring that: + a) the option is always present + b) only the minimal set of options are used + c) when there are multiple extensions, they are in a consistent order. + + The options array consists of couplets of information where the + first item in each couplet is the string describing which option + name was selected (arch, cpu, fpu) and the second is the value + passed for that option. */ +const char * +arm_canon_arch_option (int argc, const char **argv) +{ + const char *arch = NULL; + const char *cpu = NULL; + const char *fpu = NULL; + const char *abi = NULL; + static char *canonical_arch = NULL; + + /* Just in case we're called more than once. */ + if (canonical_arch) + { + free (canonical_arch); + canonical_arch = NULL; + } + + if (argc & 1) + fatal_error (input_location, + "%%:canon_for_mlib takes 1 or more pairs of parameters"); + + while (argc) + { + if (strcmp (argv[0], "arch") == 0) + arch = argv[1]; + else if (strcmp (argv[0], "cpu") == 0) + cpu = argv[1]; + else if (strcmp (argv[0], "fpu") == 0) + fpu = argv[1]; + else if (strcmp (argv[0], "abi") == 0) + abi = argv[1]; + else + fatal_error (input_location, + "unrecognized operand to %%:canon_for_mlib"); + + argc -= 2; + argv += 2; + } + + auto_sbitmap target_isa (isa_num_bits); + auto_sbitmap base_isa (isa_num_bits); + auto_sbitmap fpu_isa (isa_num_bits); + + bitmap_clear (fpu_isa); + + const arch_option *selected_arch = NULL; + + /* At least one of these must be defined by either the specs or the + user. */ + gcc_assert (cpu || arch); + + if (!fpu) + fpu = FPUTYPE_DEFAULT; + + if (!abi) + { + if (TARGET_DEFAULT_FLOAT_ABI == ARM_FLOAT_ABI_SOFT) + abi = "soft"; + else if (TARGET_DEFAULT_FLOAT_ABI == ARM_FLOAT_ABI_SOFTFP) + abi = "softfp"; + else if (TARGET_DEFAULT_FLOAT_ABI == ARM_FLOAT_ABI_HARD) + abi = "hard"; + } + + /* First build up a bitmap describing the target architecture. */ + if (arch) + { + selected_arch = arm_parse_arch_option_name (all_architectures, + "-march", arch); + + if (selected_arch == NULL) + return ""; + + arm_initialize_isa (target_isa, selected_arch->common.isa_bits); + arm_parse_option_features (target_isa, &selected_arch->common, + strchr (arch, '+')); + if (fpu && strcmp (fpu, "auto") != 0) + { + /* We assume that architectures do not have any FPU bits + enabled by default. If they did, we would need to strip + these out first. */ + const arm_fpu_desc *target_fpu = arm_parse_fpu_option (fpu); + if (target_fpu == NULL) + return ""; + + arm_initialize_isa (fpu_isa, target_fpu->isa_bits); + bitmap_ior (target_isa, target_isa, fpu_isa); + } + } + else if (cpu) + { + const cpu_option *selected_cpu + = arm_parse_cpu_option_name (all_cores, "-mcpu", cpu); + + if (selected_cpu == NULL) + return ""; + + arm_initialize_isa (target_isa, selected_cpu->common.isa_bits); + arm_parse_option_features (target_isa, &selected_cpu->common, + strchr (cpu, '+')); + if (fpu && strcmp (fpu, "auto") != 0) + { + /* The easiest and safest way to remove the default fpu + capabilities is to look for a '+no..' option that removes + the base FPU bit (isa_bit_VFPv2). If that doesn't exist + then the best we can do is strip out all the bits that + might be part of the most capable FPU we know about, + which is "crypto-neon-fp-armv8". */ + bool default_fpu_found = false; + if (selected_cpu->common.extensions) + { + const cpu_arch_extension *ext; + for (ext = selected_cpu->common.extensions; ext->name != NULL; + ++ext) + { + if (ext->remove + && check_isa_bits_for (ext->isa_bits, isa_bit_VFPv2)) + { + arm_initialize_isa (fpu_isa, ext->isa_bits); + bitmap_and_compl (target_isa, target_isa, fpu_isa); + default_fpu_found = true; + } + } + + } + + if (!default_fpu_found) + { + arm_initialize_isa + (fpu_isa, + all_fpus[TARGET_FPU_crypto_neon_fp_armv8].isa_bits); + bitmap_and_compl (target_isa, target_isa, fpu_isa); + } + + const arm_fpu_desc *target_fpu = arm_parse_fpu_option (fpu); + if (target_fpu == NULL) + return ""; + + arm_initialize_isa (fpu_isa, target_fpu->isa_bits); + bitmap_ior (target_isa, target_isa, fpu_isa); + } + + selected_arch = all_architectures + selected_cpu->arch; + } + + /* If we have a soft-float ABI, disable the FPU. */ + if (abi && strcmp (abi, "soft") == 0) + { + /* Clearing the VFPv2 bit is sufficient to stop any extention that + builds on the FPU from matching. */ + bitmap_clear_bit (target_isa, isa_bit_VFPv2); + } + + /* If we don't have a selected architecture by now, something's + badly wrong. */ + gcc_assert (selected_arch); + + arm_initialize_isa (base_isa, selected_arch->common.isa_bits); + + /* Architecture has no extension options, so just return the canonical + architecture name. */ + if (selected_arch->common.extensions == NULL) + return selected_arch->common.name; + + /* We're only interested in extension bits. */ + bitmap_and_compl (target_isa, target_isa, base_isa); + + /* There are no extensions needed. Just return the canonical architecture + name. */ + if (bitmap_empty_p (target_isa)) + return selected_arch->common.name; + + /* What is left is the architecture that the compiler will target. We + now need to map that back into a suitable option+features list. + + The list is built in two passes. First we scan every additive + option feature supported by the architecture. If the option + provides a subset of the features we need we add it to the list + of candidates. We then scan backwards over the list of + candidates and if we find a feature that adds nothing to one that + was later in the list we mark it as redundant. The result is a + minimal list of required features for the target + architecture. */ + + std::list extensions; + + auto_sbitmap target_isa_unsatisfied (isa_num_bits); + bitmap_copy (target_isa_unsatisfied, target_isa); + + sbitmap isa_bits = NULL; + for (const cpu_arch_extension *cand = selected_arch->common.extensions; + cand->name != NULL; + cand++) + { + if (cand->remove || cand->alias) + continue; + + if (isa_bits == NULL) + isa_bits = sbitmap_alloc (isa_num_bits); + + arm_initialize_isa (isa_bits, cand->isa_bits); + if (bitmap_subset_p (isa_bits, target_isa)) + { + extensions.push_back (new candidate_extension (cand, isa_bits)); + bitmap_and_compl (target_isa_unsatisfied, target_isa_unsatisfied, + isa_bits); + isa_bits = NULL; + } + } + + /* There's one extra case to consider, which is that the user has + specified an FPU that is less capable than this architecture + supports. In that case the code above will fail to find a + suitable feature. We handle this by scanning the list of options + again, matching the first option that provides an FPU that is + more capable than the selected FPU. + + Note that the other case (user specified a more capable FPU than + this architecture supports) should end up selecting the most + capable FPU variant that we do support. This is sufficient for + multilib selection. */ + + if (bitmap_bit_p (target_isa_unsatisfied, isa_bit_VFPv2) + && bitmap_bit_p (fpu_isa, isa_bit_VFPv2)) + { + std::list::iterator ipoint = extensions.begin (); + + for (const cpu_arch_extension *cand = selected_arch->common.extensions; + cand->name != NULL; + cand++) + { + if (cand->remove || cand->alias) + continue; + + if (isa_bits == NULL) + isa_bits = sbitmap_alloc (isa_num_bits); + + /* We need to keep the features in canonical order, so move the + insertion point if this feature is a candidate. */ + if (ipoint != extensions.end () + && (*ipoint)->extension == cand) + ++ipoint; + + arm_initialize_isa (isa_bits, cand->isa_bits); + if (bitmap_subset_p (fpu_isa, isa_bits)) + { + extensions.insert (ipoint, + new candidate_extension (cand, isa_bits)); + isa_bits = NULL; + break; + } + } + } + + if (isa_bits) + sbitmap_free (isa_bits); + + bitmap_clear (target_isa); + size_t len = 1; + for (std::list::reverse_iterator riter + = extensions.rbegin (); + riter != extensions.rend (); ++riter) + { + if (bitmap_subset_p ((*riter)->isa_bits, target_isa)) + (*riter)->required = false; + else + { + bitmap_ior (target_isa, target_isa, (*riter)->isa_bits); + len += strlen ((*riter)->extension->name) + 1; + } + } + + canonical_arch + = (char *) xmalloc (len + strlen (selected_arch->common.name)); + + strcpy (canonical_arch, selected_arch->common.name); + + for (std::list::iterator iter = extensions.begin (); + iter != extensions.end (); ++iter) + { + if ((*iter)->required) + { + strcat (canonical_arch, "+"); + strcat (canonical_arch, (*iter)->extension->name); + } + delete (*iter); + } + + return canonical_arch; +} + #undef ARM_CPU_NAME_LENGTH diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 590755e..dea3d0a 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -2250,9 +2250,15 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); # define MCPU_MTUNE_NATIVE_SPECS "" #endif +const char *arm_canon_arch_option (int argc, const char **argv); + +#define CANON_ARCH_SPEC_FUNCTION \ + { "canon_arch", arm_canon_arch_option }, + # define EXTRA_SPEC_FUNCTIONS \ MCPU_MTUNE_NATIVE_FUNCTIONS \ ASM_CPU_SPEC_FUNCTIONS \ + CANON_ARCH_SPEC_FUNCTION \ TARGET_MODE_SPEC_FUNCTIONS /* Automatically add -mthumb for Thumb-only targets if mode isn't specified @@ -2264,7 +2270,18 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define TARGET_MODE_SPECS \ " %{!marm:%{!mthumb:%:target_mode_check(%{march=*:arch %*;mcpu=*:cpu %*;:})}}" -#define DRIVER_SELF_SPECS MCPU_MTUNE_NATIVE_SPECS TARGET_MODE_SPECS +/* Generate a canonical string to represent the architecture selected. */ +#define ARCH_CANONICAL_SPECS \ + " -march=%:canon_arch(%{mcpu=*: cpu %*} " \ + " %{march=*: arch %* %