diff options
Diffstat (limited to 'erts/emulator')
-rw-r--r-- | erts/emulator/beam/beam_emu.c | 29 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.c | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.h | 2 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_amd64_bifs.m4 | 2 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_amd64_primops.h | 2 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_bif0.c | 20 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_bif0.tab | 2 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_bif_list.m4 | 4 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_mkliterals.c | 16 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_native_bif.c | 2 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_native_bif.h | 5 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_primops.h | 4 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_process.h | 3 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_x86.h | 2 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_x86_bifs.m4 | 2 | ||||
-rw-r--r-- | erts/emulator/hipe/hipe_x86_primops.h | 3 | ||||
-rw-r--r-- | erts/emulator/test/float_SUITE.erl | 27 |
17 files changed, 110 insertions, 19 deletions
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 9c5450bd48..028a532b4c 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -4747,7 +4747,12 @@ void process_main(void) OpCase(fclearerror): OpCase(i_fcheckerror): erl_exit(1, "fclearerror/i_fcheckerror without fpe signals (beam_emu)"); +# define ERTS_NO_FPE_CHECK_INIT ERTS_FP_CHECK_INIT +# define ERTS_NO_FPE_ERROR ERTS_FP_ERROR #else +# define ERTS_NO_FPE_CHECK_INIT(p) +# define ERTS_NO_FPE_ERROR(p, a, b) + OpCase(fclearerror): { BeamInstr *next; @@ -4763,10 +4768,6 @@ void process_main(void) ERTS_FP_ERROR(c_p, freg[0].fd, goto fbadarith); NextPF(0, next); } -# undef ERTS_FP_CHECK_INIT -# undef ERTS_FP_ERROR -# define ERTS_FP_CHECK_INIT(p) -# define ERTS_FP_ERROR(p, a, b) #endif @@ -4774,45 +4775,45 @@ void process_main(void) BeamInstr *next; PreFetch(3, next); - ERTS_FP_CHECK_INIT(c_p); + ERTS_NO_FPE_CHECK_INIT(c_p); fb(Arg(2)) = fb(Arg(0)) + fb(Arg(1)); - ERTS_FP_ERROR(c_p, fb(Arg(2)), goto fbadarith); + ERTS_NO_FPE_ERROR(c_p, fb(Arg(2)), goto fbadarith); NextPF(3, next); } OpCase(i_fsub_lll): { BeamInstr *next; PreFetch(3, next); - ERTS_FP_CHECK_INIT(c_p); + ERTS_NO_FPE_CHECK_INIT(c_p); fb(Arg(2)) = fb(Arg(0)) - fb(Arg(1)); - ERTS_FP_ERROR(c_p, fb(Arg(2)), goto fbadarith); + ERTS_NO_FPE_ERROR(c_p, fb(Arg(2)), goto fbadarith); NextPF(3, next); } OpCase(i_fmul_lll): { BeamInstr *next; PreFetch(3, next); - ERTS_FP_CHECK_INIT(c_p); + ERTS_NO_FPE_CHECK_INIT(c_p); fb(Arg(2)) = fb(Arg(0)) * fb(Arg(1)); - ERTS_FP_ERROR(c_p, fb(Arg(2)), goto fbadarith); + ERTS_NO_FPE_ERROR(c_p, fb(Arg(2)), goto fbadarith); NextPF(3, next); } OpCase(i_fdiv_lll): { BeamInstr *next; PreFetch(3, next); - ERTS_FP_CHECK_INIT(c_p); + ERTS_NO_FPE_CHECK_INIT(c_p); fb(Arg(2)) = fb(Arg(0)) / fb(Arg(1)); - ERTS_FP_ERROR(c_p, fb(Arg(2)), goto fbadarith); + ERTS_NO_FPE_ERROR(c_p, fb(Arg(2)), goto fbadarith); NextPF(3, next); } OpCase(i_fnegate_ll): { BeamInstr *next; PreFetch(2, next); - ERTS_FP_CHECK_INIT(c_p); + ERTS_NO_FPE_CHECK_INIT(c_p); fb(Arg(1)) = -fb(Arg(0)); - ERTS_FP_ERROR(c_p, fb(Arg(1)), goto fbadarith); + ERTS_NO_FPE_ERROR(c_p, fb(Arg(1)), goto fbadarith); NextPF(2, next); fbadarith: diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index a1f5069b2d..84c0ded016 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -7140,7 +7140,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->pending_exit.bp = NULL; #endif -#if !defined(NO_FPE_SIGNALS) +#if !defined(NO_FPE_SIGNALS) || defined(HIPE) p->fp_exception = 0; #endif @@ -7314,7 +7314,7 @@ void erts_init_empty_process(Process *p) p->run_queue = ERTS_RUNQ_IX(0); #endif -#if !defined(NO_FPE_SIGNALS) +#if !defined(NO_FPE_SIGNALS) || defined(HIPE) p->fp_exception = 0; #endif diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index f0c86a0851..69ff423133 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -618,7 +618,7 @@ struct process { Uint min_heap_size; /* Minimum size of heap (in words). */ Uint min_vheap_size; /* Minimum size of virtual heap (in words). */ -#if !defined(NO_FPE_SIGNALS) +#if !defined(NO_FPE_SIGNALS) || defined(HIPE) volatile unsigned long fp_exception; #endif diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4 index 97a8267647..ec25c0b9b7 100644 --- a/erts/emulator/hipe/hipe_amd64_bifs.m4 +++ b/erts/emulator/hipe/hipe_amd64_bifs.m4 @@ -549,7 +549,9 @@ ASYM($1): /* * AMD64-specific primops. */ +#ifndef NO_FPE_SIGNALS noproc_primop_interface_0(nbif_handle_fp_exception, erts_restore_fpu) +#endif /* NO_FPE_SIGNALS */ /* * Implement gc_bif_interface_0 as nofail_primop_interface_0. diff --git a/erts/emulator/hipe/hipe_amd64_primops.h b/erts/emulator/hipe/hipe_amd64_primops.h index e3c7111997..55cb0eadb8 100644 --- a/erts/emulator/hipe/hipe_amd64_primops.h +++ b/erts/emulator/hipe/hipe_amd64_primops.h @@ -19,5 +19,7 @@ PRIMOP_LIST(am_inc_stack_0, &nbif_inc_stack_0) +#ifndef NO_FPE_SIGNALS PRIMOP_LIST(am_handle_fp_exception, &nbif_handle_fp_exception) +#endif PRIMOP_LIST(am_sse2_fnegate_mask, &sse2_fnegate_mask) diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index e7fb850530..cec22b3836 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -985,6 +985,26 @@ BIF_RETTYPE hipe_conv_big_to_float(BIF_ALIST_1) BIF_RET(res); } +#ifdef NO_FPE_SIGNALS + +/* + This is the current solution to make hipe run without FPE. + The native code is the same except that a call to this primop + is made after _every_ float operation to check the result. + The native fcheckerror still done later will detect if an + "emulated" FPE has occured. + We use p->hipe.float_result to avoid passing a 'double' argument, + which has its own calling convention (on amd64 at least). + Simple and slow... +*/ +void hipe_emulate_fpe(Process* p) +{ + if (!finite(p->hipe.float_result)) { + p->fp_exception = 1; + } +} +#endif + #if 0 /* XXX: unused */ /* * At least parts of this should be inlined in native code. diff --git a/erts/emulator/hipe/hipe_bif0.tab b/erts/emulator/hipe/hipe_bif0.tab index b6c6bede23..ce641365e9 100644 --- a/erts/emulator/hipe/hipe_bif0.tab +++ b/erts/emulator/hipe/hipe_bif0.tab @@ -140,3 +140,5 @@ atom bs_put_utf16le atom bs_get_utf16 atom bs_validate_unicode atom bs_validate_unicode_retract +atom emulate_fpe + diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4 index 48c7c1bc9b..942fa0c5cb 100644 --- a/erts/emulator/hipe/hipe_bif_list.m4 +++ b/erts/emulator/hipe/hipe_bif_list.m4 @@ -245,6 +245,10 @@ noproc_primop_interface_5(nbif_bs_put_big_integer, hipe_bs_put_big_integer) gc_bif_interface_0(nbif_check_get_msg, hipe_check_get_msg) +#ifdef NO_FPE_SIGNALS +nocons_nofail_primop_interface_0(nbif_emulate_fpe, hipe_emulate_fpe) +#endif + /* * SMP-specific stuff */ diff --git a/erts/emulator/hipe/hipe_mkliterals.c b/erts/emulator/hipe/hipe_mkliterals.c index 61e15f1d58..d07d14028c 100644 --- a/erts/emulator/hipe/hipe_mkliterals.c +++ b/erts/emulator/hipe/hipe_mkliterals.c @@ -293,6 +293,11 @@ static const struct literal { { "P_NRA", offsetof(struct process, hipe.nra) }, #endif { "P_NARITY", offsetof(struct process, hipe.narity) }, + { "P_FLOAT_RESULT", +# ifdef NO_FPE_SIGNALS + offsetof(struct process, hipe.float_result) +# endif + }, # if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP) { "P_BIF_CALLEE", offsetof(struct process, hipe.bif_callee) }, # endif @@ -491,7 +496,7 @@ static const struct rts_param { #endif }, { 14, "P_FP_EXCEPTION", -#if !defined(NO_FPE_SIGNALS) +#if !defined(NO_FPE_SIGNALS) || defined(HIPE) 1, offsetof(struct process, fp_exception) #endif }, @@ -504,6 +509,15 @@ static const struct rts_param { 0 #endif }, + /* This flag is always defined, but its value is configuration-dependent. */ + { 16, "ERTS_NO_FPE_SIGNALS", + 1, +#if defined(NO_FPE_SIGNALS) + 1 +#else + 0 +#endif + }, /* This parameter is always defined, but its value depends on ERTS_SMP. */ { 19, "MSG_MESSAGE", 1, offsetof(struct erl_mesg, m[0]) diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c index 77dee6f9e9..3be821f8f7 100644 --- a/erts/emulator/hipe/hipe_native_bif.c +++ b/erts/emulator/hipe/hipe_native_bif.c @@ -189,6 +189,8 @@ void hipe_fclearerror_error(Process *p) { #if !defined(NO_FPE_SIGNALS) erts_fp_check_init_error(&p->fp_exception); +#else + erl_exit(ERTS_ABORT_EXIT, "Emulated FPE not cleared by HiPE"); #endif } diff --git a/erts/emulator/hipe/hipe_native_bif.h b/erts/emulator/hipe/hipe_native_bif.h index 8c9dec180e..9e3a156fbc 100644 --- a/erts/emulator/hipe/hipe_native_bif.h +++ b/erts/emulator/hipe/hipe_native_bif.h @@ -93,6 +93,11 @@ BIF_RETTYPE hipe_bs_validate_unicode(BIF_ALIST_1); struct erl_bin_match_buffer; int hipe_bs_validate_unicode_retract(struct erl_bin_match_buffer*, Eterm); +#ifdef NO_FPE_SIGNALS +AEXTERN(void,nbif_emulate_fpe,(Process*)); +void hipe_emulate_fpe(Process*); +#endif + /* * Stuff that is different in SMP and non-SMP. */ diff --git a/erts/emulator/hipe/hipe_primops.h b/erts/emulator/hipe/hipe_primops.h index 94113ffcd8..38509c105b 100644 --- a/erts/emulator/hipe/hipe_primops.h +++ b/erts/emulator/hipe/hipe_primops.h @@ -77,6 +77,10 @@ PRIMOP_LIST(am_nonclosure_address, &nbif_nonclosure_address) PRIMOP_LIST(am_conv_big_to_float, &nbif_conv_big_to_float) PRIMOP_LIST(am_fclearerror_error, &nbif_fclearerror_error) +#ifdef NO_FPE_SIGNALS +PRIMOP_LIST(am_emulate_fpe, &nbif_emulate_fpe) +#endif + #if defined(__sparc__) #include "hipe_sparc_primops.h" #endif diff --git a/erts/emulator/hipe/hipe_process.h b/erts/emulator/hipe/hipe_process.h index 43f47d1a28..4ee99d78a2 100644 --- a/erts/emulator/hipe/hipe_process.h +++ b/erts/emulator/hipe/hipe_process.h @@ -42,6 +42,9 @@ struct hipe_process_state { void (*nra)(void); /* Native code return address. */ #endif unsigned int narity; /* Arity of BIF call, for stack walks. */ +#ifdef NO_FPE_SIGNALS + double float_result; /* to be checked for inf/NaN by hipe_emulate_fpe */ +#endif #if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP) void (*bif_callee)(void); /* When calling BIF's via debug wrapper */ #endif diff --git a/erts/emulator/hipe/hipe_x86.h b/erts/emulator/hipe/hipe_x86.h index f0f3c158af..97f09e38cd 100644 --- a/erts/emulator/hipe/hipe_x86.h +++ b/erts/emulator/hipe/hipe_x86.h @@ -49,7 +49,9 @@ static __inline__ int hipe_word32_address_ok(void *address) #define hipe_arch_name am_x86 extern void nbif_inc_stack_0(void); +#ifndef NO_FPE_SIGNALS extern void nbif_handle_fp_exception(void); +#endif /* for hipe_bifs_enter_code_2 */ extern void *hipe_alloc_code(Uint nrbytes, Eterm callees, Eterm *trampolines, Process *p); diff --git a/erts/emulator/hipe/hipe_x86_bifs.m4 b/erts/emulator/hipe/hipe_x86_bifs.m4 index 2ea69bde3c..3cb7d67be0 100644 --- a/erts/emulator/hipe/hipe_x86_bifs.m4 +++ b/erts/emulator/hipe/hipe_x86_bifs.m4 @@ -621,7 +621,9 @@ ASYM($1): /* * x86-specific primops. */ +#ifndef NO_FPE_SIGNALS noproc_primop_interface_0(nbif_handle_fp_exception, erts_restore_fpu) +#endif /* NO_FPE_SIGNALS */ /* * Implement gc_bif_interface_0 as nofail_primop_interface_0. diff --git a/erts/emulator/hipe/hipe_x86_primops.h b/erts/emulator/hipe/hipe_x86_primops.h index 96d2336bc5..111b1fa8bd 100644 --- a/erts/emulator/hipe/hipe_x86_primops.h +++ b/erts/emulator/hipe/hipe_x86_primops.h @@ -19,4 +19,7 @@ PRIMOP_LIST(am_inc_stack_0, &nbif_inc_stack_0) +#ifndef NO_FPE_SIGNALS PRIMOP_LIST(am_handle_fp_exception, &nbif_handle_fp_exception) +#endif + diff --git a/erts/emulator/test/float_SUITE.erl b/erts/emulator/test/float_SUITE.erl index 46466427c5..8e6923ce9f 100644 --- a/erts/emulator/test/float_SUITE.erl +++ b/erts/emulator/test/float_SUITE.erl @@ -27,6 +27,7 @@ fpe/1,fp_drv/1,fp_drv_thread/1,denormalized/1,match/1, bad_float_unpack/1,cmp_zero/1, cmp_integer/1, cmp_bignum/1]). -export([otp_7178/1]). +-export([hidden_inf/1]). init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> @@ -41,7 +42,9 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [fpe, fp_drv, fp_drv_thread, otp_7178, denormalized, - match, bad_float_unpack, {group, comparison}]. + match, bad_float_unpack, {group, comparison} + ,hidden_inf + ]. groups() -> [{comparison, [parallel], [cmp_zero, cmp_integer, cmp_bignum]}]. @@ -300,3 +303,25 @@ start_node(Config) when is_list(Config) -> stop_node(Node) -> ?t:stop_node(Node). + + +%% Test that operations that might hide infinite intermediate results +%% do not supress the badarith. +hidden_inf(Config) when is_list(Config) -> + ZeroP = 0.0, + ZeroN = id(ZeroP) * (-1), + [hidden_inf_1(A, B, Z, 9.23e307) + || A <- [1.0, -1.0, 3.1415, -0.00001000131, 3.57e257, ZeroP, ZeroN], + B <- [1.0, -1.0, 3.1415, -0.00001000131, 3.57e257, ZeroP, ZeroN], + Z <- [ZeroP, ZeroN]], + ok. + +hidden_inf_1(A, B, Zero, Huge) -> + {'EXIT',{badarith,_}} = (catch (B / (A / Zero))), + {'EXIT',{badarith,_}} = (catch (B * (A / Zero))), + {'EXIT',{badarith,_}} = (catch (B / (Huge * Huge))), + {'EXIT',{badarith,_}} = (catch (B * (Huge * Huge))), + {'EXIT',{badarith,_}} = (catch (B / (Huge + Huge))), + {'EXIT',{badarith,_}} = (catch (B * (Huge + Huge))), + {'EXIT',{badarith,_}} = (catch (B / (-Huge - Huge))), + {'EXIT',{badarith,_}} = (catch (B * (-Huge - Huge))). |