Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ commands:
$PYTHON_BIN ./embuilder.py build ALL
$PYTHON_BIN tests/runner.py test_hello_world
- run:

name: embuilder (LTO)
command: |
$PYTHON_BIN ./embuilder.py build MINIMAL --lto
Expand Down
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ See docs/process.md for how version tagging works.

Current Trunk
-------------
- A new `PRINTF_LONG_DOUBLE` option allows printf to print long doubles at full
float128 precision. (#11130)
- `emscripten_async_queue_on_thread` has been renamed to
`emscripten_dispatch_to_thread` which no longer implies that it is async -
the operation is in fact only async if it is sent to another thread, while it
Expand Down
6 changes: 6 additions & 0 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1773,6 +1773,12 @@ var LLD_REPORT_UNDEFINED = 0;
// programs. This which matches the behaviour of gcc/g++ and clang/clang++.
var DEFAULT_TO_CXX = 1;

// While LLVM's wasm32 has long double = float128, we don't support printing
// that at full precision by default. Instead we print as 64-bit doubles, which
// saves libc code size. You can flip this option on to get a libc with full
// long double printing precision.
var PRINTF_LONG_DOUBLE = 0;

//===========================================
// Internal, used for testing only, from here
//===========================================
Expand Down
13 changes: 9 additions & 4 deletions system/lib/libc/musl/src/stdio/vfprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
#include <math.h>
#include <float.h>

#ifndef EMSCRIPTEN_PRINTF_LONG_DOUBLE
// XXX EMSCRIPTEN - while wasm32 has long double = float128, we don't support
// printing it at full precision; instead, we lower to
// printing at full precision by default. instead, we lower to
// 64-bit double. These macros makes our changes a little less
// invasive.
#define long_double double
typedef double long_double;
#undef LDBL_TRUE_MIN
#define LDBL_TRUE_MIN DBL_DENORM_MIN
#undef LDBL_MIN
Expand All @@ -36,6 +37,10 @@
#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
#undef frexpl
#define frexpl(x, exp) frexp(x, exp)
#else // EMSCRIPTEN_FULL_LONG_DOUBLE_PRINTING
// XXX EMSCRIPTEN - full long double printing support
typedef long double long_double;
#endif

/* Some useful macros */

Expand Down Expand Up @@ -244,9 +249,9 @@ typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long_double)
// get it linked in
// also use a double argument here, as mentioned before,
// we print float128s at double precision
typedef int (*fmt_fp_t)(FILE *f, double y, int w, int p, int fl, int t);
typedef int (*fmt_fp_t)(FILE *f, long_double y, int w, int p, int fl, int t);

static int fmt_fp(FILE *f, double y, int w, int p, int fl, int t)
static int fmt_fp(FILE *f, long_double y, int w, int p, int fl, int t)
{
uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
+ (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
Expand Down
29 changes: 29 additions & 0 deletions tests/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -10055,6 +10055,35 @@ def test(code):
self.assertGreater(lf, both - 100)
self.assertLess(lf, both - 50)

@parameterized({
'normal': ([], '''\
0.000051 => -5.123719529365189373493194580078e-05
0.000051 => -5.123719300544352718866300544498e-05
0.000051 => -5.123719300544352718866300544498e-05
'''),
'full_long_double': (['-s', 'PRINTF_LONG_DOUBLE'], '''\
0.000051 => -5.123719529365189373493194580078e-05
0.000051 => -5.123719300544352718866300544498e-05
0.000051 => -5.123719300544352710023893104250e-05
'''),
})
@no_fastcomp('float128 is wasm backend only')
def test_long_double_printing(self, args, expected):
create_test_file('src.cpp', r'''
#include <stdio.h>

int main(void) {
float f = 5.123456789e-5;
double d = 5.123456789e-5;
long double ld = 5.123456789e-5;
printf("%f => %.30e\n", f, f / (f - 1));
printf("%f => %.30e\n", d, d / (d - 1));
printf("%Lf => %.30Le\n", ld, ld / (ld - 1));
}
''')
run_process([PYTHON, EMCC, 'src.cpp'] + args)
self.assertContained(expected, run_js('a.out.js'))

# Tests that passing -s MALLOC=none will not include system malloc() to the build.
def test_malloc_none(self):
stderr = self.expect_fail([PYTHON, EMCC, path_from_root('tests', 'malloc_none.c'), '-s', 'MALLOC=none'])
Expand Down
28 changes: 23 additions & 5 deletions tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,20 @@ def get_files(self):
return libc_files


class libprintf_long_double(libc):
name = 'libprintf_long_double'

cflags = ['-DEMSCRIPTEN_PRINTF_LONG_DOUBLE']

def get_files(self):
return files_in_path(
path_components=['system', 'lib', 'libc', 'musl', 'src', 'stdio'],
filenames=['vfprintf.c'])

def can_build(self):
return super(libprintf_long_double, self).can_build() and shared.Settings.WASM_BACKEND


class libsockets(MuslInternalLibrary, MTLibrary):
name = 'libsockets'

Expand Down Expand Up @@ -1571,6 +1585,15 @@ def add_library(lib):

sanitize = shared.Settings.USE_LSAN or shared.Settings.USE_ASAN or shared.Settings.UBSAN_RUNTIME

# JS math must come before anything else, so that it overrides the normal
# libc math.
if shared.Settings.JS_MATH:
add_library(system_libs_map['libjsmath'])

# to override the normal libc printf, we must come before it
if shared.Settings.PRINTF_LONG_DOUBLE:
add_library(system_libs_map['libprintf_long_double'])

add_library(system_libs_map['libc'])
add_library(system_libs_map['libcompiler_rt'])
if not shared.Settings.WASM_BACKEND and not shared.Settings.MINIMAL_RUNTIME:
Expand Down Expand Up @@ -1633,11 +1656,6 @@ def add_library(lib):
# header methods. To avoid that, we link libc++abi last.
libs_to_link.sort(key=lambda x: x[0].endswith('libc++abi.bc'))

# JS math must come before anything else, so that it overrides the normal
# libc math.
if shared.Settings.JS_MATH:
libs_to_link = [(system_libs_map['libjsmath'].get_path(), True)] + libs_to_link

# When LINKABLE is set the entire link command line is wrapped in --whole-archive by
# Building.link_ldd. And since --whole-archive/--no-whole-archive processing does not nest we
# shouldn't add any extra `--no-whole-archive` or we will undo the intent of Building.link_ldd.
Expand Down