From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) by sourceware.org (Postfix) with ESMTPS id 8C4C43858D32 for ; Wed, 15 Nov 2023 23:59:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8C4C43858D32 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=vrull.eu Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=vrull.eu ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8C4C43858D32 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::102b ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700092763; cv=none; b=Ylz+/brDx4U6K9xdJC+pZHeHkMylST+SN8OQ1XgvW+3ItQqcEEakoCxyP11dLuqjHK8P+FANmpfi2Xx64dSu5EPjh1e8DSNuMH3bE9r5qWK2yHDm2uaw7MjvgoflYTqOk9MkXn7Be9mxtQ0Pmx4s9Gq1g9Ts6aI9oKqj2jCQdA4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700092763; c=relaxed/simple; bh=UuKR3JajM9R1hgNelgDR6cjxCnT893N1K6iBOKNoFL8=; h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To; b=bw0QFbuswDetk7X9+aRkPTVHAH0uGV62cySFZJrSlsYQK+5v3YAIyUG72FlzVJZB6g2bHmin+EYwicQCTHXRKWrHuZROEn45YEBSb3TUq/0WN9rVab3wTwoz40WgvY/ShbMyYKEZEtpfxnAOKYb6U1CcVrnQYreNv5CK+Brq8Ls= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pj1-x102b.google.com with SMTP id 98e67ed59e1d1-280351c32afso132549a91.1 for ; Wed, 15 Nov 2023 15:59:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=vrull.eu; s=google; t=1700092756; x=1700697556; darn=gcc.gnu.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=PcI3UBBkSpFQUMeh8iZxHQ6j7DY95zlDe2A09OgKjF8=; b=qMxK2X2hlcQ+VRKlDv5aBPKjLyMEkPO+l4v8HXXsQShvmOIWvnPAg/Sbvp/8h1mwDs c6kZ6k5vsE7lvan60BhDbZRYCk4ePkyhaM28rkOS2Hc31VyMbGZxi1XqiLCnU1uV6cy7 QZHomtkZ9JpqbUpB9h2wT90x+cIp5ZA0ptikfCtLuFCoo3kel9ubQC6+oLuZs3TXqco2 j/CO4hSnnHF/hWtz0zwe87+j5H4M3ilVc8Qq7c7KrXrlELM1OfcexfFqOfZOGWlKflSV YXKRkvBqtmzpjzQxEumUt0126NsCWWYpp52IEQ2UFC5AzEtbGgrpVSa2YL3cY11uMD7F NPqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700092756; x=1700697556; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=PcI3UBBkSpFQUMeh8iZxHQ6j7DY95zlDe2A09OgKjF8=; b=LM2KRqhaGWd8+xGVrTOLyQOpeQnYWO7dB+cW480Qv9OyRn/0alSrgq3WAsZ88TTQcv aW9ycWQIRV4/1chXakkm5ZwhBXyXJuH5SsRppU9pxhZ0oDi2Vh7Gg3Ot+FZlFpD/8Q97 X1TyVwhzyPA9UZ2/wBAQwaEkczCiW0SwQYeIK5MFs4IkZMJz9uOjHtrZHryGtodhBwjC Wls3bRPw+bqMAN9ah6RT19Qsw1TeE9okG5jiqapphp/ck6iJ+YIyUjb8/odp0rYL5LkW R/IpBNZ3BqN77dywV+PvNouJxb310NCajAF3472ilv2YHcUBVU01VMJkYqHibe8WK8Jq 3L/g== X-Gm-Message-State: AOJu0YxHdTP8qMwRZqBHerLrFbuUzKoZIRGM6NQmncv+QQLPHmI93xpi FSAib8k95Evw2M4aHAwgXAse+VQsy9f15ydYrj5PBA== X-Google-Smtp-Source: AGHT+IFN54DAqn7fhCxbb7opinNOVyj6CKoCTOWahL8k/P7F/Jn8WEnNSHredgJU6DAom9KmywNSP5CxYPvoaxWFY98= X-Received: by 2002:a17:90b:3504:b0:274:4161:b9dc with SMTP id ls4-20020a17090b350400b002744161b9dcmr15561091pjb.31.1700092755428; Wed, 15 Nov 2023 15:59:15 -0800 (PST) MIME-Version: 1.0 References: <20231114141513.24515-1-kito.cheng@sifive.com> In-Reply-To: <20231114141513.24515-1-kito.cheng@sifive.com> From: =?UTF-8?Q?Christoph_M=C3=BCllner?= Date: Thu, 16 Nov 2023 00:58:00 +0100 Message-ID: Subject: Re: [PATCH v2] RISC-V: Implement target attribute To: Kito Cheng Cc: gcc-patches@gcc.gnu.org, kito.cheng@gmail.com, palmer@dabbelt.com, jeffreyalaw@gmail.com Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-9.2 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,JMQ_SPF_NEUTRAL,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE,URIBL_BLACK autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Tue, Nov 14, 2023 at 3:15=E2=80=AFPM Kito Cheng = wrote: > > The target attribute which proposed in [1], target attribute allow user > to specify a local setting per-function basis. > > The syntax of target attribute is `__attribute__((target("")= ))`. > > and the syntax of `` describes below: > ``` > ATTR-STRING :=3D ATTR-STRING ';' ATTR > | ATTR > > ATTR :=3D ARCH-ATTR > | CPU-ATTR > | TUNE-ATTR > > ARCH-ATTR :=3D 'arch=3D' EXTENSIONS-OR-FULLARCH > > EXTENSIONS-OR-FULLARCH :=3D > | > > EXTENSIONS :=3D ',' > | > > FULLARCHSTR :=3D > > EXTENSION :=3D > > OP :=3D '+' > > VERSION :=3D [0-9]+ 'p' [0-9]+ > | [1-9][0-9]* > | > > EXTENSION-NAME :=3D Naming rule is defined in RISC-V ISA manual > > CPU-ATTR :=3D 'cpu=3D' > TUNE-ATTR :=3D 'tune=3D' > ``` > > Changes since v1: > - Use std::unique_ptr rather than alloca to prevent memory issue. > - Error rather than warning when attribute duplicated. > > [1] https://github.com/riscv-non-isa/riscv-c-api-doc/pull/35 I've reviewed with a focus on the utilized backend hooks and macros. Reviewed-by: Christoph M=C3=BCllner Note, that in the changelog below there are quite many empty entries. > > gcc/ChangeLog: > > * config.gcc (riscv): Add riscv-target-attr.o. > * config/riscv/riscv-protos.h (riscv_declare_function_size) New. > (riscv_option_valid_attribute_p): New. > (riscv_override_options_internal): New. > (struct riscv_tune_info): New. > (riscv_parse_tune): New. > * config/riscv/riscv-target-attr.cc > (class riscv_target_attr_parser): New. > (struct riscv_attribute_info): New. > (riscv_attributes): New. > (riscv_target_attr_parser::parse_arch): > (riscv_target_attr_parser::handle_arch): > (riscv_target_attr_parser::handle_cpu): > (riscv_target_attr_parser::handle_tune): > (riscv_target_attr_parser::update_settings): > (riscv_process_one_target_attr): > (num_occurences_in_str): > (riscv_process_target_attr): > (riscv_option_valid_attribute_p): > * config/riscv/riscv.cc: Include target-globals.h and > riscv-subset.h. > (struct riscv_tune_info): Move to riscv-protos.h. > (get_tune_str): > (riscv_parse_tune): > (riscv_declare_function_size): > (riscv_option_override): Build target_option_default_node and > target_option_current_node. > (riscv_save_restore_target_globals): > (riscv_option_restore): > (riscv_previous_fndecl): > (riscv_set_current_function): Apply the target attribute. > (TARGET_OPTION_RESTORE): Define. > (TARGET_OPTION_VALID_ATTRIBUTE_P): Ditto. > * config/riscv/riscv.h (SWITCHABLE_TARGET): Define to 1. > (ASM_DECLARE_FUNCTION_SIZE) Define. > * config/riscv/riscv.opt (mtune=3D): Add Save attribute. > (mcpu=3D): Ditto. > (mcmodel=3D): Ditto. > * config/riscv/t-riscv: Add build rule for riscv-target-attr.o > * doc/extend.texi: Add doc for target attribute. > > gcc/testsuite/ChangeLog: > > * gcc.target/riscv/target-attr-01.c: New. > * gcc.target/riscv/target-attr-02.c: Ditto. > * gcc.target/riscv/target-attr-03.c: Ditto. > * gcc.target/riscv/target-attr-04.c: Ditto. > * gcc.target/riscv/target-attr-05.c: Ditto. > * gcc.target/riscv/target-attr-06.c: Ditto. > * gcc.target/riscv/target-attr-07.c: Ditto. > * gcc.target/riscv/target-attr-bad-01.c: Ditto. > * gcc.target/riscv/target-attr-bad-02.c: Ditto. > * gcc.target/riscv/target-attr-bad-03.c: Ditto. > * gcc.target/riscv/target-attr-bad-04.c: Ditto. > * gcc.target/riscv/target-attr-bad-05.c: Ditto. > * gcc.target/riscv/target-attr-bad-06.c: Ditto. > * gcc.target/riscv/target-attr-bad-07.c: Ditto. > * gcc.target/riscv/target-attr-bad-08.c: Ditto. > * gcc.target/riscv/target-attr-bad-09.c: Ditto. > * gcc.target/riscv/target-attr-bad-10.c: Ditto. > --- > gcc/config.gcc | 2 +- > gcc/config/riscv/riscv-protos.h | 21 + > gcc/config/riscv/riscv-target-attr.cc | 395 ++++++++++++++++++ > gcc/config/riscv/riscv.cc | 192 +++++++-- > gcc/config/riscv/riscv.h | 6 + > gcc/config/riscv/riscv.opt | 6 +- > gcc/config/riscv/t-riscv | 5 + > gcc/doc/extend.texi | 58 +++ > .../gcc.target/riscv/target-attr-01.c | 31 ++ > .../gcc.target/riscv/target-attr-02.c | 31 ++ > .../gcc.target/riscv/target-attr-03.c | 26 ++ > .../gcc.target/riscv/target-attr-04.c | 28 ++ > .../gcc.target/riscv/target-attr-05.c | 27 ++ > .../gcc.target/riscv/target-attr-06.c | 27 ++ > .../gcc.target/riscv/target-attr-07.c | 25 ++ > .../gcc.target/riscv/target-attr-bad-01.c | 13 + > .../gcc.target/riscv/target-attr-bad-02.c | 13 + > .../gcc.target/riscv/target-attr-bad-03.c | 13 + > .../gcc.target/riscv/target-attr-bad-04.c | 13 + > .../gcc.target/riscv/target-attr-bad-05.c | 13 + > .../gcc.target/riscv/target-attr-bad-06.c | 13 + > .../gcc.target/riscv/target-attr-bad-07.c | 13 + > .../gcc.target/riscv/target-attr-bad-08.c | 8 + > .../gcc.target/riscv/target-attr-bad-09.c | 8 + > .../gcc.target/riscv/target-attr-bad-10.c | 8 + > 25 files changed, 950 insertions(+), 45 deletions(-) > create mode 100644 gcc/config/riscv/riscv-target-attr.cc > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-01.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-02.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-03.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-04.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-05.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-06.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-07.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c > > diff --git a/gcc/config.gcc b/gcc/config.gcc > index ba6d63e33ac..0e86e60629e 100644 > --- a/gcc/config.gcc > +++ b/gcc/config.gcc > @@ -546,7 +546,7 @@ riscv*) > extra_objs=3D"riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten= -memrefs.o riscv-selftests.o riscv-string.o" > extra_objs=3D"${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector= -costs.o riscv-avlprop.o" > extra_objs=3D"${extra_objs} riscv-vector-builtins.o riscv-vector-= builtins-shapes.o riscv-vector-builtins-bases.o" > - extra_objs=3D"${extra_objs} thead.o" > + extra_objs=3D"${extra_objs} thead.o riscv-target-attr.o" > d_target_objs=3D"riscv-d.o" > extra_headers=3D"riscv_vector.h" > target_gtfiles=3D"$target_gtfiles \$(srcdir)/config/riscv/riscv-v= ector-builtins.cc" > diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-pro= tos.h > index 8cdfadbcf10..196b53f10f3 100644 > --- a/gcc/config/riscv/riscv-protos.h > +++ b/gcc/config/riscv/riscv-protos.h > @@ -124,6 +124,7 @@ extern void riscv_split_doubleword_move (rtx, rtx); > extern const char *riscv_output_move (rtx, rtx); > extern const char *riscv_output_return (); > extern void riscv_declare_function_name (FILE *, const char *, tree); > +extern void riscv_declare_function_size (FILE *, const char *, tree); > extern void riscv_asm_output_alias (FILE *, const tree, const tree); > extern void riscv_asm_output_external (FILE *, const tree, const char *)= ; > extern bool > @@ -647,5 +648,25 @@ extern bool th_print_operand_address (FILE *, machin= e_mode, rtx); > > extern bool riscv_use_divmod_expander (void); > void riscv_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int= ); > +extern bool > +riscv_option_valid_attribute_p (tree, tree, tree, int); > +extern void > +riscv_override_options_internal (struct gcc_options *); > + > +struct riscv_tune_param; > +/* Information about one micro-arch we know about. */ > +struct riscv_tune_info { > + /* This micro-arch canonical name. */ > + const char *name; > + > + /* Which automaton to use for tuning. */ > + enum riscv_microarchitecture_type microarchitecture; > + > + /* Tuning parameters for this micro-arch. */ > + const struct riscv_tune_param *tune_param; > +}; > + > +const struct riscv_tune_info * > +riscv_parse_tune (const char *, bool); > > #endif /* ! GCC_RISCV_PROTOS_H */ > diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/ris= cv-target-attr.cc > new file mode 100644 > index 00000000000..78f259d0c96 > --- /dev/null > +++ b/gcc/config/riscv/riscv-target-attr.cc > @@ -0,0 +1,395 @@ > +/* Subroutines used for parsing target attribute for RISC-V. > + Copyright (C) 2023 Free Software Foundation, Inc. > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify > +it under the terms of the GNU General Public License as published by > +the Free Software Foundation; either version 3, or (at your option) > +any later version. > + > +GCC is distributed in the hope that it will be useful, > +but WITHOUT ANY WARRANTY; without even the implied warranty of > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +GNU General Public License for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3. If not see > +. */ > + > +#define IN_TARGET_CODE 1 > + > +#define INCLUDE_MEMORY > +#define INCLUDE_STRING > +#include "config.h" > +#include "system.h" > +#include "coretypes.h" > +#include "target.h" > +#include "tree.h" > +#include "tm_p.h" > +#include "diagnostic.h" > +#include "opts.h" > +#include "riscv-subset.h" > + > +namespace { > +class riscv_target_attr_parser > +{ > +public: > + riscv_target_attr_parser (location_t loc) > + : m_found_arch_p (false) > + , m_found_tune_p (false) > + , m_found_cpu_p (false) > + , m_subset_list (nullptr) > + , m_loc (loc) > + , m_cpu_info (nullptr) > + , m_tune (nullptr) > + { > + } > + > + bool handle_arch (const char *); > + bool handle_cpu (const char *); > + bool handle_tune (const char *); > + > + void set_loc (location_t loc) { > + m_loc =3D loc; > + } > + > + void update_settings (struct gcc_options *opts) const; > +private: > + const char *m_raw_attr_str; > + bool parse_arch (const char *); > + > + bool m_found_arch_p; > + bool m_found_tune_p; > + bool m_found_cpu_p; > + riscv_subset_list *m_subset_list; > + location_t m_loc; > + const riscv_cpu_info *m_cpu_info; > + const char *m_tune; > +}; > +} > + > +/* All the information needed to handle a target attribute. > + NAME is the name of the attribute. > + HANDLER is the function that takes the attribute string as an argumen= t. */ > + > +struct riscv_attribute_info > +{ > + const char *name; > + bool (riscv_target_attr_parser::*handler) (const char *); > +}; > + > +/* The target attributes that we support. */ > + > +static const struct riscv_attribute_info riscv_attributes[] > + =3D {{"arch", &riscv_target_attr_parser::handle_arch}, > + {"cpu", &riscv_target_attr_parser::handle_cpu}, > + {"tune", &riscv_target_attr_parser::handle_tune}}; > + > +bool > +riscv_target_attr_parser::parse_arch (const char *str) > +{ > + if (m_subset_list) > + delete m_subset_list; > + /* Check if it's setting full arch string. */ > + if (strncmp ("rv", str, strlen ("rv")) =3D=3D 0) > + { > + m_subset_list =3D riscv_subset_list::parse (str, location_t ()); > + > + if (m_subset_list =3D=3D nullptr) > + goto fail; > + > + return true; > + } > + else > + { > + /* Parsing the extension list like "+[,+]*". */ > + size_t len =3D strlen (str); > + std::unique_ptr buf (new char[len]); > + char *str_to_check =3D buf.get (); > + strcpy (str_to_check, str); > + const char *token =3D strtok_r (str_to_check, ",", &str_to_check); > + m_subset_list =3D riscv_current_subset_list ()->clone (); > + m_subset_list->set_loc (m_loc); > + while (token) > + { > + if (token[0] !=3D '+') > + { > + error_at ( > + m_loc, > + "unexpected arch for % attribute: must start " > + "with + or rv"); > + goto fail; > + } > + else > + { > + const char *result =3D m_subset_list->parse_single_ext (tok= en + 1); > + /* Check parse_single_ext has consume all string. */ > + if (*result !=3D '\0') > + { > + error_at ( > + m_loc, > + "unexpected arch for % attribute: bad " > + "string found %<%s%>", token); > + goto fail; > + } > + } > + token =3D strtok_r (NULL, ",", &str_to_check); > + } > + return true; > + } > +fail: > + if (m_subset_list !=3D nullptr) > + { > + delete m_subset_list; > + m_subset_list =3D nullptr; > + } > + return false; > +} > + > +/* Handle the ARCH_STR argument to the arch=3D target attribute. */ > + > +bool > +riscv_target_attr_parser::handle_arch (const char *str) > +{ > + if (m_found_arch_p) > + error_at (m_loc, "% attribute: arch appears more than onc= e"); > + m_found_arch_p =3D true; > + return parse_arch (str); > +} > + > +/* Handle the CPU_STR argument to the cpu=3D target attribute. */ > + > +bool > +riscv_target_attr_parser::handle_cpu (const char *str) > +{ > + if (m_found_cpu_p) > + error_at (m_loc, "% attribute: cpu appears more than once= "); > + > + m_found_cpu_p =3D true; > + const riscv_cpu_info *cpu_info =3D riscv_find_cpu (str); > + > + if (!cpu_info) > + { > + error_at (m_loc, "% attribute: unknown CPU %qs", str); > + return false; > + } > + > + if (m_subset_list =3D=3D nullptr) > + { > + const char *arch_str =3D cpu_info->arch; > + m_subset_list =3D riscv_subset_list::parse (arch_str, m_loc); > + gcc_assert (m_subset_list); > + } > + > + m_cpu_info =3D cpu_info; > + return true; > +} > + > +/* Handle the TUNE_STR argument to the tune=3D target attribute. */ > + > +bool > +riscv_target_attr_parser::handle_tune (const char *str) > +{ > + if (m_found_tune_p) > + error_at (m_loc, "% attribute: tune appears more than onc= e"); > + m_found_tune_p =3D true; > + const struct riscv_tune_info *tune =3D riscv_parse_tune (str, true); > + > + if (tune =3D=3D nullptr) > + { > + error_at (m_loc, "% attribute: unknown TUNE %qs", str); > + return false; > + } > + > + m_tune =3D tune->name; > + > + return true; > +} > + > +void > +riscv_target_attr_parser::update_settings (struct gcc_options *opts) con= st > +{ > + if (m_subset_list) > + riscv_set_arch_by_subset_list (m_subset_list, opts); > + > + if (m_cpu_info) > + opts->x_riscv_cpu_string =3D m_cpu_info->name; > + > + if (m_tune) > + opts->x_riscv_tune_string =3D m_tune; > + else > + { > + if (m_cpu_info) > + opts->x_riscv_tune_string =3D m_cpu_info->tune; > + } > +} > + > +/* Parse ARG_STR which contains the definition of one target attribute. > + Show appropriate errors if any or return true if the attribute is val= id. */ > + > +static bool > +riscv_process_one_target_attr (char *arg_str, > + location_t loc, > + riscv_target_attr_parser &attr_parser) > +{ > + size_t len =3D strlen (arg_str); > + > + if (len =3D=3D 0) > + { > + error_at (loc, "malformed % attribute"); > + return false; > + } > + > + std::unique_ptr buf (new char[len]); > + char *str_to_check =3D buf.get(); > + strcpy (str_to_check, arg_str); > + > + char *arg =3D strchr (str_to_check, '=3D'); > + > + if (!arg) > + { > + error_at ( > + loc, > + "attribute % does not accept an argument", > + str_to_check); > + return false; > + } > + > + arg[0] =3D '\0'; > + ++arg; > + for (const auto &attr : riscv_attributes) > + { > + /* 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 argum= ent > + to an attribute that expects one, fail to match. */ > + if (strncmp (str_to_check, attr.name, strlen (attr.name)) !=3D 0) > + continue; > + > + return (&attr_parser->*attr.handler) (arg); > + } > + error_at (loc, "Got unknown attribute %", str_to_chec= k); > + > + return false; > +} > + > +/* 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 =3D 0; > + while (*str !=3D '\0') > + { > + if (*str =3D=3D c) > + res++; > + > + str++; > + } > + > + return res; > +} > + > +/* Parse the tree in ARGS that contains the target attribute information > + and update the global target options space. */ > + > +static bool > +riscv_process_target_attr (tree args, location_t loc, struct gcc_options= *opts) > +{ > + if (TREE_CODE (args) =3D=3D TREE_LIST) > + { > + do > + { > + tree head =3D TREE_VALUE (args); > + if (head) > + { > + if (!riscv_process_target_attr (head, loc, opts)) > + return false; > + } > + args =3D TREE_CHAIN (args); > + } while (args); > + > + return true; > + } > + > + if (TREE_CODE (args) !=3D STRING_CST) > + { > + error_at (loc, "attribute % argument not a string"); > + return false; > + } > + size_t len =3D strlen (TREE_STRING_POINTER (args)); > + > + /* No need to emit warning or error on empty string here, generic code= already > + handle this case. */ > + if (len =3D=3D 0) > + { > + return false; > + } > + > + std::unique_ptr buf (new char[len]); > + char *str_to_check =3D buf.get (); > + strcpy (str_to_check, TREE_STRING_POINTER (args)); > + > + /* Used to catch empty spaces between commas i.e. > + attribute ((target ("attr1;;attr2"))). */ > + unsigned int num_commas =3D num_occurences_in_str (';', str_to_check); > + > + /* Handle multiple target attributes separated by ','. */ > + char *token =3D strtok_r (str_to_check, ";", &str_to_check); > + > + riscv_target_attr_parser attr_parser (loc); > + unsigned int num_attrs =3D 0; > + while (token) > + { > + num_attrs++; > + riscv_process_one_target_attr (token, loc, attr_parser); > + token =3D strtok_r (NULL, ";", &str_to_check); > + } > + > + if (num_attrs !=3D num_commas + 1) > + { > + error_at (loc, "malformed % attribute", > + TREE_STRING_POINTER (args)); > + return false; > + } > + > + /* Apply settings from target attribute. */ > + attr_parser.update_settings (opts); > + > + return true; > +} > + > +/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to > + process attribute ((target ("..."))). */ > + > +bool > +riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int) > +{ > + struct cl_target_option cur_target; > + bool ret; > + tree new_target; > + location_t loc =3D DECL_SOURCE_LOCATION (fndecl); > + > + /* Save the current target options to restore at the end. */ > + cl_target_option_save (&cur_target, &global_options, &global_options_s= et); > + > + ret =3D riscv_process_target_attr (args, loc, &global_options); > + > + if (ret) > + { > + riscv_override_options_internal (&global_options); > + new_target > + =3D build_target_option_node (&global_options, &global_options_se= t); > + } > + else > + new_target =3D NULL; > + > + if (fndecl && ret) > + { > + DECL_FUNCTION_SPECIFIC_TARGET (fndecl) =3D new_target; > + } > + > + cl_target_option_restore (&global_options, &global_options_set, &cur_t= arget); > + return ret; > +} > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc > index f09c4066903..cebd2fc0d25 100644 > --- a/gcc/config/riscv/riscv.cc > +++ b/gcc/config/riscv/riscv.cc > @@ -73,10 +73,12 @@ along with GCC; see the file COPYING3. If not see > #include "tree-vectorizer.h" > #include "gcse.h" > #include "tree-dfa.h" > +#include "target-globals.h" > > /* This file should be included last. */ > #include "target-def.h" > #include "riscv-vector-costs.h" > +#include "riscv-subset.h" > > /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */ > #define UNSPEC_ADDRESS_P(X) \ > @@ -264,17 +266,6 @@ struct riscv_tune_param > bool use_divmod_expansion; > }; > > -/* Information about one micro-arch we know about. */ > -struct riscv_tune_info { > - /* This micro-arch canonical name. */ > - const char *name; > - > - /* Which automaton to use for tuning. */ > - enum riscv_microarchitecture_type microarchitecture; > - > - /* Tuning parameters for this micro-arch. */ > - const struct riscv_tune_param *tune_param; > -}; > > /* Global variables for machine-dependent things. */ > > @@ -501,10 +492,23 @@ riscv_min_arithmetic_precision (void) > return 32; > } > > -/* Return the riscv_tune_info entry for the given name string. */ > +template > +static const char * > +get_tune_str (const T *opts) > +{ > + const char *tune_string =3D RISCV_TUNE_STRING_DEFAULT; > + if (opts->x_riscv_tune_string) > + tune_string =3D opts->x_riscv_tune_string; > + else if (opts->x_riscv_cpu_string) > + tune_string =3D opts->x_riscv_cpu_string; > + return tune_string; > +} > + > +/* Return the riscv_tune_info entry for the given name string, return nu= llptr > + if NULL_P is true, otherwise return an placeholder and report error. = */ > > -static const struct riscv_tune_info * > -riscv_parse_tune (const char *tune_string) > +const struct riscv_tune_info * > +riscv_parse_tune (const char *tune_string, bool null_p) > { > const riscv_cpu_info *cpu =3D riscv_find_cpu (tune_string); > > @@ -515,6 +519,9 @@ riscv_parse_tune (const char *tune_string) > if (strcmp (riscv_tune_info_table[i].name, tune_string) =3D=3D 0) > return riscv_tune_info_table + i; > > + if (null_p) > + return nullptr; > + > error ("unknown cpu %qs for %<-mtune%>", tune_string); > return riscv_tune_info_table; > } > @@ -7873,6 +7880,33 @@ riscv_declare_function_name (FILE *stream, const c= har *name, tree fndecl) > riscv_asm_output_variant_cc (stream, fndecl, name); > ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function"); > ASM_OUTPUT_LABEL (stream, name); > + if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl)) > + { > + fprintf (stream, "\t.option push\n"); > + std::string isa =3D riscv_current_subset_list ()->to_string (true)= ; > + fprintf (stream, "\t.option arch, %s\n", isa.c_str ()); > + > + struct cl_target_option *local_cl_target =3D > + TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (fndecl)); > + struct cl_target_option *global_cl_target =3D > + TREE_TARGET_OPTION (target_option_default_node); > + const char *local_tune_str =3D get_tune_str (local_cl_target); > + const char *global_tune_str =3D get_tune_str (global_cl_target); > + if (strcmp (local_tune_str, global_tune_str) !=3D 0) > + fprintf (stream, "\t# tune =3D %s\n", local_tune_str); > + } > +} > + > +void > +riscv_declare_function_size (FILE *stream, const char *name, tree fndecl= ) > +{ > + if (!flag_inhibit_size_directive) > + ASM_OUTPUT_MEASURED_SIZE (stream, name); > + > + if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl)) > + { > + fprintf (stream, "\t.option pop\n"); > + } > } > > /* Implement ASM_OUTPUT_DEF_FROM_DECLS. */ > @@ -8079,16 +8113,18 @@ riscv_override_options_internal (struct gcc_optio= ns *opts) > error ("%<-mdiv%> requires %<-march%> to subsume the % extension= "); > > /* Likewise floating-point division and square root. */ > - if ((TARGET_HARD_FLOAT || TARGET_ZFINX) && (target_flags_explicit & MA= SK_FDIV) =3D=3D 0) > + if ((TARGET_HARD_FLOAT_OPTS_P (opts) || TARGET_ZFINX_OPTS_P (opts)) > + && ((target_flags_explicit & MASK_FDIV) =3D=3D 0)) > opts->x_target_flags |=3D MASK_FDIV; > > /* Handle -mtune, use -mcpu if -mtune is not given, and use default -m= tune > if both -mtune and -mcpu are not given. */ > - cpu =3D riscv_parse_tune (opts->x_riscv_tune_string ? opts->x_riscv_tu= ne_string : > - (opts->x_riscv_cpu_string ? opts->x_riscv_cpu_s= tring : > - RISCV_TUNE_STRING_DEFAULT)); > + const char *tune_string =3D get_tune_str (opts); > + cpu =3D riscv_parse_tune (tune_string, false); > riscv_microarchitecture =3D cpu->microarchitecture; > - tune_param =3D opts->x_optimize_size ? &optimize_size_tune_info : cpu-= >tune_param; > + tune_param =3D opts->x_optimize_size > + ? &optimize_size_tune_info > + : cpu->tune_param; > > /* Use -mtune's setting for slow_unaligned_access, even when optimizin= g > for size. For architectures that trap and emulate unaligned access= es, > @@ -8100,7 +8136,7 @@ riscv_override_options_internal (struct gcc_options= *opts) > /* Make a note if user explicity passed -mstrict-align for later > builtin macro generation. Can't use target_flags_explicitly since > it is set even for -mno-strict-align. */ > - riscv_user_wants_strict_align =3D TARGET_STRICT_ALIGN; > + riscv_user_wants_strict_align =3D TARGET_STRICT_ALIGN_OPTS_P (opts); > > if ((target_flags_explicit & MASK_STRICT_ALIGN) =3D=3D 0 > && cpu->tune_param->slow_unaligned_access) > @@ -8258,8 +8294,41 @@ riscv_option_override (void) > init_machine_status =3D &riscv_init_machine_status; > > riscv_override_options_internal (&global_options); > + > + /* Save these options as the default ones in case we push and pop them= later > + while processing functions with potential target attributes. */ > + target_option_default_node =3D target_option_current_node > + =3D build_target_option_node (&global_options, &global_options_set); > +} > + > +/* Restore or save the TREE_TARGET_GLOBALS from or to NEW_TREE. > + Used by riscv_set_current_function to > + make sure optab availability predicates are recomputed when necessary= . */ > + > +void > +riscv_save_restore_target_globals (tree new_tree) > +{ > + if (TREE_TARGET_GLOBALS (new_tree)) > + restore_target_globals (TREE_TARGET_GLOBALS (new_tree)); > + else if (new_tree =3D=3D target_option_default_node) > + restore_target_globals (&default_target_globals); > + else > + TREE_TARGET_GLOBALS (new_tree) =3D save_target_globals_default_opts = (); > } > > +/* Implements TARGET_OPTION_RESTORE. Restore the backend codegen decisi= ons > + using the information saved in PTR. */ > + > +static void > +riscv_option_restore (struct gcc_options *opts, > + struct gcc_options * /* opts_set */, > + struct cl_target_option * /* ptr */) > +{ > + riscv_override_options_internal (opts); > +} > + > +static GTY (()) tree riscv_previous_fndecl; > + > /* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */ > > static void > @@ -8505,7 +8574,12 @@ riscv_get_interrupt_type (tree decl) > return MACHINE_MODE; > } > > -/* Implement `TARGET_SET_CURRENT_FUNCTION'. */ > +/* Implement `TARGET_SET_CURRENT_FUNCTION'. Unpack the codegen decision= s > + like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET > + of the function, if such exists. This function may be called multipl= e > + times on a single function so use aarch64_previous_fndecl to avoid > + setting up identical state. */ > + > /* Sanity cheching for above function attributes. */ > static void > riscv_set_current_function (tree decl) > @@ -8513,36 +8587,66 @@ riscv_set_current_function (tree decl) > if (decl =3D=3D NULL_TREE > || current_function_decl =3D=3D NULL_TREE > || current_function_decl =3D=3D error_mark_node > - || ! cfun->machine > - || cfun->machine->attributes_checked_p) > + || ! cfun->machine) > return; > > - cfun->machine->naked_p =3D riscv_naked_function_p (decl); > - cfun->machine->interrupt_handler_p > - =3D riscv_interrupt_type_p (TREE_TYPE (decl)); > + if (!cfun->machine->attributes_checked_p) > + { > + cfun->machine->naked_p =3D riscv_naked_function_p (decl); > + cfun->machine->interrupt_handler_p > + =3D riscv_interrupt_type_p (TREE_TYPE (decl)); > > - if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p) > - error ("function attributes %qs and %qs are mutually exclusive", > - "interrupt", "naked"); > + if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p) > + error ("function attributes %qs and %qs are mutually exclusive", > + "interrupt", "naked"); > > - if (cfun->machine->interrupt_handler_p) > - { > - tree ret =3D TREE_TYPE (TREE_TYPE (decl)); > - tree args =3D TYPE_ARG_TYPES (TREE_TYPE (decl)); > + if (cfun->machine->interrupt_handler_p) > + { > + tree ret =3D TREE_TYPE (TREE_TYPE (decl)); > + tree args =3D TYPE_ARG_TYPES (TREE_TYPE (decl)); > + > + if (TREE_CODE (ret) !=3D VOID_TYPE) > + error ("%qs function cannot return a value", "interrupt"); > > - if (TREE_CODE (ret) !=3D VOID_TYPE) > - error ("%qs function cannot return a value", "interrupt"); > + if (args && TREE_CODE (TREE_VALUE (args)) !=3D VOID_TYPE) > + error ("%qs function cannot have arguments", "interrupt"); > > - if (args && TREE_CODE (TREE_VALUE (args)) !=3D VOID_TYPE) > - error ("%qs function cannot have arguments", "interrupt"); > + cfun->machine->interrupt_mode =3D riscv_get_interrupt_type (dec= l); > > - cfun->machine->interrupt_mode =3D riscv_get_interrupt_type (decl); > + gcc_assert (cfun->machine->interrupt_mode !=3D UNKNOWN_MODE); > + } > > - gcc_assert (cfun->machine->interrupt_mode !=3D UNKNOWN_MODE); > + /* Don't print the above diagnostics more than once. */ > + cfun->machine->attributes_checked_p =3D 1; > } > > - /* Don't print the above diagnostics more than once. */ > - cfun->machine->attributes_checked_p =3D 1; > + if (!decl || decl =3D=3D riscv_previous_fndecl) > + return; > + > + tree old_tree =3D (riscv_previous_fndecl > + ? DECL_FUNCTION_SPECIFIC_TARGET (riscv_previous_fnde= cl) > + : NULL_TREE); > + > + tree new_tree =3D DECL_FUNCTION_SPECIFIC_TARGET (decl); > + > + /* If current function has no attributes but the previous one did, > + use the default node. */ > + if (!new_tree && old_tree) > + new_tree =3D target_option_default_node; > + > + /* If nothing to do, return. #pragma GCC reset or #pragma GCC pop to > + the default have been handled by aarch64_save_restore_target_global= s from > + aarch64_pragma_target_parse. */ > + if (old_tree =3D=3D new_tree) > + return; > + > + riscv_previous_fndecl =3D decl; > + > + /* First set the target options. */ > + cl_target_option_restore (&global_options, &global_options_set, > + TREE_TARGET_OPTION (new_tree)); > + > + riscv_save_restore_target_globals (new_tree); > } > > /* Implement TARGET_MERGE_DECL_ATTRIBUTES. */ > @@ -9664,6 +9768,12 @@ riscv_preferred_else_value (unsigned ifn, tree vec= type, unsigned int nops, > #undef TARGET_OPTION_OVERRIDE > #define TARGET_OPTION_OVERRIDE riscv_option_override > > +#undef TARGET_OPTION_RESTORE > +#define TARGET_OPTION_RESTORE riscv_option_restore > + > +#undef TARGET_OPTION_VALID_ATTRIBUTE_P > +#define TARGET_OPTION_VALID_ATTRIBUTE_P riscv_option_valid_attribute_p > + > #undef TARGET_LEGITIMIZE_ADDRESS > #define TARGET_LEGITIMIZE_ADDRESS riscv_legitimize_address > > diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h > index 1e9813b4f39..6205d7533f4 100644 > --- a/gcc/config/riscv/riscv.h > +++ b/gcc/config/riscv/riscv.h > @@ -25,6 +25,8 @@ along with GCC; see the file COPYING3. If not see > #include > #include "config/riscv/riscv-opts.h" > > +#define SWITCHABLE_TARGET 1 > + > /* Target CPU builtins. */ > #define TARGET_CPU_CPP_BUILTINS() riscv_cpu_cpp_builtins (pfile) > > @@ -1056,6 +1058,10 @@ while (0) > #define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL) = \ > riscv_declare_function_name (STR, NAME, DECL) > > +#undef ASM_DECLARE_FUNCTION_SIZE > +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) = \ > + riscv_declare_function_size (FILE, FNAME, DECL) > + > /* Add output .variant_cc directive for specific alias definition. */ > #undef ASM_OUTPUT_DEF_FROM_DECLS > #define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET) = \ > diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt > index 70d78151cee..1bd661a3fe4 100644 > --- a/gcc/config/riscv/riscv.opt > +++ b/gcc/config/riscv/riscv.opt > @@ -84,11 +84,11 @@ Target RejectNegative Joined Negative(march=3D) > lower-case. > > mtune=3D > -Target RejectNegative Joined Var(riscv_tune_string) > +Target RejectNegative Joined Var(riscv_tune_string) Save > -mtune=3DPROCESSOR Optimize the output for PROCESSOR. > > mcpu=3D > -Target RejectNegative Joined Var(riscv_cpu_string) > +Target RejectNegative Joined Var(riscv_cpu_string) Save > -mcpu=3DPROCESSOR Use architecture of and optimize the output for= PROCESSOR. > > msmall-data-limit=3D > @@ -106,7 +106,7 @@ memory accesses to be generated as compressed instruc= tions. Currently targets > 32-bit integer load/stores. > > mcmodel=3D > -Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TAR= GET_DEFAULT_CMODEL) > +Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TAR= GET_DEFAULT_CMODEL) Save > Specify the code model. > > mstrict-align > diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv > index 95becfc819b..3b9686daa58 100644 > --- a/gcc/config/riscv/t-riscv > +++ b/gcc/config/riscv/t-riscv > @@ -115,6 +115,11 @@ riscv-v.o: $(srcdir)/config/riscv/riscv-v.cc \ > $(COMPILE) $< > $(POSTCOMPILE) > > +riscv-target-attr.o: $(srcdir)/config/riscv/riscv-target-attr.cc $(CONFI= G_H) \ > + $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(DIAGNOSTIC_CORE_H) > + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ > + $(srcdir)/config/riscv/riscv-target-attr.cc > + > thead.o: $(srcdir)/config/riscv/thead.cc \ > $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) backend.h $(RTL_H) \ > memmodel.h $(EMIT_RTL_H) poly-int.h output.h > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 7cdfdf8c83b..856dd93d16a 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -6295,8 +6295,66 @@ void f (void) __attribute__ ((interrupt ("user")))= ; > Permissible values for this parameter are @code{user}, @code{supervisor}= , > and @code{machine}. If there is no parameter, then it defaults to > @code{machine}. > + > +@end table > + > +The following target-specific function attributes are available for the > +RISC-V target. For the most part, these options mirror the behavior of > +similar command-line options (@pxref{RISC-V Options}), but on a > +per-function basis. > + > +@table @code > +@cindex @code{arch=3D} function attribute, RISC-V > +@item arch=3D > +Specifies the architecture version and architectural extensions to use > +for this function. The behavior and permissible arguments are the same = as > +for the @option{-march=3D} command-line option, in addtion, it also supp= ort > +extension enablement list, a list of extension name and prefixed with @c= ode{+}, > +like @code{arch=3D+zba} means enable @code{zba} extension. > +Multiple extension can be enabled by separating them with a comma. For = example: > +@code{arch=3D+zba,+zbb}. > + > +@cindex @code{tune=3D} function attribute, RISC-V > +@item tune=3D > +Specifies the core for which to tune the performance of this function. > +The behavior and permissible arguments are the same as for the @option{-= mtune=3D} > +command-line option. > + > +@cindex @code{cpu=3D} function attribute, RISC-V > +@item cpu=3D > +Specifies the core for which to tune the performance of this function an= d also > +whose architectural features to use. The behavior and valid arguments a= re the > +same as for the @option{-mcpu=3D} command-line option. > + > @end table > > +The above target attributes can be specified as follows: > + > +@smallexample > +__attribute__((target("@var{attr-string}"))) > +int > +f (int a) > +@{ > + return a + 5; > +@} > +@end smallexample > + > +where @code{@var{attr-string}} is one of the attribute strings specified= above. > + > +Multiple target function attributes can be specified by separating them = with > +a semicolon. For example: > +@smallexample > +__attribute__((target("arch=3D+zba,+zbb;tune=3Drocket"))) > +int > +foo (int a) > +@{ > + return a + 5; > +@} > +@end smallexample > + > +is valid and compiles function @code{foo} with @code{zba} > +and @code{zbb} extensions and tunes it for @code{rocket}. > + > @node RL78 Function Attributes > @subsection RL78 Function Attributes > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-01.c b/gcc/testsu= ite/gcc.target/riscv/target-attr-01.c > new file mode 100644 > index 00000000000..b3f3d65d543 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-01.c > @@ -0,0 +1,31 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > + > +/* > +** foo: > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > + > + > +long foo() __attribute__((target("arch=3Drv64gc_zba"))); > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +/* > +** bar: > +** ... > +** slli\s*a1,a1,1 > +** add\s*a0,a1,a0 > +** ... > +*/ > + > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-02.c b/gcc/testsu= ite/gcc.target/riscv/target-attr-02.c > new file mode 100644 > index 00000000000..c010089a823 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-02.c > @@ -0,0 +1,31 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > + > +/* > +** foo: > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > + > + > +long foo() __attribute__((target("arch=3D+zba"))); > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +/* > +** bar: > +** ... > +** slli\s*a1,a1,1 > +** add\s*a0,a1,a0 > +** ... > +*/ > + > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-03.c b/gcc/testsu= ite/gcc.target/riscv/target-attr-03.c > new file mode 100644 > index 00000000000..b4896cb2e27 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-03.c > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc_zba -O2 -mabi=3Dlp64" } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +/* > +** foo: > +** ... > +** slli\s*a1,a1,1 > +** add\s*a0,a1,a0 > +** ... > +*/ > +long foo() __attribute__((target("arch=3Drv64gc"))); > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +/* > +** bar: > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-04.c b/gcc/testsu= ite/gcc.target/riscv/target-attr-04.c > new file mode 100644 > index 00000000000..369d6514e5a > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-04.c > @@ -0,0 +1,28 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc_zba -O2 -mabi=3Dlp64 -mtune=3Drocket" }= */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +/* > +** foo: > +** ... > +** # tune =3D sifive-7-series > +** ... > +** slli\s*a1,a1,1 > +** add\s*a0,a1,a0 > +** ... > +*/ > +long foo() __attribute__((target("cpu=3Dsifive-u74"))); > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +/* > +** bar: > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-05.c b/gcc/testsu= ite/gcc.target/riscv/target-attr-05.c > new file mode 100644 > index 00000000000..c75368dcebf > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-05.c > @@ -0,0 +1,27 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc_zba -O2 -mabi=3Dlp64 -mtune=3Drocket" }= */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +/* > +** foo: > +** ... > +** # tune =3D sifive-7-series > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > +long foo() __attribute__((target("cpu=3Dsifive-u74;arch=3Drv64gc_zba")))= ; > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +/* > +** bar: > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-06.c b/gcc/testsu= ite/gcc.target/riscv/target-attr-06.c > new file mode 100644 > index 00000000000..369c95eeb54 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-06.c > @@ -0,0 +1,27 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc_zba -O2 -mabi=3Dlp64 -mtune=3Drocket" }= */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +/* > +** foo: > +** ... > +** # tune =3D sifive-5-series > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > +long foo() __attribute__((target("cpu=3Dsifive-u74;tune=3Dsifive-5-serie= s;arch=3Drv64gc_zba"))); > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +/* > +** bar: > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-07.c b/gcc/testsu= ite/gcc.target/riscv/target-attr-07.c > new file mode 100644 > index 00000000000..4ff81166a62 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-07.c > @@ -0,0 +1,25 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc_zba -O2 -mabi=3Dlp64 -mtune=3Drocket" }= */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +/* > +** foo: > +** ... > +** # tune =3D sifive-5-series > +** ... > +*/ > +long foo() __attribute__((target("tune=3Dsifive-5-series"))); > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +/* > +** bar: > +** ... > +** sh1add\s*a0,a1,a0 > +** ... > +*/ > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-01.c > new file mode 100644 > index 00000000000..91cbcaac21d > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > + > +long foo() __attribute__((target("arch=3Drv64gc_zba;;"))); /* { dg-error= "malformed" } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-02.c > new file mode 100644 > index 00000000000..0c838bb3ca7 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > + > +long foo() __attribute__((target("cpu=3Dxyz-cpu"))); /* { dg-error "unkn= own CPU" } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-03.c > new file mode 100644 > index 00000000000..09702d1690a > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > + > +long foo() __attribute__((target("tune=3Dxyz-cpu"))); /* { dg-error "unk= nown TUNE" } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-04.c > new file mode 100644 > index 00000000000..1d9a0ffdd88 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > + > +long foo() __attribute__((target(123))); /* { dg-error "argument not a s= tring" } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-05.c > new file mode 100644 > index 00000000000..24a81c5279b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > + > +long foo() __attribute__((target(""))); /* { dg-warning "empty string in= attribute .target." } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-06.c > new file mode 100644 > index 00000000000..a0d65859d40 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > + > +long foo() __attribute__((target("arch=3D*x"))); /* { dg-error "must sta= rt with \\+ or rv" } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-07.c > new file mode 100644 > index 00000000000..8aa82504dc1 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > + > +long foo() __attribute__((target("arch=3D+zbb_zba"))); /* { dg-error "ex= tension 'zbb_zba' starts with 'z' but is unsupported standard extension" } = */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > + > +long bar(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-08.c > new file mode 100644 > index 00000000000..68d211de887 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c > @@ -0,0 +1,8 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > +long foo() __attribute__((target("arch=3Drv64gc_zba;arch=3Drv64gc_zba"))= ); /* { dg-error "arch appears more than once" } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-09.c > new file mode 100644 > index 00000000000..2b6e4982894 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c > @@ -0,0 +1,8 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > +long foo() __attribute__((target("cpu=3Dsifive-u74;cpu=3Dsifive-u74")));= /* { dg-error "cpu appears more than once" } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c b/gcc/te= stsuite/gcc.target/riscv/target-attr-bad-10.c > new file mode 100644 > index 00000000000..00cefa03e41 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c > @@ -0,0 +1,8 @@ > +/* { dg-do compile } */ > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ > +/* { dg-options "-march=3Drv64gc -O2 -mabi=3Dlp64" } */ > + > +long foo() __attribute__((target("tune=3Dsifive-u74;tune=3Dsifive-u74"))= ); /* { dg-error "tune appears more than once" } */ > +long foo(long a, long b){ > + return a + (b * 2); > +} > -- > 2.40.1 >