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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to