From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pj1-x102d.google.com (mail-pj1-x102d.google.com [IPv6:2607:f8b0:4864:20::102d]) by sourceware.org (Postfix) with ESMTPS id 944403858D1E for ; Tue, 7 Feb 2023 06:20:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 944403858D1E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-pj1-x102d.google.com with SMTP id d2so10294882pjd.5 for ; Mon, 06 Feb 2023 22:20:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=4I0g5hC2X7Hy05rT9LxwJtFygVmNaHiW7dX/meVZHjM=; b=DgoT/g5Dud6t5f/IuEQI5eZOSPmi05N2SDVzs3IefcinsD6h1BI6Vjp7VeRG7PuHXJ RoK2ScrZs8kZqrxuvlgBHR7N3anW6a5WbkNC1PzwGC+fEBH9oOhr0mYMwAVIAVj7Dnoo Dy83ZyTy4R4pJWY3ugusnpFyRjbLPB0ca5YIvvpNdo8n47llqMgeFL8Al9XA69XtqpVE jYT4w06afrAn9dJ7dclRSrNX7gniEZWNlPisQQ3H0/UIgj4MnzaWlHu4kvBIar2RYGBg nH1hiTprU5Osmn0IFZC5Tc4DHO2QpSA7dX5LvlFepBK1ckb0xV7LcTtNPi6fs32HEYyW na1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=4I0g5hC2X7Hy05rT9LxwJtFygVmNaHiW7dX/meVZHjM=; b=GPfxB6NxHUoSlamiJVvTZMRNLQ/J+Pm0h9Q0fuzZGVZ4FZrNK/3A8GOXa0VB4Zv+A+ gO51Ao4cJ/7NExTAbNTK1Ej4RxF9rqBXsVHbBZMrXDaVWGTxo6j+3Ldl2Ql1724qCynu QVdbzCInSoo23YFPtD8ab6oR8eCauQPmBKcc7wwflVe5Y9kPNOxtKI7Em22lPKBD4FCO XCuo+EaYAGM3Qv8afudjcwYORYMwvICCEfEn57r9OVbMpHAcdjWnMx3RfckSa9LLzp9A 4BM8kunuHwNzxlJIBAl6W0wPwNv1/uOaX7NvIbt4tQEHL8mIHnidnhVfy1KQIWh+Eeus OuHA== X-Gm-Message-State: AO0yUKUF8bLfCVQ+7dyljPddL49mv59cyuAM3/sSjo5Y6slHyPzzsgit R5VSQet25xvA2O/OEZcwHfnaFxB6kIXcrEnCvEk= X-Google-Smtp-Source: AK7set/njaKojCnbW6vUIHZXn6OlWr+7l8jTcd570qg21ry1UriE+Qvk+tt7wf7YhzFDPfFP5EcGOg+BQjjgz5hqDz8= X-Received: by 2002:a17:90a:6d22:b0:230:6d87:390b with SMTP id z31-20020a17090a6d2200b002306d87390bmr569164pjj.99.1675750847345; Mon, 06 Feb 2023 22:20:47 -0800 (PST) MIME-Version: 1.0 References: <20230207001618.458947-1-christoph.muellner@vrull.eu> <20230207001618.458947-7-christoph.muellner@vrull.eu> In-Reply-To: <20230207001618.458947-7-christoph.muellner@vrull.eu> From: David Abdurachmanov Date: Tue, 7 Feb 2023 07:20:10 +0100 Message-ID: Subject: Re: [RFC PATCH 06/19] riscv: Adding ISA string parser for environment variables To: Christoph Muellner Cc: libc-alpha@sourceware.org, Palmer Dabbelt , Darius Rad , Andrew Waterman , DJ Delorie , Vineet Gupta , Kito Cheng , Jeff Law , Philipp Tomsich , Heiko Stuebner Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP,URI_DOTEDU 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, Feb 7, 2023 at 1:20 AM Christoph Muellner wrote: > > From: Christoph M=C3=BCllner > > RISC-V does not have a reliable mechanism to detect hart features > like supported ISA extensions or cache block sizes at run-time > as of now. > > Not knowing the hart features limits optimization strategies of glibc > (e.g. ifunc support requires run-time hard feature knowledge). > > To circumvent this limitation this patch introduces a mechanism to > get the hart features via environment variables: > * RISCV_RT_MARCH represents a lower-case ISA string (-march string) > E.g. RISCV_RT_MARCH=3Drv64gc_zicboz > * RISCV_RT_CBOM_BLOCKSIZE represents the cbom instruction block size > E.g. RISCV_RT_CBOZ_BLOCKSIZE=3D64 > * RISCV_RT_CBOZ_BLOCKSIZE represents the cboz instruction block size Hi, Non-expert here, but have you considered defining RISCV glibc tunables? It's designed for this purpose. See: https://www.gnu.org/software/libc/manual/html_node/Tunables.html Especially hardware capability tunables: https://www.gnu.org/software/libc/manual/html_node/Hardware-Capability-Tuna= bles.html It would be nice to have tunables defined for RISC-V that could stay with us for a long time. Cheers, david > These environment variables are parsed during startup and the found > ISA extensions are stored a struct (hart_features) for evaluation > by dynamic dispatching code. > > As the parser code is executed very early, we cannot call functions > that have direct or indirect (via getenv()) dependencies to strlen() > and strncmp(), as these functions cannot be called before the ifunc > support is initialized. Therefore, this patch contains its own helper > functions for strlen(), strncmp(), and getenv(). > > Signed-off-by: Christoph M=C3=BCllner > --- > sysdeps/unix/sysv/linux/riscv/hart-features.c | 294 ++++++++++++++++++ > .../unix/sysv/linux/riscv/macro-for-each.h | 24 ++ > 2 files changed, 318 insertions(+) > create mode 100644 sysdeps/unix/sysv/linux/riscv/macro-for-each.h > > diff --git a/sysdeps/unix/sysv/linux/riscv/hart-features.c b/sysdeps/unix= /sysv/linux/riscv/hart-features.c > index 41111eff57..6de41a26cc 100644 > --- a/sysdeps/unix/sysv/linux/riscv/hart-features.c > +++ b/sysdeps/unix/sysv/linux/riscv/hart-features.c > @@ -17,12 +17,17 @@ > . */ > > #include > +#include > +#include > > /* The code in this file is executed very early, so we cannot call > indirect functions because ifunc support is not initialized. > Therefore this file adds a few simple helper functions to avoid > dependencies to functions outside of this file. */ > > +#define xstr(s) str(s) > +#define str(s) #s > + > static inline void > inhibit_loop_to_libcall > simple_memset (void *s, int c, size_t n) > @@ -35,9 +40,298 @@ simple_memset (void *s, int c, size_t n) > } > } > > +static inline size_t > +inhibit_loop_to_libcall > +simple_strlen (const char *s) > +{ > + size_t n =3D 0; > + char c =3D *s; > + while (c !=3D 0) > + { > + s++; > + n++; > + c =3D *s; > + } > + return n; > +} > + > +static inline int > +inhibit_loop_to_libcall > +simple_strncmp (const char *s1, const char *s2, size_t n) > +{ > + while (n !=3D 0) > + { > + if (*s1 =3D=3D 0 || *s1 !=3D *s2) > + return *((const unsigned char *)s1) - *((const unsigned char *)s2= ); > + n--; > + s1++; > + s2++; > + } > + return 0; > +} > + > +extern char **__environ; > +static inline char* > +simple_getenv (const char *name) > +{ > + char **ep; > + uint16_t name_start; > + > + if (__environ =3D=3D NULL || name[0] =3D=3D 0 || name[1] =3D=3D 0) > + return NULL; > + > + size_t len =3D simple_strlen (name); > +#if _STRING_ARCH_unaligned > + name_start =3D *(const uint16_t *) name; > +#else > + name_start =3D (((const unsigned char *) name)[0] > + | (((const unsigned char *) name)[1] << 8)); > +#endif > + len -=3D 2; > + name +=3D 2; > + > + for (ep =3D __environ; *ep !=3D NULL; ++ep) > + { > +#if _STRING_ARCH_unaligned > + uint16_t ep_start =3D *(uint16_t *) *ep; > +#else > + uint16_t ep_start =3D (((unsigned char *) *ep)[0] > + | (((unsigned char *) *ep)[1] << 8)); > +#endif > + if (name_start =3D=3D ep_start && !simple_strncmp (*ep + 2, name, = len) > + && (*ep)[len + 2] =3D=3D '=3D') > + return &(*ep)[len + 3]; > + } > + return NULL; > +} > + > +/* Check if the given number is a power of 2. > + Return true if so, or false otherwise. */ > +static inline int > +is_power_of_two (unsigned long v) > +{ > + return (v & (v - 1)) =3D=3D 0; > +} > + > +/* Check if the given string str starts with > + the prefix pre. Return true if so, or false > + otherwise. */ > +static inline int > +starts_with (const char *str, const char *pre) > +{ > + return simple_strncmp (pre, str, simple_strlen (pre)) =3D=3D 0; > +} > + > +/* Lower all characters of a string up to the > + first NUL-character in the string. */ > +static inline void > +strtolower (char *s) > +{ > + char c =3D *s; > + while (c !=3D '\0') > + { > + if (c >=3D 'A' && c <=3D 'Z') > + *s =3D c + 'a' - 'A'; > + s++; > + c =3D *s; > + } > +} > + > +/* Count the number of detected extensions. */ > +static inline unsigned long > +count_extensions (struct hart_features *hart_features) > +{ > + unsigned long n =3D 0; > +#define ISA_EXT(e) \ > + if (hart_features->have_##e =3D=3D 1) = \ > + n++; > +#define ISA_EXT_GROUP(g, ...) \ > + if (hart_features->have_##g =3D=3D 1) = \ > + n++; > +#include "isa-extensions.def" > + return n; > +} > + > +/* Check if the given charater is not '0'-'9'. */ > +static inline int > +notanumber (const char c) > +{ > + return (c < '0' || c > '9'); > +} > + > +/* Parse RISCV_RT_MARCH and store found extensions. */ > +static inline void > +parse_rt_march (struct hart_features *hart_features) > +{ > + const char* s =3D simple_getenv ("RISCV_RT_MARCH"); > + if (s =3D=3D NULL) > + goto end; > + > + hart_features->rt_march =3D s; > + > + /* "RISC-V ISA strings begin with either RV32I, RV32E, RV64I, or RV128= I > + indicating the supported address space size in bits for the base > + integer ISA." */ > + if (starts_with (s, "rv32") && notanumber (*(s+4))) > + { > + hart_features->xlen =3D 32; > + s +=3D 4; > + } > + else if (starts_with (s, "rv64") && notanumber (*(s+4))) > + { > + hart_features->xlen =3D 64; > + s +=3D 4; > + } > + else if (starts_with (s, "rv128") && notanumber (*(s+5))) > + { > + hart_features->xlen =3D 128; > + s +=3D 5; > + } > + else > + { > + goto fail; > + } > + > + /* Parse the extensions. */ > + const char *s_old =3D s; > + while (*s !=3D '\0') > + { > +#define ISA_EXT(e) \ > + else if (starts_with (s, xstr (e))) \ > + { \ > + hart_features->have_##e =3D 1; = \ > + s +=3D simple_strlen (xstr (e)); = \ > + } > +#define ISA_EXT_GROUP(g, ...) \ > + ISA_EXT (g) > + if (0); > +#include "isa-extensions.def" > + > + /* Consume optional version information. */ > + while (*s >=3D '0' && *s <=3D '9') > + s++; > + while (*s =3D=3D 'p') > + s++; > + while (*s >=3D '0' && *s <=3D '9') > + s++; > + > + /* Consume optional '_'. */ > + if (*s =3D=3D '_') > + s++; > + > + /* If we got stuck, bail out. */ > + if (s =3D=3D s_old) > + goto fail; > + } > + > + /* Propagate subsets (until we reach a fixpoint). */ > + unsigned long n =3D count_extensions (hart_features); > + while (1) > + { > + /* Forward-propagation. E.g.: > + if (hart_features->have_g =3D=3D 1) > + { > + hart_features->have_i =3D 1; > + ... > + hart_features->have_zifencei =3D 1; > + } */ > +#define ISA_EXT_GROUP_HEAD(y) \ > + if (hart_features->have_##y) \ > + { > +#define ISA_EXT_GROUP_SUBSET(s) = \ > + hart_features->have_##s =3D 1; > +#define ISA_EXT_GROUP_TAIL(z) \ > + } > +#define ISA_EXT_GROUP(x, ...) \ > + ISA_EXT_GROUP_HEAD (x) \ > + FOR_EACH (ISA_EXT_GROUP_SUBSET, __VA_ARGS__) \ > + ISA_EXT_GROUP_TAIL (x) > +#include "isa-extensions.def" > +#undef ISA_EXT_GROUP_HEAD > +#undef ISA_EXT_GROUP_SUBSET > +#undef ISA_EXT_GROUP_TAIL > + > + /* Backward-propagation. E.g.: > + if (1 > + && hart_features->have_i =3D=3D 1 > + ... > + && hart_features->have_zifencei =3D=3D 1 > + ) > + hart_features->have_g =3D 1; */ > +#define ISA_EXT_GROUP_HEAD(y) \ > + if (1 > +#define ISA_EXT_GROUP_SUBSET(s) = \ > + && hart_features->have_##s =3D=3D 1 > +#define ISA_EXT_GROUP_TAIL(z) \ > + ) \ > + hart_features->have_##z =3D 1; > +#define ISA_EXT_GROUP(x, ...) \ > + ISA_EXT_GROUP_HEAD (x) \ > + FOR_EACH (ISA_EXT_GROUP_SUBSET, __VA_ARGS__) \ > + ISA_EXT_GROUP_TAIL (x) > +#include "isa-extensions.def" > +#undef ISA_EXT_GROUP_HEAD > +#undef ISA_EXT_GROUP_SUBSET > +#undef ISA_EXT_GROUP_TAIL > + > + unsigned long n2 =3D count_extensions (hart_features); > + /* Stop if fix-point reached. */ > + if (n =3D=3D n2) > + break; > + n =3D n2; > + } > + > +end: > + return; > + > +fail: > + hart_features->rt_march =3D NULL; > +} > + > +/* Parse RISCV_RT_CBOM_BLOCKSIZE and store value. */ > +static inline void > +parse_rt_cbom_blocksize (struct hart_features *hart_features) > +{ > + hart_features->rt_cbom_blocksize =3D NULL; > + hart_features->cbom_blocksize =3D 0; > + > + const char *s =3D simple_getenv ("RISCV_RT_CBOM_BLOCKSIZE"); > + if (s =3D=3D NULL) > + return; > + > + uint64_t v =3D _dl_strtoul (s, NULL); > + if (!is_power_of_two (v)) > + return; > + > + hart_features->rt_cbom_blocksize =3D s; > + hart_features->cbom_blocksize =3D v; > +} > + > +/* Parse RISCV_RT_CBOZ_BLOCKSIZE and store value. */ > +static inline void > +parse_rt_cboz_blocksize (struct hart_features *hart_features) > +{ > + hart_features->rt_cboz_blocksize =3D NULL; > + hart_features->cboz_blocksize =3D 0; > + > + const char *s =3D simple_getenv ("RISCV_RT_CBOZ_BLOCKSIZE"); > + if (s =3D=3D NULL) > + return; > + > + uint64_t v =3D _dl_strtoul (s, NULL); > + if (!is_power_of_two (v)) > + return; > + > + hart_features->rt_cboz_blocksize =3D s; > + hart_features->cboz_blocksize =3D v; > +} > + > /* Discover hart features and store them. */ > static inline void > init_hart_features (struct hart_features *hart_features) > { > simple_memset (hart_features, 0, sizeof (*hart_features)); > + parse_rt_march (hart_features); > + parse_rt_cbom_blocksize (hart_features); > + parse_rt_cboz_blocksize (hart_features); > } > diff --git a/sysdeps/unix/sysv/linux/riscv/macro-for-each.h b/sysdeps/uni= x/sysv/linux/riscv/macro-for-each.h > new file mode 100644 > index 0000000000..524bef3c0a > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/riscv/macro-for-each.h > @@ -0,0 +1,24 @@ > +/* Recursive macros implementation by David Mazi=C3=A8res > + https://www.scs.stanford.edu/~dm/blog/va-opt.html */ > + > +#ifndef _MACRO_FOR_EACH_H > +#define _MACRO_FOR_EACH_H > + > +#define EXPAND1(...) __VA_ARGS__ > +#define EXPAND2(...) EXPAND1 (EXPAND1 (EXPAND1 (EXPAND1 (__VA_ARGS__)))) > +#define EXPAND3(...) EXPAND2 (EXPAND2 (EXPAND2 (EXPAND2 (__VA_ARGS__)))) > +#define EXPAND4(...) EXPAND3 (EXPAND3 (EXPAND3 (EXPAND3 (__VA_ARGS__)))) > +#define EXPAND(...) EXPAND4 (EXPAND4 (EXPAND4 (EXPAND4 (__VA_ARGS__)))) > + > +#define FOR_EACH(macro, ...) \ > + __VA_OPT__ (EXPAND (FOR_EACH_HELPER (macro, __VA_ARGS__))) > + > +#define PARENS () > + > +#define FOR_EACH_HELPER(macro, a1, ...) = \ > + macro (a1) \ > + __VA_OPT__ (FOR_EACH_AGAIN PARENS (macro, __VA_ARGS__)) > + > +#define FOR_EACH_AGAIN() FOR_EACH_HELPER > + > +#endif /* _MACRO_FOR_EACH_H */ > -- > 2.39.1 >