;; Copyright (C) 2001-2018 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 used to be expanded through interesting expansions in
;; the machine description, compiled from this code:
;;
;; #ifdef L_mulsi3
;; long __Mul (unsigned long a, unsigned long b) __attribute__ ((__const__));
;; 
;; /* This must be compiled with the -mexpand-mul flag, to synthesize the
;;    multiplication from the mstep instructions.  The check for
;;    smaller-size multiplication pays off in the order of .5-10%;
;;    estimated median 1%, depending on application.
;;     FIXME: It can be further optimized if we go to assembler code, as
;;    gcc 2.7.2 adds a few unnecessary instructions and does not put the
;;    basic blocks in optimal order.  */
;; long
;; __Mul (unsigned long a, unsigned long b)
;; {
;; #if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10
;;   /* In case other code is compiled without -march=v10, they will
;; 	contain calls to __Mul, regardless of flags at link-time.  The
;; 	"else"-code below will work, but is unnecessarily slow.  This
;; 	sometimes cuts a few minutes off from simulation time by just
;; 	returning a "mulu.d".  */
;;   return a * b;
;; #else
;;   unsigned long min;
;; 
;;   /* Get minimum via the bound insn.  */
;;   min = a < b ? a : b;
;; 
;;   /* Can we omit computation of the high part?	*/
;;   if (min > 65535)
;;     /* No.  Perform full multiplication.  */
;;     return a * b;
;;   else
;;     {
;; 	 /* Check if both operands are within 16 bits.  */
;; 	 unsigned long max;
;; 
;; 	 /* Get maximum, by knowing the minimum.
;; 	    This will partition a and b into max and min.
;; 	    This is not currently something GCC understands,
;; 	    so do this trick by asm.  */
;; 	 __asm__ ("xor %1,%0\n\txor %2,%0"
;; 		  : "=r" (max)
;; 		  :  "r" (b), "r" (a), "0" (min));
;; 
;;     if (max > 65535)
;; 	 /* Make GCC understand that only the low part of "min" will be
;; 	    used.  */
;; 	 return max * (unsigned short) min;
;;     else
;; 	 /* Only the low parts of both operands are necessary.  */
;; 	 return ((unsigned short) max) * (unsigned short) min;
;;     }
;; #endif /* not __CRIS_arch_version >= 10 */
;; }
;; #endif /* L_mulsi3 */
;;
;; That approach was abandoned since the caveats outweighted the
;; benefits.  The expand-multiplication machinery is also removed, so you
;; can't do this anymore.
;;
;; For doubters of there being any benefits, some where: insensitivity to:
;; - ABI changes (mostly for experimentation)
;; - assembler syntax differences (mostly debug format).
;; - insn scheduling issues.
;; Most ABI experiments will presumably happen with arches with mul insns,
;; so that argument doesn't really hold anymore, and it's unlikely there
;; being new arch variants needing insn scheduling and not having mul
;; insns.

;; ELF and a.out have different syntax for local labels: the "wrong"
;; one may not be omitted from the object.
#undef L
#ifdef __AOUT__
# define L(x) x
#else
# define L(x) .x
#endif

	.global ___Mul
	.type	___Mul,@function
___Mul:
#if defined (__CRIS_arch_version) && __CRIS_arch_version >= 10
;; Can't have the mulu.d last on a cache-line (in the delay-slot of the
;; "ret"), due to hardware bug.  See documentation for -mmul-bug-workaround.
;; Not worthwhile to conditionalize here.
	.p2alignw 2,0x050f
	mulu.d $r11,$r10
	ret
	nop
#else
;; See if we can avoid multiplying some of the parts, knowing
;; they're zero.

	move.d $r11,$r9
	bound.d $r10,$r9
	cmpu.w 65535,$r9
	bls L(L3)
	move.d $r10,$r12

;; Nope, have to do all the parts of a 32-bit multiplication.
;; See head comment in optabs.c:expand_doubleword_mult.

	move.d $r10,$r13
	movu.w $r11,$r9 ; ab*cd = (a*d + b*c)<<16 + b*d
	lslq 16,$r13
	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
	clear.w $r10
	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
	movu.w $r12,$r12
	clear.w $r11
	move.d $r11,$r9 ; Doubles as a "test.d" preparing for the mstep.
	mstep $r12,$r9	; b*c
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	mstep $r12,$r9
	add.w $r9,$r10
	lslq 16,$r10
	ret
	add.d $r13,$r10

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.
;; We drop the upper part of (a*d)<<16 as we're only doing a
;; 32-bit-result multiplication.

	move.d $r10,$r9
	lslq 16,$r9
	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
	clear.w $r10
	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
	lslq 16,$r10
	ret
	add.d $r9,$r10

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 b=$r13, a=$r10) it is.

	lslq 16,$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
	mstep $r13,$r10
	ret
	mstep $r13,$r10
#endif
L(Lfe1):
	.size	___Mul,L(Lfe1)-___Mul
