~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to gmp3/mpn/x86/pentium/mod_1.asm

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
dnl  Intel P5 mpn_mod_1 -- mpn by limb remainder.
 
2
dnl 
 
3
dnl  P5: 28.0 cycles/limb
 
4
 
 
5
 
 
6
dnl  Copyright (C) 1999, 2000 Free Software Foundation, Inc.
 
7
dnl 
 
8
dnl  This file is part of the GNU MP Library.
 
9
dnl 
 
10
dnl  The GNU MP Library is free software; you can redistribute it and/or
 
11
dnl  modify it under the terms of the GNU Lesser General Public License as
 
12
dnl  published by the Free Software Foundation; either version 2.1 of the
 
13
dnl  License, or (at your option) any later version.
 
14
dnl 
 
15
dnl  The GNU MP Library is distributed in the hope that it will be useful,
 
16
dnl  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
dnl  Lesser General Public License for more details.
 
19
dnl 
 
20
dnl  You should have received a copy of the GNU Lesser General Public
 
21
dnl  License along with the GNU MP Library; see the file COPYING.LIB.  If
 
22
dnl  not, write to the Free Software Foundation, Inc., 59 Temple Place -
 
23
dnl  Suite 330, Boston, MA 02111-1307, USA.
 
24
 
 
25
 
 
26
include(`../config.m4')
 
27
 
 
28
 
 
29
C mp_limb_t mpn_mod_1 (mp_srcptr src, mp_size_t size, mp_limb_t divisor);
 
30
C mp_limb_t mpn_mod_1c (mp_srcptr src, mp_size_t size, mp_limb_t divisor,
 
31
C                       mp_limb_t carry);
 
32
C mp_limb_t mpn_preinv_mod_1 (mp_srcptr src, mp_size_t size, mp_limb_t divisor,
 
33
C                             mp_limb_t inverse);
 
34
C
 
35
C This code is not unlike mpn/x86/p6/mod_1.asm, it does the same sort of
 
36
C multiply by inverse without on-the-fly shifts.  See that code for some
 
37
C general comments.
 
38
C
 
39
C Alternatives:
 
40
C
 
41
C P5 shldl is 4 cycles, so shifting on the fly would be at least 5 cycles
 
42
C slower, probably more depending what it did to register usage.  Using MMX
 
43
C on P55 would be better, but still at least 4 or 5 instructions and so 2 or
 
44
C 3 cycles.
 
45
 
 
46
 
 
47
dnl  These thresholds are the sizes where the multiply by inverse method is
 
48
dnl  used, rather than plain "divl"s.  Minimum value 2.
 
49
dnl
 
50
dnl  MUL_NORM_THRESHOLD is for an already normalized divisor (high bit set),
 
51
dnl  MUL_UNNORM_THRESHOLD for an unnormalized divisor.
 
52
dnl
 
53
dnl  With the divl loop at 44 c/l and the inverse at 28 c/l with about 70
 
54
dnl  cycles to setup, the threshold should be about ceil(70/16)==5, which is
 
55
dnl  what happens in practice.
 
56
dnl
 
57
dnl  An unnormalized divisor gets an extra 40 cycles at the end for the
 
58
dnl  final (r*2^n)%(d*2^n) and shift.  This increases the threshold by about
 
59
dnl  40/16=3.
 
60
dnl
 
61
dnl  PIC adds between 4 and 7 cycles (not sure why it varies), but this
 
62
dnl  doesn't change the thresholds.
 
63
dnl
 
64
dnl  The entry sequence code that chooses between MUL_NORM_THRESHOLD and
 
65
dnl  MUL_UNNORM_THRESHOLD is a bit horrible, but it adds only 2 cycles
 
66
dnl  (branch free) and ensures the choice between div or mul is optimal.
 
67
 
 
68
deflit(MUL_NORM_THRESHOLD,   ifdef(`PIC',5,5))
 
69
deflit(MUL_UNNORM_THRESHOLD, ifdef(`PIC',8,8))
 
70
 
 
71
deflit(MUL_NORM_DELTA, eval(MUL_NORM_THRESHOLD - MUL_UNNORM_THRESHOLD))
 
72
 
 
73
 
 
74
defframe(PARAM_INVERSE, 16)   dnl mpn_preinv_mod_1
 
75
defframe(PARAM_CARRY,   16)   dnl mpn_mod_1c
 
76
defframe(PARAM_DIVISOR, 12)
 
77
defframe(PARAM_SIZE,     8)
 
78
defframe(PARAM_SRC,      4)
 
79
 
 
80
dnl  re-using parameter space
 
81
define(VAR_NORM,    `PARAM_DIVISOR')
 
82
define(VAR_INVERSE, `PARAM_SIZE')
 
83
 
 
84
        TEXT
 
85
 
 
86
        ALIGN(8)
 
87
PROLOGUE(mpn_preinv_mod_1)
 
88
deflit(`FRAME',0)
 
89
 
 
90
        pushl   %ebp    FRAME_pushl()
 
91
        pushl   %esi    FRAME_pushl()
 
92
 
 
93
        movl    PARAM_SRC, %esi
 
94
        movl    PARAM_SIZE, %edx
 
95
 
 
96
        pushl   %edi    FRAME_pushl()
 
97
        pushl   %ebx    FRAME_pushl()
 
98
 
 
99
        movl    PARAM_DIVISOR, %ebp
 
100
        movl    PARAM_INVERSE, %eax
 
101
 
 
102
        movl    -4(%esi,%edx,4), %edi   C src high limb
 
103
        leal    -8(%esi,%edx,4), %esi   C &src[size-2]
 
104
 
 
105
        movl    $0, VAR_NORM
 
106
        decl    %edx
 
107
 
 
108
        jnz     LF(mpn_mod_1,start_preinv)
 
109
 
 
110
        subl    %ebp, %edi              C src-divisor
 
111
        popl    %ebx
 
112
 
 
113
        sbbl    %ecx, %ecx              C -1 if underflow
 
114
        movl    %edi, %eax              C src-divisor
 
115
 
 
116
        andl    %ebp, %ecx              C d if underflow
 
117
        popl    %edi
 
118
 
 
119
        addl    %ecx, %eax              C remainder, with possible addback
 
120
        popl    %esi
 
121
 
 
122
        popl    %ebp
 
123
 
 
124
        ret
 
125
 
 
126
EPILOGUE()
 
127
 
 
128
 
 
129
        ALIGN(8)
 
130
PROLOGUE(mpn_mod_1c)
 
131
deflit(`FRAME',0)
 
132
 
 
133
        movl    PARAM_DIVISOR, %eax
 
134
        movl    PARAM_SIZE, %ecx
 
135
 
 
136
        sarl    $31, %eax                       C d highbit
 
137
        movl    PARAM_CARRY, %edx
 
138
 
 
139
        orl     %ecx, %ecx
 
140
        jz      LF(mpn_mod_1,done_edx)          C result==carry if size==0
 
141
 
 
142
        andl    $MUL_NORM_DELTA, %eax
 
143
        pushl   %ebp            FRAME_pushl()
 
144
 
 
145
        addl    $MUL_UNNORM_THRESHOLD, %eax     C norm or unnorm thresh
 
146
        pushl   %esi            FRAME_pushl()
 
147
 
 
148
        movl    PARAM_SRC, %esi
 
149
        movl    PARAM_DIVISOR, %ebp
 
150
 
 
151
        cmpl    %eax, %ecx
 
152
        jb      LF(mpn_mod_1,divide_top)
 
153
 
 
154
        movl    %edx, %eax              C carry as pretend src high limb
 
155
        leal    1(%ecx), %edx           C size+1
 
156
 
 
157
        cmpl    $0x1000000, %ebp
 
158
        jmp     LF(mpn_mod_1,mul_by_inverse_1c)
 
159
 
 
160
EPILOGUE()
 
161
 
 
162
 
 
163
        ALIGN(8)
 
164
PROLOGUE(mpn_mod_1)
 
165
deflit(`FRAME',0)
 
166
 
 
167
        movl    PARAM_SIZE, %ecx
 
168
        pushl   %ebp            FRAME_pushl()
 
169
 
 
170
        orl     %ecx, %ecx
 
171
        jz      L(done_zero)
 
172
 
 
173
        movl    PARAM_SRC, %eax
 
174
        movl    PARAM_DIVISOR, %ebp
 
175
 
 
176
        sarl    $31, %ebp               C -1 if divisor normalized
 
177
        movl    -4(%eax,%ecx,4), %eax   C src high limb
 
178
 
 
179
        movl    PARAM_DIVISOR, %edx
 
180
        pushl   %esi            FRAME_pushl()
 
181
 
 
182
        andl    $MUL_NORM_DELTA, %ebp
 
183
        cmpl    %edx, %eax              C carry flag if high<divisor
 
184
 
 
185
        sbbl    %edx, %edx              C -1 if high<divisor
 
186
        addl    $MUL_UNNORM_THRESHOLD, %ebp C norm or unnorm thresh
 
187
 
 
188
        addl    %edx, %ecx              C size-1 if high<divisor
 
189
        jz      L(done_eax)
 
190
 
 
191
        cmpl    %ebp, %ecx      
 
192
        movl    PARAM_DIVISOR, %ebp
 
193
 
 
194
        movl    PARAM_SRC, %esi
 
195
        jae     L(mul_by_inverse)
 
196
 
 
197
        andl    %eax, %edx              C high as initial carry if high<divisor
 
198
 
 
199
 
 
200
L(divide_top):
 
201
        C eax   scratch (quotient)
 
202
        C ebx
 
203
        C ecx   counter, limbs, decrementing
 
204
        C edx   scratch (remainder)
 
205
        C esi   src
 
206
        C edi
 
207
        C ebp   divisor
 
208
 
 
209
        movl    -4(%esi,%ecx,4), %eax
 
210
 
 
211
        divl    %ebp
 
212
 
 
213
        decl    %ecx
 
214
        jnz     L(divide_top)
 
215
 
 
216
 
 
217
        popl    %esi
 
218
        popl    %ebp
 
219
 
 
220
L(done_edx):
 
221
        movl    %edx, %eax
 
222
 
 
223
        ret
 
224
 
 
225
 
 
226
L(done_zero):
 
227
        xorl    %eax, %eax
 
228
        popl    %ebp
 
229
 
 
230
        ret
 
231
 
 
232
 
 
233
C -----------------------------------------------------------------------------
 
234
C
 
235
C The divisor is normalized using the same code as the pentium
 
236
C count_leading_zeros in longlong.h.  Going through the GOT for PIC costs a
 
237
C couple of cycles, but is more or less unavoidable.
 
238
 
 
239
 
 
240
        ALIGN(8)
 
241
L(mul_by_inverse):
 
242
        C eax   src high limb
 
243
        C ebx
 
244
        C ecx   size or size-1
 
245
        C edx
 
246
        C esi   src
 
247
        C edi
 
248
        C ebp   divisor
 
249
 
 
250
        movl    PARAM_SIZE, %edx
 
251
        cmpl    $0x1000000, %ebp
 
252
 
 
253
L(mul_by_inverse_1c):
 
254
        sbbl    %ecx, %ecx
 
255
        cmpl    $0x10000, %ebp
 
256
 
 
257
        sbbl    $0, %ecx
 
258
        cmpl    $0x100, %ebp
 
259
 
 
260
        sbbl    $0, %ecx
 
261
        pushl   %edi            FRAME_pushl()
 
262
 
 
263
        pushl   %ebx            FRAME_pushl()
 
264
        movl    %ebp, %ebx              C d
 
265
 
 
266
ifdef(`PIC',`
 
267
        call    L(here)
 
268
L(here):
 
269
        popl    %edi
 
270
        leal    25(,%ecx,8), %ecx       C 0,-1,-2,-3 -> 25,17,9,1
 
271
 
 
272
        shrl    %cl, %ebx
 
273
        addl    $_GLOBAL_OFFSET_TABLE_+[.-L(here)], %edi
 
274
 
 
275
        C AGI
 
276
        movl    __clz_tab@GOT(%edi), %edi
 
277
        addl    $-34, %ecx
 
278
 
 
279
        C AGI
 
280
        movb    (%ebx,%edi), %bl
 
281
 
 
282
',`
 
283
        leal    25(,%ecx,8), %ecx       C 0,-1,-2,-3 -> 25,17,9,1
 
284
 
 
285
        shrl    %cl, %ebx
 
286
        addl    $-34, %ecx
 
287
 
 
288
        C AGI
 
289
        movb    __clz_tab(%ebx), %bl
 
290
')
 
291
        movl    %eax, %edi              C carry -> n1
 
292
 
 
293
        addl    %ebx, %ecx              C -34 + c + __clz_tab[d>>c] = -clz-1
 
294
        leal    -8(%esi,%edx,4), %esi   C &src[size-2]
 
295
 
 
296
        xorl    $-1, %ecx               C clz
 
297
        movl    $-1, %edx
 
298
 
 
299
        ASSERT(e,`pushl %eax            C clz calculation same as bsrl
 
300
                bsrl    %ebp, %eax
 
301
                xorl    $31, %eax
 
302
                cmpl    %eax, %ecx
 
303
                popl    %eax')
 
304
 
 
305
        shll    %cl, %ebp               C d normalized
 
306
        movl    %ecx, VAR_NORM
 
307
 
 
308
        subl    %ebp, %edx              C (b-d)-1, so edx:eax = b*(b-d)-1
 
309
        movl    $-1, %eax
 
310
 
 
311
        divl    %ebp                    C floor (b*(b-d)-1) / d
 
312
 
 
313
L(start_preinv):
 
314
        movl    %eax, VAR_INVERSE
 
315
        movl    %ebp, %eax              C d
 
316
 
 
317
        movl    %ecx, %edx              C fake high, will cancel
 
318
 
 
319
 
 
320
C For mpn_mod_1 and mpn_preinv_mod_1, the initial carry in %edi is the src
 
321
C high limb, and this may be greater than the divisor and may need one copy
 
322
C of the divisor subtracted (only one, because the divisor is normalized).
 
323
C This is accomplished by having the initial ecx:edi act as a fake previous
 
324
C n2:n10.  The initial edx:eax is d, acting as a fake (q1+1)*d which is
 
325
C subtracted from ecx:edi, with the usual addback if it produces an
 
326
C underflow.
 
327
 
 
328
 
 
329
L(inverse_top):
 
330
        C eax   scratch (n10, n1, q1, etc)
 
331
        C ebx   scratch (nadj, src limit)
 
332
        C ecx   old n2
 
333
        C edx   scratch
 
334
        C esi   src pointer, &src[size-2] to &src[0]
 
335
        C edi   old n10
 
336
        C ebp   d
 
337
 
 
338
        subl    %eax, %edi         C low  n - (q1+1)*d
 
339
        movl    (%esi), %eax       C new n10
 
340
 
 
341
        sbbl    %edx, %ecx         C high n - (q1+1)*d, 0 or -1
 
342
        movl    %ebp, %ebx         C d
 
343
 
 
344
        sarl    $31, %eax          C -n1
 
345
        andl    %ebp, %ecx         C d if underflow
 
346
 
 
347
        addl    %edi, %ecx         C remainder -> n2, and possible addback
 
348
        ASSERT(b,`cmpl %ebp, %ecx')
 
349
        andl    %eax, %ebx         C -n1 & d
 
350
 
 
351
        movl    (%esi), %edi       C n10
 
352
        andl    $1, %eax           C n1
 
353
 
 
354
        addl    %ecx, %eax         C n2+n1
 
355
        addl    %edi, %ebx         C nadj = n10 + (-n1 & d), ignoring overflow
 
356
 
 
357
        mull    VAR_INVERSE        C m*(n2+n1)
 
358
 
 
359
        addl    %eax, %ebx         C low(m*(n2+n1) + nadj), giving carry flag
 
360
        leal    1(%ecx), %eax      C 1+n2
 
361
 
 
362
        adcl    %edx, %eax         C 1 + high[n2<<32 + m*(n2+n1) + nadj] = q1+1
 
363
        movl    PARAM_SRC, %ebx
 
364
 
 
365
        sbbl    $0, %eax           C use q1 if q1+1 overflows
 
366
        subl    $4, %esi           C step src ptr
 
367
 
 
368
        mull    %ebp               C (q1+1)*d
 
369
 
 
370
        cmpl    %ebx, %esi
 
371
        jae     L(inverse_top)
 
372
 
 
373
 
 
374
 
 
375
        C %edi (after subtract and addback) is the remainder modulo d*2^n
 
376
        C and must be reduced to 0<=r<d by calculating r*2^n mod d*2^n and
 
377
        C right shifting by n.
 
378
        C
 
379
        C If d was already normalized on entry so that n==0 then nothing is
 
380
        C needed here.  This is always the case for preinv_mod_1.  For mod_1
 
381
        C or mod_1c the chance of n==0 is low, but about 40 cycles can be
 
382
        C saved.
 
383
 
 
384
        subl    %eax, %edi         C low  n - (q1+1)*d
 
385
        movl    %ecx, %ebx         C n2
 
386
 
 
387
        sbbl    %edx, %ebx         C high n - (q1+1)*d, 0 or -1
 
388
        xorl    %esi, %esi         C next n2
 
389
 
 
390
        andl    %ebp, %ebx         C d if underflow
 
391
        movl    VAR_NORM, %ecx
 
392
 
 
393
        addl    %ebx, %edi         C remainder, with possible addback
 
394
        orl     %ecx, %ecx
 
395
 
 
396
        jz      L(done_mul_edi)
 
397
 
 
398
 
 
399
        C Here using %esi=n2 and %edi=n10, unlike the above
 
400
 
 
401
        shldl(  %cl, %edi, %esi)   C n2
 
402
 
 
403
        shll    %cl, %edi          C n10
 
404
 
 
405
        movl    %edi, %eax         C n10
 
406
        movl    %edi, %ebx         C n10
 
407
 
 
408
        sarl    $31, %ebx          C -n1
 
409
 
 
410
        shrl    $31, %eax          C n1
 
411
        andl    %ebp, %ebx         C -n1 & d
 
412
 
 
413
        addl    %esi, %eax         C n2+n1
 
414
        addl    %edi, %ebx         C nadj = n10 + (-n1 & d), ignoring overflow
 
415
 
 
416
        mull    VAR_INVERSE        C m*(n2+n1)
 
417
 
 
418
        addl    %eax, %ebx         C m*(n2+n1) + nadj, low giving carry flag
 
419
        leal    1(%esi), %eax      C 1+n2
 
420
 
 
421
        adcl    %edx, %eax         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
 
422
 
 
423
        sbbl    $0, %eax           C use q1 if q1+1 overflows
 
424
 
 
425
        mull    %ebp               C (q1+1)*d
 
426
 
 
427
        subl    %eax, %edi         C low  n - (q1+1)*d
 
428
        popl    %ebx
 
429
 
 
430
        sbbl    %edx, %esi         C high n - (q1+1)*d, 0 or -1
 
431
        movl    %edi, %eax
 
432
 
 
433
        andl    %ebp, %esi         C d if underflow
 
434
        popl    %edi
 
435
 
 
436
        addl    %esi, %eax         C addback if underflow
 
437
        popl    %esi
 
438
 
 
439
        shrl    %cl, %eax          C denorm remainder
 
440
        popl    %ebp
 
441
 
 
442
        ret
 
443
 
 
444
 
 
445
L(done_mul_edi):
 
446
        movl    %edi, %eax
 
447
        popl    %ebx
 
448
 
 
449
        popl    %edi
 
450
L(done_eax):
 
451
        popl    %esi
 
452
 
 
453
        popl    %ebp
 
454
 
 
455
        ret
 
456
 
 
457
EPILOGUE()