diff options
Diffstat (limited to 'libgcc/config/epiphany/modsi3.c')
-rw-r--r-- | libgcc/config/epiphany/modsi3.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/libgcc/config/epiphany/modsi3.c b/libgcc/config/epiphany/modsi3.c new file mode 100644 index 0000000..feee3d1 --- /dev/null +++ b/libgcc/config/epiphany/modsi3.c @@ -0,0 +1,106 @@ +/* Generic signed 32 bit modulo implementation. + Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Embecosm on behalf of Adapteva, Inc. + +This file is part of GCC. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +This file 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 +General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +typedef union { unsigned int i; float f; } fu; + +unsigned int __modsi3 (unsigned int a, unsigned int b); + +unsigned int +__modsi3 (unsigned int a, unsigned int b) +{ + unsigned int sign = (int) a >> 31; + unsigned int d, t, s0, s1, s2, r0, r1; + fu u0, u1, u2, u1b, u2b; + + a = abs (a); + b = abs (b); + + if (b > a) + goto ret_a; + + /* Compute difference in number of bits in S0. */ + u0.i = 0x40000000; + u1b.i = u2b.i = u0.i; + u1.i = a; + u2.i = b; + u1.i = a | u0.i; + t = 0x4b800000 | ((a >> 23) & 0xffff); + if (a >> 23) + { + u1.i = t; + u1b.i = 0x4b800000; + } + u2.i = b | u0.i; + t = 0x4b800000 | ((b >> 23) & 0xffff); + if (b >> 23) + { + u2.i = t; + u2b.i = 0x4b800000; + } + u1.f = u1.f - u1b.f; + u2.f = u2.f - u2b.f; + s1 = u1.i >> 23; + s2 = u2.i >> 23; + s0 = s1 - s2; + +#define STEP(n) case n: d = b << n; t = a - d; if (t <= a) a = t; + switch (s0) + { + STEP (31) + STEP (30) + STEP (29) + STEP (28) + STEP (27) + STEP (26) + STEP (25) + STEP (24) + STEP (23) + STEP (22) + STEP (21) + STEP (20) + STEP (19) + STEP (18) + STEP (17) + STEP (16) + STEP (15) + STEP (14) + STEP (13) + STEP (12) + STEP (11) + STEP (10) + STEP (9) + STEP (8) + STEP (7) + STEP (6) + STEP (5) + STEP (4) + STEP (3) + STEP (2) + STEP (1) + STEP (0) + } + ret_a: + return (a ^ sign) - sign; +} |