leonardchan updated this revision to Diff 153426.
leonardchan marked 8 inline comments as done.
leonardchan added a comment.
Herald added a subscriber: mgorny.
- Renamed to APFixedPoint
- Added `FixedPointSemantics` to represent saturation and whether or not
padding is involved. Similar to `APFloatSemantics`, this indicated how the
underlying APSInt passed to this will be used (ie. is the MSB padding or not).
Repository:
rC Clang
https://reviews.llvm.org/D48661
Files:
include/clang/AST/ASTContext.h
include/clang/Basic/FixedPoint.h
include/clang/Basic/TargetInfo.h
lib/AST/ASTContext.cpp
lib/Basic/CMakeLists.txt
lib/Basic/FixedPoint.cpp
lib/Sema/SemaExpr.cpp
test/Frontend/fixed_point_declarations.c
Index: test/Frontend/fixed_point_declarations.c
===================================================================
--- test/Frontend/fixed_point_declarations.c
+++ test/Frontend/fixed_point_declarations.c
@@ -1,5 +1,4 @@
// RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-linux | FileCheck %s
-// RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-scei-ps4-ubuntu-fast | FileCheck %s
// Primary fixed point types
signed short _Accum s_short_accum; // CHECK-DAG: @s_short_accum = {{.*}}global i16 0, align 2
@@ -111,3 +110,18 @@
unsigned short _Fract u_short_fract_eps = 0x1p-8uhr; // CHECK-DAG: @u_short_fract_eps = {{.*}}global i8 1, align 1
unsigned _Fract u_fract_eps = 0x1p-16ur; // CHECK-DAG: @u_fract_eps = {{.*}}global i16 1, align 2
unsigned long _Fract u_long_fract_eps = 0x1p-32ulr; // CHECK-DAG: @u_long_fract_eps = {{.*}}global i32 1, align 4
+
+// Zero
+short _Accum short_accum_zero = 0.0hk; // CHECK-DAG: @short_accum_zero = {{.*}}global i16 0, align 2
+ _Accum accum_zero = 0.0k; // CHECK-DAG: @accum_zero = {{.*}}global i32 0, align 4
+long _Accum long_accum_zero = 0.0lk; // CHECK-DAG: @long_accum_zero = {{.*}}global i64 0, align 8
+unsigned short _Accum u_short_accum_zero = 0.0uhk; // CHECK-DAG: @u_short_accum_zero = {{.*}}global i16 0, align 2
+unsigned _Accum u_accum_zero = 0.0uk; // CHECK-DAG: @u_accum_zero = {{.*}}global i32 0, align 4
+unsigned long _Accum u_long_accum_zero = 0.0ulk; // CHECK-DAG: @u_long_accum_zero = {{.*}}global i64 0, align 8
+
+short _Fract short_fract_zero = 0.0hr; // CHECK-DAG: @short_fract_zero = {{.*}}global i8 0, align 1
+ _Fract fract_zero = 0.0r; // CHECK-DAG: @fract_zero = {{.*}}global i16 0, align 2
+long _Fract long_fract_zero = 0.0lr; // CHECK-DAG: @long_fract_zero = {{.*}}global i32 0, align 4
+unsigned short _Fract u_short_fract_zero = 0.0uhr; // CHECK-DAG: @u_short_fract_zero = {{.*}}global i8 0, align 1
+unsigned _Fract u_fract_zero = 0.0ur; // CHECK-DAG: @u_fract_zero = {{.*}}global i16 0, align 2
+unsigned long _Fract u_long_fract_zero = 0.0ulr; // CHECK-DAG: @u_long_fract_zero = {{.*}}global i32 0, align 4
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -3351,16 +3351,14 @@
bool isSigned = !Literal.isUnsigned;
unsigned scale = Context.getFixedPointScale(Ty);
- unsigned ibits = Context.getFixedPointIBits(Ty);
unsigned bit_width = Context.getTypeInfo(Ty).Width;
llvm::APInt Val(bit_width, 0, isSigned);
bool Overflowed = Literal.GetFixedPointValue(Val, scale);
+ bool ValIsZero = Val.isNullValue() && !Overflowed;
- // Do not use bit_width since some types may have padding like _Fract or
- // unsigned _Accums if SameFBits is set.
- auto MaxVal = llvm::APInt::getMaxValue(ibits + scale).zextOrSelf(bit_width);
- if (Literal.isFract && Val == MaxVal + 1)
+ auto MaxVal = Context.getFixedPointMax(Ty).getValue();
+ if (Literal.isFract && Val == MaxVal + 1 && !ValIsZero)
// Clause 6.4.4 - The value of a constant shall be in the range of
// representable values for its type, with exception for constants of a
// fract type with a value of exactly 1; such a constant shall denote
Index: lib/Basic/FixedPoint.cpp
===================================================================
--- /dev/null
+++ lib/Basic/FixedPoint.cpp
@@ -0,0 +1,171 @@
+//===- 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 {
+
+llvm::APSInt ShrToZero(const llvm::APSInt &Val, unsigned Amt) {
+ if (Val < 0)
+ return -(-Val >> Amt);
+ else
+ return Val >> Amt;
+}
+
+bool IsPaddingSema(enum FixedPointSemantics Sema) {
+ return Sema == Padding || Sema == SatPadding;
+}
+
+bool IsSaturatedSema(enum FixedPointSemantics Sema) {
+ return Sema == SatPadding || Sema == SatNoPadding;
+}
+
+void APFixedPoint::convert(const ASTContext &Context, const QualType &Ty) {
+ assert(Ty->isFixedPointType());
+
+ unsigned DstWidth = Context.getTypeSize(Ty);
+ unsigned DstScale = Context.getFixedPointScale(Ty);
+ enum FixedPointSemantics Sema = Context.getFixedPointSema(Ty);
+ saturatedRescaleAndResize(DstWidth, DstScale, Sema);
+}
+
+bool APFixedPoint::rescaleAndResize(unsigned DstWidth, unsigned DstScale) {
+ assert(DstWidth > 0 && DstScale >= 0);
+
+ if (DstWidth > Val.getBitWidth()) Val = Val.extend(DstWidth);
+
+ bool Overflowed = false;
+
+ if (DstScale > Scale) {
+ // We can overflow here
+ unsigned ShiftAmt = DstScale - Scale;
+ if (Val < 0 && Val.countLeadingOnes() >= ShiftAmt)
+ Overflowed = true;
+ else if (Val > 0 && Val.countLeadingZeros() >= ShiftAmt)
+ Overflowed = true;
+
+ Val = Val.shl(ShiftAmt);
+ } else if (DstScale < Scale) {
+ Val = ShrToZero(Val, Scale - DstScale);
+ }
+
+ // We can overflow here
+ if (DstWidth < Val.getBitWidth()) {
+ unsigned NumRemovedBits = Val.getBitWidth() - DstWidth;
+ if (Val < 0 && NumRemovedBits >= Val.countLeadingOnes()) {
+ Overflowed = true;
+ } else if (Val > 0 && NumRemovedBits >= Val.countLeadingZeros()) {
+ Overflowed = true;
+ }
+
+ Val = Val.trunc(DstWidth);
+ }
+
+ Scale = DstScale;
+ return Overflowed;
+}
+
+void APFixedPoint::saturatedRescaleAndResize(unsigned DstWidth,
+ unsigned DstScale,
+ enum FixedPointSemantics DstSema) {
+ bool DstIsSaturated = IsSaturatedSema(DstSema);
+ bool IsNegative = Val < 0;
+ bool IsUnsigned = Val.isUnsigned();
+ bool Overflowed = rescaleAndResize(DstWidth, DstScale);
+
+ if (DstIsSaturated && Overflowed) {
+ if (IsNegative) {
+ // Use min
+ Val = llvm::APSInt::getMinValue(DstWidth, IsUnsigned);
+ } else {
+ // Use max
+ Val = llvm::APSInt::getMaxValue(DstWidth, IsUnsigned);
+ if (IsUnsigned && IsPaddingSema(DstSema)) Val = Val.lshr(1);
+ }
+ }
+
+ Sema = DstSema;
+}
+
+int APFixedPoint::compare(const APFixedPoint &Other) const {
+ llvm::APSInt ThisVal = Val;
+ 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
+ if (Scale < OtherScale)
+ CommonWidth += OtherScale - Scale;
+ else if (Scale > OtherScale)
+ CommonWidth += Scale - OtherScale;
+
+ ThisVal = ThisVal.extend(CommonWidth);
+ OtherVal = OtherVal.extend(CommonWidth);
+
+ unsigned CommonScale = std::max(Scale, OtherScale);
+ if (Scale < CommonScale) ThisVal = ThisVal.shl(CommonScale - Scale);
+ if (OtherScale < CommonScale)
+ 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(unsigned NumBits, unsigned Scale, bool Signed,
+ enum FixedPointSemantics Sema) {
+ bool IsUnsigned = !Signed;
+ auto Val = llvm::APSInt::getMaxValue(NumBits, IsUnsigned);
+ if (IsUnsigned && IsPaddingSema(Sema)) Val = Val.lshr(1);
+ return APFixedPoint(Val, Scale, Sema);
+}
+
+APFixedPoint APFixedPoint::getMin(unsigned NumBits, unsigned Scale, bool Signed,
+ enum FixedPointSemantics Sema) {
+ bool IsUnsigned = !Signed;
+ auto Val = llvm::APSInt::getMinValue(NumBits, IsUnsigned);
+ return APFixedPoint(Val, Scale, Sema);
+}
+
+} // namespace clang
Index: lib/Basic/CMakeLists.txt
===================================================================
--- lib/Basic/CMakeLists.txt
+++ lib/Basic/CMakeLists.txt
@@ -54,6 +54,7 @@
DiagnosticOptions.cpp
FileManager.cpp
FileSystemStatCache.cpp
+ FixedPoint.cpp
IdentifierTable.cpp
LangOptions.cpp
MemoryBufferCache.cpp
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -10282,3 +10282,26 @@
return 0;
}
}
+
+enum FixedPointSemantics ASTContext::getFixedPointSema(QualType Ty) const {
+ assert(Ty->isFixedPointType());
+ bool Saturated = Ty->isSaturatedFixedPointType();
+ if (getTargetInfo().doUnsignedFixedPointTypesHavePadding())
+ return Saturated ? SatPadding : Padding;
+ else
+ return Saturated ? SatNoPadding : NoPadding;
+}
+
+APFixedPoint ASTContext::getFixedPointMax(QualType Ty) const {
+ assert(Ty->isFixedPointType());
+ return APFixedPoint::getMax(getTypeSize(Ty), getFixedPointScale(Ty),
+ Ty->isSignedFixedPointType(),
+ getFixedPointSema(Ty));
+}
+
+APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const {
+ assert(Ty->isFixedPointType());
+ return APFixedPoint::getMin(getTypeSize(Ty), getFixedPointScale(Ty),
+ Ty->isSignedFixedPointType(),
+ getFixedPointSema(Ty));
+}
Index: include/clang/Basic/TargetInfo.h
===================================================================
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -311,6 +311,12 @@
}
}
+ /// In the event this target uses the same number of fractional bits for its
+ /// unsigned types as it does with its signed counterparts, there will be
+ /// exactly one bit of padding.
+ /// Return true if unsigned fixed point types have padding for this target.
+ bool doUnsignedFixedPointTypesHavePadding() const { return SameFBits; }
+
/// Return the width (in bits) of the specified integer type enum.
///
/// For example, SignedInt -> getIntWidth().
Index: include/clang/Basic/FixedPoint.h
===================================================================
--- /dev/null
+++ include/clang/Basic/FixedPoint.h
@@ -0,0 +1,100 @@
+//===- 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;
+
+enum FixedPointSemantics {
+ Padding,
+ NoPadding,
+ SatPadding,
+ SatNoPadding,
+};
+
+llvm::APSInt ShrToZero(const llvm::APSInt &Val, unsigned Amt);
+
+bool IsPaddingSema(enum FixedPointSemantics Sema);
+bool IsSaturatedSema(enum FixedPointSemantics Sema);
+
+class APFixedPoint {
+ public:
+ APFixedPoint(const llvm::APSInt &Val, unsigned Scale,
+ enum FixedPointSemantics Sema)
+ : Val(Val), Scale(Scale), Sema(Sema) {}
+
+ llvm::APSInt getValue() const { return Val; }
+ unsigned getScale() const { return Scale; }
+ bool isSaturated() const { return IsSaturatedSema(Sema); }
+
+ // Convert this number to match the scale, width, and sema of the
+ // provided fixed point type.
+ void convert(const ASTContext &Context, const QualType &Ty);
+
+ // Change the width and scale of this fixed point number.
+ // Return true if overflow occurrd and false otherwise.
+ bool rescaleAndResize(unsigned DstWidth, unsigned DstScale);
+
+ // Same as rescaleAndResize but handles overflow with saturation.
+ void saturatedRescaleAndResize(unsigned DstWidth, unsigned DstScale,
+ enum FixedPointSemantics DstSema);
+
+ APFixedPoint shr(unsigned Amt) const {
+ return APFixedPoint(ShrToZero(Val, Amt), Scale, Sema);
+ }
+
+ APFixedPoint shl(unsigned Amt) const {
+ return APFixedPoint(Val << Amt, Scale, Sema);
+ }
+
+ llvm::APSInt getIntPart() const { return ShrToZero(Val, Scale); }
+
+ // 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(unsigned NumBits, unsigned scale, bool Signed,
+ enum FixedPointSemantics Sema);
+ static APFixedPoint getMin(unsigned NumBits, unsigned scale, bool Signed,
+ enum FixedPointSemantics Sema);
+
+ private:
+ llvm::APSInt Val;
+ unsigned Scale;
+ enum FixedPointSemantics Sema;
+};
+
+} // namespace clang
+
+#endif
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -30,6 +30,7 @@
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/FixedPoint.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
@@ -1949,6 +1950,9 @@
unsigned char getFixedPointScale(QualType Ty) const;
unsigned char getFixedPointIBits(QualType Ty) const;
+ enum FixedPointSemantics getFixedPointSema(QualType Ty) const;
+ APFixedPoint getFixedPointMax(QualType Ty) const;
+ APFixedPoint getFixedPointMin(QualType Ty) const;
DeclarationNameInfo getNameForTemplate(TemplateName Name,
SourceLocation NameLoc) const;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits