3
$Id: mul.c,v 9.35 2000/12/05 21:23:45 cph Exp $
5
Copyright (c) 1987-2000 Massachusetts Institute of Technology
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or (at
10
your option) any later version.
12
This program is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
/* This file contains the fixnum multiplication procedure. Returns
25
SHARP_F if the result does not fit in a fixnum. Note: The portable
26
version has only been tried on machines with long = 32 bits. This
27
file is included in the appropriate os file. */
30
EXFUN (Mul, (SCHEME_OBJECT, SCHEME_OBJECT));
32
#if (TYPE_CODE_LENGTH == 8)
34
#if defined(vax) && defined(__unix__)
38
/* Note that "register" is used here (not "fast") since the
39
assembly code requires knowledge of the location of
40
the variables and they therefore must be in registers.
41
This is a kludge. It depends on what register variables
42
get assigned to what registers. It should be entirely
43
coded in assembly language. -- JINX
45
With gcc, we do have a half-way decent interface to assembly
46
code, so the register-assignment dependency is removed. -- KR
50
DEFUN (Mul, (Arg1, Arg2),
52
AND SCHEME_OBJECT Arg2)
54
register long A = (FIXNUM_TO_LONG (Arg1));
55
register long B = (FIXNUM_TO_LONG (Arg2));
58
/* GCC isn't yet efficient enough with `long long' -- KR. */
61
asm ("emul %1,%2,$0,%0" : "=g" (X) : "g" (A), "g" (B));
63
((((X & (-1 << 23)) == 0) ||
64
((X & (-1 << 23)) == (-1 << 23)))
65
? (LONG_TO_FIXNUM ((long) X))
69
/* non-long-long version: */
76
asm ("emul %1,%2,$0,%0" : "=g" (X) : "g" (A), "g" (B));
81
#else /* not __GNUC__ */
82
asm(" emul r11,r10,$0,r10"); /* A is in 11, B in 10 */
84
/* A should have high order result, B low order */
86
((((A == 0) && (B & (-1 << 23)) == 0) ||
87
((A == -1) && (B & (-1 << 23)) == (-1 << 23)))
88
? (LONG_TO_FIXNUM (B))
92
#endif /* vax and __unix__ */
94
/* 68k family code. Uses hp9000s300 conventions for the new compiler. */
96
#if (defined(hp9000s300) || defined(__hp9000s300)) && !defined(old_cc) && !defined(__GNUC__)
99
/* The following constants are hard coded in the assembly language
100
* code below. The code assumes that d0 and d1 are scratch registers
104
#if (SHARP_F != 0) || (TC_FIXNUM != 0x1A)
105
#include "Error: types changed. Change assembly language appropriately"
108
#ifndef MC68010 /* MC68020, MC68030, or MC68040 */
110
static long Fixnum_Range[2] = {SMALLEST_FIXNUM , BIGGEST_FIXNUM};
115
asm(" bfexts 4(%sp){&8:&24},%d0");
116
asm(" bfexts 8(%sp){&8:&24},%d1");
117
asm(" muls.l %d1,%d0");
118
asm(" bvs.b result_is_nil");
119
asm(" cmp2.l %d0,_Fixnum_Range");
120
asm(" bcs.b result_is_nil");
121
asm(" moveq &0x1A,%d1");
122
asm(" bfins %d1,%d0{&0:&8}");
124
asm("result_is_nil:");
131
/* 20(sp) = arg0; 24(sp) = arg1 because of movem */
136
asm(" movem.l %d2-%d5,-(%sp)");
138
asm(" tst.b 21(%sp)");
140
asm(" bge.b coerce_1");
141
asm(" moveq &1,%d5");
142
asm(" neg.l 20(%sp)");
145
asm(" tst.b 25(%sp)");
147
asm(" bge.b after_coerce");
148
asm(" eori.b &1,%d5");
149
asm(" neg.l 24(%sp)");
150
asm("after_coerce:");
151
asm(" move.l 20(%sp),%d0");
152
asm(" move.l 24(%sp),%d1");
153
asm(" move.w %d0,%d2");
154
asm(" mulu %d1,%d2");
155
asm(" move.w %d1,%d4");
157
asm(" move.w %d1,%d3");
158
asm(" mulu %d0,%d3");
160
asm(" mulu %d0,%d4");
161
asm(" add.l %d4,%d3");
162
asm(" bcs.b result_is_nil");
163
asm(" mulu %d0,%d1");
164
asm(" bne.b result_is_nil");
166
asm(" add.w %d3,%d2");
167
asm(" bcs.b result_is_nil");
170
asm(" bne.b result_is_nil");
171
asm(" cmpi.w %d2,&0x7F");
172
asm(" bgt.b result_is_nil");
175
asm(" beq.b sign_is_right");
177
asm("sign_is_right:");
178
asm(" move.l %d2,-(%sp)");
179
asm(" move.b &0x1A,(%sp)");
180
asm(" move.l (%sp)+,%d0");
181
asm(" movem.l (%sp)+,%d2-%d5");
183
asm("result_is_nil:");
185
asm(" movem.l (%sp)+,%d2-%d5");
190
#endif /* hp9000s300 */
192
#endif /* (TYPE_CODE_LENGTH == 8) */
196
#define ONE ((unsigned long) 1)
198
#define HALF_WORD_SIZE (((sizeof (long)) * CHAR_BIT) / 2)
199
#define HALF_WORD_MASK ((ONE << HALF_WORD_SIZE) - 1)
200
#define MAX_MIDDLE (ONE << ((DATUM_LENGTH - 1) - HALF_WORD_SIZE))
201
#define MAX_FIXNUM (ONE << DATUM_LENGTH)
202
#define ABS(x) (((x) < 0) ? -(x) : (x))
205
DEFUN (Mul, (Arg1, Arg2),
207
AND SCHEME_OBJECT Arg2)
210
fast unsigned long Hi_A, Hi_B, Lo_A, Lo_B, Lo_C, Middle_C;
213
A = (FIXNUM_TO_LONG (Arg1));
214
B = (FIXNUM_TO_LONG (Arg2));
215
Sign = ((A < 0) == (B < 0));
218
Hi_A = ((A >> HALF_WORD_SIZE) & HALF_WORD_MASK);
219
Hi_B = ((B >> HALF_WORD_SIZE) & HALF_WORD_MASK);
220
if ((Hi_A > 0) && (Hi_B > 0))
222
Lo_A = (A & HALF_WORD_MASK);
223
Lo_B = (B & HALF_WORD_MASK);
224
Lo_C = (Lo_A * Lo_B);
225
if (Lo_C >= FIXNUM_SIGN_BIT)
227
Middle_C = (Lo_A * Hi_B) + (Hi_A * Lo_B);
228
if (Middle_C >= MAX_MIDDLE)
230
C = Lo_C + (Middle_C << HALF_WORD_SIZE);
231
if (LONG_TO_FIXNUM_P(C))
233
if (Sign || (C == 0))
234
return (LONG_TO_UNSIGNED_FIXNUM(C));
236
return (LONG_TO_UNSIGNED_FIXNUM(MAX_FIXNUM - C));
241
#endif /* not MUL_HANDLED */