summaryrefslogtreecommitdiff
path: root/lib/Basic/FixedPoint.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:04:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:04:05 +0000
commit676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63 (patch)
tree02a1ac369cb734d0abfa5000dd86e5b7797e6a74 /lib/Basic/FixedPoint.cpp
parentc7e70c433efc6953dc3888b9fbf9f3512d7da2b0 (diff)
Diffstat (limited to 'lib/Basic/FixedPoint.cpp')
-rw-r--r--lib/Basic/FixedPoint.cpp115
1 files changed, 115 insertions, 0 deletions
diff --git a/lib/Basic/FixedPoint.cpp b/lib/Basic/FixedPoint.cpp
new file mode 100644
index 0000000000000..bfff0fc212e0a
--- /dev/null
+++ b/lib/Basic/FixedPoint.cpp
@@ -0,0 +1,115 @@
+//===- FixedPoint.cpp - Fixed point constant handling -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Defines the implementation for the fixed point number interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/FixedPoint.h"
+
+namespace clang {
+
+APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema) const {
+ llvm::APSInt NewVal = Val;
+ unsigned DstWidth = DstSema.getWidth();
+ unsigned DstScale = DstSema.getScale();
+ bool Upscaling = DstScale > getScale();
+
+ if (Upscaling) {
+ NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
+ NewVal <<= (DstScale - getScale());
+ } else {
+ NewVal >>= (getScale() - DstScale);
+ }
+
+ if (DstSema.isSaturated()) {
+ auto Mask = llvm::APInt::getBitsSetFrom(
+ NewVal.getBitWidth(),
+ std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
+ llvm::APInt Masked(NewVal & Mask);
+
+ // Change in the bits above the sign
+ if (!(Masked == Mask || Masked == 0))
+ NewVal = NewVal.isNegative() ? Mask : ~Mask;
+
+ if (!DstSema.isSigned() && NewVal.isNegative())
+ NewVal = 0;
+ }
+
+ NewVal = NewVal.extOrTrunc(DstWidth);
+ NewVal.setIsSigned(DstSema.isSigned());
+ return APFixedPoint(NewVal, DstSema);
+}
+
+int APFixedPoint::compare(const APFixedPoint &Other) const {
+ llvm::APSInt ThisVal = getValue();
+ llvm::APSInt OtherVal = Other.getValue();
+ bool ThisSigned = Val.isSigned();
+ bool OtherSigned = OtherVal.isSigned();
+ unsigned OtherScale = Other.getScale();
+ unsigned OtherWidth = OtherVal.getBitWidth();
+
+ unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);
+
+ // Prevent overflow in the event the widths are the same but the scales differ
+ CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale
+ : OtherScale - getScale();
+
+ ThisVal = ThisVal.extOrTrunc(CommonWidth);
+ OtherVal = OtherVal.extOrTrunc(CommonWidth);
+
+ unsigned CommonScale = std::max(getScale(), OtherScale);
+ ThisVal = ThisVal.shl(CommonScale - getScale());
+ OtherVal = OtherVal.shl(CommonScale - OtherScale);
+
+ if (ThisSigned && OtherSigned) {
+ if (ThisVal.sgt(OtherVal))
+ return 1;
+ else if (ThisVal.slt(OtherVal))
+ return -1;
+ } else if (!ThisSigned && !OtherSigned) {
+ if (ThisVal.ugt(OtherVal))
+ return 1;
+ else if (ThisVal.ult(OtherVal))
+ return -1;
+ } else if (ThisSigned && !OtherSigned) {
+ if (ThisVal.isSignBitSet())
+ return -1;
+ else if (ThisVal.ugt(OtherVal))
+ return 1;
+ else if (ThisVal.ult(OtherVal))
+ return -1;
+ } else {
+ // !ThisSigned && OtherSigned
+ if (OtherVal.isSignBitSet())
+ return 1;
+ else if (ThisVal.ugt(OtherVal))
+ return 1;
+ else if (ThisVal.ult(OtherVal))
+ return -1;
+ }
+
+ return 0;
+}
+
+APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) {
+ bool IsUnsigned = !Sema.isSigned();
+ auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
+ if (IsUnsigned && Sema.hasUnsignedPadding())
+ Val = Val.lshr(1);
+ return APFixedPoint(Val, Sema);
+}
+
+APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
+ auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
+ return APFixedPoint(Val, Sema);
+}
+
+} // namespace clang