blob: 33caeb92e8b1ebfe3edd63c1dd863cd45f4605d7 [file] [log] [blame]
Leonard Chana6779422018-08-06 16:42:37 +00001//===- FixedPoint.cpp - Fixed point constant handling -----------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10/// \file
11/// Defines the implementation for the fixed point number interface.
12//
13//===----------------------------------------------------------------------===//
14
Leonard Chana6779422018-08-06 16:42:37 +000015#include "clang/Basic/FixedPoint.h"
16
17namespace clang {
18
Leonard Chand3f3e162019-01-18 21:04:25 +000019APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema,
20 bool *Overflow) const {
Leonard Chana6779422018-08-06 16:42:37 +000021 llvm::APSInt NewVal = Val;
22 unsigned DstWidth = DstSema.getWidth();
23 unsigned DstScale = DstSema.getScale();
24 bool Upscaling = DstScale > getScale();
Leonard Chand3f3e162019-01-18 21:04:25 +000025 if (Overflow)
26 *Overflow = false;
Leonard Chana6779422018-08-06 16:42:37 +000027
28 if (Upscaling) {
29 NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
30 NewVal <<= (DstScale - getScale());
31 } else {
32 NewVal >>= (getScale() - DstScale);
33 }
34
Leonard Chand3f3e162019-01-18 21:04:25 +000035 auto Mask = llvm::APInt::getBitsSetFrom(
36 NewVal.getBitWidth(),
37 std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
38 llvm::APInt Masked(NewVal & Mask);
Leonard Chana6779422018-08-06 16:42:37 +000039
Leonard Chand3f3e162019-01-18 21:04:25 +000040 // Change in the bits above the sign
41 if (!(Masked == Mask || Masked == 0)) {
42 // Found overflow in the bits above the sign
43 if (DstSema.isSaturated())
Leonard Chana6779422018-08-06 16:42:37 +000044 NewVal = NewVal.isNegative() ? Mask : ~Mask;
Leonard Chand3f3e162019-01-18 21:04:25 +000045 else if (Overflow)
46 *Overflow = true;
47 }
Leonard Chana6779422018-08-06 16:42:37 +000048
Leonard Chand3f3e162019-01-18 21:04:25 +000049 // If the dst semantics are unsigned, but our value is signed and negative, we
50 // clamp to zero.
51 if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative()) {
52 // Found negative overflow for unsigned result
53 if (DstSema.isSaturated())
Leonard Chana6779422018-08-06 16:42:37 +000054 NewVal = 0;
Leonard Chand3f3e162019-01-18 21:04:25 +000055 else if (Overflow)
56 *Overflow = true;
Leonard Chana6779422018-08-06 16:42:37 +000057 }
58
59 NewVal = NewVal.extOrTrunc(DstWidth);
60 NewVal.setIsSigned(DstSema.isSigned());
61 return APFixedPoint(NewVal, DstSema);
62}
63
64int APFixedPoint::compare(const APFixedPoint &Other) const {
65 llvm::APSInt ThisVal = getValue();
66 llvm::APSInt OtherVal = Other.getValue();
67 bool ThisSigned = Val.isSigned();
68 bool OtherSigned = OtherVal.isSigned();
69 unsigned OtherScale = Other.getScale();
70 unsigned OtherWidth = OtherVal.getBitWidth();
71
72 unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);
73
74 // Prevent overflow in the event the widths are the same but the scales differ
Leonard Chan7c4f4912018-08-06 19:31:00 +000075 CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale
76 : OtherScale - getScale();
Leonard Chana6779422018-08-06 16:42:37 +000077
78 ThisVal = ThisVal.extOrTrunc(CommonWidth);
79 OtherVal = OtherVal.extOrTrunc(CommonWidth);
80
81 unsigned CommonScale = std::max(getScale(), OtherScale);
82 ThisVal = ThisVal.shl(CommonScale - getScale());
83 OtherVal = OtherVal.shl(CommonScale - OtherScale);
84
85 if (ThisSigned && OtherSigned) {
86 if (ThisVal.sgt(OtherVal))
87 return 1;
88 else if (ThisVal.slt(OtherVal))
89 return -1;
90 } else if (!ThisSigned && !OtherSigned) {
91 if (ThisVal.ugt(OtherVal))
92 return 1;
93 else if (ThisVal.ult(OtherVal))
94 return -1;
95 } else if (ThisSigned && !OtherSigned) {
96 if (ThisVal.isSignBitSet())
97 return -1;
98 else if (ThisVal.ugt(OtherVal))
99 return 1;
100 else if (ThisVal.ult(OtherVal))
101 return -1;
102 } else {
103 // !ThisSigned && OtherSigned
104 if (OtherVal.isSignBitSet())
105 return 1;
106 else if (ThisVal.ugt(OtherVal))
107 return 1;
108 else if (ThisVal.ult(OtherVal))
109 return -1;
110 }
111
112 return 0;
113}
114
115APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) {
116 bool IsUnsigned = !Sema.isSigned();
117 auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
118 if (IsUnsigned && Sema.hasUnsignedPadding())
119 Val = Val.lshr(1);
120 return APFixedPoint(Val, Sema);
121}
122
123APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
124 auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
125 return APFixedPoint(Val, Sema);
126}
127
Leonard Chan2044ac82019-01-16 18:13:59 +0000128FixedPointSemantics FixedPointSemantics::getCommonSemantics(
129 const FixedPointSemantics &Other) const {
130 unsigned CommonScale = std::max(getScale(), Other.getScale());
131 unsigned CommonWidth =
132 std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
133
134 bool ResultIsSigned = isSigned() || Other.isSigned();
135 bool ResultIsSaturated = isSaturated() || Other.isSaturated();
136 bool ResultHasUnsignedPadding = false;
137 if (!ResultIsSigned) {
138 // Both are unsigned.
139 ResultHasUnsignedPadding = hasUnsignedPadding() &&
140 Other.hasUnsignedPadding() && !ResultIsSaturated;
141 }
142
143 // If the result is signed, add an extra bit for the sign. Otherwise, if it is
144 // unsigned and has unsigned padding, we only need to add the extra padding
145 // bit back if we are not saturating.
146 if (ResultIsSigned || ResultHasUnsignedPadding)
147 CommonWidth++;
148
149 return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
150 ResultIsSaturated, ResultHasUnsignedPadding);
151}
152
Leonard Chand3f3e162019-01-18 21:04:25 +0000153APFixedPoint APFixedPoint::add(const APFixedPoint &Other,
154 bool *Overflow) const {
155 auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics());
156 APFixedPoint ConvertedThis = convert(CommonFXSema);
157 APFixedPoint ConvertedOther = Other.convert(CommonFXSema);
158 llvm::APSInt ThisVal = ConvertedThis.getValue();
159 llvm::APSInt OtherVal = ConvertedOther.getValue();
160 bool Overflowed = false;
161
162 llvm::APSInt Result;
163 if (CommonFXSema.isSaturated()) {
164 Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal)
165 : ThisVal.uadd_sat(OtherVal);
166 } else {
167 Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed)
168 : ThisVal.uadd_ov(OtherVal, Overflowed);
169 }
170
171 if (Overflow)
172 *Overflow = Overflowed;
173
174 return APFixedPoint(Result, CommonFXSema);
175}
176
Leonard Chan86285d22019-01-16 18:53:05 +0000177void APFixedPoint::toString(llvm::SmallVectorImpl<char> &Str) const {
178 llvm::APSInt Val = getValue();
179 unsigned Scale = getScale();
180
181 if (Val.isSigned() && Val.isNegative() && Val != -Val) {
182 Val = -Val;
183 Str.push_back('-');
184 }
185
186 llvm::APSInt IntPart = Val >> Scale;
187
188 // Add 4 digits to hold the value after multiplying 10 (the radix)
189 unsigned Width = Val.getBitWidth() + 4;
190 llvm::APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
191 llvm::APInt FractPartMask = llvm::APInt::getAllOnesValue(Scale).zext(Width);
192 llvm::APInt RadixInt = llvm::APInt(Width, 10);
193
194 IntPart.toString(Str, /*radix=*/10);
195 Str.push_back('.');
196 do {
197 (FractPart * RadixInt)
198 .lshr(Scale)
199 .toString(Str, /*radix=*/10, Val.isSigned());
200 FractPart = (FractPart * RadixInt) & FractPartMask;
201 } while (FractPart != 0);
202}
203
Leonard Chand3f3e162019-01-18 21:04:25 +0000204APFixedPoint APFixedPoint::negate(bool *Overflow) const {
205 if (!isSaturated()) {
206 if (Overflow)
207 *Overflow =
208 (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue());
209 return APFixedPoint(-Val, Sema);
210 }
211
212 // We never overflow for saturation
213 if (Overflow)
214 *Overflow = false;
215
216 if (isSigned())
217 return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema);
218 else
219 return APFixedPoint(Sema);
220}
221
Leonard Chana6779422018-08-06 16:42:37 +0000222} // namespace clang