1 //===- 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 
15 #include "clang/Basic/FixedPoint.h"
16 
17 namespace clang {
18 
convert(const FixedPointSemantics & DstSema) const19 APFixedPoint 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 
compare(const APFixedPoint & Other) const51 int 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 += getScale() >= OtherScale ? getScale() - OtherScale
63                                           : OtherScale - getScale();
64 
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 
getMax(const FixedPointSemantics & Sema)102 APFixedPoint 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 
getMin(const FixedPointSemantics & Sema)110 APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
111   auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
112   return APFixedPoint(Val, Sema);
113 }
114 
115 }  // namespace clang
116