Skip to content

Commit

Permalink
workaround x87 issues
Browse files Browse the repository at this point in the history
  • Loading branch information
yamt committed Jun 5, 2023
1 parent b8a08e4 commit a536438
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
6 changes: 6 additions & 0 deletions cmake/ToywasmConfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ endif()
endif()
endif()

if(TRIPLET MATCHES "i386")
# x87 doesn't preserve sNaN as IEEE 754 and wasm expect.
# unfortunately, clang doesn't have -mno-fp-ret-in-387.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2 -mfpmath=sse")
endif()

if(CMAKE_C_COMPILER_TARGET MATCHES "wasm")
if(TOYWASM_USE_TAILCALL)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mtail-call")
Expand Down
2 changes: 2 additions & 0 deletions lib/endian.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ lef64_encode(void *p, double v)
le64_encode(p, u.i);
}

#if !defined(__i386__)
float
lef32_decode(const void *p)
{
Expand All @@ -200,3 +201,4 @@ lef64_decode(const void *p)
u.i = le64_decode(p);
return u.f;
}
#endif
41 changes: 41 additions & 0 deletions lib/endian.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#if !defined(_ENDIAN_H)
#define _ENDIAN_H
#include <stdint.h>

uint8_t le8_to_host(uint8_t v);
Expand All @@ -23,5 +25,44 @@ uint64_t le64_decode(const void *p);
void lef32_encode(void *p, float v);
void lef64_encode(void *p, double v);

/*
* x87 fld/fstp does not preserve sNaN. it breaks wasm semantics.
*
* while in later processors we can use XMM registers (eg. -msse2) which
* don't have the problem, x87 ST0 register is still used to return
* float/double function results as it's specified by the i386 ABI.
*
* while GCC has -mno-fp-ret-in-387 to alter the abi, Clang unfortunately
* doesn't seem to have an equivalent.
*/
#if defined(__i386__)
__attribute__((always_inline, used)) static float
lef32_decode(const void *p)
{
union {
uint32_t i;
float f;
} u;
u.i = le32_decode(p);
return u.f;
}
#else
float lef32_decode(const void *p);
#endif

#if defined(__i386__)
__attribute__((always_inline, used)) static double
lef64_decode(const void *p)
{
union {
uint64_t i;
double f;
} u;
u.i = le64_decode(p);
return u.f;
}
#else
double lef64_decode(const void *p);
#endif

#endif /* !defined(_ENDIAN_H) */

0 comments on commit a536438

Please sign in to comment.