[PATCH 0/2] Support libc with stdio-only I/O in libstdc++

2020-12-07 Thread Keith Packard via Gcc
The current libstdc++ basic_file_stdio.cc code assumes a POSIX API
underneath the stdio implementation provided by the host libc. This
means that the host must provide a fairly broad POSIX file API,
including read, write, open, close, lseek and ioctl.

This patch changes basic_file_stdio.cc to only use basic ANSI-C stdio
functions, allowing it to be used with libc implementations like
picolibc which may not have a POSIX operating system underneath.




[PATCH 2/2] Regenerate libstdc++-v3 autoconf files

2020-12-07 Thread Keith Packard via Gcc
These are the changes to autoconf files for the pure-stdio patch

Signed-off-by: Keith Packard 
---
 libstdc++-v3/config.h.in |  3 +++
 libstdc++-v3/configure   | 23 +++
 2 files changed, 26 insertions(+)

diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in
index 72faabfb2c1..76b1c97d2b5 100644
--- a/libstdc++-v3/config.h.in
+++ b/libstdc++-v3/config.h.in
@@ -1022,6 +1022,9 @@
 /* Define if POSIX read/write locks are available in . */
 #undef _GLIBCXX_USE_PTHREAD_RWLOCK_T
 
+/* Define to restrict code to stdio APIs. */
+#undef _GLIBCXX_USE_PURE_STDIO
+
 /* Define if /dev/random and /dev/urandom are available for the random_device
of TR1 (Chapter 5.1). */
 #undef _GLIBCXX_USE_RANDOM_TR1
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index d128de2f186..5647c986831 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -929,6 +929,7 @@ enable_extern_template
 with_python_dir
 enable_werror
 enable_vtable_verify
+enable_libstdcxx_pure_stdio
 enable_libstdcxx_time
 enable_tls
 enable_rpath
@@ -1632,6 +1633,8 @@ Optional Features:
   enable extern template [default=yes]
   --enable-werror turns on -Werror [default=no]
   --enable-vtable-verify  enable vtable verify [default=no]
+  --enable-libstdcxx-pure-stdio
+  use only stdio APIs [default=]
   --enable-libstdcxx-time[=KIND]
   use KIND for check type [default=auto]
   --enable-tlsUse thread-local storage [default=yes]
@@ -18807,6 +18810,26 @@ fi
 
 
 
+   # Check whether --enable-libstdcxx-pure-stdio was given.
+if test "${enable_libstdcxx_pure_stdio+set}" = set; then :
+  enableval=$enable_libstdcxx_pure_stdio;
+  case "$enableval" in
+   yes|no) ;;
+   *) as_fn_error $? "Argument to enable/disable libstdcxx-pure-stdio must 
be yes or no" "$LINENO" 5 ;;
+  esac
+
+else
+  enable_libstdcxx_pure_stdio=
+fi
+
+
+  if test $enable_libstdcxx_pure_stdio = yes; then
+
+$as_echo "#define _GLIBCXX_USE_PURE_STDIO 1" >>confdefs.h
+
+  fi
+
+
 # Checks for operating systems support that doesn't require linking.
 
 
-- 
2.29.2



[PATCH 1/2] libstdc++: Add --enable-pure-stdio-libstdcxx option

2020-12-07 Thread Keith Packard via Gcc
This option directs the library to only use simple stdio APIs instead
of using fileno to get the file descriptor for use with POSIX APIs.

Signed-off-by: Keith Packard 
---
 libstdc++-v3/ChangeLog | 13 ++
 libstdc++-v3/acinclude.m4  | 13 ++
 libstdc++-v3/config/io/basic_file_stdio.cc | 46 +++---
 libstdc++-v3/configure.ac  |  1 +
 4 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index d3ee18ed7d1..7f6b0697534 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1147,6 +1147,19 @@
* include/bits/uniform_int_dist.h (uniform_int_distribution::_S_nd):
Use qualified-id to refer to static member functions.
 
+2020-11-04  Keith Packard  
+
+   * acinclude.m4: Add GLIBCXX_ENABLE_PURE_STDIO for
+   --enable-libstdcxx-pure-stdio
+   * configure.ac: Use GLIBCXX_ENABLE_PURE_STDIO for
+   --enable-libstdcxx-pure-stdio
+   * configure: regenerate
+   * config.h.in: regenerate
+   * config/io/basic_file_stdio.cc: Add support for
+   _GLIBCXX_USE_PURE_STDIO. This makes libstdc++ use only defined
+   stdio entry points for all I/O operations, without direct calls to
+   underlying POSIX functions.
+
 2020-11-03  Jonathan Wakely  
 
* include/std/syncstream: Include 
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index fcd9ea3d23a..863695e68e7 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -2889,6 +2889,19 @@ AC_DEFUN([GLIBCXX_ENABLE_CSTDIO], [
 ])
 
 
+dnl
+dnl Check whether to use 'pure' stdio (no POSIX calls at all)
+dnl
+dnl Default is 'no'
+AC_DEFUN([GLIBCXX_ENABLE_PURE_STDIO], [
+  GLIBCXX_ENABLE(libstdcxx-pure-stdio,$1,,[use only stdio APIs])
+  if test $enable_libstdcxx_pure_stdio = yes; then
+AC_DEFINE(_GLIBCXX_USE_PURE_STDIO, 1,
+  [Define to restrict code to stdio APIs.])
+  fi
+])
+
+
 dnl
 dnl Check for "unusual" flags to pass to the compiler while building.
 dnl
diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc 
b/libstdc++-v3/config/io/basic_file_stdio.cc
index ba830fb9e97..d31da8497f4 100644
--- a/libstdc++-v3/config/io/basic_file_stdio.cc
+++ b/libstdc++-v3/config/io/basic_file_stdio.cc
@@ -111,13 +111,21 @@ namespace
 
   // Wrapper handling partial write.
   static std::streamsize
+#ifdef _GLIBCXX_USE_PURE_STDIO
+  xwrite(FILE *__file, const char* __s, std::streamsize __n)
+#else
   xwrite(int __fd, const char* __s, std::streamsize __n)
+#endif
   {
 std::streamsize __nleft = __n;
 
 for (;;)
   {
+#ifdef _GLIBCXX_USE_PURE_STDIO
+   const std::streamsize __ret = fwrite(__file, 1, __nleft, __file);
+#else
const std::streamsize __ret = write(__fd, __s, __nleft);
+#endif
if (__ret == -1L && errno == EINTR)
  continue;
if (__ret == -1L)
@@ -133,7 +141,7 @@ namespace
 return __n - __nleft;
   }
 
-#ifdef _GLIBCXX_HAVE_WRITEV
+#if defined(_GLIBCXX_HAVE_WRITEV) && !defined(_GLIBCXX_USE_PURE_STDIO)
   // Wrapper handling partial writev.
   static std::streamsize
   xwritev(int __fd, const char* __s1, std::streamsize __n1,
@@ -286,9 +294,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   __basic_file::is_open() const throw ()
   { return _M_cfile != 0; }
 
+#ifndef _GLIBCCXX_USE_PURE_STDIO
   int
   __basic_file::fd() throw ()
   { return fileno(_M_cfile); }
+#endif
 
   __c_file*
   __basic_file::file() throw ()
@@ -315,28 +325,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   {
 streamsize __ret;
 do
+#ifdef _GLIBCXX_USE_PURE_STDIO
+  __ret = fread(__s, 1, __n, this->file());
+#else
   __ret = read(this->fd(), __s, __n);
+#endif
 while (__ret == -1L && errno == EINTR);
 return __ret;
   }
 
   streamsize
   __basic_file::xsputn(const char* __s, streamsize __n)
-  { return xwrite(this->fd(), __s, __n); }
+  {
+#ifdef _GLIBCXX_USE_PURE_STDIO
+return xwrite(this->file(), __s, __n);
+#else
+return xwrite(this->fd(), __s, __n);
+#endif
+  }
 
   streamsize
   __basic_file::xsputn_2(const char* __s1, streamsize __n1,
   const char* __s2, streamsize __n2)
   {
 streamsize __ret = 0;
-#ifdef _GLIBCXX_HAVE_WRITEV
+#if defined(_GLIBCXX_HAVE_WRITEV) && !defined(_GLIBCXX_USE_PURE_STDIO)
 __ret = xwritev(this->fd(), __s1, __n1, __s2, __n2);
 #else
 if (__n1)
+#ifdef _GLIBCXX_USE_PURE_STDIO
+  __ret = xwrite(this->file(), __s1, __n1);
+#else
   __ret = xwrite(this->fd(), __s1, __n1);
+#endif
 
 if (__ret == __n1)
+#ifdef _GLIBCXX_USE_PURE_STDIO
+  __ret += xwrite(this->file(), __s2, __n2);
+#else
   __ret += xwrite(this->fd(), __s2, __n2);
+#endif
 #endif
 return __ret;
   }
@@ -350,7 +378,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 if (__off > numeric_limits::max()
|| __off < numeric_limits::min())
   return -1L;
+#ifdef _GLIBCXX_USE_PURE_STDIO
+return fseek(this->file(), __off, __way);
+#else

[PATCH] Add -fopt-builtin optimization option

2021-10-31 Thread Keith Packard via Gcc
This option (enabled by default) controls optimizations which convert
a sequence of operations into an equivalent sequence that includes
calls to builtin functions. Typical cases here are code which matches
memcpy, calloc, sincos.

The -ftree-loop-distribute-patterns flag only covers converting loops
into builtin calls, not numerous other places where knowledge of
builtin function semantics changes the generated code.

The goal is to allow built-in functions to be declared by the compiler
and used directly by the application, but to disable optimizations
which create new calls to them, and to allow this optimization
behavior to be changed for individual functions by decorating the
function definition like this:

void
attribute((optimize("no-opt-builtin")))
sincos(double x, double *s, double *c)
{
*s = sin(x);
*c = cos(x);
}

This also avoids converting loops into library calls like this:

void *
attribute((optimize("no-opt-builtin")))
memcpy(void *__restrict__ dst, const void *__restrict__ src, size_t n)
{
char *d = dst;
const char *s = src;

while (n--)
*d++ = *s++;
return dst;
}

As well as disabling analysis of memory lifetimes around free as in
this example:

void *
attribute((optimize("no-opt-builtin")))
erase_and_free(void *ptr)
{
memset(ptr, '\0', malloc_usable_size(ptr));
free(ptr);
}

Clang has a more sophisticated version of this mechanism which
can disable all builtins, or disable a specific builtin:

double
attribute((no_builtin("exp2")))
exp2(double x)
{
return pow (2.0, x);
}

Signed-off-by: Keith Packard 
---
 gcc/builtins.c   | 6 ++
 gcc/common.opt   | 4 
 gcc/gimple.c | 3 +++
 gcc/tree-loop-distribution.c | 2 ++
 4 files changed, 15 insertions(+)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 7d0f61fc98b..7aae57deab5 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1922,6 +1922,9 @@ mathfn_built_in_2 (tree type, combined_fn fn)
   built_in_function fcodef64x = END_BUILTINS;
   built_in_function fcodef128x = END_BUILTINS;
 
+  if (flag_no_opt_builtin)
+return END_BUILTINS;
+
   switch (fn)
 {
 #define SEQ_OF_CASE_MATHFN \
@@ -2125,6 +2128,9 @@ mathfn_built_in_type (combined_fn fn)
   case CFN_BUILT_IN_##MATHFN##L_R: \
 return long_double_type_node;
 
+  if (flag_no_opt_builtin)
+return NULL_TREE;
+
   switch (fn)
 {
 SEQ_OF_CASE_MATHFN
diff --git a/gcc/common.opt b/gcc/common.opt
index eeba1a727f2..d6111cc776a 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2142,6 +2142,10 @@ fomit-frame-pointer
 Common Var(flag_omit_frame_pointer) Optimization
 When possible do not generate stack frames.
 
+fopt-builtin
+Common Var(flag_no_opt_builtin, 0) Optimization
+Match code sequences equivalent to builtin functions
+
 fopt-info
 Common Var(flag_opt_info) Optimization
 Enable all optimization info dumps on stderr.
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 22dd6417d19..5b82b9409c0 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2790,6 +2790,9 @@ gimple_builtin_call_types_compatible_p (const gimple 
*stmt, tree fndecl)
 {
   gcc_checking_assert (DECL_BUILT_IN_CLASS (fndecl) != NOT_BUILT_IN);
 
+  if (flag_no_opt_builtin)
+return false;
+
   tree ret = gimple_call_lhs (stmt);
   if (ret
   && !useless_type_conversion_p (TREE_TYPE (ret),
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 583c01a42d8..43f22a3c7ce 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -1859,6 +1859,7 @@ loop_distribution::classify_partition (loop_p loop,
 
   /* Perform general partition disqualification for builtins.  */
   if (volatiles_p
+  || flag_no_opt_builtin
   || !flag_tree_loop_distribute_patterns)
 return has_reduction;
 
@@ -3764,6 +3765,7 @@ loop_distribution::execute (function *fun)
   /* Don't distribute multiple exit edges loop, or cold loop when
  not doing pattern detection.  */
   if (!single_exit (loop)
+ || flag_no_opt_builtin
  || (!flag_tree_loop_distribute_patterns
  && !optimize_loop_for_speed_p (loop)))
continue;
-- 
2.33.0



Re: [PATCH] Add -fopt-builtin optimization option

2021-11-02 Thread Keith Packard via Gcc
Richard Biener  writes:

> I don't think it reliably works the way you implement it.  It's also having
> more side-effects than what you document, in particular

Yeah, I made a 'minimal' patch that had the effect I needed, but it's
clearly in the wrong place as it disables the matching of builtins
against the incoming source code instead of the generation of new
builtin references from the tree.

> I think you may want to instead change builtin_decl_implicit
> to avoid code-generating a specific builtin.

Yup, I looked at that and there are numerous places which assume that
will work, so it will be a more complicated patch.

> Generally we'd also want sth like the clang attribute and _not_
> use optimize("") for this or a global flag_*, so the behavior can
> be more readily encoded in the IL.  In fact a flag on the call
> statement could be added to denote the desired effect on it.

Agreed, using the existing optimize attribute was a short-cut to
leverage the existing code handling that case. If we think providing
something that matches the clang attribute would be useful, it makes
sense to provide it using the same syntax.

> I also don't see the advantage compared to -fno-builtin[-foo].
> Declaring the function should be something that's already done.

The semantic of the clang option is not to completely disable access
to the given builtin function, but rather to stop the optimizer from
creating new builtin function references (either to a specific builtin,
or to all builtins).

If I could use "no-builtin" in a function attribute, I probably wouldn't
have bothered looking to implement the clang semantics, but -fno-builtin
isn't supported in this way. But, now that I think I understand the
behavior of attribute((no_builtin)) in clang, I think it has value
beyond what -fno-builtin performs as you can still gain access to
builtin functions when they are directly named.

I'll go implement changes in builtin_decl_implicit and all of the
affected call sites and see what that looks like.

Thanks much for your review!

-- 
-keith


signature.asc
Description: PGP signature


[PATCH] Add 'no_builtin' function attribute

2021-11-02 Thread Keith Packard via Gcc
This attribute controls optimizations which make assumptions about the
semantics of builtin functions. Typical cases here are code which
match memcpy, calloc, sincos, or which call builtins like free.

This extends on things like the -ftree-loop-distribute-patterns
flag. That flag only covers converting loops into builtin calls, not
numerous other places where knowledge of builtin function semantics
changes the generated code.

The goal is to allow built-in functions to be declared by the compiler
and used directly by the application, but to disable optimizations
which take advantage of compiler knowledge about their semantics, and
to allow this optimization behavior to be changed for individual
functions.

One place where this behavior is especially useful is when compiling
the builtin functions that gcc knows about, as in the C
library. Currently, C library source code and build systems have
various kludges to work around the compilers operations in these
areas, using a combination of -fno-tree-loop-distribute-patterns,
-fno-builtins and even symbol aliases to keep GCC from generating
infinite recursions.

This can be applied globally to a file using the -fno-optimize-builtin
flag.

This disables optimizations which translate a sequence of builtin calls
into an equivalent sequence:

void
attribute((no_builtin))
sincos(double x, double *s, double *c)
{
*s = sin(x);
*c = cos(x);
}

This also avoids converting loops into builtin calls like this:

void *
attribute((no_builtin))
memcpy(void *__restrict__ dst, const void *__restrict__ src, size_t n)
{
char *d = dst;
const char *s = src;

while (n--)
*d++ = *s++;
return dst;
}

As well as disabling analysis of memory lifetimes around free as in
this example:

void *
attribute((no_builtin))
erase_and_free(void *ptr)
{
memset(ptr, '\0', malloc_usable_size(ptr));
free(ptr);
}

It also prevents converting builtin calls into inline code:

void
attribute((no_builtin))
copy_fixed(char *dest)
{
strcpy(dest, "hello world");
}

Clang has a more sophisticated version of this mechanism which
can disable specific builtins:

double
attribute((no_builtin("exp2")))
exp2(double x)
{
return pow (2.0, x);
}

The general approach in this change is to introduce checks in some
places where builtin functions are used to see if the specific
function is 'allowed' to be used for optimization, skipping the
optimization when the desired function has been disabled.

Three new functions, builtin_decl_implicit_opt_p,
builtin_decl_explicit_opt and builtin_decl_implicit_opt are introduced
which add checks for whether the compiler can assume standard
semantics for the specified function for purposes of
optimization. These are used throughout the compiler wherever
appropriate. Code which must use builtins for correct operation
(e.g. struct assignment) are not affected.

The machinery proposed here could be extended to support the
additional clang feature by extending the attribute parsing function
and creating a list of disabled builtins checked by the builtin_decl
functions described above.

Signed-off-by: Keith Packard 
---
 gcc/builtins.c   | 12 +++---
 gcc/c-family/c-attribs.c | 68 ++
 gcc/common.opt   |  4 ++
 gcc/gimple-fold.c| 72 ++--
 gcc/gimple-match-head.c  |  2 +-
 gcc/tree-loop-distribution.c |  7 
 gcc/tree-ssa-alias.c |  3 +-
 gcc/tree-ssa-strlen.c| 48 ++--
 gcc/tree-ssa-structalias.c   |  3 +-
 gcc/tree.h   | 39 +++
 10 files changed, 194 insertions(+), 64 deletions(-)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 7d0f61fc98b..d665ee716e8 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -2061,7 +2061,7 @@ mathfn_built_in_1 (tree type, combined_fn fn, bool 
implicit_p)
   if (fcode2 == END_BUILTINS)
 return NULL_TREE;
 
-  if (implicit_p && !builtin_decl_implicit_p (fcode2))
+  if (implicit_p && !builtin_decl_implicit_opt_p (fcode2))
 return NULL_TREE;
 
   return builtin_decl_explicit (fcode2);
@@ -3481,9 +3481,9 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, 
machine_mode mode)
   src = CALL_EXPR_ARG (exp, 1);
 
   /* If return value is ignored, transform stpcpy into strcpy.  */
-  if (target == const0_rtx && builtin_decl_implicit (BUILT_IN_STRCPY))
+  if (target == const0_rtx && builtin_decl_implicit_opt (BUILT_IN_STRCPY))
 {
-  tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+  tree fn = builtin_decl_implicit_opt (BUILT_IN_STRCPY);
   tree result = build_call_nofold_loc (loc, fn, 2, dst

Re: [PATCH] Add 'no_builtin' function attribute

2021-11-03 Thread Keith Packard via Gcc
Martin Sebor  writes:

> Can this option be used in attribute optimize?  If yes, what's
> the advantage of also providing an atttribute?

Compatibility with the clang attribute.

> It seems to me that as a matter of QOI, GCC should be able to
> disable the expansion of built-ins to calls to themselves in
> their bodies (I would view it as a bug if GCC expanded a byte
> copying loop into a call to __builtin_memcpy in the body of
> a function named memcpy, without issuing a warnings; but even
> with a warning I'd hope it to do the sensible thing and avoid
> introducing infinite recursion).

That's a pretty sensible plan and would resolve many of the issues
caused by these optimizations while implementing libc itself. Of course,
that wouldn't fix other places where the compiler is using knowledge of
builtin semantics to drive optimization (like the memset call before
free).

> A compiler may not be able
> to do that in calls made from those functions, and for that
> the built-in expansion needs to be disabled explicitly.
> -fno-builtin isn't good enough because it doesn't prevent GCC
> from introiducing calls to __builtin_ functions, and that's
> what this feature is for.  Do I understand correctly?

-fno-builtin has two problems:

 1. Cannot be used in source code, only on the command line.

 2. Also disables explicit use of builtin functions.

> If we end up adding a new attribute (as opposed to relying
> on attribute optimize) and the attribute is expected to have
> an effect only on the definitions of functions and not also
> on their callers, I would suggest to consider having
> the handler check that it is, in fact, on a definiton and
> not a declaration and issuing a warning that it has no effect
> on a declaration, to avoid misunderstandings.

Hrm. I copied the code from the 'optimize' attribute to make this have
the same effect; as above, this new attribute offers clang compatibility
for something that can also be done with the existing optimize
attribute.

> If either a new attribute or a new option is introduced they
> need to be documented in the manual.  From your description
> it's not clear to me if it's just about disabling the expansion
> of the built-ins or if it's meant to prevent GCC from making
> any assumptions about their semantics in calls to the annotated
> functions.  That will likely be of interest to users and it
> matters for diagnostics.

Yes, I definitely need to add documentation. I'm actually using this
thread to help clarify precisely what those semantics should be; it's a
pretty subtle operation when compared with -fno-builtin.

> We will also need to add tests for the feature.  There are many
> built-ins in GCC but the patch only affects a small subset of
> them (e.g., I see it affects a few stdio and string functions
> but I'm not sure the printf family are among them -- all those
> handled in gimple-ssa-sprintf.c).

Yeah, I can get started on tests.

Keeping this operation from affecting things that it shouldn't while
hitting everything it should is a bit more difficult than I had hoped; I
suspect we'll be finding cases for some time unless I can discover an
easier place to hook this into.

> Besides its effect on codegen, I would also hope for a few test
> cases for warnings, those issued by the strlen pass in particular,
> to make sure their effects either are preserved or are disabled
> (whichever is appropriate).

Because the goal is to have the optimizer "forget" about the semantics of
builtins, but let them still be used when explicitly named in the code,
these warnings would still need to be enabled, so I left them in.

I think we need to get a clear description of what this attribute should
do before making many more changes in the code. Here's a first stab:

 no_builtin

This attribute directs GCC to not use knowledge of the semantics
of built-in functions to direct code optimization.  GCC will not
add or remove usage of builtin functions, or restructure code in
ways that depend on built-in knowledge of their
operation. Explicit use of builtin functions will still use any
internal implementations.

In contrast to -fno-builtin, the no_builtin attribute does not
disable declaration of the built-in functions, so messages
related to use and definition will still be enabled, and they
can still be used when named explicitly. In addition, the
no_builtin attribute can be applied on a function-at-a-time
level, while -fno-builtin must be specified on the command line.

-- 
-keith


signature.asc
Description: PGP signature


[PATCH 2/3] picolibc: Add newlib and picolibc as default C library choices

2022-08-24 Thread Keith Packard via Gcc
Signed-off-by: Keith Packard 
---
 gcc/config.gcc | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/gcc/config.gcc b/gcc/config.gcc
index f8b6da4f4e7..0aa4bd6c3dd 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -639,7 +639,7 @@ case ${target} in
 esac
 
 # Common C libraries.
-tm_defines="$tm_defines LIBC_GLIBC=1 LIBC_UCLIBC=2 LIBC_BIONIC=3 LIBC_MUSL=4"
+tm_defines="$tm_defines LIBC_GLIBC=1 LIBC_UCLIBC=2 LIBC_BIONIC=3 LIBC_MUSL=4 
LIBC_NEWLIB=5 LIBC_PICOLIBC=6"
 
 default_libc=""
 
@@ -5878,6 +5878,12 @@ bionic)
 musl)
 default_libc=LIBC_MUSL
 ;;
+newlib)
+default_libc=LIBC_NEWLIB
+;;
+picolibc)
+default_libc=LIBC_PICOLIBC
+;;
 esac
 
 case "$default_libc" in
-- 
2.36.1



[PATCH 1/3] picolibc: Allow default libc to be specified to configure

2022-08-24 Thread Keith Packard via Gcc
The default C library is normally computed based on the target
triplet. However, for embedded systems, it can be useful to leave the
triplet alone while changing which C library is used by default. Other
C libraries may still be available on the system so the compiler and
can be used by specifying suitable include and library paths at build
time.

Signed-off-by: Keith Packard 
---
 gcc/config.gcc   | 42 ++
 gcc/configure.ac |  4 
 2 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 02f58970db0..f8b6da4f4e7 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -641,6 +641,8 @@ esac
 # Common C libraries.
 tm_defines="$tm_defines LIBC_GLIBC=1 LIBC_UCLIBC=2 LIBC_BIONIC=3 LIBC_MUSL=4"
 
+default_libc=""
+
 # 32-bit x86 processors supported by --with-arch=.  Each processor
 # MUST be separated by exactly one space.
 x86_archs="athlon athlon-4 athlon-fx athlon-mp athlon-tbird \
@@ -847,16 +849,16 @@ case ${target} in
   esac
   case $target in
 *-*-*android*)
-  tm_defines="$tm_defines DEFAULT_LIBC=LIBC_BIONIC"
+  default_libc=LIBC_BIONIC
   ;;
 *-*-*uclibc* | *-*-uclinuxfdpiceabi)
-  tm_defines="$tm_defines DEFAULT_LIBC=LIBC_UCLIBC"
+  default_libc=LIBC_UCLIBC
   ;;
 *-*-*musl*)
-  tm_defines="$tm_defines DEFAULT_LIBC=LIBC_MUSL"
+  default_libc=LIBC_MUSL
   ;;
 *)
-  tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC"
+  default_libc=LIBC_GLIBC
   ;;
   esac
   # Assume that glibc or uClibc or Bionic are being used and so __cxa_atexit
@@ -949,7 +951,8 @@ case ${target} in
   case ${enable_threads} in
 "" | yes | posix) thread_file='posix' ;;
   esac
-  tm_defines="$tm_defines DEFAULT_LIBC=LIBC_UCLIBC SINGLE_LIBC"
+  tm_defines="$tm_defines SINGLE_LIBC"
+  default_libc=LIBC_UCLIBC
   ;;
 *-*-rdos*)
   use_gcc_stdint=wrap
@@ -1606,13 +1609,13 @@ csky-*-*)
 
case ${target} in
csky-*-linux-gnu*)
-   tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC"
+   default_libc=LIBC_GLIBC
# Force .init_array support.  The configure script 
cannot always
# automatically detect that GAS supports it, yet we 
require it.
gcc_cv_initfini_array=yes
;;
csky-*-linux-uclibc*)
-   tm_defines="$tm_defines DEFAULT_LIBC=LIBC_UCLIBC"
+   default_libc=LIBC_UCLIBC
default_use_cxa_atexit=no
;;
*)
@@ -3065,7 +3068,7 @@ powerpc*-wrs-vxworks7r*)
tmake_file="${tmake_file} t-linux rs6000/t-linux64 rs6000/t-fprules 
rs6000/t-ppccomm"
tmake_file="${tmake_file} rs6000/t-vxworks"
 
-   tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC"
+   default_libc=LIBC_GLIBC
extra_objs="$extra_objs linux.o rs6000-linux.o"
;;
 powerpc-wrs-vxworks*)
@@ -5861,3 +5864,26 @@ i[34567]86-*-* | x86_64-*-*)
fi
;;
 esac
+
+case "${with_default_libc}" in
+glibc)
+default_libc=LIBC_GLIBC
+;;
+uclibc)
+default_libc=LIBC_UCLIBC
+;;
+bionic)
+default_libc=LIBC_BIONIC
+;;
+musl)
+default_libc=LIBC_MUSL
+;;
+esac
+
+case "$default_libc" in
+"")
+;;
+*)
+   tm_defines="$tm_defines DEFAULT_LIBC=$default_libc"
+   ;;
+esac
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 819b490d1b6..0b76613b635 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2490,6 +2490,10 @@ if { { test x$host != x$target && test "x$with_sysroot" 
= x ; } ||
 fi
 AC_SUBST(inhibit_libc)
 
+AC_ARG_WITH(default-libc,
+   [AS_HELP_STRING([--with-default-libc],
+   [Use specified default C library])])
+
 # When building gcc with a cross-compiler, we need to adjust things so
 # that the generator programs are still built with the native compiler.
 # Also, we cannot run fixincludes.
-- 
2.36.1



[PATCH 3/3] picolibc: Add '--oslib=' option when default C library is picolibc

2022-08-24 Thread Keith Packard via Gcc
This option allows targets to insert an OS library after the C library
in the LIB_PATH spec file fragment. This library maps a few POSIX APIs
used by picolibc to underlying system capabilities.

For example, picolibc provides 'libsemihost' on various targets which
maps these APIs to semihosting capabilities. This would be used with
this option by specifying --oslib=semihost

This patch enables --oslib= on arm, nds32, riscv and sh.

Signed-off-by: Keith Packard 
---
 gcc/config.gcc|  6 ++
 gcc/config/arm/elf.h  |  5 +
 gcc/config/nds32/elf.h|  4 
 gcc/config/picolibc.opt   | 26 ++
 gcc/config/riscv/elf.h|  4 
 gcc/config/sh/embed-elf.h |  5 +
 6 files changed, 50 insertions(+)
 create mode 100644 gcc/config/picolibc.opt

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 0aa4bd6c3dd..80740d8f04e 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -5893,3 +5893,9 @@ case "$default_libc" in
tm_defines="$tm_defines DEFAULT_LIBC=$default_libc"
;;
 esac
+
+case "$default_libc" in
+LIBC_PICOLIBC)
+   extra_options="${extra_options} picolibc.opt"
+   ;;
+esac
diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h
index 3d111433ede..d83ee4a1a8c 100644
--- a/gcc/config/arm/elf.h
+++ b/gcc/config/arm/elf.h
@@ -150,3 +150,8 @@
 #undef L_floatundisf
 #endif
 
+#if defined(DEFAULT_LIBC) && defined(LIBC_PICOLIBC) && DEFAULT_LIBC == 
LIBC_PICOLIBC
+#undef  LIB_SPEC
+#define LIB_SPEC "--start-group %(libgcc)  -lc %{-oslib=*:-l%*} --end-group"
+#endif
+
diff --git a/gcc/config/nds32/elf.h b/gcc/config/nds32/elf.h
index ebdc18cee2a..a956d531ef4 100644
--- a/gcc/config/nds32/elf.h
+++ b/gcc/config/nds32/elf.h
@@ -34,8 +34,12 @@
   " %{shared:-shared}" \
   NDS32_RELAX_SPEC
 
+#if defined(DEFAULT_LIBC) && defined(LIBC_PICOLIBC) && DEFAULT_LIBC == 
LIBC_PICOLIBC
+#define LIB_SPEC "--start-group %(libgcc)  -lc %{-oslib=*:-l%*} --end-group"
+#else
 #define LIB_SPEC \
   " -lc -lgloss"
+#endif
 
 #define LIBGCC_SPEC \
   " -lgcc"
diff --git a/gcc/config/picolibc.opt b/gcc/config/picolibc.opt
new file mode 100644
index 000..194b3362b03
--- /dev/null
+++ b/gcc/config/picolibc.opt
@@ -0,0 +1,26 @@
+; Processor-independent options for picolibc.
+;
+; Copyright (C) 2022 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
+; .
+
+-oslib
+Driver Separate Alias(-oslib=)
+
+-oslib=
+Driver Joined
+Specify an OS support library to load after libc.
diff --git a/gcc/config/riscv/elf.h b/gcc/config/riscv/elf.h
index f0e865d6ef4..ca906afcd52 100644
--- a/gcc/config/riscv/elf.h
+++ b/gcc/config/riscv/elf.h
@@ -27,7 +27,11 @@ along with GCC; see the file COPYING3.  If not see
 /* Link against Newlib libraries, because the ELF backend assumes Newlib.
Handle the circular dependence between libc and libgloss. */
 #undef  LIB_SPEC
+#if defined(DEFAULT_LIBC) && defined(LIBC_PICOLIBC) && DEFAULT_LIBC == 
LIBC_PICOLIBC
+#define LIB_SPEC "--start-group %(libgcc)  -lc %{-oslib=*:-l%*} --end-group"
+#else
 #define LIB_SPEC "--start-group -lc %{!specs=nosys.specs:-lgloss} --end-group"
+#endif
 
 #undef  STARTFILE_SPEC
 #define STARTFILE_SPEC "crt0%O%s crtbegin%O%s"
diff --git a/gcc/config/sh/embed-elf.h b/gcc/config/sh/embed-elf.h
index 21e51dd0bb9..e8605849e07 100644
--- a/gcc/config/sh/embed-elf.h
+++ b/gcc/config/sh/embed-elf.h
@@ -34,3 +34,8 @@ along with GCC; see the file COPYING3.  If not see
   %{Os: -lgcc-Os-4-200} \
   -lgcc \
   %{!Os: -lgcc-Os-4-200}"
+
+#if defined(DEFAULT_LIBC) && defined(LIBC_PICOLIBC) && DEFAULT_LIBC == 
LIBC_PICOLIBC
+#undef  LIB_SPEC
+#define LIB_SPEC "--start-group %(libgcc)  -lc %{-oslib=*:-l%*} --end-group"
+#endif
-- 
2.36.1



[PATCH 0/3] picolibc: Add picolibc linking help

2022-08-24 Thread Keith Packard via Gcc
Picolibc is a C library for embedded systems based on code from newlib
and avr libc. To connect some system-dependent picolibc functions
(like stdio) to an underlying platform, the platform may provide an OS
library.

This OS library must follow the C library in the link command line. In
current picolibc, that is done by providing an alternate .specs file
which can rewrite the *lib spec to insert the OS library in the right
spot.

This patch series adds the ability to specify the OS library on the
gcc command line when GCC is configured to us picolibc as the default
C library, and then hooks that up for arm, nds32, riscv and sh targets.

Keith Packard (3):
  Allow default libc to be specified to configure
  Add newlib and picolibc as default C library choices
  Add '--oslib=' option when default C library is picolibc

 gcc/config.gcc| 56 ---
 gcc/config/arm/elf.h  |  5 
 gcc/config/nds32/elf.h|  4 +++
 gcc/config/picolibc.opt   | 26 ++
 gcc/config/riscv/elf.h|  4 +++
 gcc/config/sh/embed-elf.h |  5 
 gcc/configure.ac  |  4 +++
 7 files changed, 95 insertions(+), 9 deletions(-)
 create mode 100644 gcc/config/picolibc.opt

-- 
2.36.1



Re: [PATCH 0/3] picolibc: Add picolibc linking help

2022-09-02 Thread Keith Packard via Gcc
Richard Sandiford  writes:

Thanks much for reviewing this series. I really appreciate it.

>   should there be a default case that raises an error for unrecognised
>   libcs?  Command-line checking for configure isn't very tight, but we
>   do raise similar errors for things like invalid --enable-threads
>   values.

Good thinking. It's way to easy to introduce a typo somewhere and have
it get missed.

>   On balance I think it would be better to accept
>   --with-default-libc=newlib but set default_libc to the empty string.

That also makes good sense -- leave existing configurations unchanged.

> - Should we raise an error for toolchains that don't support the given
>   C library?  It feels like we should, but I realise that could be
>   difficult to do.

That would be nice, but it also feels like making it reliable enough to
be useful would be difficult to maintain in the future, even if we did
manage to make it mostly work today.

> - Very minor, but in lines like:
>
>   +#if defined(DEFAULT_LIBC) && defined(LIBC_PICOLIBC) && DEFAULT_LIBC == 
> LIBC_PICOLIBC
>
>   is LIBC_PICOLIB ever undefined?  It looks like config.gcc provides
>   an unconditional definition.  If it is always defined then:
>
>   #if DEFAULT_LIBC == LIBC_PICOLIB
>
>   would be clearer.

Agreed. Thanks again for taking a look; I'll send a new series with
these issues fixed shortly.

-- 
-keith


signature.asc
Description: PGP signature