clang  10.0.0svn
FixedPoint.cpp
Go to the documentation of this file.
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 
19  bool *Overflow) const {
20  llvm::APSInt NewVal = Val;
21  unsigned DstWidth = DstSema.getWidth();
22  unsigned DstScale = DstSema.getScale();
23  bool Upscaling = DstScale > getScale();
24  if (Overflow)
25  *Overflow = false;
26 
27  if (Upscaling) {
28  NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
29  NewVal <<= (DstScale - getScale());
30  } else {
31  NewVal >>= (getScale() - DstScale);
32  }
33 
34  auto Mask = llvm::APInt::getBitsSetFrom(
35  NewVal.getBitWidth(),
36  std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
37  llvm::APInt Masked(NewVal & Mask);
38 
39  // Change in the bits above the sign
40  if (!(Masked == Mask || Masked == 0)) {
41  // Found overflow in the bits above the sign
42  if (DstSema.isSaturated())
43  NewVal = NewVal.isNegative() ? Mask : ~Mask;
44  else if (Overflow)
45  *Overflow = true;
46  }
47 
48  // If the dst semantics are unsigned, but our value is signed and negative, we
49  // clamp to zero.
50  if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative()) {
51  // Found negative overflow for unsigned result
52  if (DstSema.isSaturated())
53  NewVal = 0;
54  else if (Overflow)
55  *Overflow = true;
56  }
57 
58  NewVal = NewVal.extOrTrunc(DstWidth);
59  NewVal.setIsSigned(DstSema.isSigned());
60  return APFixedPoint(NewVal, DstSema);
61 }
62 
63 int APFixedPoint::compare(const APFixedPoint &Other) const {
64  llvm::APSInt ThisVal = getValue();
65  llvm::APSInt OtherVal = Other.getValue();
66  bool ThisSigned = Val.isSigned();
67  bool OtherSigned = OtherVal.isSigned();
68  unsigned OtherScale = Other.getScale();
69  unsigned OtherWidth = OtherVal.getBitWidth();
70 
71  unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);
72 
73  // Prevent overflow in the event the widths are the same but the scales differ
74  CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale
75  : OtherScale - getScale();
76 
77  ThisVal = ThisVal.extOrTrunc(CommonWidth);
78  OtherVal = OtherVal.extOrTrunc(CommonWidth);
79 
80  unsigned CommonScale = std::max(getScale(), OtherScale);
81  ThisVal = ThisVal.shl(CommonScale - getScale());
82  OtherVal = OtherVal.shl(CommonScale - OtherScale);
83 
84  if (ThisSigned && OtherSigned) {
85  if (ThisVal.sgt(OtherVal))
86  return 1;
87  else if (ThisVal.slt(OtherVal))
88  return -1;
89  } else if (!ThisSigned && !OtherSigned) {
90  if (ThisVal.ugt(OtherVal))
91  return 1;
92  else if (ThisVal.ult(OtherVal))
93  return -1;
94  } else if (ThisSigned && !OtherSigned) {
95  if (ThisVal.isSignBitSet())
96  return -1;
97  else if (ThisVal.ugt(OtherVal))
98  return 1;
99  else if (ThisVal.ult(OtherVal))
100  return -1;
101  } else {
102  // !ThisSigned && OtherSigned
103  if (OtherVal.isSignBitSet())
104  return 1;
105  else if (ThisVal.ugt(OtherVal))
106  return 1;
107  else if (ThisVal.ult(OtherVal))
108  return -1;
109  }
110 
111  return 0;
112 }
113 
115  bool IsUnsigned = !Sema.isSigned();
116  auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
117  if (IsUnsigned && Sema.hasUnsignedPadding())
118  Val = Val.lshr(1);
119  return APFixedPoint(Val, Sema);
120 }
121 
123  auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
124  return APFixedPoint(Val, Sema);
125 }
126 
128  const FixedPointSemantics &Other) const {
129  unsigned CommonScale = std::max(getScale(), Other.getScale());
130  unsigned CommonWidth =
131  std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
132 
133  bool ResultIsSigned = isSigned() || Other.isSigned();
134  bool ResultIsSaturated = isSaturated() || Other.isSaturated();
135  bool ResultHasUnsignedPadding = false;
136  if (!ResultIsSigned) {
137  // Both are unsigned.
138  ResultHasUnsignedPadding = hasUnsignedPadding() &&
139  Other.hasUnsignedPadding() && !ResultIsSaturated;
140  }
141 
142  // If the result is signed, add an extra bit for the sign. Otherwise, if it is
143  // unsigned and has unsigned padding, we only need to add the extra padding
144  // bit back if we are not saturating.
145  if (ResultIsSigned || ResultHasUnsignedPadding)
146  CommonWidth++;
147 
148  return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
149  ResultIsSaturated, ResultHasUnsignedPadding);
150 }
151 
153  bool *Overflow) const {
154  auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
155  APFixedPoint ConvertedThis = convert(CommonFXSema);
156  APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
157  llvm::APSInt ThisVal = ConvertedThis.getValue();
158  llvm::APSInt OtherVal = ConvertedOther.getValue();
159  bool Overflowed = false;
160 
162  if (CommonFXSema.isSaturated()) {
163  Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal)
164  : ThisVal.uadd_sat(OtherVal);
165  } else {
166  Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed)
167  : ThisVal.uadd_ov(OtherVal, Overflowed);
168  }
169 
170  if (Overflow)
171  *Overflow = Overflowed;
172 
173  return APFixedPoint(Result, CommonFXSema);
174 }
175 
177  llvm::APSInt Val = getValue();
178  unsigned Scale = getScale();
179 
180  if (Val.isSigned() && Val.isNegative() && Val != -Val) {
181  Val = -Val;
182  Str.push_back('-');
183  }
184 
185  llvm::APSInt IntPart = Val >> Scale;
186 
187  // Add 4 digits to hold the value after multiplying 10 (the radix)
188  unsigned Width = Val.getBitWidth() + 4;
189  llvm::APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
190  llvm::APInt FractPartMask = llvm::APInt::getAllOnesValue(Scale).zext(Width);
191  llvm::APInt RadixInt = llvm::APInt(Width, 10);
192 
193  IntPart.toString(Str, /*Radix=*/10);
194  Str.push_back('.');
195  do {
196  (FractPart * RadixInt)
197  .lshr(Scale)
198  .toString(Str, /*Radix=*/10, Val.isSigned());
199  FractPart = (FractPart * RadixInt) & FractPartMask;
200  } while (FractPart != 0);
201 }
202 
203 APFixedPoint APFixedPoint::negate(bool *Overflow) const {
204  if (!isSaturated()) {
205  if (Overflow)
206  *Overflow =
207  (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue());
208  return APFixedPoint(-Val, Sema);
209  }
210 
211  // We never overflow for saturation
212  if (Overflow)
213  *Overflow = false;
214 
215  if (isSigned())
216  return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);
217  else
218  return APFixedPoint(Sema);
219 }
220 
221 llvm::APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign,
222  bool *Overflow) const {
224  unsigned SrcWidth = getWidth();
225 
226  llvm::APSInt DstMin = llvm::APSInt::getMinValue(DstWidth, !DstSign);
227  llvm::APSInt DstMax = llvm::APSInt::getMaxValue(DstWidth, !DstSign);
228 
229  if (SrcWidth < DstWidth) {
230  Result = Result.extend(DstWidth);
231  } else if (SrcWidth > DstWidth) {
232  DstMin = DstMin.extend(SrcWidth);
233  DstMax = DstMax.extend(SrcWidth);
234  }
235 
236  if (Overflow) {
237  if (Result.isSigned() && !DstSign) {
238  *Overflow = Result.isNegative() || Result.ugt(DstMax);
239  } else if (Result.isUnsigned() && DstSign) {
240  *Overflow = Result.ugt(DstMax);
241  } else {
242  *Overflow = Result < DstMin || Result > DstMax;
243  }
244  }
245 
246  Result.setIsSigned(DstSign);
247  return Result.extOrTrunc(DstWidth);
248 }
249 
251  const FixedPointSemantics &DstFXSema,
252  bool *Overflow) {
254  Value.getBitWidth(), Value.isSigned());
255  return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow);
256 }
257 
258 } // namespace clang
static APFixedPoint getFromIntValue(const llvm::APSInt &Value, const FixedPointSemantics &DstFXSema, bool *Overflow=nullptr)
Create an APFixedPoint with a value equal to that of the provided integer, and in the same semantics ...
Definition: FixedPoint.cpp:250
static APFixedPoint getMax(const FixedPointSemantics &Sema)
Definition: FixedPoint.cpp:114
llvm::APSInt getValue() const
Definition: FixedPoint.h:110
The fixed point semantics work similarly to llvm::fltSemantics.
Definition: FixedPoint.h:33
unsigned getScale() const
Definition: FixedPoint.h:112
unsigned getWidth() const
Definition: FixedPoint.h:111
bool isSaturated() const
Definition: FixedPoint.h:113
APFixedPoint add(const APFixedPoint &Other, bool *Overflow=nullptr) const
Definition: FixedPoint.cpp:152
llvm::APSInt getIntPart() const
Return the integral part of this fixed point number, rounded towards zero.
Definition: FixedPoint.h:146
int compare(const APFixedPoint &Other) const
Definition: FixedPoint.cpp:63
unsigned getIntegralBits() const
Return the number of integral bits represented by these semantics.
Definition: FixedPoint.h:55
__DEVICE__ int max(int __a, int __b)
static APFixedPoint getMin(const FixedPointSemantics &Sema)
Definition: FixedPoint.cpp:122
bool isSigned() const
Definition: FixedPoint.h:114
unsigned getScale() const
Definition: FixedPoint.h:45
std::string toString() const
Definition: FixedPoint.h:165
The APFixedPoint class works similarly to APInt/APSInt in that it is a functional replacement for a s...
Definition: FixedPoint.h:95
APFixedPoint negate(bool *Overflow=nullptr) const
Perform a unary negation (-X) on this fixed point type, taking into account saturation if applicable...
Definition: FixedPoint.cpp:203
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:331
bool hasUnsignedPadding() const
Definition: FixedPoint.h:48
FixedPointSemantics getCommonSemantics(const FixedPointSemantics &Other) const
Return the FixedPointSemantics that allows for calculating the full precision semantic that can preci...
Definition: FixedPoint.cpp:127
The result type of a method or function.
llvm::APSInt APSInt
FixedPointSemantics getSemantics() const
Definition: FixedPoint.h:116
llvm::APInt APInt
Definition: Integral.h:27
bool isSaturated() const
Definition: FixedPoint.h:47
Defines the fixed point number interface.
Dataflow Directional Tag Classes.
static FixedPointSemantics GetIntegerSemantics(unsigned Width, bool IsSigned)
Return the FixedPointSemantics for an integer type.
Definition: FixedPoint.h:70
APFixedPoint convert(const FixedPointSemantics &DstSema, bool *Overflow=nullptr) const
Definition: FixedPoint.cpp:18
unsigned getWidth() const
Definition: FixedPoint.h:44
APFixedPoint(const llvm::APInt &Val, const FixedPointSemantics &Sema)
Definition: FixedPoint.h:97
__DEVICE__ int min(int __a, int __b)
llvm::APSInt convertToInt(unsigned DstWidth, bool DstSign, bool *Overflow=nullptr) const
Return the integral part of this fixed point number, rounded towards zero.
Definition: FixedPoint.cpp:221