leonardchan updated this revision to Diff 148116.
leonardchan added a comment.

- formatting
- Running `lli` threw a segfault in the test, though this was probably because 
it was using whatever hist jit was available to optimize the code instead of 
just interpreting it. Forcing it just interpret fixes this.


Repository:
  rC Clang

https://reviews.llvm.org/D46986

Files:
  include/clang/AST/Type.h
  include/clang/Basic/FixedPoint.h.in
  lib/AST/Type.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Sema/SemaExpr.cpp
  test/Frontend/fixed_point_all_builtin_operations.c
  test/Frontend/fixed_point_builtin_macros.c

Index: test/Frontend/fixed_point_builtin_macros.c
===================================================================
--- test/Frontend/fixed_point_builtin_macros.c
+++ test/Frontend/fixed_point_builtin_macros.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli
+// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli -force-interpreter=true
 
 #define assert(b) if (!(b)) { return 1; }
 
Index: test/Frontend/fixed_point_all_builtin_operations.c
===================================================================
--- test/Frontend/fixed_point_all_builtin_operations.c
+++ test/Frontend/fixed_point_all_builtin_operations.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Werror %s
+// RUN: %clang_cc1 -Werror -S -emit-llvm %s -o - | lli -force-interpreter=true
 
 // Check that we can use all supported binary and unary operations according to
 // clause 4.1.6 in N1169.
@@ -66,3 +66,60 @@
 ALL_OPERATIONS(short _Accum, ShortAccum);
 ALL_OPERATIONS(_Accum, Accum);
 ALL_OPERATIONS(long _Accum, LongAccum);
+
+#define ASSERT(x) \
+  if (!(x)) return 1;
+
+#define BINARY_OPS_FOR_TYPE(TYPE, ID, SUFFIX)         \
+  {                                                   \
+    TYPE a = 0.5##SUFFIX;                             \
+    TYPE b = 0.25##SUFFIX;                            \
+    ASSERT(add##ID(a, b) == 0.75##SUFFIX);            \
+    ASSERT(sub##ID(a, b) == 0.25##SUFFIX);            \
+    ASSERT(mul##ID(a, b) == 0.125##SUFFIX);           \
+    ASSERT(div##ID(b, a) == 0.5##SUFFIX);             \
+    ASSERT(shl##ID(b, 1) == a);                       \
+    ASSERT(shr##ID(a, 1) == b);                       \
+    ASSERT(lt##ID(b, a));                             \
+    ASSERT(le##ID(b, a));                             \
+    ASSERT(gt##ID(a, b));                             \
+    ASSERT(ge##ID(a, b));                             \
+    ASSERT(eq##ID(a, b) == 0);                        \
+    ASSERT(ne##ID(a, b));                             \
+    ASSERT(augmented_add##ID(a, b) == 0.75##SUFFIX);  \
+    ASSERT(augmented_sub##ID(a, b) == 0.25##SUFFIX);  \
+    ASSERT(augmented_mul##ID(a, b) == 0.125##SUFFIX); \
+    ASSERT(augmented_div##ID(b, a) == 0.5##SUFFIX);   \
+    ASSERT(augmented_shl##ID(b, 1) == a);             \
+    ASSERT(augmented_shr##ID(a, 1) == b);             \
+  }
+
+#define BINARY_OPS(TYPE, ID, SUFFIX)                            \
+  BINARY_OPS_FOR_TYPE(TYPE, ID, SUFFIX);                        \
+  BINARY_OPS_FOR_TYPE(signed TYPE, Signed##ID, SUFFIX);         \
+  BINARY_OPS_FOR_TYPE(unsigned TYPE, Unsigned##ID, u##SUFFIX);  \
+  BINARY_OPS_FOR_TYPE(_Sat TYPE, Sat##ID, SUFFIX);              \
+  BINARY_OPS_FOR_TYPE(_Sat signed TYPE, SatSigned##ID, SUFFIX); \
+  BINARY_OPS_FOR_TYPE(_Sat unsigned TYPE, SatUnsigned##ID, u##SUFFIX);
+
+#define FRACT_SAT_BINARY_OPS(TYPE, ID, SUFFIX) \
+  {                                            \
+    TYPE a = 0.7##SUFFIX;                      \
+    TYPE b = 0.9##SUFFIX;                      \
+    ASSERT(add##ID(a, b) == 1.0##SUFFIX);      \
+  }
+
+int main() {
+  BINARY_OPS(short _Fract, ShortFract, hr);
+  BINARY_OPS(_Fract, Fract, r);
+  BINARY_OPS(long _Fract, LongFract, lr);
+  BINARY_OPS(short _Accum, ShortAccum, hk);
+  BINARY_OPS(_Accum, Accum, k);
+  BINARY_OPS(long _Accum, LongAccum, lk);
+
+  FRACT_SAT_BINARY_OPS(_Sat short _Fract, SatShortFract, hr);
+  FRACT_SAT_BINARY_OPS(_Sat _Fract, SatFract, r);
+  FRACT_SAT_BINARY_OPS(_Sat long _Fract, SatLongFract, lr);
+
+  return 0;
+}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -1258,8 +1258,12 @@
   return FixedPointTy;
 }
 
-/// \brief Handle arithmethic conversion with fixed point types.  Helper
-/// function of UsualArithmeticConversions().
+/// \brief Handle arithmethic conversion with fixed point types. The usual
+/// arithmetic conversions do not apply to fixed point type conversions between
+/// integers or other fixed point types due to potential loss of precision.
+/// For this case of fixed point types, the resulting type in a binary operation
+/// does not need to be exactly one of the 2 operand types.
+/// Implemented according to Clause 6.3.1.8 of ISO/IEC JTC1 SC22 WG14 N1169.
 static QualType handleFixedPointConversion(Sema &S, ExprResult &LHS,
                                            ExprResult &RHS, QualType LHSType,
                                            QualType RHSType,
@@ -1271,30 +1275,25 @@
   bool RHSFixed = RHSType->isFixedPointType();
 
   if (LHSFixed && RHSFixed) {
-    // Cast up the smaller operand to the bigger
+    bool LHSSigned = LHSType->isSignedFixedPointType();
+    bool RHSSigned = RHSType->isSignedFixedPointType();
+    bool LHSSat = LHSType->isSaturatedFixedPointType();
+    bool RHSSat = RHSType->isSaturatedFixedPointType();
     int order = S.Context.getFixedPointTypeOrder(LHSType, RHSType);
-    if (order > 0) {
-      RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FixedPointCast);
-      return LHSType;
-    } else if (!order) {
-      bool LHSSigned = LHSType->isSignedFixedPointType();
-      bool RHSSigned = RHSType->isSignedFixedPointType();
-      if (LHSSigned && !RHSSigned) {
-        RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FixedPointCast);
-        return LHSType;
-      } else if (!LHSSigned && RHSSigned) {
-        if (!IsCompAssign)
-          LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FixedPointCast);
-        return RHSType;
-      } else {
-        assert(LHSType == RHSType);
-        return LHSType;
-      }
-    } else {
-      if (!IsCompAssign)
-        LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FixedPointCast);
-      return RHSType;
-    }
+
+    QualType result = (order >= 0) ? LHSType : RHSType;
+    if (LHSSigned || RHSSigned)
+      result = getCorrespondingSignedFixedPointType(S.Context, *result);
+    if (LHSSat || RHSSat)
+      result = getCorrespondingSaturatedFixedPointType(S.Context, *result);
+
+    if (LHSType != result && !IsCompAssign)
+      LHS = S.ImpCastExprToType(LHS.get(), result, CK_FixedPointCast);
+
+    if (RHSType != result)
+      RHS = S.ImpCastExprToType(RHS.get(), result, CK_FixedPointCast);
+
+    return result;
   } else if (LHSFixed) {
     assert(RHSType->isIntegerType());
     return handleIntToFixedPointConversion(S, LHS, RHS, LHSType, RHSType);
@@ -3549,10 +3548,19 @@
     double int_part;
     double fract_part = modf(float_val, &int_part);
     uint64_t int_part_as_int = static_cast<uint64_t>(int_part);
+    uint64_t fract_part_as_int =
+        static_cast<uint64_t>(fract_part * (1ULL << fbits));
+    uint64_t final_fixed_point_as_int =
+        (int_part_as_int << fbits) + fract_part_as_int;
 
-    if (Literal.fixedPointType == FPT_FRACT && int_part_as_int) {
-      Diag(Tok.getLocation(), diag::err_integral_part_on_fract);
-    } else {
+    if (Literal.fixedPointType == FPT_FRACT) {
+      if (float_val > 1) {
+        Diag(Tok.getLocation(), diag::err_integral_part_on_fract);
+      } else if (int_part_as_int == 1) {
+        // Represent 1.0r as the max possible value for this _Fract type
+        final_fixed_point_as_int = (1ULL << fbits) - 1;
+      }
+    } else if (Literal.fixedPointType == FPT_ACCUM) {
       // Make sure the integral part fits into the integral bits we have.
       uint64_t max_int_val = 0;
       if (isSigned) {
@@ -3572,11 +3580,6 @@
       }
     }
 
-    uint64_t fract_part_as_int =
-        static_cast<uint64_t>(fract_part * (1ULL << fbits));
-    uint64_t final_fixed_point_as_int =
-        (int_part_as_int << fbits) + fract_part_as_int;
-
     llvm::APInt ResultVal(bit_width, final_fixed_point_as_int, isSigned);
     Res = FixedPointLiteral::CreateFromRawInt(Context, ResultVal, Ty,
                                               Tok.getLocation());
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -3138,6 +3138,110 @@
     return propagateFMFlags(V, op);
   }
 
+  if (op.Ty->isSaturatedFixedPointType()) {
+    llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(op.Ty);
+
+    assert(op.LHS->getType() == op.RHS->getType());
+    assert(op.LHS->getType() == opTy);
+
+    llvm::Value *SatMaxVal;
+    llvm::Value *SatMinVal;
+
+    const auto &BT = op.Ty->getAs<BuiltinType>();
+    switch (BT->getKind()) {
+      default:
+        llvm_unreachable("Unhandled saturated signed fixed point type");
+      case BuiltinType::SatShortAccum:
+        SatMaxVal = llvm::ConstantInt::get(opTy, SACCUM_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, SACCUM_MIN_AS_INT);
+        break;
+      case BuiltinType::SatAccum:
+        SatMaxVal = llvm::ConstantInt::get(opTy, ACCUM_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, ACCUM_MIN_AS_INT);
+        break;
+      case BuiltinType::SatLongAccum:
+        SatMaxVal = llvm::ConstantInt::get(opTy, LACCUM_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, LACCUM_MIN_AS_INT);
+        break;
+      case BuiltinType::SatUShortAccum:
+        SatMaxVal = llvm::ConstantInt::get(opTy, USACCUM_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, USACCUM_MIN_AS_INT);
+        break;
+      case BuiltinType::SatUAccum:
+        SatMaxVal = llvm::ConstantInt::get(opTy, UACCUM_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, UACCUM_MIN_AS_INT);
+        break;
+      case BuiltinType::SatULongAccum:
+        SatMaxVal = llvm::ConstantInt::get(opTy, ULACCUM_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, ULACCUM_MIN_AS_INT);
+        break;
+      case BuiltinType::SatShortFract:
+        SatMaxVal = llvm::ConstantInt::get(opTy, SFRACT_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, SFRACT_MIN_AS_INT);
+        break;
+      case BuiltinType::SatFract:
+        SatMaxVal = llvm::ConstantInt::get(opTy, FRACT_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, FRACT_MIN_AS_INT);
+        break;
+      case BuiltinType::SatLongFract:
+        SatMaxVal = llvm::ConstantInt::get(opTy, LFRACT_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, LFRACT_MIN_AS_INT);
+        break;
+      case BuiltinType::SatUShortFract:
+        SatMaxVal = llvm::ConstantInt::get(opTy, USFRACT_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, USFRACT_MIN_AS_INT);
+        break;
+      case BuiltinType::SatUFract:
+        SatMaxVal = llvm::ConstantInt::get(opTy, UFRACT_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, UFRACT_MIN_AS_INT);
+        break;
+      case BuiltinType::SatULongFract:
+        SatMaxVal = llvm::ConstantInt::get(opTy, ULFRACT_MAX_AS_INT);
+        SatMinVal = llvm::ConstantInt::get(opTy, ULFRACT_MIN_AS_INT);
+        break;
+    }
+
+    unsigned MSBBitShift;
+    if (op.Ty->isSignedFixedPointType()) {
+      MSBBitShift = getFixedPointIBits(op.Ty) + getFixedPointFBits(op.Ty);
+    } else {
+      MSBBitShift = getFixedPointIBits(op.Ty) + getFixedPointFBits(op.Ty) - 1;
+    }
+
+    llvm::Value *Sum = Builder.CreateAdd(op.LHS, op.RHS);
+    llvm::Value *LHSMSB = Builder.CreateLShr(op.LHS, MSBBitShift);
+    llvm::Value *RHSMSB = Builder.CreateLShr(op.RHS, MSBBitShift);
+    llvm::Value *ResultMSB = Builder.CreateLShr(Sum, MSBBitShift);
+
+    if (op.Ty->isSignedFixedPointType()) {
+      // Cap at max if both operand signs were 0 and the result sign is 1
+      llvm::Value *UseSatMax = Builder.CreateAnd(
+          Builder.CreateNot(Builder.CreateOr(LHSMSB, RHSMSB)), ResultMSB);
+      UseSatMax = Builder.CreateIntCast(
+          UseSatMax, llvm::Type::getInt1Ty(ResultMSB->getContext()),
+          /*isSigned=*/true);
+
+      // Cap at min if both operand signs were 1 and the result sign is 0
+      llvm::Value *UseSatMin = Builder.CreateAnd(
+          Builder.CreateAnd(LHSMSB, RHSMSB), Builder.CreateNot(ResultMSB));
+      UseSatMin = Builder.CreateIntCast(
+          UseSatMin, llvm::Type::getInt1Ty(ResultMSB->getContext()),
+          /*isSigned=*/true);
+
+      return Builder.CreateSelect(
+          UseSatMax, SatMaxVal,
+          Builder.CreateSelect(UseSatMin, SatMinVal, Sum));
+    } else {
+      // Cap at max if the resulting MSB is less than either operand MSB
+      llvm::Value *UseSatMax = Builder.CreateAnd(
+          Builder.CreateOr(LHSMSB, RHSMSB), Builder.CreateNot(ResultMSB));
+      UseSatMax = Builder.CreateIntCast(
+          UseSatMax, llvm::Type::getInt1Ty(ResultMSB->getContext()),
+          /*isSigned=*/true);
+      return Builder.CreateSelect(UseSatMax, SatMaxVal, Sum);
+    }
+  }
+
   return Builder.CreateAdd(op.LHS, op.RHS, "add");
 }
 
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -4097,3 +4097,125 @@
       return 0;
   }
 }
+
+// For a given fixed point type, if the type is unsaturated,
+// return the saturated equivalent of it. Otherwise if it is
+// saturated, return back the type itself.
+QualType clang::getCorrespondingSaturatedFixedPointType(ASTContext &Context,
+                                                        const Type &Ty) {
+  assert(Ty.isFixedPointType());
+
+  const auto &BT = Ty.getAs<BuiltinType>();
+  switch (BT->getKind()) {
+    default:
+      llvm_unreachable("Not a fixed point type!");
+    case BuiltinType::ShortAccum:
+    case BuiltinType::SatShortAccum:
+      return Context.SatShortAccumTy;
+
+    case BuiltinType::Accum:
+    case BuiltinType::SatAccum:
+      return Context.SatAccumTy;
+
+    case BuiltinType::LongAccum:
+    case BuiltinType::SatLongAccum:
+      return Context.SatLongAccumTy;
+
+    case BuiltinType::UShortAccum:
+    case BuiltinType::SatUShortAccum:
+      return Context.SatUnsignedShortAccumTy;
+
+    case BuiltinType::UAccum:
+    case BuiltinType::SatUAccum:
+      return Context.SatUnsignedAccumTy;
+
+    case BuiltinType::ULongAccum:
+    case BuiltinType::SatULongAccum:
+      return Context.SatUnsignedLongAccumTy;
+
+    case BuiltinType::ShortFract:
+    case BuiltinType::SatShortFract:
+      return Context.SatShortFractTy;
+
+    case BuiltinType::Fract:
+    case BuiltinType::SatFract:
+      return Context.SatFractTy;
+
+    case BuiltinType::LongFract:
+    case BuiltinType::SatLongFract:
+      return Context.SatLongFractTy;
+
+    case BuiltinType::UShortFract:
+    case BuiltinType::SatUShortFract:
+      return Context.SatUnsignedShortFractTy;
+
+    case BuiltinType::UFract:
+    case BuiltinType::SatUFract:
+      return Context.SatUnsignedFractTy;
+
+    case BuiltinType::ULongFract:
+    case BuiltinType::SatULongFract:
+      return Context.SatUnsignedLongFractTy;
+  }
+}
+
+// For a given fixed point type, if the type is unsigned,
+// return the signed equivalent of it. Otherwise if it is
+// signed, return back the type itself.
+QualType clang::getCorrespondingSignedFixedPointType(ASTContext &Context,
+                                                     const Type &Ty) {
+  assert(Ty.isFixedPointType());
+
+  const auto &BT = Ty.getAs<BuiltinType>();
+  switch (BT->getKind()) {
+    default:
+      llvm_unreachable("Not a fixed point type!");
+    case BuiltinType::ShortAccum:
+    case BuiltinType::UShortAccum:
+      return Context.ShortAccumTy;
+
+    case BuiltinType::Accum:
+    case BuiltinType::UAccum:
+      return Context.AccumTy;
+
+    case BuiltinType::LongAccum:
+    case BuiltinType::ULongAccum:
+      return Context.LongAccumTy;
+
+    case BuiltinType::SatShortAccum:
+    case BuiltinType::SatUShortAccum:
+      return Context.SatShortAccumTy;
+
+    case BuiltinType::SatAccum:
+    case BuiltinType::SatUAccum:
+      return Context.SatAccumTy;
+
+    case BuiltinType::SatLongAccum:
+    case BuiltinType::SatULongAccum:
+      return Context.SatLongAccumTy;
+
+    case BuiltinType::ShortFract:
+    case BuiltinType::UShortFract:
+      return Context.ShortFractTy;
+
+    case BuiltinType::Fract:
+    case BuiltinType::UFract:
+      return Context.FractTy;
+
+    case BuiltinType::LongFract:
+    case BuiltinType::ULongFract:
+      return Context.LongFractTy;
+
+    case BuiltinType::SatShortFract:
+    case BuiltinType::SatUShortFract:
+      return Context.SatShortFractTy;
+
+    case BuiltinType::SatFract:
+    case BuiltinType::SatUFract:
+      return Context.SatFractTy;
+
+    case BuiltinType::SatLongFract:
+    case BuiltinType::SatULongFract:
+      return Context.SatLongFractTy;
+  }
+}
Index: include/clang/Basic/FixedPoint.h.in
===================================================================
--- include/clang/Basic/FixedPoint.h.in
+++ include/clang/Basic/FixedPoint.h.in
@@ -1,6 +1,10 @@
 #ifndef LLVM_CLANG_BASIC_FIXEDPOINT_H
 #define LLVM_CLANG_BASIC_FIXEDPOINT_H
 
+#include <climits>
+
+/************ Bit widths ******************/
+
 // Fractional bits of _Accum types
 #define BUILTIN_SACCUM_FBIT     @SACCUM_FBIT@
 #define BUILTIN_ACCUM_FBIT      @ACCUM_FBIT@
@@ -25,4 +29,58 @@
 #define BUILTIN_UACCUM_IBIT     @UACCUM_IBIT@
 #define BUILTIN_ULACCUM_IBIT    @ULACCUM_IBIT@
 
+/************ Max/min vals ******************/
+
+// Max values of each _Accum type as integer bytes
+#define SACCUM_MAX_AS_INT       ((1ULL << (BUILTIN_SACCUM_FBIT + BUILTIN_SACCUM_IBIT)) - 1)
+#define ACCUM_MAX_AS_INT        ((1ULL << (BUILTIN_ACCUM_FBIT + BUILTIN_ACCUM_IBIT)) - 1)
+#define LACCUM_MAX_AS_INT       ((1ULL << (BUILTIN_LACCUM_FBIT + BUILTIN_LACCUM_IBIT)) - 1)
+#define USACCUM_MAX_AS_INT      ((1ULL << (BUILTIN_USACCUM_FBIT + BUILTIN_USACCUM_IBIT)) - 1)
+#define UACCUM_MAX_AS_INT       ((1ULL << (BUILTIN_UACCUM_FBIT + BUILTIN_UACCUM_IBIT)) - 1)
+#define ULACCUM_MAX_AS_INT      ((static_cast<__int128>(1ULL) << (BUILTIN_ULACCUM_FBIT + BUILTIN_ULACCUM_IBIT)) - 1)
+
+// Max values of each _Fract type as integer bytes
+#define SFRACT_MAX_AS_INT       ((1ULL << BUILTIN_SFRACT_FBIT) - 1)
+#define FRACT_MAX_AS_INT        ((1ULL << BUILTIN_FRACT_FBIT) - 1)
+#define LFRACT_MAX_AS_INT       ((1ULL << BUILTIN_LFRACT_FBIT) - 1)
+#define USFRACT_MAX_AS_INT      ((1ULL << BUILTIN_USFRACT_FBIT) - 1)
+#define UFRACT_MAX_AS_INT       ((1ULL << BUILTIN_UFRACT_FBIT) - 1)
+#define ULFRACT_MAX_AS_INT      ((1ULL << BUILTIN_ULFRACT_FBIT) - 1)
+
+// Min values of each _Accum type as integer bytes
+#define SACCUM_MIN_AS_INT       (1ULL << (BUILTIN_SACCUM_FBIT + BUILTIN_SACCUM_IBIT))
+#define ACCUM_MIN_AS_INT        (1ULL << (BUILTIN_ACCUM_FBIT + BUILTIN_ACCUM_IBIT))
+#define LACCUM_MIN_AS_INT       (1ULL << (BUILTIN_LACCUM_FBIT + BUILTIN_LACCUM_IBIT))
+#define USACCUM_MIN_AS_INT      0ULL
+#define UACCUM_MIN_AS_INT       0ULL
+#define ULACCUM_MIN_AS_INT      0ULL
+
+// Min values of each _Fract type as integer bytes
+#define SFRACT_MIN_AS_INT       (1ULL << BUILTIN_SFRACT_FBIT)
+#define FRACT_MIN_AS_INT        (1ULL << BUILTIN_FRACT_FBIT)
+#define LFRACT_MIN_AS_INT       (1ULL << BUILTIN_LFRACT_FBIT)
+#define USFRACT_MIN_AS_INT      0ULL
+#define UFRACT_MIN_AS_INT       0ULL
+#define ULFRACT_MIN_AS_INT      0ULL
+
+/************ Fixed Point Bitmasks ******************/
+
+// Used to capture only the relevant bits when comparing with other types
+
+// _Accum bitmasks
+#define SACCUM_MASK             ((1ULL << (BUILTIN_SACCUM_FBIT + BUILTIN_SACCUM_IBIT + 1)) - 1)
+#define ACCUM_MASK              ((1ULL << (BUILTIN_ACCUM_FBIT + BUILTIN_ACCUM_IBIT + 1)) - 1)
+#define LACCUM_MASK             ((1ULL << (BUILTIN_LACCUM_FBIT + BUILTIN_LACCUM_IBIT + 1)) - 1)
+#define USACCUM_MASK            ((1ULL << (BUILTIN_USACCUM_FBIT + BUILTIN_USACCUM_IBIT)) - 1)
+#define UACCUM_MASK             ((1ULL << (BUILTIN_UACCUM_FBIT + BUILTIN_UACCUM_IBIT)) - 1)
+#define ULACCUM_MASK            ((1ULL << (BUILTIN_ULACCUM_FBIT + BUILTIN_ULACCUM_IBIT)) - 1)
+
+// _Fract bitmasks
+#define SFRACT_MASK             ((1ULL << (BUILTIN_SFRACT_FBIT + 1)) - 1)
+#define FRACT_MASK              ((1ULL << (BUILTIN_FRACT_FBIT + 1)) - 1)
+#define LFRACT_MASK             ((1ULL << (BUILTIN_LFRACT_FBIT + 1)) - 1)
+#define USFRACT_MASK            ((1ULL << BUILTIN_USFRACT_FBIT) - 1)
+#define UFRACT_MASK             ((1ULL << BUILTIN_UFRACT_FBIT) - 1)
+#define ULFRACT_MASK            ((1ULL << BUILTIN_ULFRACT_FBIT) - 1)
+
 #endif
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -6585,6 +6585,18 @@
   return getFixedPointIBits(*Ty);
 }
 
+// For a given fixed point type, if the type is unsaturated,
+// return the saturated equivalent of it. Otherwise if it is
+// saturated, return back the type itself.
+QualType getCorrespondingSaturatedFixedPointType(ASTContext &Context,
+                                                 const Type &Ty);
+
+// For a given fixed point type, if the type is unsigned,
+// return the signed equivalent of it. Otherwise if it is
+// signed, return back the type itself.
+QualType getCorrespondingSignedFixedPointType(ASTContext &Context,
+                                              const Type &Ty);
+
 } // namespace clang
 
 #endif // LLVM_CLANG_AST_TYPE_H
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to