blob: e3cffe628fd013af34c0aad8ac5ca2e304d2c69c [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
19APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema) const {
20 llvm::APSInt NewVal = Val;
21 unsigned DstWidth = DstSema.getWidth();
22 unsigned DstScale = DstSema.getScale();
23 bool Upscaling = DstScale > getScale();
24
25 if (Upscaling) {
26 NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
27 NewVal <<= (DstScale - getScale());
28 } else {
29 NewVal >>= (getScale() - DstScale);
30 }
31
32 if (DstSema.isSaturated()) {
33 auto Mask = llvm::APInt::getBitsSetFrom(
34 NewVal.getBitWidth(),
35 std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
36 llvm::APInt Masked(NewVal & Mask);
37
38 // Change in the bits above the sign
39 if (!(Masked == Mask || Masked == 0))
40 NewVal = NewVal.isNegative() ? Mask : ~Mask;
41
42 if (!DstSema.isSigned() && NewVal.isNegative())
43 NewVal = 0;
44 }
45
46 NewVal = NewVal.extOrTrunc(DstWidth);
47 NewVal.setIsSigned(DstSema.isSigned());
48 return APFixedPoint(NewVal, DstSema);
49}
50
51int APFixedPoint::compare(const APFixedPoint &Other) const {
52 llvm::APSInt ThisVal = getValue();
53 llvm::APSInt OtherVal = Other.getValue();
54 bool ThisSigned = Val.isSigned();
55 bool OtherSigned = OtherVal.isSigned();
56 unsigned OtherScale = Other.getScale();
57 unsigned OtherWidth = OtherVal.getBitWidth();
58
59 unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);
60
61 // Prevent overflow in the event the widths are the same but the scales differ
Leonard Chan7c4f4912018-08-06 19:31:00 +000062 CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale
63 : OtherScale - getScale();
Leonard Chana6779422018-08-06 16:42:37 +000064
65 ThisVal = ThisVal.extOrTrunc(CommonWidth);
66 OtherVal = OtherVal.extOrTrunc(CommonWidth);
67
68 unsigned CommonScale = std::max(getScale(), OtherScale);
69 ThisVal = ThisVal.shl(CommonScale - getScale());
70 OtherVal = OtherVal.shl(CommonScale - OtherScale);
71
72 if (ThisSigned && OtherSigned) {
73 if (ThisVal.sgt(OtherVal))
74 return 1;
75 else if (ThisVal.slt(OtherVal))
76 return -1;
77 } else if (!ThisSigned && !OtherSigned) {
78 if (ThisVal.ugt(OtherVal))
79 return 1;
80 else if (ThisVal.ult(OtherVal))
81 return -1;
82 } else if (ThisSigned && !OtherSigned) {
83 if (ThisVal.isSignBitSet())
84 return -1;
85 else if (ThisVal.ugt(OtherVal))
86 return 1;
87 else if (ThisVal.ult(OtherVal))
88 return -1;
89 } else {
90 // !ThisSigned && OtherSigned
91 if (OtherVal.isSignBitSet())
92 return 1;
93 else if (ThisVal.ugt(OtherVal))
94 return 1;
95 else if (ThisVal.ult(OtherVal))
96 return -1;
97 }
98
99 return 0;
100}
101
102APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) {
103 bool IsUnsigned = !Sema.isSigned();
104 auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
105 if (IsUnsigned && Sema.hasUnsignedPadding())
106 Val = Val.lshr(1);
107 return APFixedPoint(Val, Sema);
108}
109
110APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
111 auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
112 return APFixedPoint(Val, Sema);
113}
114
Leonard Chan2044ac82019-01-16 18:13:59 +0000115FixedPointSemantics FixedPointSemantics::getCommonSemantics(
116 const FixedPointSemantics &Other) const {
117 unsigned CommonScale = std::max(getScale(), Other.getScale());
118 unsigned CommonWidth =
119 std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;
120
121 bool ResultIsSigned = isSigned() || Other.isSigned();
122 bool ResultIsSaturated = isSaturated() || Other.isSaturated();
123 bool ResultHasUnsignedPadding = false;
124 if (!ResultIsSigned) {
125 // Both are unsigned.
126 ResultHasUnsignedPadding = hasUnsignedPadding() &&
127 Other.hasUnsignedPadding() && !ResultIsSaturated;
128 }
129
130 // If the result is signed, add an extra bit for the sign. Otherwise, if it is
131 // unsigned and has unsigned padding, we only need to add the extra padding
132 // bit back if we are not saturating.
133 if (ResultIsSigned || ResultHasUnsignedPadding)
134 CommonWidth++;
135
136 return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
137 ResultIsSaturated, ResultHasUnsignedPadding);
138}
139
Leonard Chan86285d22019-01-16 18:53:05 +0000140void APFixedPoint::toString(llvm::SmallVectorImpl<char> &Str) const {
141 llvm::APSInt Val = getValue();
142 unsigned Scale = getScale();
143
144 if (Val.isSigned() && Val.isNegative() && Val != -Val) {
145 Val = -Val;
146 Str.push_back('-');
147 }
148
149 llvm::APSInt IntPart = Val >> Scale;
150
151 // Add 4 digits to hold the value after multiplying 10 (the radix)
152 unsigned Width = Val.getBitWidth() + 4;
153 llvm::APInt FractPart = Val.zextOrTrunc(Scale).zext(Width);
154 llvm::APInt FractPartMask = llvm::APInt::getAllOnesValue(Scale).zext(Width);
155 llvm::APInt RadixInt = llvm::APInt(Width, 10);
156
157 IntPart.toString(Str, /*radix=*/10);
158 Str.push_back('.');
159 do {
160 (FractPart * RadixInt)
161 .lshr(Scale)
162 .toString(Str, /*radix=*/10, Val.isSigned());
163 FractPart = (FractPart * RadixInt) & FractPartMask;
164 } while (FractPart != 0);
165}
166
Leonard Chana6779422018-08-06 16:42:37 +0000167} // namespace clang