~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/gmp/mpn/x86/k7/mmx/divrem_1.asm

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-05-17 02:46:26 UTC
  • Revision ID: james.westby@ubuntu.com-20060517024626-lljr08ftv9g9vefl
Tags: upstream-0.9h-20060510
ImportĀ upstreamĀ versionĀ 0.9h-20060510

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
dnl  AMD K7 mpn_divrem_1, mpn_divrem_1c, mpn_preinv_divrem_1 -- mpn by limb
 
2
dnl  division.
 
3
 
 
4
dnl  Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
5
dnl
 
6
dnl  This file is part of the GNU MP Library.
 
7
dnl
 
8
dnl  The GNU MP Library is free software; you can redistribute it and/or
 
9
dnl  modify it under the terms of the GNU Lesser General Public License as
 
10
dnl  published by the Free Software Foundation; either version 2.1 of the
 
11
dnl  License, or (at your option) any later version.
 
12
dnl
 
13
dnl  The GNU MP Library is distributed in the hope that it will be useful,
 
14
dnl  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
dnl  Lesser General Public License for more details.
 
17
dnl
 
18
dnl  You should have received a copy of the GNU Lesser General Public
 
19
dnl  License along with the GNU MP Library; see the file COPYING.LIB.  If
 
20
dnl  not, write to the Free Software Foundation, Inc., 59 Temple Place -
 
21
dnl  Suite 330, Boston, MA 02111-1307, USA.
 
22
 
 
23
include(`../config.m4')
 
24
 
 
25
 
 
26
C K7: 17.0 cycles/limb integer part, 15.0 cycles/limb fraction part.
 
27
 
 
28
 
 
29
C mp_limb_t mpn_divrem_1 (mp_ptr dst, mp_size_t xsize,
 
30
C                         mp_srcptr src, mp_size_t size,
 
31
C                         mp_limb_t divisor);
 
32
C mp_limb_t mpn_divrem_1c (mp_ptr dst, mp_size_t xsize,
 
33
C                          mp_srcptr src, mp_size_t size,
 
34
C                          mp_limb_t divisor, mp_limb_t carry);
 
35
C mp_limb_t mpn_preinv_divrem_1 (mp_ptr dst, mp_size_t xsize,
 
36
C                                mp_srcptr src, mp_size_t size,
 
37
C                                mp_limb_t divisor, mp_limb_t inverse,
 
38
C                                unsigned shift);
 
39
C
 
40
C The method and nomenclature follow part 8 of "Division by Invariant
 
41
C Integers using Multiplication" by Granlund and Montgomery, reference in
 
42
C gmp.texi.
 
43
C
 
44
C The "and"s shown in the paper are done here with "cmov"s.  "m" is written
 
45
C for m', and "d" for d_norm, which won't cause any confusion since it's
 
46
C only the normalized divisor that's of any use in the code.  "b" is written
 
47
C for 2^N, the size of a limb, N being 32 here.
 
48
C
 
49
C mpn_divrem_1 and mpn_preinv_divrem_1 avoid one division if the src high
 
50
C limb is less than the divisor.  mpn_divrem_1c doesn't check for a zero
 
51
C carry, since in normal circumstances that will be a very rare event.
 
52
C
 
53
C The test for skipping a division is branch free (once size>=1 is tested).
 
54
C The store to the destination high limb is 0 when a divide is skipped, or
 
55
C if it's not skipped then a copy of the src high limb is used.  The latter
 
56
C is in case src==dst.
 
57
C
 
58
C There's a small bias towards expecting xsize==0, by having code for
 
59
C xsize==0 in a straight line and xsize!=0 under forward jumps.
 
60
C
 
61
C Alternatives:
 
62
C
 
63
C If the divisor is normalized (high bit set) then a division step can
 
64
C always be skipped, since the high destination limb is always 0 or 1 in
 
65
C that case.  It doesn't seem worth checking for this though, since it
 
66
C probably occurs infrequently, in particular note that big_base for a
 
67
C decimal mpn_get_str is not normalized in a 32-bit limb.
 
68
 
 
69
 
 
70
dnl  MUL_THRESHOLD is the value of xsize+size at which the multiply by
 
71
dnl  inverse method is used, rather than plain "divl"s.  Minimum value 1.
 
72
dnl
 
73
dnl  The inverse takes about 50 cycles to calculate, but after that the
 
74
dnl  multiply is 17 c/l versus division at 42 c/l.
 
75
dnl
 
76
dnl  At 3 limbs the mul is a touch faster than div on the integer part, and
 
77
dnl  even more so on the fractional part.
 
78
 
 
79
deflit(MUL_THRESHOLD, 3)
 
80
 
 
81
 
 
82
defframe(PARAM_PREINV_SHIFT,   28)  dnl mpn_preinv_divrem_1
 
83
defframe(PARAM_PREINV_INVERSE, 24)  dnl mpn_preinv_divrem_1
 
84
defframe(PARAM_CARRY,  24)          dnl mpn_divrem_1c
 
85
defframe(PARAM_DIVISOR,20)
 
86
defframe(PARAM_SIZE,   16)
 
87
defframe(PARAM_SRC,    12)
 
88
defframe(PARAM_XSIZE,  8)
 
89
defframe(PARAM_DST,    4)
 
90
 
 
91
defframe(SAVE_EBX,    -4)
 
92
defframe(SAVE_ESI,    -8)
 
93
defframe(SAVE_EDI,    -12)
 
94
defframe(SAVE_EBP,    -16)
 
95
 
 
96
defframe(VAR_NORM,    -20)
 
97
defframe(VAR_INVERSE, -24)
 
98
defframe(VAR_SRC,     -28)
 
99
defframe(VAR_DST,     -32)
 
100
defframe(VAR_DST_STOP,-36)
 
101
 
 
102
deflit(STACK_SPACE, 36)
 
103
 
 
104
        TEXT
 
105
        ALIGN(32)
 
106
 
 
107
PROLOGUE(mpn_preinv_divrem_1)
 
108
deflit(`FRAME',0)
 
109
        movl    PARAM_XSIZE, %ecx
 
110
        movl    PARAM_DST, %edx
 
111
        subl    $STACK_SPACE, %esp      FRAME_subl_esp(STACK_SPACE)
 
112
 
 
113
        movl    %esi, SAVE_ESI
 
114
        movl    PARAM_SRC, %esi
 
115
 
 
116
        movl    %ebx, SAVE_EBX
 
117
        movl    PARAM_SIZE, %ebx
 
118
 
 
119
        leal    8(%edx,%ecx,4), %edx    C &dst[xsize+2]
 
120
        movl    %ebp, SAVE_EBP
 
121
        movl    PARAM_DIVISOR, %ebp
 
122
 
 
123
        movl    %edx, VAR_DST_STOP      C &dst[xsize+2]
 
124
        movl    %edi, SAVE_EDI
 
125
        xorl    %edi, %edi              C carry
 
126
 
 
127
        movl    -4(%esi,%ebx,4), %eax   C src high limb
 
128
        xor     %ecx, %ecx
 
129
 
 
130
        C
 
131
 
 
132
        C
 
133
 
 
134
        cmpl    %ebp, %eax              C high cmp divisor
 
135
 
 
136
        cmovc(  %eax, %edi)             C high is carry if high<divisor
 
137
        cmovnc( %eax, %ecx)             C 0 if skip div, src high if not
 
138
                                        C (the latter in case src==dst)
 
139
 
 
140
        movl    %ecx, -12(%edx,%ebx,4)  C dst high limb
 
141
        sbbl    $0, %ebx                C skip one division if high<divisor
 
142
        movl    PARAM_PREINV_SHIFT, %ecx
 
143
 
 
144
        leal    -8(%edx,%ebx,4), %edx   C &dst[xsize+size]
 
145
        movl    $32, %eax
 
146
 
 
147
        movl    %edx, VAR_DST           C &dst[xsize+size]
 
148
 
 
149
        shll    %cl, %ebp               C d normalized
 
150
        subl    %ecx, %eax
 
151
        movl    %ecx, VAR_NORM
 
152
 
 
153
        movd    %eax, %mm7              C rshift
 
154
        movl    PARAM_PREINV_INVERSE, %eax
 
155
        jmp     L(start_preinv)
 
156
 
 
157
EPILOGUE()
 
158
 
 
159
 
 
160
        ALIGN(16)
 
161
 
 
162
PROLOGUE(mpn_divrem_1c)
 
163
deflit(`FRAME',0)
 
164
        movl    PARAM_CARRY, %edx
 
165
        movl    PARAM_SIZE, %ecx
 
166
        subl    $STACK_SPACE, %esp
 
167
deflit(`FRAME',STACK_SPACE)
 
168
 
 
169
        movl    %ebx, SAVE_EBX
 
170
        movl    PARAM_XSIZE, %ebx
 
171
 
 
172
        movl    %edi, SAVE_EDI
 
173
        movl    PARAM_DST, %edi
 
174
 
 
175
        movl    %ebp, SAVE_EBP
 
176
        movl    PARAM_DIVISOR, %ebp
 
177
 
 
178
        movl    %esi, SAVE_ESI
 
179
        movl    PARAM_SRC, %esi
 
180
 
 
181
        leal    -4(%edi,%ebx,4), %edi   C &dst[xsize-1]
 
182
        jmp     L(start_1c)
 
183
 
 
184
EPILOGUE()
 
185
 
 
186
 
 
187
        C offset 0xa1, close enough to aligned
 
188
PROLOGUE(mpn_divrem_1)
 
189
deflit(`FRAME',0)
 
190
 
 
191
        movl    PARAM_SIZE, %ecx
 
192
        movl    $0, %edx                C initial carry (if can't skip a div)
 
193
        subl    $STACK_SPACE, %esp
 
194
deflit(`FRAME',STACK_SPACE)
 
195
 
 
196
        movl    %esi, SAVE_ESI
 
197
        movl    PARAM_SRC, %esi
 
198
 
 
199
        movl    %ebx, SAVE_EBX
 
200
        movl    PARAM_XSIZE, %ebx
 
201
 
 
202
        movl    %ebp, SAVE_EBP
 
203
        movl    PARAM_DIVISOR, %ebp
 
204
        orl     %ecx, %ecx              C size
 
205
 
 
206
        movl    %edi, SAVE_EDI
 
207
        movl    PARAM_DST, %edi
 
208
        leal    -4(%edi,%ebx,4), %edi   C &dst[xsize-1]
 
209
 
 
210
        jz      L(no_skip_div)          C if size==0
 
211
        movl    -4(%esi,%ecx,4), %eax   C src high limb
 
212
        xorl    %esi, %esi
 
213
 
 
214
        cmpl    %ebp, %eax              C high cmp divisor
 
215
 
 
216
        cmovc(  %eax, %edx)             C high is carry if high<divisor
 
217
        cmovnc( %eax, %esi)             C 0 if skip div, src high if not
 
218
 
 
219
        movl    %esi, (%edi,%ecx,4)     C dst high limb
 
220
        sbbl    $0, %ecx                C size-1 if high<divisor
 
221
        movl    PARAM_SRC, %esi         C reload
 
222
L(no_skip_div):
 
223
 
 
224
 
 
225
L(start_1c):
 
226
        C eax
 
227
        C ebx   xsize
 
228
        C ecx   size
 
229
        C edx   carry
 
230
        C esi   src
 
231
        C edi   &dst[xsize-1]
 
232
        C ebp   divisor
 
233
 
 
234
        leal    (%ebx,%ecx), %eax       C size+xsize
 
235
        cmpl    $MUL_THRESHOLD, %eax
 
236
        jae     L(mul_by_inverse)
 
237
 
 
238
 
 
239
C With MUL_THRESHOLD set to 3, the simple loops here only do 0 to 2 limbs.
 
240
C It'd be possible to write them out without the looping, but no speedup
 
241
C would be expected.
 
242
C
 
243
C Using PARAM_DIVISOR instead of %ebp measures 1 cycle/loop faster on the
 
244
C integer part, but curiously not on the fractional part, where %ebp is a
 
245
C (fixed) couple of cycles faster.
 
246
 
 
247
        orl     %ecx, %ecx
 
248
        jz      L(divide_no_integer)
 
249
 
 
250
L(divide_integer):
 
251
        C eax   scratch (quotient)
 
252
        C ebx   xsize
 
253
        C ecx   counter
 
254
        C edx   scratch (remainder)
 
255
        C esi   src
 
256
        C edi   &dst[xsize-1]
 
257
        C ebp   divisor
 
258
 
 
259
        movl    -4(%esi,%ecx,4), %eax
 
260
 
 
261
        divl    PARAM_DIVISOR
 
262
 
 
263
        movl    %eax, (%edi,%ecx,4)
 
264
        decl    %ecx
 
265
        jnz     L(divide_integer)
 
266
 
 
267
 
 
268
L(divide_no_integer):
 
269
        movl    PARAM_DST, %edi
 
270
        orl     %ebx, %ebx
 
271
        jnz     L(divide_fraction)
 
272
 
 
273
L(divide_done):
 
274
        movl    SAVE_ESI, %esi
 
275
        movl    SAVE_EDI, %edi
 
276
        movl    %edx, %eax
 
277
 
 
278
        movl    SAVE_EBX, %ebx
 
279
        movl    SAVE_EBP, %ebp
 
280
        addl    $STACK_SPACE, %esp
 
281
 
 
282
        ret
 
283
 
 
284
 
 
285
L(divide_fraction):
 
286
        C eax   scratch (quotient)
 
287
        C ebx   counter
 
288
        C ecx
 
289
        C edx   scratch (remainder)
 
290
        C esi
 
291
        C edi   dst
 
292
        C ebp   divisor
 
293
 
 
294
        movl    $0, %eax
 
295
 
 
296
        divl    %ebp
 
297
 
 
298
        movl    %eax, -4(%edi,%ebx,4)
 
299
        decl    %ebx
 
300
        jnz     L(divide_fraction)
 
301
 
 
302
        jmp     L(divide_done)
 
303
 
 
304
 
 
305
 
 
306
C -----------------------------------------------------------------------------
 
307
 
 
308
L(mul_by_inverse):
 
309
        C eax
 
310
        C ebx   xsize
 
311
        C ecx   size
 
312
        C edx   carry
 
313
        C esi   src
 
314
        C edi   &dst[xsize-1]
 
315
        C ebp   divisor
 
316
 
 
317
        bsrl    %ebp, %eax              C 31-l
 
318
 
 
319
        leal    12(%edi), %ebx          C &dst[xsize+2], loop dst stop
 
320
        leal    4(%edi,%ecx,4), %edi    C &dst[xsize+size]
 
321
 
 
322
        movl    %edi, VAR_DST
 
323
        movl    %ebx, VAR_DST_STOP
 
324
 
 
325
        movl    %ecx, %ebx              C size
 
326
        movl    $31, %ecx
 
327
 
 
328
        movl    %edx, %edi              C carry
 
329
        movl    $-1, %edx
 
330
 
 
331
        C
 
332
 
 
333
        xorl    %eax, %ecx              C l
 
334
        incl    %eax                    C 32-l
 
335
 
 
336
        shll    %cl, %ebp               C d normalized
 
337
        movl    %ecx, VAR_NORM
 
338
 
 
339
        movd    %eax, %mm7
 
340
 
 
341
        movl    $-1, %eax
 
342
        subl    %ebp, %edx              C (b-d)-1 giving edx:eax = b*(b-d)-1
 
343
 
 
344
        divl    %ebp                    C floor (b*(b-d)-1) / d
 
345
 
 
346
L(start_preinv):
 
347
        C eax   inverse
 
348
        C ebx   size
 
349
        C ecx   shift
 
350
        C edx
 
351
        C esi   src
 
352
        C edi   carry
 
353
        C ebp   divisor
 
354
        C
 
355
        C mm7   rshift
 
356
 
 
357
        orl     %ebx, %ebx              C size
 
358
        movl    %eax, VAR_INVERSE
 
359
        leal    -12(%esi,%ebx,4), %eax  C &src[size-3]
 
360
 
 
361
        jz      L(start_zero)
 
362
        movl    %eax, VAR_SRC
 
363
        cmpl    $1, %ebx
 
364
 
 
365
        movl    8(%eax), %esi           C src high limb
 
366
        jz      L(start_one)
 
367
 
 
368
L(start_two_or_more):
 
369
        movl    4(%eax), %edx           C src second highest limb
 
370
 
 
371
        shldl(  %cl, %esi, %edi)        C n2 = carry,high << l
 
372
 
 
373
        shldl(  %cl, %edx, %esi)        C n10 = high,second << l
 
374
 
 
375
        cmpl    $2, %ebx
 
376
        je      L(integer_two_left)
 
377
        jmp     L(integer_top)
 
378
 
 
379
 
 
380
L(start_one):
 
381
        shldl(  %cl, %esi, %edi)        C n2 = carry,high << l
 
382
 
 
383
        shll    %cl, %esi               C n10 = high << l
 
384
        movl    %eax, VAR_SRC
 
385
        jmp     L(integer_one_left)
 
386
 
 
387
 
 
388
L(start_zero):
 
389
        C Can be here with xsize==0 if mpn_preinv_divrem_1 had size==1 and
 
390
        C skipped a division.
 
391
 
 
392
        shll    %cl, %edi               C n2 = carry << l
 
393
        movl    %edi, %eax              C return value for zero_done
 
394
        cmpl    $0, PARAM_XSIZE
 
395
 
 
396
        je      L(zero_done)
 
397
        jmp     L(fraction_some)
 
398
 
 
399
 
 
400
 
 
401
C -----------------------------------------------------------------------------
 
402
C
 
403
C The multiply by inverse loop is 17 cycles, and relies on some out-of-order
 
404
C execution.  The instruction scheduling is important, with various
 
405
C apparently equivalent forms running 1 to 5 cycles slower.
 
406
C
 
407
C A lower bound for the time would seem to be 16 cycles, based on the
 
408
C following successive dependencies.
 
409
C
 
410
C                     cycles
 
411
C               n2+n1   1
 
412
C               mul     6
 
413
C               q1+1    1
 
414
C               mul     6
 
415
C               sub     1
 
416
C               addback 1
 
417
C                      ---
 
418
C                      16
 
419
C
 
420
C This chain is what the loop has already, but 16 cycles isn't achieved.
 
421
C K7 has enough decode, and probably enough execute (depending maybe on what
 
422
C a mul actually consumes), but nothing running under 17 has been found.
 
423
C
 
424
C In theory n2+n1 could be done in the sub and addback stages (by
 
425
C calculating both n2 and n2+n1 there), but lack of registers makes this an
 
426
C unlikely proposition.
 
427
C
 
428
C The jz in the loop keeps the q1+1 stage to 1 cycle.  Handling an overflow
 
429
C from q1+1 with an "sbbl $0, %ebx" would add a cycle to the dependent
 
430
C chain, and nothing better than 18 cycles has been found when using it.
 
431
C The jump is taken only when q1 is 0xFFFFFFFF, and on random data this will
 
432
C be an extremely rare event.
 
433
C
 
434
C Branch mispredictions will hit random occurrances of q1==0xFFFFFFFF, but
 
435
C if some special data is coming out with this always, the q1_ff special
 
436
C case actually runs at 15 c/l.  0x2FFF...FFFD divided by 3 is a good way to
 
437
C induce the q1_ff case, for speed measurements or testing.  Note that
 
438
C 0xFFF...FFF divided by 1 or 2 doesn't induce it.
 
439
C
 
440
C The instruction groupings and empty comments show the cycles for a naive
 
441
C in-order view of the code (conveniently ignoring the load latency on
 
442
C VAR_INVERSE).  This shows some of where the time is going, but is nonsense
 
443
C to the extent that out-of-order execution rearranges it.  In this case
 
444
C there's 19 cycles shown, but it executes at 17.
 
445
 
 
446
        ALIGN(16)
 
447
L(integer_top):
 
448
        C eax   scratch
 
449
        C ebx   scratch (nadj, q1)
 
450
        C ecx   scratch (src, dst)
 
451
        C edx   scratch
 
452
        C esi   n10
 
453
        C edi   n2
 
454
        C ebp   divisor
 
455
        C
 
456
        C mm0   scratch (src qword)
 
457
        C mm7   rshift for normalization
 
458
 
 
459
        cmpl    $0x80000000, %esi  C n1 as 0=c, 1=nc
 
460
        movl    %edi, %eax         C n2
 
461
        movl    VAR_SRC, %ecx
 
462
 
 
463
        leal    (%ebp,%esi), %ebx
 
464
        cmovc(  %esi, %ebx)        C nadj = n10 + (-n1 & d), ignoring overflow
 
465
        sbbl    $-1, %eax          C n2+n1
 
466
 
 
467
        mull    VAR_INVERSE        C m*(n2+n1)
 
468
 
 
469
        movq    (%ecx), %mm0       C next limb and the one below it
 
470
        subl    $4, %ecx
 
471
 
 
472
        movl    %ecx, VAR_SRC
 
473
 
 
474
        C
 
475
 
 
476
        addl    %ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
 
477
        leal    1(%edi), %ebx      C n2+1
 
478
        movl    %ebp, %eax         C d
 
479
 
 
480
        C
 
481
 
 
482
        adcl    %edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
 
483
        jz      L(q1_ff)
 
484
        movl    VAR_DST, %ecx
 
485
 
 
486
        mull    %ebx               C (q1+1)*d
 
487
 
 
488
        psrlq   %mm7, %mm0
 
489
 
 
490
        leal    -4(%ecx), %ecx
 
491
 
 
492
        C
 
493
 
 
494
        subl    %eax, %esi
 
495
        movl    VAR_DST_STOP, %eax
 
496
 
 
497
        C
 
498
 
 
499
        sbbl    %edx, %edi         C n - (q1+1)*d
 
500
        movl    %esi, %edi         C remainder -> n2
 
501
        leal    (%ebp,%esi), %edx
 
502
 
 
503
        movd    %mm0, %esi
 
504
 
 
505
        cmovc(  %edx, %edi)        C n - q1*d if underflow from using q1+1
 
506
        sbbl    $0, %ebx           C q
 
507
        cmpl    %eax, %ecx
 
508
 
 
509
        movl    %ebx, (%ecx)
 
510
        movl    %ecx, VAR_DST
 
511
        jne     L(integer_top)
 
512
 
 
513
 
 
514
L(integer_loop_done):
 
515
 
 
516
 
 
517
C -----------------------------------------------------------------------------
 
518
C
 
519
C Here, and in integer_one_left below, an sbbl $0 is used rather than a jz
 
520
C q1_ff special case.  This make the code a bit smaller and simpler, and
 
521
C costs only 1 cycle (each).
 
522
 
 
523
L(integer_two_left):
 
524
        C eax   scratch
 
525
        C ebx   scratch (nadj, q1)
 
526
        C ecx   scratch (src, dst)
 
527
        C edx   scratch
 
528
        C esi   n10
 
529
        C edi   n2
 
530
        C ebp   divisor
 
531
        C
 
532
        C mm7   rshift
 
533
 
 
534
        cmpl    $0x80000000, %esi  C n1 as 0=c, 1=nc
 
535
        movl    %edi, %eax         C n2
 
536
        movl    PARAM_SRC, %ecx
 
537
 
 
538
        leal    (%ebp,%esi), %ebx
 
539
        cmovc(  %esi, %ebx)        C nadj = n10 + (-n1 & d), ignoring overflow
 
540
        sbbl    $-1, %eax          C n2+n1
 
541
 
 
542
        mull    VAR_INVERSE        C m*(n2+n1)
 
543
 
 
544
        movd    (%ecx), %mm0       C src low limb
 
545
 
 
546
        movl    VAR_DST_STOP, %ecx
 
547
 
 
548
        C
 
549
 
 
550
        addl    %ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
 
551
        leal    1(%edi), %ebx      C n2+1
 
552
        movl    %ebp, %eax         C d
 
553
 
 
554
        adcl    %edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
 
555
 
 
556
        sbbl    $0, %ebx
 
557
 
 
558
        mull    %ebx               C (q1+1)*d
 
559
 
 
560
        psllq   $32, %mm0
 
561
 
 
562
        psrlq   %mm7, %mm0
 
563
 
 
564
        C
 
565
 
 
566
        subl    %eax, %esi
 
567
 
 
568
        C
 
569
 
 
570
        sbbl    %edx, %edi         C n - (q1+1)*d
 
571
        movl    %esi, %edi         C remainder -> n2
 
572
        leal    (%ebp,%esi), %edx
 
573
 
 
574
        movd    %mm0, %esi
 
575
 
 
576
        cmovc(  %edx, %edi)        C n - q1*d if underflow from using q1+1
 
577
        sbbl    $0, %ebx           C q
 
578
 
 
579
        movl    %ebx, -4(%ecx)
 
580
 
 
581
 
 
582
C -----------------------------------------------------------------------------
 
583
L(integer_one_left):
 
584
        C eax   scratch
 
585
        C ebx   scratch (nadj, q1)
 
586
        C ecx   dst
 
587
        C edx   scratch
 
588
        C esi   n10
 
589
        C edi   n2
 
590
        C ebp   divisor
 
591
        C
 
592
        C mm7   rshift
 
593
 
 
594
        movl    VAR_DST_STOP, %ecx
 
595
        cmpl    $0x80000000, %esi  C n1 as 0=c, 1=nc
 
596
        movl    %edi, %eax         C n2
 
597
 
 
598
        leal    (%ebp,%esi), %ebx
 
599
        cmovc(  %esi, %ebx)        C nadj = n10 + (-n1 & d), ignoring overflow
 
600
        sbbl    $-1, %eax          C n2+n1
 
601
 
 
602
        mull    VAR_INVERSE        C m*(n2+n1)
 
603
 
 
604
        C
 
605
 
 
606
        C
 
607
 
 
608
        C
 
609
 
 
610
        addl    %ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
 
611
        leal    1(%edi), %ebx      C n2+1
 
612
        movl    %ebp, %eax         C d
 
613
 
 
614
        C
 
615
 
 
616
        adcl    %edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
 
617
 
 
618
        sbbl    $0, %ebx           C q1 if q1+1 overflowed
 
619
 
 
620
        mull    %ebx
 
621
 
 
622
        C
 
623
 
 
624
        C
 
625
 
 
626
        C
 
627
 
 
628
        subl    %eax, %esi
 
629
 
 
630
        C
 
631
 
 
632
        sbbl    %edx, %edi         C n - (q1+1)*d
 
633
        movl    %esi, %edi         C remainder -> n2
 
634
        leal    (%ebp,%esi), %edx
 
635
 
 
636
        cmovc(  %edx, %edi)        C n - q1*d if underflow from using q1+1
 
637
        sbbl    $0, %ebx           C q
 
638
 
 
639
        movl    %ebx, -8(%ecx)
 
640
        subl    $8, %ecx
 
641
 
 
642
 
 
643
 
 
644
L(integer_none):
 
645
        cmpl    $0, PARAM_XSIZE
 
646
        jne     L(fraction_some)
 
647
 
 
648
        movl    %edi, %eax
 
649
L(fraction_done):
 
650
        movl    VAR_NORM, %ecx
 
651
L(zero_done):
 
652
        movl    SAVE_EBP, %ebp
 
653
 
 
654
        movl    SAVE_EDI, %edi
 
655
        movl    SAVE_ESI, %esi
 
656
 
 
657
        movl    SAVE_EBX, %ebx
 
658
        addl    $STACK_SPACE, %esp
 
659
 
 
660
        shrl    %cl, %eax
 
661
        emms
 
662
 
 
663
        ret
 
664
 
 
665
 
 
666
C -----------------------------------------------------------------------------
 
667
C
 
668
C Special case for q1=0xFFFFFFFF, giving q=0xFFFFFFFF meaning the low dword
 
669
C of q*d is simply -d and the remainder n-q*d = n10+d
 
670
 
 
671
L(q1_ff):
 
672
        C eax   (divisor)
 
673
        C ebx   (q1+1 == 0)
 
674
        C ecx
 
675
        C edx
 
676
        C esi   n10
 
677
        C edi   n2
 
678
        C ebp   divisor
 
679
 
 
680
        movl    VAR_DST, %ecx
 
681
        movl    VAR_DST_STOP, %edx
 
682
        subl    $4, %ecx
 
683
 
 
684
        psrlq   %mm7, %mm0
 
685
        leal    (%ebp,%esi), %edi       C n-q*d remainder -> next n2
 
686
        movl    %ecx, VAR_DST
 
687
 
 
688
        movd    %mm0, %esi              C next n10
 
689
 
 
690
        movl    $-1, (%ecx)
 
691
        cmpl    %ecx, %edx
 
692
        jne     L(integer_top)
 
693
 
 
694
        jmp     L(integer_loop_done)
 
695
 
 
696
 
 
697
 
 
698
C -----------------------------------------------------------------------------
 
699
C
 
700
C Being the fractional part, the "source" limbs are all zero, meaning
 
701
C n10=0, n1=0, and hence nadj=0, leading to many instructions eliminated.
 
702
C
 
703
C The loop runs at 15 cycles.  The dependent chain is the same as the
 
704
C general case above, but without the n2+n1 stage (due to n1==0), so 15
 
705
C would seem to be the lower bound.
 
706
C
 
707
C A not entirely obvious simplification is that q1+1 never overflows a limb,
 
708
C and so there's no need for the sbbl $0 or jz q1_ff from the general case.
 
709
C q1 is the high word of m*n2+b*n2 and the following shows q1<=b-2 always.
 
710
C rnd() means rounding down to a multiple of d.
 
711
C
 
712
C       m*n2 + b*n2 <= m*(d-1) + b*(d-1)
 
713
C                    = m*d + b*d - m - b
 
714
C                    = floor((b(b-d)-1)/d)*d + b*d - m - b
 
715
C                    = rnd(b(b-d)-1) + b*d - m - b
 
716
C                    = rnd(b(b-d)-1 + b*d) - m - b
 
717
C                    = rnd(b*b-1) - m - b
 
718
C                    <= (b-2)*b
 
719
C
 
720
C Unchanged from the general case is that the final quotient limb q can be
 
721
C either q1 or q1+1, and the q1+1 case occurs often.  This can be seen from
 
722
C equation 8.4 of the paper which simplifies as follows when n1==0 and
 
723
C n0==0.
 
724
C
 
725
C       n-q1*d = (n2*k+q0*d)/b <= d + (d*d-2d)/b
 
726
C
 
727
C As before, the instruction groupings and empty comments show a naive
 
728
C in-order view of the code, which is made a nonsense by out of order
 
729
C execution.  There's 17 cycles shown, but it executes at 15.
 
730
C
 
731
C Rotating the store q and remainder->n2 instructions up to the top of the
 
732
C loop gets the run time down from 16 to 15.
 
733
 
 
734
        ALIGN(16)
 
735
L(fraction_some):
 
736
        C eax
 
737
        C ebx
 
738
        C ecx
 
739
        C edx
 
740
        C esi
 
741
        C edi   carry
 
742
        C ebp   divisor
 
743
 
 
744
        movl    PARAM_DST, %esi
 
745
        movl    VAR_DST_STOP, %ecx      C &dst[xsize+2]
 
746
        movl    %edi, %eax
 
747
 
 
748
        subl    $8, %ecx                C &dst[xsize]
 
749
        jmp     L(fraction_entry)
 
750
 
 
751
 
 
752
        ALIGN(16)
 
753
L(fraction_top):
 
754
        C eax   n2 carry, then scratch
 
755
        C ebx   scratch (nadj, q1)
 
756
        C ecx   dst, decrementing
 
757
        C edx   scratch
 
758
        C esi   dst stop point
 
759
        C edi   (will be n2)
 
760
        C ebp   divisor
 
761
 
 
762
        movl    %ebx, (%ecx)    C previous q
 
763
        movl    %eax, %edi      C remainder->n2
 
764
 
 
765
L(fraction_entry):
 
766
        mull    VAR_INVERSE     C m*n2
 
767
 
 
768
        movl    %ebp, %eax      C d
 
769
        subl    $4, %ecx        C dst
 
770
        leal    1(%edi), %ebx
 
771
 
 
772
        C
 
773
 
 
774
        C
 
775
 
 
776
        C
 
777
 
 
778
        C
 
779
 
 
780
        addl    %edx, %ebx      C 1 + high(n2<<32 + m*n2) = q1+1
 
781
 
 
782
        mull    %ebx            C (q1+1)*d
 
783
 
 
784
        C
 
785
 
 
786
        C
 
787
 
 
788
        C
 
789
 
 
790
        negl    %eax            C low of n - (q1+1)*d
 
791
 
 
792
        C
 
793
 
 
794
        sbbl    %edx, %edi      C high of n - (q1+1)*d, caring only about carry
 
795
        leal    (%ebp,%eax), %edx
 
796
 
 
797
        cmovc(  %edx, %eax)     C n - q1*d if underflow from using q1+1
 
798
        sbbl    $0, %ebx        C q
 
799
        cmpl    %esi, %ecx
 
800
 
 
801
        jne     L(fraction_top)
 
802
 
 
803
 
 
804
        movl    %ebx, (%ecx)
 
805
        jmp     L(fraction_done)
 
806
 
 
807
EPILOGUE()