Coverage Report

Created: 2020-02-18 08:44

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Basic/FixedPoint.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- FixedPoint.cpp - Fixed point constant handling -----------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
/// \file
10
/// Defines the implementation for the fixed point number interface.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/Basic/FixedPoint.h"
15
16
namespace clang {
17
18
APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema,
19
799
                                   bool *Overflow) const {
20
799
  llvm::APSInt NewVal = Val;
21
799
  unsigned DstWidth = DstSema.getWidth();
22
799
  unsigned DstScale = DstSema.getScale();
23
799
  bool Upscaling = DstScale > getScale();
24
799
  if (Overflow)
25
261
    *Overflow = false;
26
799
27
799
  if (Upscaling) {
28
273
    NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
29
273
    NewVal <<= (DstScale - getScale());
30
526
  } else {
31
526
    NewVal >>= (getScale() - DstScale);
32
526
  }
33
799
34
799
  auto Mask = llvm::APInt::getBitsSetFrom(
35
799
      NewVal.getBitWidth(),
36
799
      std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
37
799
  llvm::APInt Masked(NewVal & Mask);
38
799
39
799
  // Change in the bits above the sign
40
799
  if (!(Masked == Mask || 
Masked == 0519
)) {
41
81
    // Found overflow in the bits above the sign
42
81
    if (DstSema.isSaturated())
43
60
      NewVal = NewVal.isNegative() ? 
Mask4
:
~Mask56
;
44
21
    else if (Overflow)
45
15
      *Overflow = true;
46
81
  }
47
799
48
799
  // If the dst semantics are unsigned, but our value is signed and negative, we
49
799
  // clamp to zero.
50
799
  if (!DstSema.isSigned() && 
NewVal.isSigned()324
&&
NewVal.isNegative()178
) {
51
69
    // Found negative overflow for unsigned result
52
69
    if (DstSema.isSaturated())
53
57
      NewVal = 0;
54
12
    else if (Overflow)
55
9
      *Overflow = true;
56
69
  }
57
799
58
799
  NewVal = NewVal.extOrTrunc(DstWidth);
59
799
  NewVal.setIsSigned(DstSema.isSigned());
60
799
  return APFixedPoint(NewVal, DstSema);
61
799
}
62
63
687
int APFixedPoint::compare(const APFixedPoint &Other) const {
64
687
  llvm::APSInt ThisVal = getValue();
65
687
  llvm::APSInt OtherVal = Other.getValue();
66
687
  bool ThisSigned = Val.isSigned();
67
687
  bool OtherSigned = OtherVal.isSigned();
68
687
  unsigned OtherScale = Other.getScale();
69
687
  unsigned OtherWidth = OtherVal.getBitWidth();
70
687
71
687
  unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);
72
687
73
687
  // Prevent overflow in the event the widths are the same but the scales differ
74
687
  CommonWidth += getScale() >= OtherScale ? 
getScale() - OtherScale579
75
687
                                          : 
OtherScale - getScale()108
;
76
687
77
687
  ThisVal = ThisVal.extOrTrunc(CommonWidth);
78
687
  OtherVal = OtherVal.extOrTrunc(CommonWidth);
79
687
80
687
  unsigned CommonScale = std::max(getScale(), OtherScale);
81
687
  ThisVal = ThisVal.shl(CommonScale - getScale());
82
687
  OtherVal = OtherVal.shl(CommonScale - OtherScale);
83
687
84
687
  if (ThisSigned && 
OtherSigned457
) {
85
275
    if (ThisVal.sgt(OtherVal))
86
51
      return 1;
87
224
    else if (ThisVal.slt(OtherVal))
88
40
      return -1;
89
412
  } else if (!ThisSigned && 
!OtherSigned230
) {
90
215
    if (ThisVal.ugt(OtherVal))
91
5
      return 1;
92
210
    else if (ThisVal.ult(OtherVal))
93
5
      return -1;
94
197
  } else if (ThisSigned && 
!OtherSigned182
) {
95
182
    if (ThisVal.isSignBitSet())
96
3
      return -1;
97
179
    else if (ThisVal.ugt(OtherVal))
98
63
      return 1;
99
116
    else if (ThisVal.ult(OtherVal))
100
24
      return -1;
101
15
  } else {
102
15
    // !ThisSigned && OtherSigned
103
15
    if (OtherVal.isSignBitSet())
104
1
      return 1;
105
14
    else if (ThisVal.ugt(OtherVal))
106
1
      return 1;
107
13
    else if (ThisVal.ult(OtherVal))
108
1
      return -1;
109
493
  }
110
493
111
493
  return 0;
112
493
}
113
114
514
APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) {
115
514
  bool IsUnsigned = !Sema.isSigned();
116
514
  auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
117
514
  if (IsUnsigned && 
Sema.hasUnsignedPadding()200
)
118
73
    Val = Val.lshr(1);
119
514
  return APFixedPoint(Val, Sema);
120
514
}
121
122
119
APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
123
119
  auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
124
119
  return APFixedPoint(Val, Sema);
125
119
}
126
127
FixedPointSemantics FixedPointSemantics::getCommonSemantics(
128
293
    const FixedPointSemantics &Other) const {
129
293
  unsigned CommonScale = std::max(getScale(), Other.getScale());
130
293
  unsigned CommonWidth =
131
293
      std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
132
293
133
293
  bool ResultIsSigned = isSigned() || 
Other.isSigned()90
;
134
293
  bool ResultIsSaturated = isSaturated() || 
Other.isSaturated()241
;
135
293
  bool ResultHasUnsignedPadding = false;
136
293
  if (!ResultIsSigned) {
137
62
    // Both are unsigned.
138
62
    ResultHasUnsignedPadding = hasUnsignedPadding() &&
139
62
                               
Other.hasUnsignedPadding()31
&&
!ResultIsSaturated24
;
140
62
  }
141
293
142
293
  // If the result is signed, add an extra bit for the sign. Otherwise, if it is
143
293
  // unsigned and has unsigned padding, we only need to add the extra padding
144
293
  // bit back if we are not saturating.
145
293
  if (ResultIsSigned || 
ResultHasUnsignedPadding62
)
146
246
    CommonWidth++;
147
293
148
293
  return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
149
293
                             ResultIsSaturated, ResultHasUnsignedPadding);
150
293
}
151
152
APFixedPoint APFixedPoint::add(const APFixedPoint &Other,
153
111
                               bool *Overflow) const {
154
111
  auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
155
111
  APFixedPoint ConvertedThis = convert(CommonFXSema);
156
111
  APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
157
111
  llvm::APSInt ThisVal = ConvertedThis.getValue();
158
111
  llvm::APSInt OtherVal = ConvertedOther.getValue();
159
111
  bool Overflowed = false;
160
111
161
111
  llvm::APSInt Result;
162
111
  if (CommonFXSema.isSaturated()) {
163
30
    Result = CommonFXSema.isSigned() ? 
ThisVal.sadd_sat(OtherVal)24
164
30
                                     : 
ThisVal.uadd_sat(OtherVal)6
;
165
81
  } else {
166
81
    Result = ThisVal.isSigned() ? 
ThisVal.sadd_ov(OtherVal, Overflowed)75
167
81
                                : 
ThisVal.uadd_ov(OtherVal, Overflowed)6
;
168
81
  }
169
111
170
111
  if (Overflow)
171
111
    *Overflow = Overflowed;
172
111
173
111
  return APFixedPoint(Result, CommonFXSema);
174
111
}
175
176
89
void APFixedPoint::toString(llvm::SmallVectorImpl<char> &Str) const {
177
89
  llvm::APSInt Val = getValue();
178
89
  unsigned Scale = getScale();
179
89
180
89
  if (Val.isSigned() && 
Val.isNegative()27
&&
Val != -Val13
) {
181
6
    Val = -Val;
182
6
    Str.push_back('-');
183
6
  }
184
89
185
89
  llvm::APSInt IntPart = Val >> Scale;
186
89
187
89
  // Add 4 digits to hold the value after multiplying 10 (the radix)
188
89
  unsigned Width = Val.getBitWidth() + 4;
189
89
  llvm::APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
190
89
  llvm::APInt FractPartMask = llvm::APInt::getAllOnesValue(Scale).zext(Width);
191
89
  llvm::APInt RadixInt = llvm::APInt(Width, 10);
192
89
193
89
  IntPart.toString(Str, /*Radix=*/10);
194
89
  Str.push_back('.');
195
740
  do {
196
740
    (FractPart * RadixInt)
197
740
        .lshr(Scale)
198
740
        .toString(Str, /*Radix=*/10, Val.isSigned());
199
740
    FractPart = (FractPart * RadixInt) & FractPartMask;
200
740
  } while (FractPart != 0);
201
89
}
202
203
60
APFixedPoint APFixedPoint::negate(bool *Overflow) const {
204
60
  if (!isSaturated()) {
205
60
    if (Overflow)
206
60
      *Overflow =
207
60
          (!isSigned() && 
Val != 00
) || (isSigned() && Val.isMinSignedValue());
208
60
    return APFixedPoint(-Val, Sema);
209
60
  }
210
0
211
0
  // We never overflow for saturation
212
0
  if (Overflow)
213
0
    *Overflow = false;
214
0
215
0
  if (isSigned())
216
0
    return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);
217
0
  else
218
0
    return APFixedPoint(Sema);
219
0
}
220
221
llvm::APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
222
74
                                        bool *Overflow) const {
223
74
  llvm::APSInt Result = getIntPart();
224
74
  unsigned SrcWidth = getWidth();
225
74
226
74
  llvm::APSInt DstMin = llvm::APSInt::getMinValue(DstWidth, !DstSign);
227
74
  llvm::APSInt DstMax = llvm::APSInt::getMaxValue(DstWidth, !DstSign);
228
74
229
74
  if (SrcWidth < DstWidth) {
230
34
    Result = Result.extend(DstWidth);
231
40
  } else if (SrcWidth > DstWidth) {
232
28
    DstMin = DstMin.extend(SrcWidth);
233
28
    DstMax = DstMax.extend(SrcWidth);
234
28
  }
235
74
236
74
  if (Overflow) {
237
74
    if (Result.isSigned() && 
!DstSign62
) {
238
22
      *Overflow = Result.isNegative() || 
Result.ugt(DstMax)14
;
239
52
    } else if (Result.isUnsigned() && 
DstSign12
) {
240
8
      *Overflow = Result.ugt(DstMax);
241
44
    } else {
242
44
      *Overflow = Result < DstMin || Result > DstMax;
243
44
    }
244
74
  }
245
74
246
74
  Result.setIsSigned(DstSign);
247
74
  return Result.extOrTrunc(DstWidth);
248
74
}
249
250
APFixedPoint APFixedPoint::getFromIntValue(const llvm::APSInt &Value,
251
                                           const FixedPointSemantics &DstFXSema,
252
66
                                           bool *Overflow) {
253
66
  FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics(
254
66
      Value.getBitWidth(), Value.isSigned());
255
66
  return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
256
66
}
257
258
}  // namespace clang