* [PATCH v2 3/4] stdlib: Remove if inline asm context casts if compiler does not support it
2022-11-02 14:55 [PATCH v2 0/4] Initial fixes for clang build support Adhemerval Zanella
2022-11-02 14:55 ` [PATCH v2 1/4] Disable __USE_EXTERN_INLINES for clang Adhemerval Zanella
2022-11-02 14:55 ` [PATCH v2 2/4] Rewrite find_cxx_header config configure.ac Adhemerval Zanella
@ 2022-11-02 14:55 ` Adhemerval Zanella
2022-11-02 14:55 ` [PATCH v2 4/4] Apply asm redirection in gmp.h before first use Adhemerval Zanella
3 siblings, 0 replies; 9+ messages in thread
From: Adhemerval Zanella @ 2022-11-02 14:55 UTC (permalink / raw)
To: libc-alpha, Fangrui Song
The inline asm constraints lvalue casts on longlong.h are not fully
supported on all compilers. The clang rejects the code by default:
error: invalid use of a cast in a inline asm context requiring an
lvalue: remove the cast or build with -fheinous-gnu-extensions
And even using -fheinous-gnu-extensions it does not seem to be a long-term
solution, since clang accepts it but still throws an warning:
warning: invalid use of a cast in an inline asm context requiring an
lvalue: accepted due to -fheinous-gnu-extensions, but clang may remove
support for this in the future
And clang also does not provide a a -Wno-heinous-gnu-extensions to suppress
it.
For GCC the cast acts as a limited form of typechecking where if the cast
can be removed, then the output operand had a type of the proper width,
otherwise compiler issue an error. That's the main reason why the casts
are still kept in GCC [1], although there are a long-standing bug report
to actually remove them [2].
To enable longlong.h support on clang this patch uses a simple mechanism
to remove casts them if compiler does not fully support it. The script
uses simple string substitution to remove the cast if the asm constraint
is found. For GCC it should be a no-op, the longlong.h is copies as-is.
Checked on a build for all affected ABIs.
[1] https://gcc.gnu.org/pipermail/gcc-patches/2021-October/581722.html
[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=2803
---
Makerules | 13 ++++
configure | 29 ++++++++
configure.ac | 22 ++++++
scripts/filter-asm-inline-cast.py | 102 +++++++++++++++++++++++++++
stdlib/{longlong.h => longlong.h.in} | 0
stdlib/strtod_l.c | 2 +-
6 files changed, 167 insertions(+), 1 deletion(-)
create mode 100755 scripts/filter-asm-inline-cast.py
rename stdlib/{longlong.h => longlong.h.in} (100%)
diff --git a/Makerules b/Makerules
index 09c0cf8357..1ca16bf080 100644
--- a/Makerules
+++ b/Makerules
@@ -351,6 +351,19 @@ $(common-objpfx)$(lib-names-stmp-abi): $(..)scripts/lib-names.awk \
endif
common-generated += $(lib-names-h-abi) $(lib-names-stmp-abi)
endif
+
+# The inline asm constraints lvalue casts on longlong.h are not fully
+# supported on all compilers. However, the cast acts as a limited form of
+# typechecking where if the cast can be removed, then the output operand
+# had a type of the proper width, otherwise compiler issue an error.
+# For the case compiler does not fully support the script tries to remove
+# it.
+before-compile += $(common-objpfx)stdlib/longlong.h
+$(common-objpfx)stdlib/longlong.h: $(..)stdlib/longlong.h.in $(..)scripts/filter-asm-inline-cast.py
+ $(make-target-directory)
+ $(PYTHON) $(..)scripts/filter-asm-inline-cast.py --filter $(config-remove-cast-inline-asm) $< $@.tmp
+ mv -f $@.tmp $@
+common-generated += $(common-objpfx)stdlib/longlong.h
\f
###############################################################################
# NOTE! Everything adding to before-compile needs to come before this point! #
diff --git a/configure b/configure
index e23ea95a49..045a51cfba 100755
--- a/configure
+++ b/configure
@@ -6376,6 +6376,35 @@ $as_echo "$libc_cv_wno_ignored_attributes" >&6; }
config_vars="$config_vars
config-cflags-wno-ignored-attributes = $libc_cv_wno_ignored_attributes"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if cast in inline asm context is supported" >&5
+$as_echo_n "checking if cast in inline asm context is supported... " >&6; }
+if ${libc_cv_cast_inline_asm_context+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat > conftest.c <<EOF
+void foo (void)
+{
+ int i;
+ __asm ("" : "=r" ((unsigned int) i));
+}
+EOF
+libc_cv_remove_cast_inline_asm=no
+if ! { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -c conftest.c'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+then
+ libc_cv_remove_cast_inline_asm=yes
+fi
+rm -f conftest.*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cast_inline_asm_context" >&5
+$as_echo "$libc_cv_cast_inline_asm_context" >&6; }
+config_vars="$config_vars
+config-remove-cast-inline-asm = $libc_cv_remove_cast_inline_asm"
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc puts quotes around section names" >&5
$as_echo_n "checking whether cc puts quotes around section names... " >&6; }
if ${libc_cv_have_section_quotes+:} false; then :
diff --git a/configure.ac b/configure.ac
index 7275b53345..238a7267ef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1426,6 +1426,28 @@ rm -f conftest*])
LIBC_CONFIG_VAR([config-cflags-wno-ignored-attributes],
[$libc_cv_wno_ignored_attributes])
+dnl clang emits and error for cast usage in inline asm context and although
+dnl -fheinous-gnu-extensions option allows to just instruct it to emit an
+dnl warning, clang also explicit warns that the option might be removed in
+dnl the future.
+AC_CACHE_CHECK([if cast in inline asm context is supported],
+ libc_cv_cast_inline_asm_context, [dnl
+cat > conftest.c <<EOF
+void foo (void)
+{
+ int i;
+ __asm ("" : "=r" ((unsigned int) i));
+}
+EOF
+libc_cv_remove_cast_inline_asm=no
+if ! AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -Werror -c conftest.c])
+then
+ libc_cv_remove_cast_inline_asm=yes
+fi
+rm -f conftest.*])
+LIBC_CONFIG_VAR([config-remove-cast-inline-asm],
+ [$libc_cv_remove_cast_inline_asm])
+
AC_CACHE_CHECK(whether cc puts quotes around section names,
libc_cv_have_section_quotes,
[cat > conftest.c <<EOF
diff --git a/scripts/filter-asm-inline-cast.py b/scripts/filter-asm-inline-cast.py
new file mode 100755
index 0000000000..319751e7f2
--- /dev/null
+++ b/scripts/filter-asm-inline-cast.py
@@ -0,0 +1,102 @@
+#!/usr/bin/python3
+# Filter out inline asm casts.
+# Copyright (C) 2018-2022 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+import re
+
+# Each asm constraint where the cast occurs.
+CONSTRAINT_LIST=(
+ '\"%0\"',
+ '\"%1\"',
+ '\"%dI\"'
+ '\"%rJ\"',
+ '\"%r\"',
+ '\"0\"',
+ '\"1\"',
+ '\"=&g\"',
+ '\"=&r\"',
+ '\"=a\"',
+ '\"=d\"',
+ '\"=g\"',
+ '\"=r\"',
+ '\"dI\"',
+ '\"g\"',
+ '\"rICal\"',
+ '\"rI\"',
+ '\"rJ\"',
+ '\"%rJ\"',
+ '\"rM\"',
+ '\"rQR\"',
+ '\"r\"',
+ '\"rm\"',
+ '\"rme\"',
+ '\"x\"',
+ '\"d\"',
+ '\"=&d\"',
+ '\"dmi\"',
+ '\"%rM\"',
+)
+
+# The cast type used in lvalue asm contraint input.
+REPLACE_CASTS = (
+ "(UDItype)",
+ "(USItype)",
+ "(unsigned int)",
+)
+
+def multireplace(string, repl):
+ if not repl:
+ return string
+
+ # Place longer string first, to avoid shorter substring to match first.
+ rep_sorted = sorted(repl, key=len, reverse=True)
+ rep_escaped = map(re.escape, rep_sorted)
+ pattern = re.compile("|".join(rep_escaped), 0)
+
+ return pattern.sub(lambda match: "", string)
+
+
+def get_parser():
+ def strbool(string):
+ return True if string.lower() == 'yes' else False
+
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--filter', dest='filter',
+ help='Filter out inoine asm casts',
+ type=strbool)
+ parser.add_argument('input', help='Input file')
+ parser.add_argument('output', help='Ouput file')
+ return parser
+
+
+def main(argv):
+ """The main entry point."""
+ parser = get_parser()
+ opts = parser.parse_args(argv)
+ with open(opts.input, 'r') as i_file, open(opts.output, 'w') as o_file:
+ for line in i_file:
+ replace = REPLACE_CASTS \
+ if opts.filter and any(substring in line for substring in CONSTRAINT_LIST) \
+ else None
+ o_file.write(multireplace(line, replace))
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/stdlib/longlong.h b/stdlib/longlong.h.in
similarity index 100%
rename from stdlib/longlong.h
rename to stdlib/longlong.h.in
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
index 3ebb491e22..fe59907cb2 100644
--- a/stdlib/strtod_l.c
+++ b/stdlib/strtod_l.c
@@ -81,7 +81,7 @@ extern double ____strtod_l_internal (const char *, char **, int, locale_t);
#include <gmp-mparam.h>
#include <gmp.h>
#include "gmp-impl.h"
-#include "longlong.h"
+#include <stdlib/longlong.h>
#include "fpioconst.h"
#include <assert.h>
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 4/4] Apply asm redirection in gmp.h before first use
2022-11-02 14:55 [PATCH v2 0/4] Initial fixes for clang build support Adhemerval Zanella
` (2 preceding siblings ...)
2022-11-02 14:55 ` [PATCH v2 3/4] stdlib: Remove if inline asm context casts if compiler does not support it Adhemerval Zanella
@ 2022-11-02 14:55 ` Adhemerval Zanella
2022-11-06 23:33 ` Fangrui Song
3 siblings, 1 reply; 9+ messages in thread
From: Adhemerval Zanella @ 2022-11-02 14:55 UTC (permalink / raw)
To: libc-alpha, Fangrui Song
For clang the redeclaration after the first use, the visibility attribute
is silently ignored (symbol is STV_DEFAULT) while the asm label attribute
causes an error.
---
include/gmp.h | 12 ---------
stdlib/gmp.h | 72 ++++++++++++++++++++++++++++-----------------------
2 files changed, 39 insertions(+), 45 deletions(-)
diff --git a/include/gmp.h b/include/gmp.h
index 657c7a0148..791900b2cb 100644
--- a/include/gmp.h
+++ b/include/gmp.h
@@ -41,18 +41,6 @@ extern _Float128 __mpn_construct_float128 (mp_srcptr frac_ptr, int expt,
int sign) attribute_hidden;
#endif
-extern __typeof (mpn_add_1) mpn_add_1 attribute_hidden;
-extern __typeof (mpn_addmul_1) mpn_addmul_1 attribute_hidden;
-extern __typeof (mpn_add_n) mpn_add_n attribute_hidden;
-extern __typeof (mpn_cmp) mpn_cmp attribute_hidden;
-extern __typeof (mpn_divrem) mpn_divrem attribute_hidden;
-extern __typeof (mpn_lshift) mpn_lshift attribute_hidden;
-extern __typeof (mpn_mul) mpn_mul attribute_hidden;
-extern __typeof (mpn_mul_1) mpn_mul_1 attribute_hidden;
-extern __typeof (mpn_rshift) mpn_rshift attribute_hidden;
-extern __typeof (mpn_sub_1) mpn_sub_1 attribute_hidden;
-extern __typeof (mpn_submul_1) mpn_submul_1 attribute_hidden;
-extern __typeof (mpn_sub_n) mpn_sub_n attribute_hidden;
#endif
#endif
diff --git a/stdlib/gmp.h b/stdlib/gmp.h
index a206e36cf8..ca9ebd2bc9 100644
--- a/stdlib/gmp.h
+++ b/stdlib/gmp.h
@@ -48,6 +48,12 @@ along with the GNU MP Library; see the file COPYING.LIB. If not, see
#endif
#endif
+#ifdef _LIBC
+#define _ATTRIBUTE_HIDDEN attribute_hidden
+#else
+#define _ATTRIBUTE_HIDDEN
+#endif
+
#ifdef _SHORT_LIMB
typedef unsigned int mp_limb_t;
typedef int mp_limb_signed_t;
@@ -389,39 +395,39 @@ void mpf_ui_sub _PROTO ((mpf_ptr, unsigned long int, mpf_srcptr));
#if defined (__cplusplus)
extern "C" {
#endif
-mp_limb_t mpn_add _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t));
-mp_limb_t mpn_add_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t));
-mp_limb_t mpn_add_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t));
-mp_limb_t mpn_addmul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t));
-mp_limb_t mpn_bdivmod _PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int));
-int mpn_cmp _PROTO ((mp_srcptr, mp_srcptr, mp_size_t));
-mp_limb_t mpn_divmod_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t));
-mp_limb_t mpn_divrem _PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t));
-mp_limb_t mpn_divrem_1 _PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t));
-void mpn_dump _PROTO ((mp_srcptr, mp_size_t));
-mp_size_t mpn_gcd _PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t));
-mp_limb_t mpn_gcd_1 _PROTO ((mp_srcptr, mp_size_t, mp_limb_t));
-mp_size_t mpn_gcdext _PROTO ((mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t));
-size_t mpn_get_str _PROTO ((unsigned char *, int, mp_ptr, mp_size_t));
-unsigned long int mpn_hamdist _PROTO ((mp_srcptr, mp_srcptr, mp_size_t));
-mp_limb_t mpn_lshift _PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int));
-mp_limb_t mpn_mod_1 _PROTO ((mp_srcptr, mp_size_t, mp_limb_t));
-mp_limb_t mpn_mul _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t));
-mp_limb_t mpn_mul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t));
-void mpn_mul_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t));
-int mpn_perfect_square_p _PROTO ((mp_srcptr, mp_size_t));
-unsigned long int mpn_popcount _PROTO ((mp_srcptr, mp_size_t));
-mp_limb_t mpn_preinv_mod_1 _PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t));
-void mpn_random2 _PROTO ((mp_ptr, mp_size_t));
-mp_limb_t mpn_rshift _PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int));
-unsigned long int mpn_scan0 _PROTO ((mp_srcptr, unsigned long int));
-unsigned long int mpn_scan1 _PROTO ((mp_srcptr, unsigned long int));
-mp_size_t mpn_set_str _PROTO ((mp_ptr, const unsigned char *, size_t, int));
-mp_size_t mpn_sqrtrem _PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t));
-mp_limb_t mpn_sub _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t));
-mp_limb_t mpn_sub_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t));
-mp_limb_t mpn_sub_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t));
-mp_limb_t mpn_submul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t));
+mp_limb_t mpn_add _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_add_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_add_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_addmul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_bdivmod _PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, unsigned long int)) _ATTRIBUTE_HIDDEN;
+int mpn_cmp _PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_divmod_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_divrem _PROTO ((mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_divrem_1 _PROTO ((mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+void mpn_dump _PROTO ((mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_size_t mpn_gcd _PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_gcd_1 _PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+mp_size_t mpn_gcdext _PROTO ((mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+size_t mpn_get_str _PROTO ((unsigned char *, int, mp_ptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+unsigned long int mpn_hamdist _PROTO ((mp_srcptr, mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_lshift _PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_mod_1 _PROTO ((mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_mul _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_mul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+void mpn_mul_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+int mpn_perfect_square_p _PROTO ((mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+unsigned long int mpn_popcount _PROTO ((mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_preinv_mod_1 _PROTO ((mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+void mpn_random2 _PROTO ((mp_ptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_rshift _PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)) _ATTRIBUTE_HIDDEN;
+unsigned long int mpn_scan0 _PROTO ((mp_srcptr, unsigned long int)) _ATTRIBUTE_HIDDEN;
+unsigned long int mpn_scan1 _PROTO ((mp_srcptr, unsigned long int)) _ATTRIBUTE_HIDDEN;
+mp_size_t mpn_set_str _PROTO ((mp_ptr, const unsigned char *, size_t, int)) _ATTRIBUTE_HIDDEN;
+mp_size_t mpn_sqrtrem _PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_sub _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_sub_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_sub_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)) _ATTRIBUTE_HIDDEN;
+mp_limb_t mpn_submul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)) _ATTRIBUTE_HIDDEN;
#if defined (__cplusplus)
}
#endif
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread