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

« back to all changes in this revision

Viewing changes to src/gmp/mpn/sparc64/mode1o.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_modexact_1c_odd -- mpn by limb exact style remainder.
 
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, 2002, 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:       ?                ?
 
37
*/
 
38
 
 
39
 
 
40
/* This implementation reduces the number of multiplies done, knowing that
 
41
   on ultrasparc 1 and 2 the mulx instruction stalls the whole chip.
 
42
 
 
43
   The key idea is to use the fact that the low limb of q*d equals l, this
 
44
   being the whole purpose of the q calculated.  It means there's no need to
 
45
   calculate the lowest 32x32->64 part of the q*d, instead it can be
 
46
   inferred from l and the other three 32x32->64 parts.  See sparc64.h for
 
47
   details.
 
48
 
 
49
   When d is 32-bits, the same applies, but in this case there's only one
 
50
   other 32x32->64 part (ie. HIGH(q)*d).
 
51
 
 
52
   The net effect is that for 64-bit divisor each limb is 4 mulx, or for
 
53
   32-bit divisor each is 2 mulx.
 
54
 
 
55
   Enhancements:
 
56
 
 
57
   No doubt this could be done in assembler, if that helped the scheduling,
 
58
   or perhaps guaranteed good code irrespective of the compiler.
 
59
 
 
60
   Alternatives:
 
61
 
 
62
   It might be possibly to use floating point.  The loop is dominated by
 
63
   multiply latency, so not sure if floats would improve that.  One
 
64
   possibility would be to take two limbs at a time, with a 128 bit inverse,
 
65
   if there's enough registers, which could effectively use float throughput
 
66
   to reduce total latency across two limbs.  */
 
67
 
 
68
#define ASSERT_RETVAL(r)                \
 
69
  ASSERT (orig_c < d ? r < d : r <= d)
 
70
 
 
71
mp_limb_t
 
72
mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d, mp_limb_t orig_c)
 
73
{
 
74
  mp_limb_t  c = orig_c;
 
75
  mp_limb_t  s, l, q, h, inverse;
 
76
 
 
77
  ASSERT (size >= 1);
 
78
  ASSERT (d & 1);
 
79
  ASSERT_MPN (src, size);
 
80
  ASSERT_LIMB (d);
 
81
  ASSERT_LIMB (c);
 
82
 
 
83
  /* udivx is faster than 10 or 12 mulx's for one limb via an inverse */
 
84
  if (size == 1)
 
85
    {
 
86
      s = src[0];
 
87
      if (s > c)
 
88
        {
 
89
          l = s-c;
 
90
          h = l % d;
 
91
          if (h != 0)
 
92
            h = d - h;
 
93
        }
 
94
      else
 
95
        {
 
96
          l = c-s;
 
97
          h = l % d;
 
98
        }
 
99
      return h;
 
100
    }
 
101
 
 
102
  modlimb_invert (inverse, d);
 
103
 
 
104
  if (d <= 0xFFFFFFFF)
 
105
    {
 
106
      s = *src++;
 
107
      size--;
 
108
      do
 
109
        {
 
110
          SUBC_LIMB (c, l, s, c);
 
111
          s = *src++;
 
112
          q = l * inverse;
 
113
          umul_ppmm_half_lowequal (h, q, d, l);
 
114
          c += h;
 
115
          size--;
 
116
        }
 
117
      while (size != 0);
 
118
 
 
119
      if (s <= d)
 
120
        {
 
121
          /* With high s <= d the final step can be a subtract and addback.
 
122
             If c==0 then the addback will restore to l>=0.  If c==d then
 
123
             will get l==d if s==0, but that's ok per the function
 
124
             definition.  */
 
125
 
 
126
          l = c - s;
 
127
          l += (l > c ? d : 0);
 
128
 
 
129
          ASSERT_RETVAL (l);
 
130
          return l;
 
131
        }
 
132
      else
 
133
        {
 
134
          /* Can't skip a divide, just do the loop code once more. */
 
135
          SUBC_LIMB (c, l, s, c);
 
136
          q = l * inverse;
 
137
          umul_ppmm_half_lowequal (h, q, d, l);
 
138
          c += h;
 
139
 
 
140
          ASSERT_RETVAL (c);
 
141
          return c;
 
142
        }
 
143
    }
 
144
  else
 
145
    {
 
146
      mp_limb_t  dl = LOW32 (d);
 
147
      mp_limb_t  dh = HIGH32 (d);
 
148
      long i;
 
149
 
 
150
      s = *src++;
 
151
      size--;
 
152
      do
 
153
        {
 
154
          SUBC_LIMB (c, l, s, c);
 
155
          s = *src++;
 
156
          q = l * inverse;
 
157
          umul_ppmm_lowequal (h, q, d, dh, dl, l);
 
158
          c += h;
 
159
          size--;
 
160
        }
 
161
      while (size != 0);
 
162
 
 
163
      if (s <= d)
 
164
        {
 
165
          /* With high s <= d the final step can be a subtract and addback.
 
166
             If c==0 then the addback will restore to l>=0.  If c==d then
 
167
             will get l==d if s==0, but that's ok per the function
 
168
             definition.  */
 
169
 
 
170
          l = c - s;
 
171
          l += (l > c ? d : 0);
 
172
 
 
173
          ASSERT_RETVAL (l);
 
174
          return l;
 
175
        }
 
176
      else
 
177
        {
 
178
          /* Can't skip a divide, just do the loop code once more. */
 
179
          SUBC_LIMB (c, l, s, c);
 
180
          q = l * inverse;
 
181
          umul_ppmm_lowequal (h, q, d, dh, dl, l);
 
182
          c += h;
 
183
 
 
184
          ASSERT_RETVAL (c);
 
185
          return c;
 
186
        }
 
187
    }
 
188
}