| /* Signed and unsigned multiplication and division and modulus for CRIS. |
| Contributed by Axis Communications. |
| Written by Hans-Peter Nilsson <hp@axis.se>, c:a 1992. |
| |
| Copyright (C) 1998-2021 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC 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/>. */ |
| |
| |
| /* Note that we provide prototypes for all "const" functions, to attach |
| the const attribute. This is necessary in 2.7.2 - adding the |
| attribute to the function *definition* is a syntax error. |
| This did not work with e.g. 2.1; back then, the return type had to |
| be "const". */ |
| |
| #include "config.h" |
| |
| #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 3 |
| #define LZ(v) __builtin_clz (v) |
| #endif |
| |
| /* In (at least) the 4.7 series, GCC doesn't automatically choose the |
| most optimal strategy, possibly related to insufficient modelling of |
| delay-slot costs. */ |
| #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10 |
| #define SIGNMULT(s, a) ((s) * (a)) /* Cheap multiplication, better than branch. */ |
| #else |
| #define SIGNMULT(s, a) ((s) < 0 ? -(a) : (a)) /* Branches are still better. */ |
| #endif |
| |
| #if defined (L_udivsi3) || defined (L_divsi3) || defined (L_umodsi3) \ |
| || defined (L_modsi3) |
| /* Result type of divmod worker function. */ |
| struct quot_rem |
| { |
| long quot; |
| long rem; |
| }; |
| |
| /* This is the worker function for div and mod. It is inlined into the |
| respective library function. Parameter A must have bit 31 == 0. */ |
| |
| static __inline__ struct quot_rem |
| do_31div (unsigned long a, unsigned long b) |
| __attribute__ ((__const__, __always_inline__)); |
| |
| static __inline__ struct quot_rem |
| do_31div (unsigned long a, unsigned long b) |
| { |
| /* Adjust operands and result if a is 31 bits. */ |
| long extra = 0; |
| int quot_digits = 0; |
| |
| if (b == 0) |
| { |
| struct quot_rem ret; |
| ret.quot = 0xffffffff; |
| ret.rem = 0xffffffff; |
| return ret; |
| } |
| |
| if (a < b) |
| return (struct quot_rem) { 0, a }; |
| |
| #ifdef LZ |
| if (b <= a) |
| { |
| quot_digits = LZ (b) - LZ (a); |
| quot_digits += (a >= (b << quot_digits)); |
| b <<= quot_digits; |
| } |
| #else |
| while (b <= a) |
| { |
| b <<= 1; |
| quot_digits++; |
| } |
| #endif |
| |
| /* Is a 31 bits? Note that bit 31 is handled by the caller. */ |
| if (a & 0x40000000) |
| { |
| /* Then make b:s highest bit max 0x40000000, because it must have |
| been 0x80000000 to be 1 bit higher than a. */ |
| b >>= 1; |
| |
| /* Adjust a to be maximum 0x3fffffff, i.e. two upper bits zero. */ |
| if (a >= b) |
| { |
| a -= b; |
| extra = 1 << (quot_digits - 1); |
| } |
| else |
| { |
| a -= b >> 1; |
| |
| /* Remember that we adjusted a by subtracting b * 2 ** Something. */ |
| extra = 1 << quot_digits; |
| } |
| |
| /* The number of quotient digits will be one less, because |
| we just adjusted b. */ |
| quot_digits--; |
| } |
| |
| /* Now do the division part. */ |
| |
| /* Subtract b and add ones to the right when a >= b |
| i.e. "a - (b - 1) == (a - b) + 1". */ |
| b--; |
| |
| #define DS __asm__ ("dstep %2,%0" : "=r" (a) : "0" (a), "r" (b)); \ |
| __attribute__ ((__fallthrough__)) |
| |
| switch (quot_digits) |
| { |
| case 32: DS; case 31: DS; case 30: DS; case 29: DS; |
| case 28: DS; case 27: DS; case 26: DS; case 25: DS; |
| case 24: DS; case 23: DS; case 22: DS; case 21: DS; |
| case 20: DS; case 19: DS; case 18: DS; case 17: DS; |
| case 16: DS; case 15: DS; case 14: DS; case 13: DS; |
| case 12: DS; case 11: DS; case 10: DS; case 9: DS; |
| case 8: DS; case 7: DS; case 6: DS; case 5: DS; |
| case 4: DS; case 3: DS; case 2: DS; case 1: DS; |
| case 0:; |
| } |
| |
| { |
| struct quot_rem ret; |
| ret.quot = (a & ((1 << quot_digits) - 1)) + extra; |
| ret.rem = a >> quot_digits; |
| return ret; |
| } |
| } |
| |
| #ifdef L_udivsi3 |
| unsigned long |
| __Udiv (unsigned long a, unsigned long b) __attribute__ ((__const__)); |
| |
| unsigned long |
| __Udiv (unsigned long a, unsigned long b) |
| { |
| long extra = 0; |
| |
| /* Adjust operands and result, if a and/or b is 32 bits. */ |
| /* Effectively: b & 0x80000000. */ |
| if ((long) b < 0) |
| return a >= b; |
| |
| /* Effectively: a & 0x80000000. */ |
| if ((long) a < 0) |
| { |
| int tmp = 0; |
| |
| if (b == 0) |
| return 0xffffffff; |
| #ifdef LZ |
| tmp = LZ (b); |
| #else |
| for (tmp = 31; (((long) b & (1 << tmp)) == 0); tmp--) |
| ; |
| |
| tmp = 31 - tmp; |
| #endif |
| |
| if ((b << tmp) > a) |
| { |
| extra = 1 << (tmp-1); |
| a -= b << (tmp - 1); |
| } |
| else |
| { |
| extra = 1 << tmp; |
| a -= b << tmp; |
| } |
| } |
| |
| return do_31div (a, b).quot+extra; |
| } |
| #endif /* L_udivsi3 */ |
| |
| #ifdef L_divsi3 |
| long |
| __Div (long a, long b) __attribute__ ((__const__)); |
| |
| long |
| __Div (long a, long b) |
| { |
| long extra = 0; |
| long sign = (b < 0) ? -1 : 1; |
| long res; |
| |
| /* We need to handle a == -2147483648 as expected and must while |
| doing that avoid producing a sequence like "abs (a) < 0" as GCC |
| may optimize out the test. That sequence may not be obvious as |
| we call inline functions. Testing for a being negative and |
| handling (presumably much rarer than positive) enables us to get |
| a bit of optimization for an (accumulated) reduction of the |
| penalty of the 0x80000000 special-case. */ |
| if (a < 0) |
| { |
| sign = -sign; |
| |
| if ((a & 0x7fffffff) == 0) |
| { |
| /* We're at 0x80000000. Tread carefully. */ |
| a -= SIGNMULT (sign, b); |
| extra = sign; |
| } |
| a = -a; |
| } |
| |
| res = do_31div (a, __builtin_labs (b)).quot; |
| return SIGNMULT (sign, res) + extra; |
| } |
| #endif /* L_divsi3 */ |
| |
| |
| #ifdef L_umodsi3 |
| unsigned long |
| __Umod (unsigned long a, unsigned long b) __attribute__ ((__const__)); |
| |
| unsigned long |
| __Umod (unsigned long a, unsigned long b) |
| { |
| /* Adjust operands and result if a and/or b is 32 bits. */ |
| if ((long) b < 0) |
| return a >= b ? a - b : a; |
| |
| if ((long) a < 0) |
| { |
| int tmp = 0; |
| |
| if (b == 0) |
| return a; |
| #ifdef LZ |
| tmp = LZ (b); |
| #else |
| for (tmp = 31; (((long) b & (1 << tmp)) == 0); tmp--) |
| ; |
| tmp = 31 - tmp; |
| #endif |
| |
| if ((b << tmp) > a) |
| { |
| a -= b << (tmp - 1); |
| } |
| else |
| { |
| a -= b << tmp; |
| } |
| } |
| |
| return do_31div (a, b).rem; |
| } |
| #endif /* L_umodsi3 */ |
| |
| #ifdef L_modsi3 |
| long |
| __Mod (long a, long b) __attribute__ ((__const__)); |
| |
| long |
| __Mod (long a, long b) |
| { |
| long sign = 1; |
| long res; |
| |
| /* We need to handle a == -2147483648 as expected and must while |
| doing that avoid producing a sequence like "abs (a) < 0" as GCC |
| may optimize out the test. That sequence may not be obvious as |
| we call inline functions. Testing for a being negative and |
| handling (presumably much rarer than positive) enables us to get |
| a bit of optimization for an (accumulated) reduction of the |
| penalty of the 0x80000000 special-case. */ |
| if (a < 0) |
| { |
| sign = -1; |
| if ((a & 0x7fffffff) == 0) |
| /* We're at 0x80000000. Tread carefully. */ |
| a += __builtin_labs (b); |
| a = -a; |
| } |
| |
| res = do_31div (a, __builtin_labs (b)).rem; |
| return SIGNMULT (sign, res); |
| } |
| #endif /* L_modsi3 */ |
| #endif /* L_udivsi3 || L_divsi3 || L_umodsi3 || L_modsi3 */ |
| |
| /* |
| * Local variables: |
| * eval: (c-set-style "gnu") |
| * indent-tabs-mode: t |
| * End: |
| */ |