r339028 - [Fixed Point Arithmetic] Fixed Point Constant

Leonard Chan via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 6 09:42:37 PDT 2018


Author: leonardchan
Date: Mon Aug  6 09:42:37 2018
New Revision: 339028

URL: http://llvm.org/viewvc/llvm-project?rev=339028&view=rev
Log:
[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

Added:
    cfe/trunk/include/clang/Basic/FixedPoint.h
    cfe/trunk/lib/Basic/FixedPoint.cpp
    cfe/trunk/unittests/Basic/FixedPointTest.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/Basic/TargetInfo.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/Basic/CMakeLists.txt
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/Frontend/fixed_point_declarations.c
    cfe/trunk/unittests/Basic/CMakeLists.txt

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=339028&r1=339027&r2=339028&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Mon Aug  6 09:42:37 2018
@@ -79,6 +79,7 @@ struct fltSemantics;
 
 namespace clang {
 
+class APFixedPoint;
 class APValue;
 class ASTMutationListener;
 class ASTRecordLayout;
@@ -92,6 +93,7 @@ class CXXMethodDecl;
 class CXXRecordDecl;
 class DiagnosticsEngine;
 class Expr;
+class FixedPointSemantics;
 class MangleContext;
 class MangleNumberingContext;
 class MaterializeTemporaryExpr;
@@ -1961,6 +1963,9 @@ public:
 
   unsigned char getFixedPointScale(QualType Ty) const;
   unsigned char getFixedPointIBits(QualType Ty) const;
+  FixedPointSemantics getFixedPointSemantics(QualType Ty) const;
+  APFixedPoint getFixedPointMax(QualType Ty) const;
+  APFixedPoint getFixedPointMin(QualType Ty) const;
 
   DeclarationNameInfo getNameForTemplate(TemplateName Name,
                                          SourceLocation NameLoc) const;

Added: cfe/trunk/include/clang/Basic/FixedPoint.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/FixedPoint.h?rev=339028&view=auto
==============================================================================
--- cfe/trunk/include/clang/Basic/FixedPoint.h (added)
+++ cfe/trunk/include/clang/Basic/FixedPoint.h Mon Aug  6 09:42:37 2018
@@ -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

Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=339028&r1=339027&r2=339028&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
+++ cfe/trunk/include/clang/Basic/TargetInfo.h Mon Aug  6 09:42:37 2018
@@ -312,6 +312,14 @@ public:
     }
   }
 
+  /// 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 PaddingOnUnsignedFixedPoint;
+  }
+
   /// Return the width (in bits) of the specified integer type enum.
   ///
   /// For example, SignedInt -> getIntWidth().

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=339028&r1=339027&r2=339028&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Aug  6 09:42:37 2018
@@ -48,6 +48,7 @@
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/CommentOptions.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
+#include "clang/Basic/FixedPoint.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
@@ -10433,3 +10434,22 @@ unsigned char ASTContext::getFixedPointI
       return 0;
   }
 }
+
+FixedPointSemantics ASTContext::getFixedPointSemantics(QualType Ty) const {
+  assert(Ty->isFixedPointType());
+  bool isSigned = Ty->isSignedFixedPointType();
+  return FixedPointSemantics(
+      static_cast<unsigned>(getTypeSize(Ty)), getFixedPointScale(Ty), isSigned,
+      Ty->isSaturatedFixedPointType(),
+      !isSigned && getTargetInfo().doUnsignedFixedPointTypesHavePadding());
+}
+
+APFixedPoint ASTContext::getFixedPointMax(QualType Ty) const {
+  assert(Ty->isFixedPointType());
+  return APFixedPoint::getMax(getFixedPointSemantics(Ty));
+}
+
+APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const {
+  assert(Ty->isFixedPointType());
+  return APFixedPoint::getMin(getFixedPointSemantics(Ty));
+}

Modified: cfe/trunk/lib/Basic/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/CMakeLists.txt?rev=339028&r1=339027&r2=339028&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/CMakeLists.txt (original)
+++ cfe/trunk/lib/Basic/CMakeLists.txt Mon Aug  6 09:42:37 2018
@@ -54,6 +54,7 @@ add_clang_library(clangBasic
   DiagnosticOptions.cpp
   FileManager.cpp
   FileSystemStatCache.cpp
+  FixedPoint.cpp
   IdentifierTable.cpp
   LangOptions.cpp
   MemoryBufferCache.cpp

Added: cfe/trunk/lib/Basic/FixedPoint.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FixedPoint.cpp?rev=339028&view=auto
==============================================================================
--- cfe/trunk/lib/Basic/FixedPoint.cpp (added)
+++ cfe/trunk/lib/Basic/FixedPoint.cpp Mon Aug  6 09:42:37 2018
@@ -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

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=339028&r1=339027&r2=339028&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Aug  6 09:42:37 2018
@@ -26,6 +26,7 @@
 #include "clang/AST/ExprOpenMP.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/Basic/FixedPoint.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -3363,16 +3364,14 @@ ExprResult Sema::ActOnNumericConstant(co
 
     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 PaddingOnUnsignedFixedPoint 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

Modified: cfe/trunk/test/Frontend/fixed_point_declarations.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Frontend/fixed_point_declarations.c?rev=339028&r1=339027&r2=339028&view=diff
==============================================================================
--- cfe/trunk/test/Frontend/fixed_point_declarations.c (original)
+++ cfe/trunk/test/Frontend/fixed_point_declarations.c Mon Aug  6 09:42:37 2018
@@ -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 @@ long _Fract           long_fract_eps
 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

Modified: cfe/trunk/unittests/Basic/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/CMakeLists.txt?rev=339028&r1=339027&r2=339028&view=diff
==============================================================================
--- cfe/trunk/unittests/Basic/CMakeLists.txt (original)
+++ cfe/trunk/unittests/Basic/CMakeLists.txt Mon Aug  6 09:42:37 2018
@@ -6,6 +6,7 @@ add_clang_unittest(BasicTests
   CharInfoTest.cpp
   DiagnosticTest.cpp
   FileManagerTest.cpp
+  FixedPointTest.cpp
   MemoryBufferCacheTest.cpp
   SourceManagerTest.cpp
   VirtualFileSystemTest.cpp
@@ -13,6 +14,7 @@ add_clang_unittest(BasicTests
 
 target_link_libraries(BasicTests
   PRIVATE
+  clangAST
   clangBasic
   clangLex
   )

Added: cfe/trunk/unittests/Basic/FixedPointTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/FixedPointTest.cpp?rev=339028&view=auto
==============================================================================
--- cfe/trunk/unittests/Basic/FixedPointTest.cpp (added)
+++ cfe/trunk/unittests/Basic/FixedPointTest.cpp Mon Aug  6 09:42:37 2018
@@ -0,0 +1,683 @@
+//===- unittests/Basic/FixedPointTest.cpp -- fixed point number tests -----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/FixedPoint.h"
+#include "llvm/ADT/APSInt.h"
+#include "gtest/gtest.h"
+
+using clang::APFixedPoint;
+using clang::FixedPointSemantics;
+using llvm::APInt;
+using llvm::APSInt;
+
+namespace {
+
+FixedPointSemantics Saturated(FixedPointSemantics Sema) {
+  Sema.setSaturated(true);
+  return Sema;
+}
+
+FixedPointSemantics getSAccumSema() {
+  return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/true,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getAccumSema() {
+  return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/true,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getLAccumSema() {
+  return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/true,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getSFractSema() {
+  return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/true,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getFractSema() {
+  return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/true,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getLFractSema() {
+  return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/true,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getUSAccumSema() {
+  return FixedPointSemantics(/*width=*/16, /*scale=*/8, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getUAccumSema() {
+  return FixedPointSemantics(/*width=*/32, /*scale=*/16, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getULAccumSema() {
+  return FixedPointSemantics(/*width=*/64, /*scale=*/32, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getUSFractSema() {
+  return FixedPointSemantics(/*width=*/8, /*scale=*/8, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getUFractSema() {
+  return FixedPointSemantics(/*width=*/16, /*scale=*/16, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getULFractSema() {
+  return FixedPointSemantics(/*width=*/32, /*scale=*/32, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/false);
+}
+
+FixedPointSemantics getPadUSAccumSema() {
+  return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/true);
+}
+
+FixedPointSemantics getPadUAccumSema() {
+  return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/true);
+}
+
+FixedPointSemantics getPadULAccumSema() {
+  return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/true);
+}
+
+FixedPointSemantics getPadUSFractSema() {
+  return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/true);
+}
+
+FixedPointSemantics getPadUFractSema() {
+  return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/true);
+}
+
+FixedPointSemantics getPadULFractSema() {
+  return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/false,
+                             /*isSaturated=*/false,
+                             /*hasUnsignedPadding=*/true);
+}
+
+void CheckUnpaddedMax(const FixedPointSemantics &Sema) {
+  ASSERT_EQ(APFixedPoint::getMax(Sema).getValue(),
+            APSInt::getMaxValue(Sema.getWidth(), !Sema.isSigned()));
+}
+
+void CheckPaddedMax(const FixedPointSemantics &Sema) {
+  ASSERT_EQ(APFixedPoint::getMax(Sema).getValue(),
+            APSInt::getMaxValue(Sema.getWidth(), !Sema.isSigned()) >> 1);
+}
+
+void CheckMin(const FixedPointSemantics &Sema) {
+  ASSERT_EQ(APFixedPoint::getMin(Sema).getValue(),
+            APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned()));
+}
+
+TEST(FixedPointTest, getMax) {
+  CheckUnpaddedMax(getSAccumSema());
+  CheckUnpaddedMax(getAccumSema());
+  CheckUnpaddedMax(getLAccumSema());
+  CheckUnpaddedMax(getUSAccumSema());
+  CheckUnpaddedMax(getUAccumSema());
+  CheckUnpaddedMax(getULAccumSema());
+  CheckUnpaddedMax(getSFractSema());
+  CheckUnpaddedMax(getFractSema());
+  CheckUnpaddedMax(getLFractSema());
+  CheckUnpaddedMax(getUSFractSema());
+  CheckUnpaddedMax(getUFractSema());
+  CheckUnpaddedMax(getULFractSema());
+
+  CheckPaddedMax(getPadUSAccumSema());
+  CheckPaddedMax(getPadUAccumSema());
+  CheckPaddedMax(getPadULAccumSema());
+  CheckPaddedMax(getPadUSFractSema());
+  CheckPaddedMax(getPadUFractSema());
+  CheckPaddedMax(getPadULFractSema());
+}
+
+TEST(FixedPointTest, getMin) {
+  CheckMin(getSAccumSema());
+  CheckMin(getAccumSema());
+  CheckMin(getLAccumSema());
+  CheckMin(getUSAccumSema());
+  CheckMin(getUAccumSema());
+  CheckMin(getULAccumSema());
+  CheckMin(getSFractSema());
+  CheckMin(getFractSema());
+  CheckMin(getLFractSema());
+  CheckMin(getUSFractSema());
+  CheckMin(getUFractSema());
+  CheckMin(getULFractSema());
+
+  CheckMin(getPadUSAccumSema());
+  CheckMin(getPadUAccumSema());
+  CheckMin(getPadULAccumSema());
+  CheckMin(getPadUSFractSema());
+  CheckMin(getPadUFractSema());
+  CheckMin(getPadULFractSema());
+}
+
+void CheckIntPart(const FixedPointSemantics &Sema, int64_t IntPart) {
+  unsigned Scale = Sema.getScale();
+
+  // Value with a fraction
+  APFixedPoint ValWithFract(APInt(Sema.getWidth(),
+                                  (IntPart << Scale) + (1ULL << (Scale - 1)),
+                                  Sema.isSigned()),
+                            Sema);
+  ASSERT_EQ(ValWithFract.getIntPart(), IntPart);
+
+  // Just fraction
+  APFixedPoint JustFract(
+      APInt(Sema.getWidth(), (1ULL << (Scale - 1)), Sema.isSigned()), Sema);
+  ASSERT_EQ(JustFract.getIntPart(), 0);
+
+  // Whole number
+  APFixedPoint WholeNum(
+      APInt(Sema.getWidth(), (IntPart << Scale), Sema.isSigned()), Sema);
+  ASSERT_EQ(WholeNum.getIntPart(), IntPart);
+
+  // Negative
+  if (Sema.isSigned()) {
+    APFixedPoint Negative(
+        APInt(Sema.getWidth(), (IntPart << Scale), Sema.isSigned()), Sema);
+    ASSERT_EQ(Negative.getIntPart(), IntPart);
+  }
+}
+
+void CheckIntPartMin(const FixedPointSemantics &Sema, int64_t Expected) {
+  ASSERT_EQ(APFixedPoint::getMin(Sema).getIntPart(), Expected);
+}
+
+void CheckIntPartMax(const FixedPointSemantics &Sema, uint64_t Expected) {
+  ASSERT_EQ(APFixedPoint::getMax(Sema).getIntPart(), Expected);
+}
+
+TEST(FixedPoint, getIntPart) {
+  // Normal values
+  CheckIntPart(getSAccumSema(), 2);
+  CheckIntPart(getAccumSema(), 2);
+  CheckIntPart(getLAccumSema(), 2);
+  CheckIntPart(getUSAccumSema(), 2);
+  CheckIntPart(getUAccumSema(), 2);
+  CheckIntPart(getULAccumSema(), 2);
+
+  // Zero
+  CheckIntPart(getSAccumSema(), 0);
+  CheckIntPart(getAccumSema(), 0);
+  CheckIntPart(getLAccumSema(), 0);
+  CheckIntPart(getUSAccumSema(), 0);
+  CheckIntPart(getUAccumSema(), 0);
+  CheckIntPart(getULAccumSema(), 0);
+
+  CheckIntPart(getSFractSema(), 0);
+  CheckIntPart(getFractSema(), 0);
+  CheckIntPart(getLFractSema(), 0);
+  CheckIntPart(getUSFractSema(), 0);
+  CheckIntPart(getUFractSema(), 0);
+  CheckIntPart(getULFractSema(), 0);
+
+  // Min
+  CheckIntPartMin(getSAccumSema(), -256);
+  CheckIntPartMin(getAccumSema(), -65536);
+  CheckIntPartMin(getLAccumSema(), -4294967296);
+
+  CheckIntPartMin(getSFractSema(), -1);
+  CheckIntPartMin(getFractSema(), -1);
+  CheckIntPartMin(getLFractSema(), -1);
+
+  // Max
+  CheckIntPartMax(getSAccumSema(), 255);
+  CheckIntPartMax(getAccumSema(), 65535);
+  CheckIntPartMax(getLAccumSema(), 4294967295);
+  CheckIntPartMax(getUSAccumSema(), 255);
+  CheckIntPartMax(getUAccumSema(), 65535);
+  CheckIntPartMax(getULAccumSema(), 4294967295);
+
+  CheckIntPartMax(getSFractSema(), 0);
+  CheckIntPartMax(getFractSema(), 0);
+  CheckIntPartMax(getLFractSema(), 0);
+  CheckIntPartMax(getUSFractSema(), 0);
+  CheckIntPartMax(getUFractSema(), 0);
+  CheckIntPartMax(getULFractSema(), 0);
+
+  // Padded
+  // Normal Values
+  CheckIntPart(getPadUSAccumSema(), 2);
+  CheckIntPart(getPadUAccumSema(), 2);
+  CheckIntPart(getPadULAccumSema(), 2);
+
+  // Zero
+  CheckIntPart(getPadUSAccumSema(), 0);
+  CheckIntPart(getPadUAccumSema(), 0);
+  CheckIntPart(getPadULAccumSema(), 0);
+
+  CheckIntPart(getPadUSFractSema(), 0);
+  CheckIntPart(getPadUFractSema(), 0);
+  CheckIntPart(getPadULFractSema(), 0);
+
+  // Max
+  CheckIntPartMax(getPadUSAccumSema(), 255);
+  CheckIntPartMax(getPadUAccumSema(), 65535);
+  CheckIntPartMax(getPadULAccumSema(), 4294967295);
+
+  CheckIntPartMax(getPadUSFractSema(), 0);
+  CheckIntPartMax(getPadUFractSema(), 0);
+  CheckIntPartMax(getPadULFractSema(), 0);
+}
+
+TEST(FixedPoint, compare) {
+  // Equality
+  // With fractional part (2.5)
+  // Across sizes
+  ASSERT_EQ(APFixedPoint(320, getSAccumSema()),
+            APFixedPoint(81920, getAccumSema()));
+  ASSERT_EQ(APFixedPoint(320, getSAccumSema()),
+            APFixedPoint(5368709120, getLAccumSema()));
+  ASSERT_EQ(APFixedPoint(0, getSAccumSema()), APFixedPoint(0, getLAccumSema()));
+
+  // Across types (0.5)
+  ASSERT_EQ(APFixedPoint(64, getSAccumSema()),
+            APFixedPoint(64, getSFractSema()));
+  ASSERT_EQ(APFixedPoint(16384, getAccumSema()),
+            APFixedPoint(16384, getFractSema()));
+  ASSERT_EQ(APFixedPoint(1073741824, getLAccumSema()),
+            APFixedPoint(1073741824, getLFractSema()));
+
+  // Across widths and types (0.5)
+  ASSERT_EQ(APFixedPoint(64, getSAccumSema()),
+            APFixedPoint(16384, getFractSema()));
+  ASSERT_EQ(APFixedPoint(64, getSAccumSema()),
+            APFixedPoint(1073741824, getLFractSema()));
+
+  // Across saturation
+  ASSERT_EQ(APFixedPoint(320, getSAccumSema()),
+            APFixedPoint(81920, Saturated(getAccumSema())));
+
+  // Across signs
+  ASSERT_EQ(APFixedPoint(320, getSAccumSema()),
+            APFixedPoint(640, getUSAccumSema()));
+  ASSERT_EQ(APFixedPoint(-320, getSAccumSema()),
+            APFixedPoint(-81920, getAccumSema()));
+
+  // Across padding
+  ASSERT_EQ(APFixedPoint(320, getSAccumSema()),
+            APFixedPoint(320, getPadUSAccumSema()));
+  ASSERT_EQ(APFixedPoint(640, getUSAccumSema()),
+            APFixedPoint(320, getPadUSAccumSema()));
+
+  // Less than
+  ASSERT_LT(APFixedPoint(-1, getSAccumSema()), APFixedPoint(0, getAccumSema()));
+  ASSERT_LT(APFixedPoint(-1, getSAccumSema()),
+            APFixedPoint(0, getUAccumSema()));
+  ASSERT_LT(APFixedPoint(0, getSAccumSema()), APFixedPoint(1, getAccumSema()));
+  ASSERT_LT(APFixedPoint(0, getSAccumSema()), APFixedPoint(1, getUAccumSema()));
+  ASSERT_LT(APFixedPoint(0, getUSAccumSema()), APFixedPoint(1, getAccumSema()));
+  ASSERT_LT(APFixedPoint(0, getUSAccumSema()),
+            APFixedPoint(1, getUAccumSema()));
+
+  // Greater than
+  ASSERT_GT(APFixedPoint(0, getAccumSema()), APFixedPoint(-1, getSAccumSema()));
+  ASSERT_GT(APFixedPoint(0, getUAccumSema()),
+            APFixedPoint(-1, getSAccumSema()));
+  ASSERT_GT(APFixedPoint(1, getAccumSema()), APFixedPoint(0, getSAccumSema()));
+  ASSERT_GT(APFixedPoint(1, getUAccumSema()), APFixedPoint(0, getSAccumSema()));
+  ASSERT_GT(APFixedPoint(1, getAccumSema()), APFixedPoint(0, getUSAccumSema()));
+  ASSERT_GT(APFixedPoint(1, getUAccumSema()),
+            APFixedPoint(0, getUSAccumSema()));
+}
+
+// Check that a fixed point value in one sema is the same in another sema
+void CheckUnsaturatedConversion(FixedPointSemantics Src,
+                                FixedPointSemantics Dst, int64_t TestVal) {
+  int64_t ScaledVal = TestVal;
+  if (Dst.getScale() > Src.getScale()) {
+    ScaledVal <<= (Dst.getScale() - Src.getScale());
+  } else {
+    ScaledVal >>= (Src.getScale() - Dst.getScale());
+  }
+
+  APFixedPoint Fixed(TestVal, Src);
+  APFixedPoint Expected(ScaledVal, Dst);
+  ASSERT_EQ(Fixed.convert(Dst), Expected);
+}
+
+// Check the value in a given fixed point sema overflows to the saturated min
+// for another sema
+void CheckSaturatedConversionMin(FixedPointSemantics Src,
+                                 FixedPointSemantics Dst, int64_t TestVal) {
+  APFixedPoint Fixed(TestVal, Src);
+  ASSERT_EQ(Fixed.convert(Dst), APFixedPoint::getMin(Dst));
+}
+
+// Check the value in a given fixed point sema overflows to the saturated max
+// for another sema
+void CheckSaturatedConversionMax(FixedPointSemantics Src,
+                                 FixedPointSemantics Dst, int64_t TestVal) {
+  APFixedPoint Fixed(TestVal, Src);
+  ASSERT_EQ(Fixed.convert(Dst), APFixedPoint::getMax(Dst));
+}
+
+// Check one signed _Accum sema converted to other sema for different values.
+void CheckSignedAccumConversionsAgainstOthers(FixedPointSemantics Src,
+                                              int64_t OneVal) {
+  int64_t NormalVal = (OneVal * 2) + (OneVal / 2); // 2.5
+  int64_t HalfVal = (OneVal / 2);                  // 0.5
+
+  // +Accums to Accums
+  CheckUnsaturatedConversion(Src, getSAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getLAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getUSAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getUAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getULAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getPadUSAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getPadUAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getPadULAccumSema(), NormalVal);
+
+  // -Accums to Accums
+  CheckUnsaturatedConversion(Src, getSAccumSema(), -NormalVal);
+  CheckUnsaturatedConversion(Src, getAccumSema(), -NormalVal);
+  CheckUnsaturatedConversion(Src, getLAccumSema(), -NormalVal);
+  CheckSaturatedConversionMin(Src, Saturated(getUSAccumSema()), -NormalVal);
+  CheckSaturatedConversionMin(Src, Saturated(getUAccumSema()), -NormalVal);
+  CheckSaturatedConversionMin(Src, Saturated(getULAccumSema()), -NormalVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadUSAccumSema()), -NormalVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadUAccumSema()), -NormalVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadULAccumSema()), -NormalVal);
+
+  // +Accums to Fracts
+  CheckUnsaturatedConversion(Src, getSFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getLFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getUSFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getUFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getULFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getPadUSFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getPadUFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getPadULFractSema(), HalfVal);
+
+  // -Accums to Fracts
+  CheckUnsaturatedConversion(Src, getSFractSema(), -HalfVal);
+  CheckUnsaturatedConversion(Src, getFractSema(), -HalfVal);
+  CheckUnsaturatedConversion(Src, getLFractSema(), -HalfVal);
+  CheckSaturatedConversionMin(Src, Saturated(getUSFractSema()), -HalfVal);
+  CheckSaturatedConversionMin(Src, Saturated(getUFractSema()), -HalfVal);
+  CheckSaturatedConversionMin(Src, Saturated(getULFractSema()), -HalfVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadUSFractSema()), -HalfVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadUFractSema()), -HalfVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadULFractSema()), -HalfVal);
+
+  // 0 to Accums
+  CheckUnsaturatedConversion(Src, getSAccumSema(), 0);
+  CheckUnsaturatedConversion(Src, getAccumSema(), 0);
+  CheckUnsaturatedConversion(Src, getLAccumSema(), 0);
+  CheckUnsaturatedConversion(Src, getUSAccumSema(), 0);
+  CheckUnsaturatedConversion(Src, getUAccumSema(), 0);
+  CheckUnsaturatedConversion(Src, getULAccumSema(), 0);
+  CheckUnsaturatedConversion(Src, getPadUSAccumSema(), 0);
+  CheckUnsaturatedConversion(Src, getPadUAccumSema(), 0);
+  CheckUnsaturatedConversion(Src, getPadULAccumSema(), 0);
+
+  // 0 to Fracts
+  CheckUnsaturatedConversion(Src, getSFractSema(), 0);
+  CheckUnsaturatedConversion(Src, getFractSema(), 0);
+  CheckUnsaturatedConversion(Src, getLFractSema(), 0);
+  CheckUnsaturatedConversion(Src, getUSFractSema(), 0);
+  CheckUnsaturatedConversion(Src, getUFractSema(), 0);
+  CheckUnsaturatedConversion(Src, getULFractSema(), 0);
+  CheckUnsaturatedConversion(Src, getPadUSFractSema(), 0);
+  CheckUnsaturatedConversion(Src, getPadUFractSema(), 0);
+  CheckUnsaturatedConversion(Src, getPadULFractSema(), 0);
+}
+
+// Check one unsigned _Accum sema converted to other sema for different
+// values.
+void CheckUnsignedAccumConversionsAgainstOthers(FixedPointSemantics Src,
+                                                int64_t OneVal) {
+  int64_t NormalVal = (OneVal * 2) + (OneVal / 2); // 2.5
+  int64_t HalfVal = (OneVal / 2);                  // 0.5
+
+  // +UAccums to Accums
+  CheckUnsaturatedConversion(Src, getSAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getLAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getUSAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getUAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getULAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getPadUSAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getPadUAccumSema(), NormalVal);
+  CheckUnsaturatedConversion(Src, getPadULAccumSema(), NormalVal);
+
+  // +UAccums to Fracts
+  CheckUnsaturatedConversion(Src, getSFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getLFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getUSFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getUFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getULFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getPadUSFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getPadUFractSema(), HalfVal);
+  CheckUnsaturatedConversion(Src, getPadULFractSema(), HalfVal);
+}
+
+TEST(FixedPoint, AccumConversions) {
+  // Normal conversions
+  CheckSignedAccumConversionsAgainstOthers(getSAccumSema(), 128);
+  CheckUnsignedAccumConversionsAgainstOthers(getUSAccumSema(), 256);
+  CheckSignedAccumConversionsAgainstOthers(getAccumSema(), 32768);
+  CheckUnsignedAccumConversionsAgainstOthers(getUAccumSema(), 65536);
+  CheckSignedAccumConversionsAgainstOthers(getLAccumSema(), 2147483648);
+  CheckUnsignedAccumConversionsAgainstOthers(getULAccumSema(), 4294967296);
+
+  CheckUnsignedAccumConversionsAgainstOthers(getPadUSAccumSema(), 128);
+  CheckUnsignedAccumConversionsAgainstOthers(getPadUAccumSema(), 32768);
+  CheckUnsignedAccumConversionsAgainstOthers(getPadULAccumSema(), 2147483648);
+}
+
+TEST(FixedPoint, AccumConversionOverflow) {
+  // To SAccum max limit (65536)
+  CheckSaturatedConversionMax(getLAccumSema(), Saturated(getAccumSema()),
+                              140737488355328);
+  CheckSaturatedConversionMax(getLAccumSema(), Saturated(getUAccumSema()),
+                              140737488355328);
+  CheckSaturatedConversionMax(getLAccumSema(), Saturated(getPadUAccumSema()),
+                              140737488355328);
+  CheckSaturatedConversionMax(getULAccumSema(), Saturated(getAccumSema()),
+                              281474976710656);
+  CheckSaturatedConversionMax(getULAccumSema(), Saturated(getUAccumSema()),
+                              281474976710656);
+  CheckSaturatedConversionMax(getULAccumSema(), Saturated(getPadUAccumSema()),
+                              281474976710656);
+
+  CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getAccumSema()),
+                              140737488355328);
+  CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getUAccumSema()),
+                              140737488355328);
+  CheckSaturatedConversionMax(getPadULAccumSema(),
+                              Saturated(getPadUAccumSema()), 140737488355328);
+
+  // To SAccum min limit (-65536)
+  CheckSaturatedConversionMin(getLAccumSema(), Saturated(getAccumSema()),
+                              -140737488355328);
+  CheckSaturatedConversionMin(getLAccumSema(), Saturated(getUAccumSema()),
+                              -140737488355328);
+  CheckSaturatedConversionMin(getLAccumSema(), Saturated(getPadUAccumSema()),
+                              -140737488355328);
+}
+
+TEST(FixedPoint, SAccumConversionOverflow) {
+  // To SAccum max limit (256)
+  CheckSaturatedConversionMax(getAccumSema(), Saturated(getSAccumSema()),
+                              8388608);
+  CheckSaturatedConversionMax(getAccumSema(), Saturated(getUSAccumSema()),
+                              8388608);
+  CheckSaturatedConversionMax(getAccumSema(), Saturated(getPadUSAccumSema()),
+                              8388608);
+  CheckSaturatedConversionMax(getUAccumSema(), Saturated(getSAccumSema()),
+                              16777216);
+  CheckSaturatedConversionMax(getUAccumSema(), Saturated(getUSAccumSema()),
+                              16777216);
+  CheckSaturatedConversionMax(getUAccumSema(), Saturated(getPadUSAccumSema()),
+                              16777216);
+  CheckSaturatedConversionMax(getLAccumSema(), Saturated(getSAccumSema()),
+                              549755813888);
+  CheckSaturatedConversionMax(getLAccumSema(), Saturated(getUSAccumSema()),
+                              549755813888);
+  CheckSaturatedConversionMax(getLAccumSema(), Saturated(getPadUSAccumSema()),
+                              549755813888);
+  CheckSaturatedConversionMax(getULAccumSema(), Saturated(getSAccumSema()),
+                              1099511627776);
+  CheckSaturatedConversionMax(getULAccumSema(), Saturated(getUSAccumSema()),
+                              1099511627776);
+  CheckSaturatedConversionMax(getULAccumSema(), Saturated(getPadUSAccumSema()),
+                              1099511627776);
+
+  CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getSAccumSema()),
+                              8388608);
+  CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getUSAccumSema()),
+                              8388608);
+  CheckSaturatedConversionMax(getPadUAccumSema(),
+                              Saturated(getPadUSAccumSema()), 8388608);
+  CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getSAccumSema()),
+                              549755813888);
+  CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getUSAccumSema()),
+                              549755813888);
+  CheckSaturatedConversionMax(getPadULAccumSema(),
+                              Saturated(getPadUSAccumSema()), 549755813888);
+
+  // To SAccum min limit (-256)
+  CheckSaturatedConversionMin(getAccumSema(), Saturated(getSAccumSema()),
+                              -8388608);
+  CheckSaturatedConversionMin(getAccumSema(), Saturated(getUSAccumSema()),
+                              -8388608);
+  CheckSaturatedConversionMin(getAccumSema(), Saturated(getPadUSAccumSema()),
+                              -8388608);
+  CheckSaturatedConversionMin(getLAccumSema(), Saturated(getSAccumSema()),
+                              -549755813888);
+  CheckSaturatedConversionMin(getLAccumSema(), Saturated(getUSAccumSema()),
+                              -549755813888);
+  CheckSaturatedConversionMin(getLAccumSema(), Saturated(getPadUSAccumSema()),
+                              -549755813888);
+}
+
+void CheckSaturatedConversionToFractMax(FixedPointSemantics Src,
+                                        int64_t OneVal) {
+  CheckSaturatedConversionMax(Src, Saturated(getSFractSema()), OneVal);
+  CheckSaturatedConversionMax(Src, Saturated(getFractSema()), OneVal);
+  CheckSaturatedConversionMax(Src, Saturated(getLFractSema()), OneVal);
+  CheckSaturatedConversionMax(Src, Saturated(getUSFractSema()), OneVal);
+  CheckSaturatedConversionMax(Src, Saturated(getUFractSema()), OneVal);
+  CheckSaturatedConversionMax(Src, Saturated(getPadULFractSema()), OneVal);
+  CheckSaturatedConversionMax(Src, Saturated(getPadUSFractSema()), OneVal);
+  CheckSaturatedConversionMax(Src, Saturated(getPadUFractSema()), OneVal);
+  CheckSaturatedConversionMax(Src, Saturated(getPadULFractSema()), OneVal);
+}
+
+void CheckSaturatedConversionToFractMin(FixedPointSemantics Src,
+                                        int64_t MinusOneVal) {
+  CheckSaturatedConversionMin(Src, Saturated(getSFractSema()), MinusOneVal);
+  CheckSaturatedConversionMin(Src, Saturated(getFractSema()), MinusOneVal);
+  CheckSaturatedConversionMin(Src, Saturated(getLFractSema()), MinusOneVal);
+  CheckSaturatedConversionMin(Src, Saturated(getUSFractSema()), MinusOneVal);
+  CheckSaturatedConversionMin(Src, Saturated(getUFractSema()), MinusOneVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadULFractSema()), MinusOneVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadUSFractSema()), MinusOneVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadUFractSema()), MinusOneVal);
+  CheckSaturatedConversionMin(Src, Saturated(getPadULFractSema()), MinusOneVal);
+}
+
+TEST(FixedPoint, OverflowConversionsToFract) {
+  CheckSaturatedConversionToFractMax(getSAccumSema(), 128);
+  CheckSaturatedConversionToFractMin(getSAccumSema(), -128);
+  CheckSaturatedConversionToFractMax(getAccumSema(), 32768);
+  CheckSaturatedConversionToFractMin(getAccumSema(), -32768);
+  CheckSaturatedConversionToFractMax(getLAccumSema(), 2147483648);
+  CheckSaturatedConversionToFractMin(getLAccumSema(), -2147483648);
+
+  // Unsigned
+  CheckSaturatedConversionToFractMax(getUSAccumSema(), 256);
+  CheckSaturatedConversionToFractMax(getUAccumSema(), 65536);
+  CheckSaturatedConversionToFractMax(getULAccumSema(), 4294967296);
+
+  // Padded unsigned
+  CheckSaturatedConversionToFractMax(getPadUSAccumSema(), 128);
+  CheckSaturatedConversionToFractMax(getPadUAccumSema(), 32768);
+  CheckSaturatedConversionToFractMax(getPadULAccumSema(), 2147483648);
+}
+
+TEST(FixedPoint, GetValueSignAfterConversion) {
+  APFixedPoint Fixed(255 << 7, getSAccumSema());
+  ASSERT_TRUE(Fixed.getValue().isSigned());
+  APFixedPoint UFixed = Fixed.convert(getUSAccumSema());
+  ASSERT_TRUE(UFixed.getValue().isUnsigned());
+  ASSERT_EQ(UFixed.getValue(), APSInt::getUnsigned(255 << 8).extOrTrunc(16));
+}
+
+TEST(FixedPoint, ModularWrapAround) {
+  // Positive to negative
+  APFixedPoint Val = APFixedPoint(1ULL << 7, getSAccumSema());
+  ASSERT_EQ(Val.convert(getLFractSema()).getValue(), -(1ULL << 31));
+
+  Val = APFixedPoint(1ULL << 23, getAccumSema());
+  ASSERT_EQ(Val.convert(getSAccumSema()).getValue(), -(1ULL << 15));
+
+  Val = APFixedPoint(1ULL << 47, getLAccumSema());
+  ASSERT_EQ(Val.convert(getAccumSema()).getValue(), -(1ULL << 31));
+
+  // Negative to positive
+  Val = APFixedPoint(/*-1.5*/ -192, getSAccumSema());
+  ASSERT_EQ(Val.convert(getLFractSema()).getValue(), 1ULL << 30);
+
+  Val = APFixedPoint(-(257 << 15), getAccumSema());
+  ASSERT_EQ(Val.convert(getSAccumSema()).getValue(), 255 << 7);
+
+  Val = APFixedPoint(-(65537ULL << 31), getLAccumSema());
+  ASSERT_EQ(Val.convert(getAccumSema()).getValue(), 65535 << 15);
+
+  // Signed to unsigned
+  Val = APFixedPoint(-(1 << 7), getSAccumSema());
+  ASSERT_EQ(Val.convert(getUSAccumSema()).getValue(), 255 << 8);
+
+  Val = APFixedPoint(-(1 << 15), getAccumSema());
+  ASSERT_EQ(Val.convert(getUAccumSema()).getValue(), 65535ULL << 16);
+
+  Val = APFixedPoint(-(1ULL << 31), getLAccumSema());
+  ASSERT_EQ(Val.convert(getULAccumSema()).getValue().getZExtValue(),
+            4294967295ULL << 32);
+}
+
+} // namespace




More information about the cfe-commits mailing list