summaryrefslogtreecommitdiff
path: root/libm/metag/fraiseexcpt.c
diff options
context:
space:
mode:
Diffstat (limited to 'libm/metag/fraiseexcpt.c')
-rw-r--r--libm/metag/fraiseexcpt.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/libm/metag/fraiseexcpt.c b/libm/metag/fraiseexcpt.c
new file mode 100644
index 000000000..9ab39bbf6
--- /dev/null
+++ b/libm/metag/fraiseexcpt.c
@@ -0,0 +1,92 @@
+/* Raise given exceptions.
+ Copyright (C) 2013 Imagination Technologies Ltd.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <fenv.h>
+#include <math.h>
+
+libm_hidden_proto(feraiseexcept)
+
+int
+feraiseexcept (int excepts)
+{
+ /* Raise exceptions represented by EXPECTS. But we must raise only
+ one signal at a time. It is important that if the overflow/underflow
+ exception and the inexact exception are given at the same time,
+ the overflow/underflow exception follows the inexact exception. */
+
+ /* First: invalid exception. */
+ if ((FE_INVALID & excepts) != 0)
+ {
+ /* Reciprocal square root of a negative number is invalid. */
+ __asm__ volatile(
+ "F MOV FX.0,#0xc000 ! -2\n"
+ "F RSQ FX.1,FX.0\n"
+ );
+ }
+
+ /* Next: division by zero. */
+ if ((FE_DIVBYZERO & excepts) != 0)
+ {
+ __asm__ volatile(
+ "F MOV FX.0,#0\n"
+ "F RCP FX.1,FX.0\n"
+ );
+ }
+
+ /* Next: overflow. */
+ if ((FE_OVERFLOW & excepts) != 0)
+ {
+ /* Adding a large number in single precision can cause overflow. */
+ __asm__ volatile(
+ " MOVT D0.0,#0x7f7f\n"
+ " ADD D0.0,D0.0,#0xffff\n"
+ "F MOV FX.0,D0.0\n"
+ "F ADD FX.1,FX.0,FX.0\n"
+ );
+ }
+
+ /* Next: underflow. */
+ if ((FE_UNDERFLOW & excepts) != 0)
+ {
+ /* Multiplying a small value by 0.5 will cause an underflow. */
+ __asm__ volatile(
+ " MOV D0.0,#1\n"
+ "F MOV FX.0,D0.0\n"
+ " MOVT D0.0,#0x3f00\n"
+ "F MOV FX.1,D0.0\n"
+ "F MUL FX.2,FX.1,FX.0\n"
+ );
+ }
+
+ /* Last: inexact. */
+ if ((FE_INEXACT & excepts) != 0)
+ {
+ /* Converting a small single precision value to half precision
+ can cause an inexact exception. */
+ __asm__ volatile(
+ " MOV D0.0,#0x0001\n"
+ "F MOV FX.0,D0.0\n"
+ "F FTOH FX.1,FX.0\n"
+ );
+ }
+
+ /* Success. */
+ return 0;
+}
+libm_hidden_def(feraiseexcept)