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

« back to all changes in this revision

Viewing changes to src/gmp/mpn/sparc64/dive_1.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2007-04-09 11:51:51 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20070409115151-ql8cr0kalzx1jmla
Tags: 0.9i-20070324-2
Upload to unstable. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* UltraSPARC 64 mpn_divexact_1 -- mpn by limb exact division.
 
2
 
 
3
   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
 
4
   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
 
5
   FUTURE GNU MP RELEASES.
 
6
 
 
7
Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
 
8
 
 
9
This file is part of the GNU MP Library.
 
10
 
 
11
The GNU MP Library is free software; you can redistribute it and/or modify
 
12
it under the terms of the GNU Lesser General Public License as published by
 
13
the Free Software Foundation; either version 2.1 of the License, or (at your
 
14
option) any later version.
 
15
 
 
16
The GNU MP Library is distributed in the hope that it will be useful, but
 
17
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
18
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
19
License for more details.
 
20
 
 
21
You should have received a copy of the GNU Lesser General Public License
 
22
along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
 
23
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
24
MA 02110-1301, USA. */
 
25
 
 
26
#include "gmp.h"
 
27
#include "gmp-impl.h"
 
28
#include "longlong.h"
 
29
 
 
30
#include "mpn/sparc64/sparc64.h"
 
31
 
 
32
 
 
33
/*                 64-bit divisor   32-bit divisor
 
34
                    cycles/limb      cycles/limb
 
35
                     (approx)         (approx)
 
36
   Ultrasparc 2i:      110               70
 
37
*/
 
38
 
 
39
 
 
40
/* There are two key ideas here to reduce mulx's.  Firstly when the divisor
 
41
   is 32-bits the high of q*d can be calculated without the two 32x32->64
 
42
   cross-products involving the high 32-bits of the divisor, that being zero
 
43
   of course.  Secondly umul_ppmm_lowequal and umul_ppmm_half_lowequal save
 
44
   one mulx (each) knowing the low of q*d is equal to the input limb l.
 
45
 
 
46
   For size==1, a simple udivx is used.  This is faster than calculating an
 
47
   inverse.
 
48
 
 
49
   For a 32-bit divisor and small sizes, an attempt was made at a simple
 
50
   udivx loop (two per 64-bit limb), but it turned out to be slower than
 
51
   mul-by-inverse.  At size==2 the inverse is about 260 cycles total
 
52
   compared to a udivx at 291.  Perhaps the latter would suit when size==2
 
53
   but the high 32-bits of the second limb is zero (saving one udivx), but
 
54
   it doesn't seem worth a special case just for that.  */
 
55
 
 
56
void
 
57
mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor)
 
58
{
 
59
  mp_limb_t  inverse, s, s_next, c, l, ls, q;
 
60
  unsigned   rshift, lshift;
 
61
  mp_limb_t  lshift_mask;
 
62
  mp_limb_t  divisor_h;
 
63
 
 
64
  ASSERT (size >= 1);
 
65
  ASSERT (divisor != 0);
 
66
  ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size));
 
67
  ASSERT_MPN (src, size);
 
68
  ASSERT_LIMB (divisor);
 
69
 
 
70
  s = *src++;                 /* src low limb */
 
71
  size--;
 
72
  if (size == 0)
 
73
    {
 
74
      *dst = s / divisor;
 
75
      return;
 
76
    }
 
77
 
 
78
  if ((divisor & 1) == 0)
 
79
    {
 
80
      count_trailing_zeros (rshift, divisor);
 
81
      divisor >>= rshift;
 
82
    }
 
83
  else
 
84
    rshift = 0;
 
85
 
 
86
  modlimb_invert (inverse, divisor);
 
87
 
 
88
  lshift = 64 - rshift;
 
89
 
 
90
  /* lshift==64 means no shift, so must mask out other part in this case */
 
91
  lshift_mask = (rshift == 0 ? 0 : MP_LIMB_T_MAX);
 
92
 
 
93
  c = 0;
 
94
  divisor_h = HIGH32 (divisor);
 
95
 
 
96
  if (divisor_h == 0)
 
97
    {
 
98
      /* 32-bit divisor */
 
99
      do
 
100
        {
 
101
          s_next = *src++;
 
102
          ls = (s >> rshift) | ((s_next << lshift) & lshift_mask);
 
103
          s = s_next;
 
104
 
 
105
          SUBC_LIMB (c, l, ls, c);
 
106
 
 
107
          q = l * inverse;
 
108
          *dst++ = q;
 
109
 
 
110
          umul_ppmm_half_lowequal (l, q, divisor, l);
 
111
          c += l;
 
112
 
 
113
          size--;
 
114
        }
 
115
      while (size != 0);
 
116
 
 
117
      ls = s >> rshift;
 
118
      l = ls - c;
 
119
      q = l * inverse;
 
120
      *dst = q;
 
121
    }
 
122
  else
 
123
    {
 
124
      /* 64-bit divisor */
 
125
      mp_limb_t  divisor_l = LOW32 (divisor);
 
126
      do
 
127
        {
 
128
          s_next = *src++;
 
129
          ls = (s >> rshift) | ((s_next << lshift) & lshift_mask);
 
130
          s = s_next;
 
131
 
 
132
          SUBC_LIMB (c, l, ls, c);
 
133
 
 
134
          q = l * inverse;
 
135
          *dst++ = q;
 
136
 
 
137
          umul_ppmm_lowequal (l, q, divisor, divisor_h, divisor_l, l);
 
138
          c += l;
 
139
 
 
140
          size--;
 
141
        }
 
142
      while (size != 0);
 
143
 
 
144
      ls = s >> rshift;
 
145
      l = ls - c;
 
146
      q = l * inverse;
 
147
      *dst = q;
 
148
    }
 
149
}