diff options
Diffstat (limited to 'gcc-4.9/libgcc/config/cris/umulsidi3.S')
-rw-r--r-- | gcc-4.9/libgcc/config/cris/umulsidi3.S | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/gcc-4.9/libgcc/config/cris/umulsidi3.S b/gcc-4.9/libgcc/config/cris/umulsidi3.S new file mode 100644 index 000000000..b5f011cab --- /dev/null +++ b/gcc-4.9/libgcc/config/cris/umulsidi3.S @@ -0,0 +1,289 @@ +;; Copyright (C) 2001-2014 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. +;; +;; GCC 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/>. +;; +;; This code is derived from mulsi3.S, observing that the mstep*16-based +;; multiplications there, from which it is formed, are actually +;; zero-extending; in gcc-speak "umulhisi3". The difference to *this* +;; function is just a missing top mstep*16 sequence and shifts and 64-bit +;; additions for the high part. Compared to an implementation based on +;; calling __Mul four times (see default implementation of umul_ppmm in +;; longlong.h), this will complete in a time between a fourth and a third +;; of that, assuming the value-based optimizations don't strike. If they +;; all strike there (very often) but none here, we still win, though by a +;; lesser margin, due to lesser total overhead. + +#define L(x) .x +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +#ifdef __USER_LABEL_PREFIX__ +# define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) +#else +# define SYM(x) x +#endif + + .global SYM(__umulsidi3) + .type SYM(__umulsidi3),@function +SYM(__umulsidi3): +#if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10 +;; Can't have the mulu.d last on a cache-line, due to a hardware bug. See +;; the documentation for -mmul-bug-workaround. +;; Not worthwhile to conditionalize here. + .p2alignw 2,0x050f + mulu.d $r11,$r10 + ret + move $mof,$r11 +#else + move.d $r11,$r9 + bound.d $r10,$r9 + cmpu.w 65535,$r9 + bls L(L3) + move.d $r10,$r12 + + move.d $r10,$r13 + movu.w $r11,$r9 ; ab*cd = (a*c)<<32 (a*d + b*c)<<16 + b*d + +;; We're called for floating point numbers very often with the "low" 16 +;; bits zero, so it's worthwhile to optimize for that. + + beq L(L6) ; d == 0? + lslq 16,$r13 + + beq L(L7) ; b == 0? + clear.w $r10 + + mstep $r9,$r13 ; d*b + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + mstep $r9,$r13 + +L(L7): + test.d $r10 + mstep $r9,$r10 ; d*a + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + mstep $r9,$r10 + +;; d*a in $r10, d*b in $r13, ab in $r12 and cd in $r11 +;; $r9 = d, need to do b*c and a*c; we can drop d. +;; so $r9 is up for use and we can shift down $r11 as the mstep +;; source for the next mstep-part. + +L(L8): + lsrq 16,$r11 + move.d $r12,$r9 + lslq 16,$r9 + beq L(L9) ; b == 0? + mstep $r11,$r9 + + mstep $r11,$r9 ; b*c + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 + mstep $r11,$r9 +L(L9): + +;; d*a in $r10, d*b in $r13, c*b in $r9, ab in $r12 and c in $r11, +;; need to do a*c. We want that to end up in $r11, so we shift up $r11 to +;; now use as the destination operand. We'd need a test insn to update N +;; to do it the other way round. + + lsrq 16,$r12 + lslq 16,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + mstep $r12,$r11 + +;; d*a in $r10, d*b in $r13, c*b in $r9, a*c in $r11 ($r12 free). +;; Need (a*d + b*c)<<16 + b*d into $r10 and +;; a*c + (a*d + b*c)>>16 plus carry from the additions into $r11. + + add.d $r9,$r10 ; (a*d + b*c) - may produce a carry. + scs $r12 ; The carry corresponds to bit 16 of $r11. + lslq 16,$r12 + add.d $r12,$r11 ; $r11 = a*c + carry from (a*d + b*c). + +#if defined (__CRIS_arch_version) && __CRIS_arch_version >= 8 + swapw $r10 + addu.w $r10,$r11 ; $r11 = a*c + (a*d + b*c) >> 16 including carry. + clear.w $r10 ; $r10 = (a*d + b*c) << 16 +#else + move.d $r10,$r9 + lsrq 16,$r9 + add.d $r9,$r11 ; $r11 = a*c + (a*d + b*c) >> 16 including carry. + lslq 16,$r10 ; $r10 = (a*d + b*c) << 16 +#endif + add.d $r13,$r10 ; $r10 = (a*d + b*c) << 16 + b*d - may produce a carry. + scs $r9 + ret + add.d $r9,$r11 ; Last carry added to the high-order 32 bits. + +L(L6): + clear.d $r13 + ba L(L8) + clear.d $r10 + +L(L11): + clear.d $r10 + ret + clear.d $r11 + +L(L3): +;; Form the maximum in $r10, by knowing the minimum, $r9. +;; (We don't know which one of $r10 or $r11 it is.) +;; Check if the largest operand is still just 16 bits. + + xor $r9,$r10 + xor $r11,$r10 + cmpu.w 65535,$r10 + bls L(L5) + movu.w $r9,$r13 + +;; We have ab*cd = (a*c)<<32 + (a*d + b*c)<<16 + b*d, but c==0 +;; so we only need (a*d)<<16 + b*d with d = $r13, ab = $r10. +;; Remember that the upper part of (a*d)<<16 goes into the lower part +;; of $r11 and there may be a carry from adding the low 32 parts. + beq L(L11) ; d == 0? + move.d $r10,$r9 + + lslq 16,$r9 + beq L(L10) ; b == 0? + clear.w $r10 + + mstep $r13,$r9 ; b*d + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 + mstep $r13,$r9 +L(L10): + test.d $r10 + mstep $r13,$r10 ; a*d + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + move.d $r10,$r11 + lsrq 16,$r11 + lslq 16,$r10 + add.d $r9,$r10 + scs $r12 + ret + add.d $r12,$r11 + +L(L5): +;; We have ab*cd = (a*c)<<32 + (a*d + b*c)<<16 + b*d, but a and c==0 +;; so b*d (with min=b=$r13, max=d=$r10) it is. As it won't overflow the +;; 32-bit part, just set $r11 to 0. + + lslq 16,$r10 + clear.d $r11 + + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + mstep $r13,$r10 + ret + mstep $r13,$r10 +#endif +L(Lfe1): + .size SYM(__umulsidi3),L(Lfe1)-SYM(__umulsidi3) |