diff --git a/GNUmakefile b/GNUmakefile index 627640a520..4083ff3270 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -471,12 +471,9 @@ TEST_PACKAGES_NONWASM = \ # # * No filesystem is available, so packages like compress/zlib can't be tested # (just like wasm). -# * picolibc math functions apparently are less precise, the math package -# fails on baremetal. TEST_PACKAGES_BAREMETAL = $(filter-out $(TEST_PACKAGES_NONBAREMETAL), $(TEST_PACKAGES_FAST)) TEST_PACKAGES_NONBAREMETAL = \ $(TEST_PACKAGES_NONWASM) \ - math \ $(nil) TEST_PACKAGES_FAST_WASI = $(filter-out $(TEST_PACKAGES_NOWASI), $(TEST_PACKAGES_FAST)) @@ -1109,8 +1106,8 @@ build/release: tinygo gen-device $(if $(filter 1,$(USE_SYSTEM_BINARYEN)),,binary @mkdir -p build/release/tinygo/lib/musl/crt @mkdir -p build/release/tinygo/lib/musl/src @mkdir -p build/release/tinygo/lib/nrfx - @mkdir -p build/release/tinygo/lib/picolibc/newlib/libc - @mkdir -p build/release/tinygo/lib/picolibc/newlib/libm + @mkdir -p build/release/tinygo/lib/picolibc/libc + @mkdir -p build/release/tinygo/lib/picolibc/libm @mkdir -p build/release/tinygo/lib/wasi-libc/dlmalloc @mkdir -p build/release/tinygo/lib/wasi-libc/libc-bottom-half @mkdir -p build/release/tinygo/lib/wasi-libc/libc-top-half/musl/arch @@ -1175,13 +1172,14 @@ endif @cp -rp lib/mingw-w64/mingw-w64-headers/defaults/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults @cp -rp lib/mingw-w64/mingw-w64-headers/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers @cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx - @cp -rp lib/picolibc/newlib/libc/ctype build/release/tinygo/lib/picolibc/newlib/libc - @cp -rp lib/picolibc/newlib/libc/include build/release/tinygo/lib/picolibc/newlib/libc - @cp -rp lib/picolibc/newlib/libc/locale build/release/tinygo/lib/picolibc/newlib/libc - @cp -rp lib/picolibc/newlib/libc/string build/release/tinygo/lib/picolibc/newlib/libc - @cp -rp lib/picolibc/newlib/libc/tinystdio build/release/tinygo/lib/picolibc/newlib/libc - @cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm - @cp -rp lib/picolibc/newlib/libm/math build/release/tinygo/lib/picolibc/newlib/libm + @cp -rp lib/picolibc/libc/ctype build/release/tinygo/lib/picolibc/libc + @cp -rp lib/picolibc/libc/include build/release/tinygo/lib/picolibc/libc + @cp -rp lib/picolibc/libc/locale build/release/tinygo/lib/picolibc/libc + @cp -rp lib/picolibc/libc/stdlib build/release/tinygo/lib/picolibc/libc + @cp -rp lib/picolibc/libc/string build/release/tinygo/lib/picolibc/libc + @cp -rp lib/picolibc/libc/stdio build/release/tinygo/lib/picolibc/libc + @cp -rp lib/picolibc/libm/common build/release/tinygo/lib/picolibc/libm + @cp -rp lib/picolibc/libm/math build/release/tinygo/lib/picolibc/libm @cp -rp lib/picolibc-stdio.c build/release/tinygo/lib @cp -rp lib/wasi-libc/dlmalloc/src build/release/tinygo/lib/wasi-libc/dlmalloc @cp -rp lib/wasi-libc/libc-bottom-half/cloudlibc build/release/tinygo/lib/wasi-libc/libc-bottom-half diff --git a/builder/picolibc.go b/builder/picolibc.go index 43837fa1dc..f6712a5cd5 100644 --- a/builder/picolibc.go +++ b/builder/picolibc.go @@ -3,7 +3,6 @@ package builder import ( "os" "path/filepath" - "strings" "github.com/tinygo-org/tinygo/goenv" ) @@ -20,46 +19,35 @@ var libPicolibc = Library{ return f.Close() }, cflags: func(target, headerPath string) []string { - newlibDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") + picolibcDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc") return []string{ "-Werror", "-Wall", "-std=gnu11", - "-D_COMPILING_NEWLIB", - "-D_HAVE_ALIAS_ATTRIBUTE", - "-DTINY_STDIO", - "-DPOSIX_IO", - "-DFORMAT_DEFAULT_INTEGER", // use __i_vfprintf and __i_vfscanf by default - "-D_IEEE_LIBM", + "-D__TINY_STDIO", + "-D_XOPEN_SOURCE=700", + "-D__IO_DEFAULT='i'", // use __i_vfprintf and __i_vfscanf by default + "-D__IEEE_LIBM", "-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU "-D__OBSOLETE_MATH_DOUBLE=0", - "-D_WANT_IO_C99_FORMATS", + "-D__IO_C99_FORMATS", "-D__PICOLIBC_ERRNO_FUNCTION=__errno_location", "-nostdlibinc", - "-isystem", newlibDir + "/libc/include", - "-I" + newlibDir + "/libc/tinystdio", - "-I" + newlibDir + "/libm/common", + "-isystem", picolibcDir + "/libc/include", + "-I" + picolibcDir + "/libc/stdio", + "-I" + picolibcDir + "/libc/locale", + "-I" + picolibcDir + "/libm/common", "-I" + headerPath, } }, - sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") }, + sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc") }, librarySources: func(target string, _ bool) ([]string, error) { - sources := append([]string(nil), picolibcSources...) - if !strings.HasPrefix(target, "avr") { - // Small chips without long jumps can't compile many files (printf, - // pow, etc). Therefore exclude those source files for those chips. - // Unfortunately it's difficult to exclude only some chips, so this - // excludes those files on all AVR chips for now. - // More information: - // https://github.com/llvm/llvm-project/issues/67042 - sources = append(sources, picolibcSourcesLarge...) - } - return sources, nil + return append([]string(nil), picolibcSources...), nil }, } var picolibcSources = []string{ - "../../picolibc-stdio.c", + "../picolibc-stdio.c", "libc/string/bcmp.c", "libc/string/bcopy.c", @@ -126,7 +114,6 @@ var picolibcSources = []string{ "libc/string/swab.c", "libc/string/timingsafe_bcmp.c", "libc/string/timingsafe_memcmp.c", - "libc/string/u_strerr.c", "libc/string/wcpcpy.c", "libc/string/wcpncpy.c", "libc/string/wcscasecmp.c", @@ -164,87 +151,82 @@ var picolibcSources = []string{ "libc/string/wmempcpy.c", "libc/string/wmemset.c", "libc/string/xpg_strerror_r.c", -} -// Parts of picolibc that are too large for small AVRs. -var picolibcSourcesLarge = []string{ - // srcs_tinystdio - "libc/tinystdio/asprintf.c", - "libc/tinystdio/bufio.c", - "libc/tinystdio/clearerr.c", - "libc/tinystdio/ecvt_r.c", - "libc/tinystdio/ecvt.c", - "libc/tinystdio/ecvtf_r.c", - "libc/tinystdio/ecvtf.c", - "libc/tinystdio/fcvt.c", - "libc/tinystdio/fcvt_r.c", - "libc/tinystdio/fcvtf.c", - "libc/tinystdio/fcvtf_r.c", - "libc/tinystdio/gcvt.c", - "libc/tinystdio/gcvtf.c", - "libc/tinystdio/fclose.c", - "libc/tinystdio/fdevopen.c", - "libc/tinystdio/feof.c", - "libc/tinystdio/ferror.c", - "libc/tinystdio/fflush.c", - "libc/tinystdio/fgetc.c", - "libc/tinystdio/fgets.c", - "libc/tinystdio/fileno.c", - "libc/tinystdio/filestrget.c", - "libc/tinystdio/filestrput.c", - "libc/tinystdio/filestrputalloc.c", - "libc/tinystdio/fmemopen.c", - "libc/tinystdio/fprintf.c", - "libc/tinystdio/fputc.c", - "libc/tinystdio/fputs.c", - "libc/tinystdio/fread.c", - //"libc/tinystdio/freopen.c", // crashes with AVR, see: https://github.com/picolibc/picolibc/pull/369 - "libc/tinystdio/fscanf.c", - "libc/tinystdio/fseek.c", - "libc/tinystdio/fseeko.c", - "libc/tinystdio/ftell.c", - "libc/tinystdio/ftello.c", - "libc/tinystdio/fwrite.c", - "libc/tinystdio/getchar.c", - "libc/tinystdio/gets.c", - "libc/tinystdio/matchcaseprefix.c", - "libc/tinystdio/mktemp.c", - "libc/tinystdio/perror.c", - "libc/tinystdio/printf.c", - "libc/tinystdio/putchar.c", - "libc/tinystdio/puts.c", - "libc/tinystdio/rewind.c", - "libc/tinystdio/scanf.c", - "libc/tinystdio/setbuf.c", - "libc/tinystdio/setbuffer.c", - "libc/tinystdio/setlinebuf.c", - "libc/tinystdio/setvbuf.c", - "libc/tinystdio/snprintf.c", - "libc/tinystdio/sprintf.c", - "libc/tinystdio/snprintfd.c", - "libc/tinystdio/snprintff.c", - "libc/tinystdio/sprintff.c", - "libc/tinystdio/sprintfd.c", - "libc/tinystdio/sscanf.c", - "libc/tinystdio/strfromf.c", - "libc/tinystdio/strfromd.c", - "libc/tinystdio/strtof.c", - "libc/tinystdio/strtof_l.c", - "libc/tinystdio/strtod.c", - "libc/tinystdio/strtod_l.c", - "libc/tinystdio/ungetc.c", - "libc/tinystdio/vasprintf.c", - "libc/tinystdio/vfiprintf.c", - "libc/tinystdio/vfprintf.c", - "libc/tinystdio/vfprintff.c", - "libc/tinystdio/vfscanf.c", - "libc/tinystdio/vfiscanf.c", - "libc/tinystdio/vfscanff.c", - "libc/tinystdio/vprintf.c", - "libc/tinystdio/vscanf.c", - "libc/tinystdio/vsscanf.c", - "libc/tinystdio/vsnprintf.c", - "libc/tinystdio/vsprintf.c", + // srcs_stdio + "libc/stdio/asprintf.c", + "libc/stdio/bufio.c", + "libc/stdio/clearerr.c", + "libc/stdio/ecvt_r.c", + "libc/stdio/ecvt.c", + "libc/stdio/ecvtf_r.c", + "libc/stdio/ecvtf.c", + "libc/stdio/fcvt.c", + "libc/stdio/fcvt_r.c", + "libc/stdio/fcvtf.c", + "libc/stdio/fcvtf_r.c", + "libc/stdio/gcvt.c", + "libc/stdio/gcvtf.c", + "libc/stdio/fclose.c", + "libc/stdio/fdevopen.c", + "libc/stdio/feof.c", + "libc/stdio/ferror.c", + "libc/stdio/fflush.c", + "libc/stdio/fgetc.c", + "libc/stdio/fgets.c", + "libc/stdio/fileno.c", + "libc/stdio/filestrget.c", + "libc/stdio/filestrput.c", + "libc/stdio/filestrputalloc.c", + "libc/stdio/fmemopen.c", + "libc/stdio/fprintf.c", + "libc/stdio/fputc.c", + "libc/stdio/fputs.c", + "libc/stdio/fread.c", + "libc/stdio/freopen.c", + "libc/stdio/fscanf.c", + "libc/stdio/fseek.c", + "libc/stdio/fseeko.c", + "libc/stdio/ftell.c", + "libc/stdio/ftello.c", + "libc/stdio/fwrite.c", + "libc/stdio/getchar.c", + "libc/stdio/gets.c", + "libc/stdio/matchcaseprefix.c", + "libc/stdio/mktemp.c", + "libc/stdio/perror.c", + "libc/stdio/printf.c", + "libc/stdio/putchar.c", + "libc/stdio/puts.c", + "libc/stdio/rewind.c", + "libc/stdio/scanf.c", + "libc/stdio/setbuf.c", + "libc/stdio/setbuffer.c", + "libc/stdio/setlinebuf.c", + "libc/stdio/setvbuf.c", + "libc/stdio/snprintf.c", + "libc/stdio/sprintf.c", + "libc/stdio/snprintfd.c", + "libc/stdio/snprintff.c", + "libc/stdio/sprintff.c", + "libc/stdio/sprintfd.c", + "libc/stdio/sscanf.c", + "libc/stdio/strfromf.c", + "libc/stdio/strfromd.c", + "libc/stdio/strtof.c", + "libc/stdio/strtof_l.c", + "libc/stdio/strtod.c", + "libc/stdio/strtod_l.c", + "libc/stdio/ungetc.c", + "libc/stdio/vasprintf.c", + "libc/stdio/vfiprintf.c", + "libc/stdio/vfprintf.c", + "libc/stdio/vfscanf.c", + "libc/stdio/vfiscanf.c", + "libc/stdio/vprintf.c", + "libc/stdio/vscanf.c", + "libc/stdio/vsscanf.c", + "libc/stdio/vsnprintf.c", + "libc/stdio/vsprintf.c", "libm/common/sf_finite.c", "libm/common/sf_copysign.c", @@ -256,9 +238,7 @@ var picolibcSourcesLarge = []string{ "libm/common/sf_ilogb.c", "libm/common/sf_infinity.c", "libm/common/sf_isinf.c", - "libm/common/sf_isinff.c", "libm/common/sf_isnan.c", - "libm/common/sf_isnanf.c", "libm/common/sf_issignaling.c", "libm/common/sf_log1p.c", "libm/common/sf_nan.c", @@ -301,9 +281,7 @@ var picolibcSourcesLarge = []string{ "libm/common/s_infinity.c", "libm/common/s_iseqsig.c", "libm/common/s_isinf.c", - "libm/common/s_isinfd.c", "libm/common/s_isnan.c", - "libm/common/s_isnand.c", "libm/common/s_issignaling.c", "libm/common/s_log1p.c", "libm/common/s_nan.c", @@ -359,7 +337,6 @@ var picolibcSourcesLarge = []string{ "libm/math/k_sin.c", "libm/math/k_tan.c", "libm/math/kf_cos.c", - "libm/math/kf_rem_pio2.c", "libm/math/kf_sin.c", "libm/math/kf_tan.c", "libm/math/s_acos.c", diff --git a/compileopts/config.go b/compileopts/config.go index 7786cd2178..8793a78f64 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -383,13 +383,13 @@ func (c *Config) LibcCFlags() []string { } case "picolibc": root := goenv.Get("TINYGOROOT") - picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc") + picolibcDir := filepath.Join(root, "lib", "picolibc", "libc") path := c.LibraryPath("picolibc") return []string{ "-nostdlibinc", "-isystem", filepath.Join(path, "include"), "-isystem", filepath.Join(picolibcDir, "include"), - "-isystem", filepath.Join(picolibcDir, "tinystdio"), + "-isystem", filepath.Join(picolibcDir, "stdio"), "-D__PICOLIBC_ERRNO_FUNCTION=__errno_location", } case "musl": diff --git a/compiler/intrinsics.go b/compiler/intrinsics.go index 9df0bda3bc..a31359a33b 100644 --- a/compiler/intrinsics.go +++ b/compiler/intrinsics.go @@ -201,6 +201,17 @@ func (b *builder) defineMathOp() bool { if !ok { return false } + if strings.HasPrefix(b.Triple, "avr") { + // LLVM assumes the traditional AVR ABI where double is 32 bits and + // therefore does not provide f64 runtime libcalls for sin and cos. + // TinyGo uses 64-bit doubles on AVR, which picolibc supports directly. + switch b.fn.Name() { + case "Cos": + llvmName = "cos" + case "Sin": + llvmName = "sin" + } + } if strings.HasSuffix(b.Triple, "-wasi") || llvmutil.Version() < 19 { // We don't have a real libc for wasip2. Until that is fixed, we need to // limit math intrinsics on WASI to a subset supported natively in diff --git a/lib/picolibc b/lib/picolibc index b92edfda8a..003f3e6806 160000 --- a/lib/picolibc +++ b/lib/picolibc @@ -1 +1 @@ -Subproject commit b92edfda8ac6853772d87cadaeeeaa21b78609b6 +Subproject commit 003f3e68067ba71814c0faf0936fa0c93fadd561 diff --git a/main_test.go b/main_test.go index 2dfd1683f6..0766420e36 100644 --- a/main_test.go +++ b/main_test.go @@ -333,10 +333,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) { // Too big for AVR. Doesn't fit in flash/RAM. continue - case "math.go": - // Needs newer picolibc version (for sqrt). - continue - case "cgo/": // CGo function pointers don't work on AVR (needs LLVM 16 and // some compiler changes). @@ -379,7 +375,12 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) { name := name // redefine to avoid race condition t.Run(name, func(t *testing.T) { t.Parallel() - runTest(name, options, t, nil, nil) + testOptions := options + if testOptions.Target == "simavr" && name == "math.go" { + // This test exceeds simavr's default 384-byte goroutine stack. + testOptions.StackSize = 512 + } + runTest(name, testOptions, t, nil, nil) }) } if !strings.HasPrefix(spec.Emulator, "simavr ") {