Coverage Report

Created: 2025-06-24 06:45

/src/binutils-gdb/gas/flonum-mult.c
Line
Count
Source (jump to first uncovered line)
1
/* flonum_mult.c - multiply two flonums
2
   Copyright (C) 1987-2025 Free Software Foundation, Inc.
3
4
   This file is part of GAS, the GNU Assembler.
5
6
   GAS is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3, or (at your option)
9
   any later version.
10
11
   GAS is distributed in the hope that it will be useful, but WITHOUT
12
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14
   License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with GAS; see the file COPYING.  If not, write to the Free
18
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19
   02110-1301, USA.  */
20
21
#include "ansidecl.h"
22
#include "flonum.h"
23
24
/*  plan for a . b => p(roduct)
25
26
  +-------+-------+-/   /-+-------+-------+
27
  | a | a |  ...  | a | a |
28
  |  A  |  A-1  | |  1  |  0  |
29
  +-------+-------+-/   /-+-------+-------+
30
31
  +-------+-------+-/   /-+-------+-------+
32
  | b | b |  ...  | b | b |
33
  |  B  |  B-1  | |  1  |  0  |
34
  +-------+-------+-/   /-+-------+-------+
35
36
  +-------+-------+-/   /-+-------+-/   /-+-------+-------+
37
  | p | p |  ...  | p |  ...  | p | p |
38
  |  A+B+1|  A+B  | |  N  | |  1  |  0  |
39
  +-------+-------+-/   /-+-------+-/   /-+-------+-------+
40
41
  /^\
42
  (carry) a .b     ...      |    ...   a .b  a .b
43
  A  B        |     0  1    0  0
44
  |
45
  ...     |    ...   a .b
46
  |     1  0
47
  |
48
  |    ...
49
  |
50
  |
51
  |
52
  |     ___
53
  |     \
54
  +-----  P  =   >  a .b
55
  N   /__  i  j
56
57
  N = 0 ... A+B
58
59
  for all i,j where i+j=N
60
  [i,j integers > 0]
61
62
  a[], b[], p[] may not intersect.
63
  Zero length factors signify 0 significant bits: treat as 0.0.
64
  0.0 factors do the right thing.
65
  Zero length product OK.
66
67
  I chose the ForTran accent "foo[bar]" instead of the C accent "*garply"
68
  because I felt the ForTran way was more intuitive. The C way would
69
  probably yield better code on most C compilers. Dean Elsner.
70
  (C style also gives deeper insight [to me] ... oh well ...)  */
71

72
void
73
flonum_multip (const FLONUM_TYPE *a, const FLONUM_TYPE *b,
74
         FLONUM_TYPE *product)
75
15.3k
{
76
15.3k
  int size_of_a;    /* 0 origin  */
77
15.3k
  int size_of_b;    /* 0 origin  */
78
15.3k
  int size_of_product;    /* 0 origin  */
79
15.3k
  int size_of_sum;    /* 0 origin  */
80
15.3k
  int extra_product_positions;  /* 1 origin  */
81
15.3k
  unsigned long work;
82
15.3k
  unsigned long carry;
83
15.3k
  long exponent;
84
15.3k
  LITTLENUM_TYPE *q;
85
15.3k
  long significant;   /* TRUE when we emit a non-0 littlenum  */
86
  /* ForTran accent follows.  */
87
15.3k
  int P;      /* Scan product low-order -> high.  */
88
15.3k
  int N;      /* As in sum above.  */
89
15.3k
  int A;      /* Which [] of a?  */
90
15.3k
  int B;      /* Which [] of b?  */
91
92
15.3k
  if ((a->sign != '-' && a->sign != '+')
93
15.3k
      || (b->sign != '-' && b->sign != '+'))
94
0
    {
95
      /* Got to fail somehow.  Any suggestions?  */
96
0
      product->sign = 0;
97
0
      return;
98
0
    }
99
15.3k
  product->sign = (a->sign == b->sign) ? '+' : '-';
100
15.3k
  size_of_a = a->leader - a->low;
101
15.3k
  size_of_b = b->leader - b->low;
102
15.3k
  exponent = a->exponent + b->exponent;
103
15.3k
  size_of_product = product->high - product->low;
104
15.3k
  size_of_sum = size_of_a + size_of_b;
105
15.3k
  extra_product_positions = size_of_product - size_of_sum;
106
15.3k
  if (extra_product_positions < 0)
107
3.30k
    {
108
3.30k
      P = extra_product_positions;  /* P < 0  */
109
3.30k
      exponent -= extra_product_positions;  /* Increases exponent.  */
110
3.30k
    }
111
12.0k
  else
112
12.0k
    {
113
12.0k
      P = 0;
114
12.0k
    }
115
15.3k
  carry = 0;
116
15.3k
  significant = 0;
117
242k
  for (N = 0; N <= size_of_sum; N++)
118
227k
    {
119
227k
      work = carry;
120
227k
      carry = 0;
121
2.57M
      for (A = 0; A <= N; A++)
122
2.34M
  {
123
2.34M
    B = N - A;
124
2.34M
    if (A <= size_of_a && B <= size_of_b && B >= 0)
125
330k
      {
126
#ifdef TRACE
127
        printf ("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n",
128
          A, a->low[A], B, b->low[B], work);
129
#endif
130
        /* Watch out for sign extension!  Without the casts, on
131
     the DEC Alpha, the multiplication result is *signed*
132
     int, which gets sign-extended to convert to the
133
     unsigned long!  */
134
330k
        work += (unsigned long) a->low[A] * (unsigned long) b->low[B];
135
330k
        carry += work >> LITTLENUM_NUMBER_OF_BITS;
136
330k
        work &= LITTLENUM_MASK;
137
#ifdef TRACE
138
        printf ("work=%08x carry=%04x\n", work, carry);
139
#endif
140
330k
      }
141
2.34M
  }
142
227k
      significant |= work;
143
227k
      if (significant || P < 0)
144
227k
  {
145
227k
    if (P >= 0)
146
177k
      {
147
177k
        product->low[P] = work;
148
#ifdef TRACE
149
        printf ("P=%d. work[p]:=%04x\n", P, work);
150
#endif
151
177k
      }
152
227k
    P++;
153
227k
  }
154
1
      else
155
1
  {
156
1
    extra_product_positions++;
157
1
    exponent++;
158
1
  }
159
227k
    }
160
  /* [P]-> position # size_of_sum + 1.
161
     This is where 'carry' should go.  */
162
#ifdef TRACE
163
  printf ("final carry =%04x\n", carry);
164
#endif
165
15.3k
  if (carry)
166
1.35k
    {
167
1.35k
      if (extra_product_positions > 0)
168
78
  product->low[P] = carry;
169
1.27k
      else
170
1.27k
  {
171
    /* No room at high order for carry littlenum.  */
172
    /* Shift right 1 to make room for most significant littlenum.  */
173
1.27k
    exponent++;
174
1.27k
    P--;
175
6.48k
    for (q = product->low + P; q >= product->low; q--)
176
5.21k
      {
177
5.21k
        work = *q;
178
5.21k
        *q = carry;
179
5.21k
        carry = work;
180
5.21k
      }
181
1.27k
  }
182
1.35k
    }
183
13.9k
  else
184
13.9k
    P--;
185
15.3k
  product->leader = product->low + P;
186
15.3k
  product->exponent = exponent;
187
15.3k
}