Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Fixed Point Arithmetic] Fixed Point Constant
This patch proposes an abstract type that represents fixed point numbers, similar to APInt or APSInt that was discussed in https://reviews.llvm.org/D48456#inline-425585. This type holds a value, scale, and saturation and is meant to perform intermediate calculations on constant fixed point values. Currently this class is used as a way for handling the conversions between fixed point numbers with different sizes and radixes. For example, if I'm casting from a signed _Accum to a saturated unsigned short _Accum, I will need to check the value of the signed _Accum to see if it fits into the short _Accum which involves getting and comparing against the max/min values of the short _Accum. The FixedPointNumber class currently handles the radix shifting and extension when converting to a signed _Accum. Differential Revision: https://reviews.llvm.org/D48661 llvm-svn: 339028
- Loading branch information
Showing
10 changed files
with
991 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
//===- FixedPoint.h - 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 fixed point number interface. | ||
/// This is a class for abstracting various operations performed on fixed point | ||
/// types described in ISO/IEC JTC1 SC22 WG14 N1169 starting at clause 4. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_BASIC_FIXEDPOINT_H | ||
#define LLVM_CLANG_BASIC_FIXEDPOINT_H | ||
|
||
#include "llvm/ADT/APSInt.h" | ||
|
||
namespace clang { | ||
|
||
class ASTContext; | ||
class QualType; | ||
|
||
/// The fixed point semantics work similarly to llvm::fltSemantics. The width | ||
/// specifies the whole bit width of the underlying scaled integer (with padding | ||
/// if any). The scale represents the number of fractional bits in this type. | ||
/// When HasUnsignedPadding is true and this type is signed, the first bit | ||
/// in the value this represents is treaded as padding. | ||
class FixedPointSemantics { | ||
public: | ||
FixedPointSemantics(unsigned Width, unsigned Scale, bool IsSigned, | ||
bool IsSaturated, bool HasUnsignedPadding) | ||
: Width(Width), Scale(Scale), IsSigned(IsSigned), | ||
IsSaturated(IsSaturated), HasUnsignedPadding(HasUnsignedPadding) { | ||
assert(Width >= Scale && "Not enough room for the scale"); | ||
} | ||
|
||
unsigned getWidth() const { return Width; } | ||
unsigned getScale() const { return Scale; } | ||
bool isSigned() const { return IsSigned; } | ||
bool isSaturated() const { return IsSaturated; } | ||
bool hasUnsignedPadding() const { return HasUnsignedPadding; } | ||
|
||
void setSaturated(bool Saturated) { IsSaturated = Saturated; } | ||
|
||
unsigned getIntegralBits() const { | ||
if (IsSigned || (!IsSigned && HasUnsignedPadding)) | ||
return Width - Scale - 1; | ||
else | ||
return Width - Scale; | ||
} | ||
|
||
private: | ||
unsigned Width; | ||
unsigned Scale; | ||
bool IsSigned; | ||
bool IsSaturated; | ||
bool HasUnsignedPadding; | ||
}; | ||
|
||
/// The APFixedPoint class works similarly to APInt/APSInt in that it is a | ||
/// functional replacement for a scaled integer. It is meant to replicate the | ||
/// fixed point types proposed in ISO/IEC JTC1 SC22 WG14 N1169. The class carries | ||
/// info about the fixed point type's width, sign, scale, and saturation, and | ||
/// provides different operations that would normally be performed on fixed point | ||
/// types. | ||
/// | ||
/// Semantically this does not represent any existing C type other than fixed | ||
/// point types and should eventually be moved to LLVM if fixed point types gain | ||
/// native IR support. | ||
class APFixedPoint { | ||
public: | ||
APFixedPoint(const llvm::APInt &Val, const FixedPointSemantics &Sema) | ||
: Val(Val, !Sema.isSigned()), Sema(Sema) { | ||
assert(Val.getBitWidth() == Sema.getWidth() && | ||
"The value should have a bit width that matches the Sema width"); | ||
} | ||
|
||
APFixedPoint(uint64_t Val, const FixedPointSemantics &Sema) | ||
: APFixedPoint(llvm::APInt(Sema.getWidth(), Val, Sema.isSigned()), | ||
Sema) {} | ||
|
||
llvm::APSInt getValue() const { return llvm::APSInt(Val, !Sema.isSigned()); } | ||
inline unsigned getWidth() const { return Sema.getWidth(); } | ||
inline unsigned getScale() const { return Sema.getScale(); } | ||
inline bool isSaturated() const { return Sema.isSaturated(); } | ||
inline bool isSigned() const { return Sema.isSigned(); } | ||
inline bool hasPadding() const { return Sema.hasUnsignedPadding(); } | ||
|
||
// Convert this number to match the semantics provided. | ||
APFixedPoint convert(const FixedPointSemantics &DstSema) const; | ||
|
||
APFixedPoint shr(unsigned Amt) const { | ||
return APFixedPoint(Val >> Amt, Sema); | ||
} | ||
|
||
APFixedPoint shl(unsigned Amt) const { | ||
return APFixedPoint(Val << Amt, Sema); | ||
} | ||
|
||
llvm::APSInt getIntPart() const { | ||
if (Val < 0 && Val != -Val) // Cover the case when we have the min val | ||
return -(-Val >> getScale()); | ||
else | ||
return Val >> getScale(); | ||
} | ||
|
||
// If LHS > RHS, return 1. If LHS == RHS, return 0. If LHS < RHS, return -1. | ||
int compare(const APFixedPoint &Other) const; | ||
bool operator==(const APFixedPoint &Other) const { | ||
return compare(Other) == 0; | ||
} | ||
bool operator!=(const APFixedPoint &Other) const { | ||
return compare(Other) != 0; | ||
} | ||
bool operator>(const APFixedPoint &Other) const { return compare(Other) > 0; } | ||
bool operator<(const APFixedPoint &Other) const { return compare(Other) < 0; } | ||
bool operator>=(const APFixedPoint &Other) const { | ||
return compare(Other) >= 0; | ||
} | ||
bool operator<=(const APFixedPoint &Other) const { | ||
return compare(Other) <= 0; | ||
} | ||
|
||
static APFixedPoint getMax(const FixedPointSemantics &Sema); | ||
static APFixedPoint getMin(const FixedPointSemantics &Sema); | ||
|
||
private: | ||
llvm::APSInt Val; | ||
FixedPointSemantics Sema; | ||
}; | ||
|
||
} // namespace clang | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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/AST/ASTContext.h" | ||
#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 += std::abs(static_cast<int>(getScale() - OtherScale)); | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.