Permalink
Browse files

Merge branch 'sverk/hipe-without-fpe/OTP-9724'

* sverk/hipe-without-fpe/OTP-9724:
  otp_build: Disable FPE by default on Linux
  stdlib: Make sure qlc_SUITE:otp_6964 restores backtrace_depth
  erts: Add test for inf/NaN intermediate float results
  hipe,erts: Allow hipe without floating point exceptions
  hipe: Fix bug in hipe_rtl_lcm:calc_killed_expr_bb
  erts: Rename macros used by float instructions without FPE
  • Loading branch information...
2 parents b130455 + 327c072 commit 7d9ef0fdde8119e1be0a47e3e45c9cdb85f926d8 @sverker sverker committed Nov 18, 2011
View
@@ -3076,8 +3076,6 @@ dnl done up where floating point is checked, need to descide there already...
if test X${enable_hipe} = Xyes; then
if test X$ac_cv_sizeof_void_p != X4 -a X$ARCH != Xamd64 -a X$ARCH != Xppc64; then
AC_MSG_WARN([HiPE is not supported in 64-bit builds])
- elif test X$FPE != Xreliable -a X$ARCH != Xarm; then
- AC_MSG_WARN([HiPE is not supported on $ARCH without reliable floating-point exceptions])
else
HIPE_ENABLED=yes
AC_DEFINE(HIPE,[1],[Define to enable HiPE])
@@ -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,56 +4768,52 @@ 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
OpCase(i_fadd_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_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:
@@ -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
@@ -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
@@ -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.
@@ -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)
@@ -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.
@@ -140,3 +140,5 @@ atom bs_put_utf16le
atom bs_get_utf16
atom bs_validate_unicode
atom bs_validate_unicode_retract
+atom emulate_fpe
+
@@ -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
*/
@@ -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])
@@ -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
}
@@ -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.
*/
@@ -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
@@ -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
@@ -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);
@@ -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.
@@ -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
+
@@ -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))).
@@ -781,8 +781,11 @@ fstore_src_update(F, NewSrc) -> F#fstore{src=NewSrc}.
%% fp
%%
+
mk_fp(Dst, Src1, Op, Src2) ->
- #fp{dst=Dst, src1=Src1, op=Op, src2=Src2}.
+ [#fp{dst=Dst, src1=Src1, op=Op, src2=Src2}
+ | hipe_rtl_arch:mk_fp_check_result(Dst)].
+
fp_dst(#fp{dst=Dst}) -> Dst.
fp_dst_update(Fp, NewDst) -> Fp#fp{dst=NewDst}.
fp_src1(#fp{src1=Src1}) -> Src1.
@@ -65,7 +65,8 @@
%% alignment/0,
nr_of_return_regs/0,
log2_word_size/0,
- word_size/0
+ word_size/0,
+ mk_fp_check_result/1
]).
-include("hipe_literals.hrl").
@@ -558,6 +559,12 @@ eval_cond_bits(Cond, N, Z, V, C) ->
%%----------------------------------------------------------------------
fwait() ->
+ case ?ERTS_NO_FPE_SIGNALS of
+ 1 -> [];
+ 0 -> fwait_real()
+ end.
+
+fwait_real() ->
case get(hipe_target_arch) of
x86 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
amd64 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
@@ -573,6 +580,12 @@ fwait() ->
%% Returns RTL code to restore the FPU after a floating-point exception.
%% @end
handle_fp_exception() ->
+ case ?ERTS_NO_FPE_SIGNALS of
+ 1 -> [];
+ 0 -> handle_real_fp_exception()
+ end.
+
+handle_real_fp_exception() ->
case get(hipe_target_arch) of
x86 ->
ContLbl = hipe_rtl:mk_new_label(),
@@ -655,3 +668,15 @@ nr_of_return_regs() ->
1
%% hipe_amd64_registers:nr_rets();
end.
+
+
+mk_fp_check_result(Result) ->
+ case ?ERTS_NO_FPE_SIGNALS of
+ 0 ->
+ [];
+ 1 ->
+ [hipe_rtl:mk_fstore(proc_pointer(),
+ hipe_rtl:mk_imm(?P_FLOAT_RESULT),
+ Result),
+ hipe_rtl:mk_call([], emulate_fpe, [], [], [], not_remote)]
+ end.
Oops, something went wrong.

0 comments on commit 7d9ef0f

Please sign in to comment.