blob: 58037ff39834a5e42b058abce9a39a730ed324ea [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
62 CommonWidth += std::abs(static_cast<int>(getScale() - OtherScale));
63
64 ThisVal = ThisVal.extOrTrunc(CommonWidth);
65 OtherVal = OtherVal.extOrTrunc(CommonWidth);
66
67 unsigned CommonScale = std::max(getScale(), OtherScale);
68 ThisVal = ThisVal.shl(CommonScale - getScale());
69 OtherVal = OtherVal.shl(CommonScale - OtherScale);
70
71 if (ThisSigned && OtherSigned) {
72 if (ThisVal.sgt(OtherVal))
73 return 1;
74 else if (ThisVal.slt(OtherVal))
75 return -1;
76 } else if (!ThisSigned && !OtherSigned) {
77 if (ThisVal.ugt(OtherVal))
78 return 1;
79 else if (ThisVal.ult(OtherVal))
80 return -1;
81 } else if (ThisSigned && !OtherSigned) {
82 if (ThisVal.isSignBitSet())
83 return -1;
84 else if (ThisVal.ugt(OtherVal))
85 return 1;
86 else if (ThisVal.ult(OtherVal))
87 return -1;
88 } else {
89 // !ThisSigned && OtherSigned
90 if (OtherVal.isSignBitSet())
91 return 1;
92 else if (ThisVal.ugt(OtherVal))
93 return 1;
94 else if (ThisVal.ult(OtherVal))
95 return -1;
96 }
97
98 return 0;
99}
100
101APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) {
102 bool IsUnsigned = !Sema.isSigned();
103 auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
104 if (IsUnsigned && Sema.hasUnsignedPadding())
105 Val = Val.lshr(1);
106 return APFixedPoint(Val, Sema);
107}
108
109APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
110 auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
111 return APFixedPoint(Val, Sema);
112}
113
114} // namespace clang