# HG changeset patch # User Jaroslav Hajek # Date 1270103243 -7200 # Node ID e8811e5dd6999d11d873fa18e946b94be1d7c1a4 # Parent 19e1e4470e01a3481c8ca5efa28a022a3f23dcde avoid exception throwing in mx-inline loops diff --git a/liboctave/ChangeLog b/liboctave/ChangeLog --- a/liboctave/ChangeLog +++ b/liboctave/ChangeLog @@ -1,3 +1,13 @@ +2010-04-01 Jaroslav Hajek + + * mx-inlines.cc: Declare all loops as throw (). Ditto for + corresponding applier arguments. + (do_mx_check): New applier. + (logical_value): Do not throw exceptions. + * mx-op-defs.h (SNANCHK, MNANCHK): New helper macros. + (MS_BOOL_OP, SM_BOOL_OP, MM_BOOL_OP, NDS_BOOL_OP, SND_BOOL_OP, + NDND_BOOL_OP): Use them here. + 2010-03-31 Jaroslav Hajek * Sparse.cc (Sparse::Sparse (const Array&, diff --git a/liboctave/mx-inlines.cc b/liboctave/mx-inlines.cc --- a/liboctave/mx-inlines.cc +++ b/liboctave/mx-inlines.cc @@ -41,26 +41,26 @@ // Provides some commonly repeated, basic loop templates. template -inline void mx_inline_fill (size_t n, R *r, S s) +inline void mx_inline_fill (size_t n, R *r, S s) throw () { for (size_t i = 0; i < n; i++) r[i] = s; } #define DEFMXUNOP(F, OP) \ template \ -inline void F (size_t n, R *r, const X *x) \ +inline void F (size_t n, R *r, const X *x) throw () \ { for (size_t i = 0; i < n; i++) r[i] = OP x[i]; } DEFMXUNOP (mx_inline_uminus, -) #define DEFMXUNOPEQ(F, OP) \ template \ -inline void F (size_t n, R *r) \ +inline void F (size_t n, R *r) throw () \ { for (size_t i = 0; i < n; i++) r[i] = OP r[i]; } DEFMXUNOPEQ (mx_inline_uminus2, -) #define DEFMXUNBOOLOP(F, OP) \ template \ -inline void F (size_t n, bool *r, const X *x) \ +inline void F (size_t n, bool *r, const X *x) throw () \ { const X zero = X(); for (size_t i = 0; i < n; i++) r[i] = x[i] OP zero; } DEFMXUNBOOLOP (mx_inline_iszero, ==) @@ -68,13 +68,13 @@ #define DEFMXBINOP(F, OP) \ template \ -inline void F (size_t n, R *r, const X *x, const Y *y) \ +inline void F (size_t n, R *r, const X *x, const Y *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = x[i] OP y[i]; } \ template \ -inline void F (size_t n, R *r, const X *x, Y y) \ +inline void F (size_t n, R *r, const X *x, Y y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = x[i] OP y; } \ template \ -inline void F (size_t n, R *r, X x, const Y *y) \ +inline void F (size_t n, R *r, X x, const Y *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = x OP y[i]; } DEFMXBINOP (mx_inline_add, +) @@ -84,10 +84,10 @@ #define DEFMXBINOPEQ(F, OP) \ template \ -inline void F (size_t n, R *r, const X *x) \ +inline void F (size_t n, R *r, const X *x) throw () \ { for (size_t i = 0; i < n; i++) r[i] OP x[i]; } \ template \ -inline void F (size_t n, R *r, X x) \ +inline void F (size_t n, R *r, X x) throw () \ { for (size_t i = 0; i < n; i++) r[i] OP x; } DEFMXBINOPEQ (mx_inline_add2, +=) @@ -97,13 +97,13 @@ #define DEFMXCMPOP(F, OP) \ template \ -inline void F (size_t n, bool *r, const X *x, const Y *y) \ +inline void F (size_t n, bool *r, const X *x, const Y *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = x[i] OP y[i]; } \ template \ -inline void F (size_t n, bool *r, const X *x, Y y) \ +inline void F (size_t n, bool *r, const X *x, Y y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = x[i] OP y; } \ template \ -inline void F (size_t n, bool *r, X x, const Y *y) \ +inline void F (size_t n, bool *r, X x, const Y *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = x OP y[i]; } DEFMXCMPOP (mx_inline_lt, <) @@ -115,48 +115,39 @@ // Convert to logical value, for logical op purposes. template inline bool logical_value (T x) { return x; } +template inline bool logical_value (const std::complex& x) +{ return x.real () != 0 && x.imag () != 0; } template inline bool logical_value (const octave_int& x) { return x.value (); } -// NaNs in real data should generate an error. Doing it on-the-fly is faster. - -#define DEFLOGCHKNAN(ARG, ZERO) \ -inline bool logical_value (ARG x) \ -{ if (xisnan (x)) gripe_nan_to_logical_conversion (); return x != ZERO; } - -DEFLOGCHKNAN (double, 0.0) -DEFLOGCHKNAN (const Complex&, 0.0) -DEFLOGCHKNAN (float, 0.0f) -DEFLOGCHKNAN (const FloatComplex&, 0.0f) - template -void mx_inline_not (size_t n, bool *r, const X* x) +void mx_inline_not (size_t n, bool *r, const X* x) throw () { for (size_t i = 0; i < n; i++) r[i] = ! logical_value (x[i]); } -inline void mx_inline_not2 (size_t n, bool *r) +inline void mx_inline_not2 (size_t n, bool *r) throw () { for (size_t i = 0; i < n; i++) r[i] = ! r[i]; } #define DEFMXBOOLOP(F, NOT1, OP, NOT2) \ template \ -inline void F (size_t n, bool *r, const X *x, const Y *y) \ +inline void F (size_t n, bool *r, const X *x, const Y *y) throw () \ { \ for (size_t i = 0; i < n; i++) \ r[i] = (NOT1 logical_value (x[i])) OP (NOT2 logical_value (y[i])); \ } \ template \ -inline void F (size_t n, bool *r, const X *x, Y y) \ +inline void F (size_t n, bool *r, const X *x, Y y) throw () \ { \ const bool yy = (NOT2 logical_value (y)); \ for (size_t i = 0; i < n; i++) \ r[i] = (NOT1 logical_value (x[i])) OP yy; \ } \ template \ -inline void F (size_t n, bool *r, X x, const Y *y) \ +inline void F (size_t n, bool *r, X x, const Y *y) throw () \ { \ const bool xx = (NOT1 logical_value (x)); \ for (size_t i = 0; i < n; i++) \ @@ -172,7 +163,7 @@ #define DEFMXBOOLOPEQ(F, OP) \ template \ -inline void F (size_t n, bool *r, const X *x) \ +inline void F (size_t n, bool *r, const X *x) throw () \ { \ for (size_t i = 0; i < n; i++) \ r[i] OP logical_value (x[i]); \ @@ -183,7 +174,7 @@ template inline bool -mx_inline_any_nan (size_t n, const T* x) +mx_inline_any_nan (size_t n, const T* x) throw () { for (size_t i = 0; i < n; i++) { @@ -196,7 +187,7 @@ template inline bool -mx_inline_any_negative (size_t n, const T* x) +mx_inline_any_negative (size_t n, const T* x) throw () { for (size_t i = 0; i < n; i++) { @@ -209,7 +200,7 @@ template inline bool -mx_inline_all_real (size_t n, const std::complex* x) +mx_inline_all_real (size_t n, const std::complex* x) throw () { for (size_t i = 0; i < n; i++) { @@ -222,26 +213,26 @@ #define DEFMXMAPPER(F, FUN) \ template \ -inline void F (size_t n, T *r, const T *x) \ +inline void F (size_t n, T *r, const T *x) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i]); } template -inline void mx_inline_real (size_t n, T *r, const std::complex* x) +inline void mx_inline_real (size_t n, T *r, const std::complex* x) throw () { for (size_t i = 0; i < n; i++) r[i] = x[i].real (); } template -inline void mx_inline_imag (size_t n, T *r, const std::complex* x) +inline void mx_inline_imag (size_t n, T *r, const std::complex* x) throw () { for (size_t i = 0; i < n; i++) r[i] = x[i].imag (); } // Pairwise minimums/maximums #define DEFMXMAPPER2(F, FUN) \ template \ -inline void F (size_t n, T *r, const T *x, const T *y) \ +inline void F (size_t n, T *r, const T *x, const T *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i], y[i]); } \ template \ -inline void F (size_t n, T *r, const T *x, T y) \ +inline void F (size_t n, T *r, const T *x, T y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i], y); } \ template \ -inline void F (size_t n, T *r, T x, const T *y) \ +inline void F (size_t n, T *r, T x, const T *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x, y[i]); } DEFMXMAPPER2 (mx_inline_xmin, xmin) @@ -250,7 +241,7 @@ // Specialize array-scalar max/min #define DEFMINMAXSPEC(T, F, OP) \ template <> \ -inline void F (size_t n, T *r, const T *x, T y) \ +inline void F (size_t n, T *r, const T *x, T y) throw () \ { \ if (xisnan (y)) \ std::memcpy (r, x, n * sizeof (T)); \ @@ -258,7 +249,7 @@ for (size_t i = 0; i < n; i++) r[i] = (x[i] OP y) ? x[i] : y; \ } \ template <> \ -inline void F (size_t n, T *r, T x, const T *y) \ +inline void F (size_t n, T *r, T x, const T *y) throw () \ { \ if (xisnan (x)) \ std::memcpy (r, y, n * sizeof (T)); \ @@ -274,13 +265,13 @@ // Pairwise power #define DEFMXMAPPER2X(F, FUN) \ template \ -inline void F (size_t n, R *r, const X *x, const Y *y) \ +inline void F (size_t n, R *r, const X *x, const Y *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i], y[i]); } \ template \ -inline void F (size_t n, R *r, const X *x, Y y) \ +inline void F (size_t n, R *r, const X *x, Y y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x[i], y); } \ template \ -inline void F (size_t n, R *r, X x, const Y *y) \ +inline void F (size_t n, R *r, X x, const Y *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x, y[i]); } DEFMXMAPPER2X (mx_inline_pow, std::pow) @@ -288,11 +279,11 @@ // Arbitrary function appliers. The function is a template parameter to enable // inlining. template -inline void mx_inline_map (size_t n, R *r, const X *x) +inline void mx_inline_map (size_t n, R *r, const X *x) throw () { for (size_t i = 0; i < n; i++) r[i] = fun (x[i]); } template -inline void mx_inline_map (size_t n, R *r, const X *x) +inline void mx_inline_map (size_t n, R *r, const X *x) throw () { for (size_t i = 0; i < n; i++) r[i] = fun (x[i]); } // Appliers. Since these call the operation just once, we pass it as @@ -301,7 +292,7 @@ template inline Array do_mx_unary_op (const Array& x, - void (*op) (size_t, R *, const X *)) + void (*op) (size_t, R *, const X *) throw ()) { Array r (x.dims ()); op (r.numel (), r.fortran_vec (), x.data ()); @@ -327,7 +318,7 @@ template inline Array& do_mx_inplace_op (Array& r, - void (*op) (size_t, R *)) + void (*op) (size_t, R *) throw ()) { op (r.numel (), r.fortran_vec ()); return r; @@ -337,7 +328,7 @@ template inline Array do_mm_binary_op (const Array& x, const Array& y, - void (*op) (size_t, R *, const X *, const Y *), + void (*op) (size_t, R *, const X *, const Y *) throw (), const char *opname) { dim_vector dx = x.dims (), dy = y.dims (); @@ -357,7 +348,7 @@ template inline Array do_ms_binary_op (const Array& x, const Y& y, - void (*op) (size_t, R *, const X *, Y)) + void (*op) (size_t, R *, const X *, Y) throw ()) { Array r (x.dims ()); op (r.length (), r.fortran_vec (), x.data (), y); @@ -367,7 +358,7 @@ template inline Array do_sm_binary_op (const X& x, const Array& y, - void (*op) (size_t, R *, X, const Y *)) + void (*op) (size_t, R *, X, const Y *) throw ()) { Array r (y.dims ()); op (r.length (), r.fortran_vec (), x, y.data ()); @@ -377,7 +368,7 @@ template inline Array& do_mm_inplace_op (Array& r, const Array& x, - void (*op) (size_t, R *, const X *), + void (*op) (size_t, R *, const X *) throw (), const char *opname) { dim_vector dr = r.dims (), dx = x.dims (); @@ -391,7 +382,7 @@ template inline Array& do_ms_inplace_op (Array& r, const X& x, - void (*op) (size_t, R *, X)) + void (*op) (size_t, R *, X) throw ()) { op (r.length (), r.fortran_vec (), x); return r; @@ -399,7 +390,7 @@ template inline bool -mx_inline_equal (size_t n, const T1 *x, const T2 *y) +mx_inline_equal (size_t n, const T1 *x, const T2 *y) throw () { for (size_t i = 0; i < n; i++) if (x[i] != y[i]) @@ -407,9 +398,16 @@ return true; } -// FIXME: Due to a performance defect in g++ (<= 4.3), std::norm is slow unless -// ffast-math is on (not by default even with -O3). The following helper function -// gives the expected straightforward implementation of std::norm. +template +inline bool +do_mx_check (const Array& a, + bool (*op) (size_t, const T *) throw ()) +{ + return op (a.numel (), a.data ()); +} + +// NOTE: we don't use std::norm because it typically does some heavyweight +// magic to avoid underflows, which we don't need here. template inline T cabsq (const std::complex& c) { return c.real () * c.real () + c.imag () * c.imag (); } diff --git a/liboctave/mx-op-defs.h b/liboctave/mx-op-defs.h --- a/liboctave/mx-op-defs.h +++ b/liboctave/mx-op-defs.h @@ -29,6 +29,14 @@ #include "mx-op-decl.h" #include "mx-inlines.cc" +#define SNANCHK(s) \ + if (xisnan (s)) \ + gripe_nan_to_logical_conversion () + +#define MNANCHK(m) \ + if (do_mx_check (m, mx_inline_any_nan)) \ + gripe_nan_to_logical_conversion () + // vector by scalar operations. #define VS_BIN_OP(R, F, OP, V, S) \ @@ -108,6 +116,8 @@ boolMatrix \ F (const M& m, const S& s) \ { \ + MNANCHK (m); \ + SNANCHK (s); \ return do_ms_binary_op (m, s, OP); \ } @@ -149,6 +159,8 @@ boolMatrix \ F (const S& s, const M& m) \ { \ + SNANCHK (s); \ + MNANCHK (m); \ return do_sm_binary_op (s, m, OP); \ } @@ -190,6 +202,8 @@ boolMatrix \ F (const M1& m1, const M2& m2) \ { \ + MNANCHK (m1); \ + MNANCHK (m2); \ return do_mm_binary_op (m1, m2, OP, #F); \ } @@ -231,6 +245,8 @@ boolNDArray \ F (const ND& m, const S& s) \ { \ + MNANCHK (m); \ + SNANCHK (s); \ return do_ms_binary_op (m, s, OP); \ } @@ -276,6 +292,8 @@ boolNDArray \ F (const S& s, const ND& m) \ { \ + SNANCHK (s); \ + MNANCHK (m); \ return do_sm_binary_op (s, m, OP); \ } @@ -321,6 +339,8 @@ boolNDArray \ F (const ND1& m1, const ND2& m2) \ { \ + MNANCHK (m1); \ + MNANCHK (m2); \ return do_mm_binary_op (m1, m2, OP, #F); \ }