aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/libgcc/config/cris/umulsidi3.S
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/libgcc/config/cris/umulsidi3.S')
-rw-r--r--gcc-4.9/libgcc/config/cris/umulsidi3.S289
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)