Skip to content

Commit b92ce01

Browse files
authored
Normalize floating point environment on startup (#38420)
In #38419 we noticed that on AArch64 Darwin, processes start with the FZ and DN floating point flags set. To maintain consistency across platforms, reset these flags whenever we start julia. Not that default_nans isn't available on x86, so while we do have julia-level wrappers for the fz flag, I'm not adding any for the dn flag. The function is exported, so if somebody really needs it in some aarch64-specific code, they can ccall it.
1 parent c9a149b commit b92ce01

File tree

5 files changed

+60
-1
lines changed

5 files changed

+60
-1
lines changed

src/init.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#undef DEFINE_BUILTIN_GLOBALS
2929
#include "threading.h"
3030
#include "julia_assert.h"
31+
#include "processor.h"
3132

3233
#ifdef __cplusplus
3334
extern "C" {
@@ -618,6 +619,13 @@ static void jl_set_io_wait(int v)
618619

619620
extern jl_mutex_t jl_modules_mutex;
620621

622+
static void restore_fp_env(void)
623+
{
624+
if (jl_set_zero_subnormals(0) || jl_set_default_nans(0)) {
625+
jl_error("Failed to configure floating point environment");
626+
}
627+
}
628+
621629
void _julia_init(JL_IMAGE_SEARCH rel)
622630
{
623631
jl_init_timing();
@@ -634,6 +642,7 @@ void _julia_init(JL_IMAGE_SEARCH rel)
634642
// best to call this first, since it also initializes libuv
635643
jl_init_uv();
636644
init_stdio();
645+
restore_fp_env();
637646
restore_signals();
638647

639648
jl_page_size = jl_getpagesize();

src/processor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ JL_DLLEXPORT jl_value_t *jl_get_cpu_name(void);
166166
// For debugging only
167167
JL_DLLEXPORT void jl_dump_host_cpu(void);
168168

169+
JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero);
170+
JL_DLLEXPORT int32_t jl_get_zero_subnormals(void);
171+
JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault);
172+
JL_DLLEXPORT int32_t jl_get_default_nans(void);
169173
#ifdef __cplusplus
170174
}
171175

src/processor_arm.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1808,8 +1808,10 @@ extern "C" int jl_test_cpu_feature(jl_cpu_feature_t feature)
18081808
}
18091809

18101810
#ifdef _CPU_AARCH64_
1811-
// FZ, bit [24]
1811+
// FPCR FZ, bit [24]
18121812
static constexpr uint32_t fpcr_fz_mask = 1 << 24;
1813+
// FPCR DN, bit [25]
1814+
static constexpr uint32_t fpcr_dn_mask = 1 << 25;
18131815

18141816
static inline uint32_t get_fpcr_aarch64(void)
18151817
{
@@ -1835,6 +1837,19 @@ extern "C" JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero)
18351837
set_fpcr_aarch64(fpcr);
18361838
return 0;
18371839
}
1840+
1841+
extern "C" JL_DLLEXPORT int32_t jl_get_default_nans(void)
1842+
{
1843+
return (get_fpcr_aarch64() & fpcr_dn_mask) != 0;
1844+
}
1845+
1846+
extern "C" JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault)
1847+
{
1848+
uint32_t fpcr = get_fpcr_aarch64();
1849+
fpcr = isDefault ? (fpcr | fpcr_dn_mask) : (fpcr & ~fpcr_dn_mask);
1850+
set_fpcr_aarch64(fpcr);
1851+
return 0;
1852+
}
18381853
#else
18391854
extern "C" JL_DLLEXPORT int32_t jl_get_zero_subnormals(void)
18401855
{
@@ -1845,4 +1860,14 @@ extern "C" JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero)
18451860
{
18461861
return isZero;
18471862
}
1863+
1864+
extern "C" JL_DLLEXPORT int32_t jl_get_default_nans(void)
1865+
{
1866+
return 0;
1867+
}
1868+
1869+
extern "C" JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault)
1870+
{
1871+
return isDefault;
1872+
}
18481873
#endif

src/processor_fallback.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,13 @@ extern "C" JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero)
160160
{
161161
return isZero;
162162
}
163+
164+
extern "C" JL_DLLEXPORT int32_t jl_get_default_nans(void)
165+
{
166+
return 0;
167+
}
168+
169+
extern "C" JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault)
170+
{
171+
return isDefault;
172+
}

src/processor_x86.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,3 +1102,14 @@ extern "C" JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero)
11021102
return isZero;
11031103
}
11041104
}
1105+
1106+
// X86 does not support default NaNs
1107+
extern "C" JL_DLLEXPORT int32_t jl_get_default_nans(void)
1108+
{
1109+
return 0;
1110+
}
1111+
1112+
extern "C" JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault)
1113+
{
1114+
return isDefault;
1115+
}

0 commit comments

Comments
 (0)