leonardchan created this revision.
leonardchan added reviewers: phosek, mcgrathr, jakehehrlich.
leonardchan added a project: clang.
Herald added a subscriber: mgorny.

This diff includes the logic for setting the precision bits for each primary 
fixed point type when building clang and logic for initializing a fixed point 
literal.

The precision bits are set when building cmake via the flags

  SACCUM_FBIT
  ACCUM_FBIT
  LACCUM_FBIT
  ...

More checks to ensure the bit values used are valid will be added in future 
patches.

Fixed point literals are declared using the suffixes

  hr: short _Fract
  uhr: unsigned short _Fract
  r: _Fract
  ur: unsigned _Fract
  lr: long _Fract
  ulr: unsigned long _Fract
  hk: short _Accum
  uhk: unsigned short _Accum
  k: _Accum
  uk: unsigned _Accum

Errors are also thrown for literal values that exceed the range of the type 
corresponding to the suffix

  unsigned short _Accum u_short_accum = 256.0uhk;   // expected-error{{the 
integral part of this literal is too large for this unsigned _Accum type}}

This is a parent of https://reviews.llvm.org/D46911


Repository:
  rC Clang

https://reviews.llvm.org/D46915

Files:
  CMakeLists.txt
  cmake/modules/InitFixedPointBits.cmake
  include/clang/AST/Expr.h
  include/clang/AST/OperationKinds.def
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Type.h
  include/clang/Basic/DiagnosticCommonKinds.td
  include/clang/Basic/FixedPoint.h.in
  include/clang/Basic/StmtNodes.td
  include/clang/Lex/LiteralSupport.h
  lib/AST/ASTContext.cpp
  lib/AST/ASTDumper.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/AST/Type.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CGExprConstant.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Edit/RewriteObjCFoundationAPI.cpp
  lib/Lex/LiteralSupport.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngineC.cpp
  test/Frontend/fixed_point.c
  test/Frontend/fixed_point_declarations.c
  test/Frontend/fixed_point_errors.c
  test/Frontend/fixed_point_validation.c
  tools/libclang/CXCursor.cpp

Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -305,6 +305,10 @@
     K = CXCursor_IntegerLiteral;
     break;
 
+  case Stmt::FixedPointLiteralClass:
+    llvm_unreachable("No cursor for FixedPointLiteralClass");
+    break;
+
   case Stmt::FloatingLiteralClass:
     K = CXCursor_FloatingLiteral;
     break;
Index: test/Frontend/fixed_point_validation.c
===================================================================
--- /dev/null
+++ test/Frontend/fixed_point_validation.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli
+
+// Run simple validation tests
+
+#define assert(b) if (!(b)) { return 1; }
+
+int main(){
+  short _Accum s_accum;
+  short _Accum s_accum2 = 2.0hk;
+  short _Fract s_fract = 0.999hr;
+  short _Fract s_fract2 = -0.999hr;
+
+  assert(s_accum == 0);
+
+  s_accum = s_accum2;
+
+  assert(s_accum == s_accum2);
+  assert(s_accum == 2);
+}
Index: test/Frontend/fixed_point_errors.c
===================================================================
--- test/Frontend/fixed_point_errors.c
+++ test/Frontend/fixed_point_errors.c
@@ -1,14 +1,23 @@
 // RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s
 
-long long _Accum longlong_accum;  // expected-error{{'long long _Accum' is invalid}}
-unsigned long long _Accum u_longlong_accum;  // expected-error{{'long long _Accum' is invalid}}
-long long _Fract longlong_fract;  // expected-error{{'long long _Fract' is invalid}}
-unsigned long long _Fract u_longlong_fract;  // expected-error{{'long long _Fract' is invalid}}
+long long _Accum longlong_accum;              // expected-error{{'long long _Accum' is invalid}}
+unsigned long long _Accum u_longlong_accum;   // expected-error{{'long long _Accum' is invalid}}
+long long _Fract longlong_fract;              // expected-error{{'long long _Fract' is invalid}}
+unsigned long long _Fract u_longlong_fract;   // expected-error{{'long long _Fract' is invalid}}
 
 _Sat int i;  // expected-error{{'int' cannot be saturated. Only _Fract and _Accum can.}}
 _Sat _Sat _Fract fract;  // expected-warning{{duplicate '_Sat' declaration specifier}}
 
-_Sat long long _Accum sat_longlong_accum;  // expected-error{{'long long _Accum' is invalid}}
+_Sat long long _Accum sat_longlong_accum;             // expected-error{{'long long _Accum' is invalid}}
 _Sat unsigned long long _Accum sat_u_longlong_accum;  // expected-error{{'long long _Accum' is invalid}}
-_Sat long long _Fract sat_longlong_fract;  // expected-error{{'long long _Fract' is invalid}}
+_Sat long long _Fract sat_longlong_fract;             // expected-error{{'long long _Fract' is invalid}}
 _Sat unsigned long long _Fract sat_u_longlong_fract;  // expected-error{{'long long _Fract' is invalid}}
+
+short _Fract fract2 = 1.2hr;  // expected-error{{a _Fract type cannot have an integral part}}
+
+signed short _Accum s_short_accum = 129.0hk;      // expected-error{{the integral part of this literal is too large for this signed _Accum type}}
+unsigned short _Accum u_short_accum = 256.0uhk;   // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}}
+signed _Accum s_accum = 32770.0k;                 // expected-error{{the integral part of this literal is too large for this signed _Accum type}}
+unsigned _Accum u_accum = 65536.0uk;              // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}}
+short _Accum short_accum = 129.0hk;               // expected-error{{the integral part of this literal is too large for this signed _Accum type}}
+_Accum accum = 32770.0k;                          // expected-error{{the integral part of this literal is too large for this signed _Accum type}}
Index: test/Frontend/fixed_point_declarations.c
===================================================================
--- /dev/null
+++ test/Frontend/fixed_point_declarations.c
@@ -0,0 +1,33 @@
+// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s
+
+// Primary fixed point types
+signed short _Accum s_short_accum;    // CHECK-DAG: @s_short_accum =  common dso_local global i16 0, align 2
+signed _Accum s_accum;                // CHECK-DAG: @s_accum =        common dso_local global i32 0, align 4
+signed long _Accum s_long_accum;      // CHECK-DAG: @s_long_accum =   common dso_local global i64 0, align 8
+unsigned short _Accum u_short_accum;  // CHECK-DAG: @u_short_accum =  common dso_local global i16 0, align 2
+unsigned _Accum u_accum;              // CHECK-DAG: @u_accum =        common dso_local global i32 0, align 4
+unsigned long _Accum u_long_accum;    // CHECK-DAG: @u_long_accum =   common dso_local global i64 0, align 8
+signed short _Fract s_short_fract;    // CHECK-DAG: @s_short_fract =  common dso_local global i16 0, align 2
+signed _Fract s_fract;                // CHECK-DAG: @s_fract =        common dso_local global i32 0, align 4
+signed long _Fract s_long_fract;      // CHECK-DAG: @s_long_fract =   common dso_local global i64 0, align 8
+unsigned short _Fract u_short_fract;  // CHECK-DAG: @u_short_fract =  common dso_local global i16 0, align 2
+unsigned _Fract u_fract;              // CHECK-DAG: @u_fract =        common dso_local global i32 0, align 4
+unsigned long _Fract u_long_fract;    // CHECK-DAG: @u_long_fract =   common dso_local global i64 0, align 8
+
+// There are 7 bits allocated to the fractional part and 8
+// bits allocated to the integral part of a short _Accum by default.
+
+signed short _Accum s_short_accum2 = 2.5hk;  // CHECK-DAG: @s_short_accum2 = dso_local global i16 320, align 2
+short _Fract short_fract = 0.33333333333hr;  // CHECK-DAG: @short_fract = dso_local global i16 42, align 2
+
+void func() {
+  s_short_accum = s_short_accum2;
+  // CHECK-DAG: %0 = load i16, i16* @s_short_accum2, align 2
+  // CHECK-DAG: store i16 %0, i16* @s_short_accum, align 2
+
+  s_short_accum == 0;
+  // CHECK-DAG: %1 = load i16, i16* @s_short_accum, align 2
+  // CHECK-DAG: %cmp = icmp eq i16 %1, 0
+
+  s_accum == 2;
+}
Index: test/Frontend/fixed_point.c
===================================================================
--- test/Frontend/fixed_point.c
+++ test/Frontend/fixed_point.c
@@ -79,4 +79,9 @@
 //CHECK-NEXT: |-VarDecl {{.*}} sat_long_accum '_Sat long _Accum'
 //CHECK-NEXT: |-VarDecl {{.*}} sat_short_fract '_Sat short _Fract'
 //CHECK-NEXT: |-VarDecl {{.*}} sat_fract '_Sat _Fract'
-//CHECK-NEXT: `-VarDecl {{.*}} sat_long_fract '_Sat long _Fract'
+//CHECK-NEXT: |-VarDecl {{.*}} sat_long_fract '_Sat long _Fract'
+
+signed short _Accum s_short_accum2 = 2.5hk;
+
+//CHECK-NEXT: `-VarDecl {{.*}} s_short_accum2 'short _Accum' cinit
+//CHECK-NEXT:   `-FixedPointLiteral {{.*}} 'short _Accum' 320
Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -321,6 +321,7 @@
     const LocationContext *LCtx = Pred->getLocationContext();
 
     switch (CastE->getCastKind()) {
+      case CK_IntegralToFixedPoint: llvm_unreachable("ExprEngine::VisitCast CK_IntegralToFixedPoint"); // TODO
       case CK_LValueToRValue:
         llvm_unreachable("LValueToRValue casts handled earlier.");
       case CK_ToVoid:
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1436,6 +1436,7 @@
     case Stmt::AddrLabelExprClass:
     case Stmt::AttributedStmtClass:
     case Stmt::IntegerLiteralClass:
+    case Stmt::FixedPointLiteralClass:
     case Stmt::CharacterLiteralClass:
     case Stmt::ImplicitValueInitExprClass:
     case Stmt::CXXScalarValueInitExprClass:
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -444,6 +444,10 @@
   Code = serialization::EXPR_INTEGER_LITERAL;
 }
 
+void ASTStmtWriter::VisitFixedPointLiteral(FixedPointLiteral *E) {
+  llvm_unreachable("ASTStmtWriter::VisitFixedPointLiteral");
+}
+
 void ASTStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) {
   VisitExpr(E);
   Record.push_back(E->getRawSemantics());
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -533,6 +533,12 @@
   E->setValue(Record.getContext(), Record.readAPInt());
 }
 
+void ASTStmtReader::VisitFixedPointLiteral(FixedPointLiteral *E) {
+  VisitExpr(E);
+  E->setLocation(ReadSourceLocation());
+  E->setValue(Record.getContext(), Record.readAPInt());
+}
+
 void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
   VisitExpr(E);
   E->setRawSemantics(static_cast<Stmt::APFloatSemantics>(Record.readInt()));
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -8888,6 +8888,12 @@
   return E;
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformFixedPointLiteral(FixedPointLiteral *E) {
+  return E;
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) {
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -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"
@@ -1217,6 +1218,53 @@
                               CK_IntegralRealToComplex);
   return ComplexType;
 }
+/// \brief Handle arithmetic conversion from integer to fixed point.  Helper function
+/// of UsualArithmeticConversions()
+static QualType handleIntToFixedPointConversion(Sema &S, ExprResult &FixedPointExpr,
+                                                ExprResult &IntExpr,
+                                                QualType FixedPointTy, QualType IntTy) {
+  assert(IntTy->isIntegerType());
+  assert(FixedPointTy->isFixedPointType());
+
+  IntExpr = S.ImpCastExprToType(IntExpr.get(), FixedPointTy, CK_IntegralToFixedPoint);
+  return FixedPointTy;
+}
+
+/// \brief Handle arithmethic conversion with fixed point types.  Helper
+/// function of UsualArithmeticConversions().
+static QualType handleFixedPointConversion(Sema &S, ExprResult &LHS,
+                                           ExprResult &RHS, QualType LHSType,
+                                           QualType RHSType,
+                                           bool IsCompAssign) {
+  // At this point, the only other type we should be able to convert to is
+  // integer types since all prior types were handled beforehand in
+  // UsualArithmeticConventions().
+  bool LHSFixed = LHSType->isFixedPointType();
+  bool RHSFixed = RHSType->isFixedPointType();
+
+  if (LHSFixed && RHSFixed) {
+    // Cast up the smaller operand to the bigger
+    llvm_unreachable("Unhandled conversion between fixed point types");  // TODO
+    //int order = S.Context.getFixedPointTypeOrder(LHSType, RHSType);
+    //if (order > 0) {
+    //  RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FixedPointCast);
+    //  return LHSType;
+    //}
+
+    //assert(order < 0 && "illegal fixed point comparison");
+    //if (!IsCompAssign)
+    //  LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FixedPointCast);
+    //return RHSType;
+  } else if (LHSFixed) {
+    assert(RHSType->isIntegerType());
+    return handleIntToFixedPointConversion(S, LHS, RHS, LHSType, RHSType);
+  } else if (RHSFixed) {
+    assert(LHSType->isIntegerType());
+    return handleIntToFixedPointConversion(S, RHS, LHS, RHSType, LHSType);
+  } else {
+    llvm_unreachable("Expected LHS and RHS to both be fixed point types.");
+  }
+}
 
 /// UsualArithmeticConversions - Performs various conversions that are common to
 /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
@@ -1290,6 +1338,12 @@
     return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType,
                                       IsCompAssign);
 
+  // Handle floating point types
+  if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) {
+    return handleFixedPointConversion(*this, LHS, RHS, LHSType, RHSType,
+                                      IsCompAssign);
+  }
+
   // Finally, we have two differing integer types.
   return handleIntegerConversion<doIntegralCast, doIntegralCast>
            (*this, LHS, RHS, LHSType, RHSType, IsCompAssign);
@@ -3139,33 +3193,40 @@
                                 Context.IntTy, Loc);
 }
 
-static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
-                                  QualType Ty, SourceLocation Loc) {
-  const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty);
-
-  using llvm::APFloat;
-  APFloat Val(Format);
-
-  APFloat::opStatus result = Literal.GetFloatValue(Val);
-
+static void HandleFloatOverflow(Sema &S, QualType Ty, SourceLocation Loc,
+                                const llvm::APFloat::opStatus& result,
+                                const llvm::APFloat& Val,
+                                const llvm::fltSemantics& Format){
   // Overflow is always an error, but underflow is only an error if
   // we underflowed to zero (APFloat reports denormals as underflow).
-  if ((result & APFloat::opOverflow) ||
-      ((result & APFloat::opUnderflow) && Val.isZero())) {
+  if ((result & llvm::APFloat::opOverflow) ||
+      ((result & llvm::APFloat::opUnderflow) && Val.isZero())) {
     unsigned diagnostic;
     SmallString<20> buffer;
-    if (result & APFloat::opOverflow) {
+    if (result & llvm::APFloat::opOverflow) {
       diagnostic = diag::warn_float_overflow;
-      APFloat::getLargest(Format).toString(buffer);
+      llvm::APFloat::getLargest(Format).toString(buffer);
     } else {
       diagnostic = diag::warn_float_underflow;
-      APFloat::getSmallest(Format).toString(buffer);
+      llvm::APFloat::getSmallest(Format).toString(buffer);
     }
 
     S.Diag(Loc, diagnostic)
       << Ty
       << StringRef(buffer.data(), buffer.size());
   }
+}
+
+static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
+                                  QualType Ty, SourceLocation Loc) {
+  const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty);
+
+  using llvm::APFloat;
+  APFloat Val(Format);
+
+  APFloat::opStatus result = Literal.GetFloatValue(Val);
+
+  HandleFloatOverflow(S, Ty, Loc, result, Val, Format);
 
   bool isExact = (result == APFloat::opOK);
   return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc);
@@ -3321,7 +3382,155 @@
 
   Expr *Res;
 
-  if (Literal.isFloatingLiteral()) {
+  if (Literal.isFixedPointLiteral()){
+    constexpr auto FPS_UNSPECIFIED = NumericLiteralParser::FPS_UNSPECIFIED;
+    constexpr auto FPS_SHORT = NumericLiteralParser::FPS_SHORT;
+    constexpr auto FPS_LONG = NumericLiteralParser::FPS_LONG;
+    constexpr auto FPT_ACCUM = NumericLiteralParser::FPT_ACCUM;
+    constexpr auto FPT_FRACT = NumericLiteralParser::FPT_FRACT;
+
+    QualType floatingTy = Context.DoubleTy;
+    const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(floatingTy);
+    bool isSigned = !Literal.isUnsigned;
+
+    unsigned fbits;
+    unsigned ibits = 0;  // Defaults to 0 for _Fract type
+    unsigned bit_width;
+    QualType Ty;
+
+    switch (Literal.fixedPointSize) {
+      case FPS_UNSPECIFIED:
+        bit_width = Context.getTargetInfo().getIntWidth();
+        break;
+      case FPS_SHORT:
+        bit_width = Context.getTargetInfo().getShortWidth();
+        break;
+      case FPS_LONG:
+        bit_width = Context.getTargetInfo().getLongWidth();
+        break;
+    }
+
+    if (Literal.fixedPointType == FPT_ACCUM) {
+      if (isSigned) {
+        switch (Literal.fixedPointSize) {
+          case FPS_UNSPECIFIED:
+            fbits = BUILTIN_ACCUM_FBIT;
+            ibits = BUILTIN_ACCUM_IBIT;
+            Ty = Context.AccumTy;
+            break;
+          case FPS_SHORT:
+            fbits = BUILTIN_SACCUM_FBIT;
+            ibits = BUILTIN_SACCUM_IBIT;
+            Ty = Context.ShortAccumTy;
+            break;
+          case FPS_LONG:
+            fbits = BUILTIN_LACCUM_FBIT;
+            ibits = BUILTIN_LACCUM_IBIT;
+            Ty = Context.LongAccumTy;
+            break;
+        }
+      } else {
+        switch (Literal.fixedPointSize) {
+          case FPS_UNSPECIFIED:
+            fbits = BUILTIN_UACCUM_FBIT;
+            ibits = BUILTIN_UACCUM_IBIT;
+            Ty = Context.UnsignedAccumTy;
+            break;
+          case FPS_SHORT:
+            fbits = BUILTIN_USACCUM_FBIT;
+            ibits = BUILTIN_USACCUM_IBIT;
+            Ty = Context.UnsignedShortAccumTy;
+            break;
+          case FPS_LONG:
+            fbits = BUILTIN_ULACCUM_FBIT;
+            ibits = BUILTIN_ULACCUM_IBIT;
+            Ty = Context.UnsignedLongAccumTy;
+            break;
+        }
+      }
+    } else if (Literal.fixedPointType == FPT_FRACT) {
+      if (isSigned) {
+        switch (Literal.fixedPointSize) {
+          case FPS_UNSPECIFIED:
+            fbits = BUILTIN_FRACT_FBIT;
+            Ty = Context.FractTy;
+            break;
+          case FPS_SHORT:
+            fbits = BUILTIN_SFRACT_FBIT;
+            Ty = Context.ShortFractTy;
+            break;
+          case FPS_LONG:
+            fbits = BUILTIN_LFRACT_FBIT;
+            Ty = Context.LongFractTy;
+            break;
+        }
+      } else {
+        switch (Literal.fixedPointSize) {
+          case FPS_UNSPECIFIED:
+            fbits = BUILTIN_UFRACT_FBIT;
+            Ty = Context.UnsignedFractTy;
+            break;
+          case FPS_SHORT:
+            fbits = BUILTIN_USFRACT_FBIT;
+            Ty = Context.UnsignedShortFractTy;
+            break;
+          case FPS_LONG:
+            fbits = BUILTIN_ULFRACT_FBIT;
+            Ty = Context.UnsignedLongFractTy;
+            break;
+        }
+      }
+    } else {
+      llvm_unreachable("Expected the literal to be a fixed point type");
+    }
+
+    if (isSigned) {
+      assert((fbits + ibits + 1 <= bit_width) && "The total fractional, integral, and sign bits exceed the bit width");
+    } else {
+      assert((fbits + ibits <= bit_width) && "The total fractional and integral bits exceed the bit width");
+    }
+
+    using llvm::APFloat;
+    APFloat Val(Format);
+    APFloat::opStatus result = Literal.GetFloatValue(Val);
+
+    HandleFloatOverflow(*this, floatingTy, Tok.getLocation(), result, Val, Format);
+
+    // TODO: Check sizes to make sure we don't overflow or fit a value that
+    // can't fit into the number of bits we have.
+    double float_val = Val.convertToDouble();
+    assert(float_val > 0);
+    double int_part;
+    double fract_part = modf(float_val, &int_part);
+    uint64_t int_part_as_int = static_cast<uint64_t>(int_part);
+
+    if (Literal.fixedPointType == FPT_FRACT && int_part_as_int) {
+      Diag(Tok.getLocation(), diag::err_integral_part_on_fract);
+    } else {
+      // Make sure the integral part fits into the integral bits we have.
+      uint64_t max_int_val = 0;
+      if (isSigned) {
+        max_int_val = 1 << (ibits - 1);  // min signed is -2^(n-1)
+      } else {
+        max_int_val = (1 << ibits) - 1;
+      }
+
+      // TODO: What should be done for literals with no unsigned suffix whose
+      // value is equal to the absolute value of the smallest possible value for
+      // that type. Ie. 128.0hk -> -128.0hk? What happens is user writes
+      // "-128.0hk" since we are only interpretting a literal and do now know of
+      // the unary operator?
+      if (int_part_as_int > max_int_val) {
+        Diag(Tok.getLocation(), diag::err_integral_part_of_accum_too_large) << (isSigned ? 0 : 1);
+      }
+    }
+
+    uint64_t fract_part_as_int = static_cast<uint64_t>(fabs(fract_part) * (1 << 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());
+  } else if (Literal.isFloatingLiteral()) {
     QualType Ty;
     if (Literal.isHalf){
       if (getOpenCLOptions().isEnabled("cl_khr_fp16"))
@@ -5802,13 +6011,17 @@
     case Type::STK_FloatingComplex:
     case Type::STK_IntegralComplex:
     case Type::STK_MemberPointer:
+    case Type::STK_FixedPoint:
       llvm_unreachable("illegal cast from pointer");
     }
     llvm_unreachable("Should have returned before this");
 
+  case Type::STK_FixedPoint: llvm_unreachable("Sema::PrepareScalarCast from STK_FixedPoint to anything");  // TODO
+
   case Type::STK_Bool: // casting from bool is like casting from an integer
   case Type::STK_Integral:
     switch (DestTy->getScalarTypeKind()) {
+    case Type::STK_FixedPoint: llvm_unreachable("Sema::PrepareScalarCast from STK_Integral to STK_FixedPoint");  // TODO
     case Type::STK_CPointer:
     case Type::STK_ObjCObjectPointer:
     case Type::STK_BlockPointer:
@@ -5839,6 +6052,7 @@
 
   case Type::STK_Floating:
     switch (DestTy->getScalarTypeKind()) {
+    case Type::STK_FixedPoint: llvm_unreachable("Sema::PrepareScalarCast from STK_Floating to STK_FixedPoint");  // TODO
     case Type::STK_Floating:
       return CK_FloatingCast;
     case Type::STK_Bool:
@@ -5866,6 +6080,7 @@
 
   case Type::STK_FloatingComplex:
     switch (DestTy->getScalarTypeKind()) {
+    case Type::STK_FixedPoint: llvm_unreachable("Sema::PrepareScalarCast from STK_FloatingComplex to STK_FixedPoint");  // TODO
     case Type::STK_FloatingComplex:
       return CK_FloatingComplexCast;
     case Type::STK_IntegralComplex:
@@ -5895,6 +6110,7 @@
 
   case Type::STK_IntegralComplex:
     switch (DestTy->getScalarTypeKind()) {
+    case Type::STK_FixedPoint: llvm_unreachable("Sema::PrepareScalarCast from STK_IntegralComplex to STK_FixedPoint");  // TODO
     case Type::STK_FloatingComplex:
       return CK_IntegralComplexToFloatingComplex;
     case Type::STK_IntegralComplex:
@@ -12893,7 +13109,7 @@
     CondExpr = CondICE.get();
     CondIsTrue = condEval.getZExtValue();
 
-    // If the condition is > zero, then the AST type is the same as the LSHExpr.
+    // If the condition is > zero, then the AST type is the same as the LHSExpr.
     Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr;
 
     resType = ActiveExpr->getType();
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1294,6 +1294,7 @@
   case Expr::ImaginaryLiteralClass:
   case Expr::ImplicitValueInitExprClass:
   case Expr::IntegerLiteralClass:
+  case Expr::FixedPointLiteralClass:
   case Expr::ArrayInitIndexExprClass:
   case Expr::NoInitExprClass:
   case Expr::ObjCEncodeExprClass:
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -529,6 +529,7 @@
   case Type::STK_Floating: return CK_FloatingToBoolean;
   case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean;
   case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean;
+  case Type::STK_FixedPoint: llvm_unreachable("Sema::ScalarTypeToBooleanCastKind for fixed point"); // TODO
   }
   llvm_unreachable("unknown scalar type kind");
 }
Index: lib/Lex/LiteralSupport.cpp
===================================================================
--- lib/Lex/LiteralSupport.cpp
+++ lib/Lex/LiteralSupport.cpp
@@ -547,6 +547,8 @@
   isFloat16 = false;
   isFloat128 = false;
   MicrosoftInteger = 0;
+  fixedPointType = FPT_UNSPECIFIED;
+  fixedPointSize = FPS_UNSPECIFIED;
   hadError = false;
 
   if (*s == '0') { // parse radix
@@ -572,12 +574,40 @@
   // integer constant.
   bool isFPConstant = isFloatingLiteral();
 
+  // Initial scan to lookahead for fixed point suffix. If we find one, we can
+  // ignore some of the rules that break in association with isFPConstant since
+  // fixed point types can be provided as decimals.
+  bool treatFPConstantAsFixedPoint = false;
+  for (const char* c = s; c != ThisTokEnd; ++c) {
+    if (*c == 'r' || *c == 'k' || *c == 'R' || *c == 'K') {
+      treatFPConstantAsFixedPoint = true;
+      break;
+    }
+  }
+
   // Loop over all of the characters of the suffix.  If we see something bad,
   // we break out of the loop.
   for (; s != ThisTokEnd; ++s) {
     switch (*s) {
+    case 'R':
+    case 'r':
+      if (fixedPointType != FPT_UNSPECIFIED) break;  // Cannot repeat
+      fixedPointType = FPT_FRACT;
+      continue;
+    case 'K':
+    case 'k':
+      if (fixedPointType != FPT_UNSPECIFIED) break;  // Cannot repeat
+      fixedPointType = FPT_ACCUM;
+      continue;
     case 'h':      // FP Suffix for "half".
     case 'H':
+      // Floating point instances for fixed point types (hr, hk)
+      if (treatFPConstantAsFixedPoint) {
+        if (fixedPointSize != FPS_UNSPECIFIED) break;
+        fixedPointSize = FPS_SHORT;
+        continue;
+      }
+
       // OpenCL Extension v1.2 s9.5 - h or H suffix for half type.
       if (!PP.getLangOpts().Half) break;
       if (!isFPConstant) break;  // Error for integer constant.
@@ -607,12 +637,24 @@
       continue;  // Success.
     case 'u':
     case 'U':
+      if (treatFPConstantAsFixedPoint) {
+        if (isUnsigned) break;  // Cannot repeat
+        isUnsigned = true;
+        continue;
+      }
+
       if (isFPConstant) break;  // Error for floating constant.
       if (isUnsigned) break;    // Cannot be repeated.
       isUnsigned = true;
       continue;  // Success.
     case 'l':
     case 'L':
+      if (treatFPConstantAsFixedPoint) {
+        if (fixedPointSize != FPS_UNSPECIFIED) break;  // Cannot repeat
+        fixedPointSize = FPS_LONG;
+        continue;
+      }
+
       if (isLong || isLongLong) break;  // Cannot be repeated.
       if (isHalf || isFloat || isFloat128) break;     // LH, LF, LQ invalid.
 
Index: lib/Edit/RewriteObjCFoundationAPI.cpp
===================================================================
--- lib/Edit/RewriteObjCFoundationAPI.cpp
+++ lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1002,6 +1002,7 @@
 
   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
     switch (ICE->getCastKind()) {
+    case CK_IntegralToFixedPoint: llvm_unreachable("rewriteToNumericBoxedExpression CK_IntegralToFixedPoint"); // TODO
     case CK_LValueToRValue:
     case CK_NoOp:
     case CK_UserDefinedConversion:
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -23,6 +23,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/FixedPoint.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Frontend/CodeGenOptions.h"
 #include "llvm/ADT/Optional.h"
@@ -387,6 +388,9 @@
   Value *VisitIntegerLiteral(const IntegerLiteral *E) {
     return Builder.getInt(E->getValue());
   }
+  Value *VisitFixedPointLiteral(const FixedPointLiteral *E) {
+    return Builder.getInt(E->getValue());
+  }
   Value *VisitFloatingLiteral(const FloatingLiteral *E) {
     return llvm::ConstantFP::get(VMContext, E->getValue());
   }
@@ -1772,6 +1776,32 @@
     return Builder.CreateVectorSplat(NumElements, Elt, "splat");
   }
 
+  case CK_IntegralToFixedPoint: {
+    assert(DestTy->isFixedPointType());
+    assert(E->getType()->isIntegerType());
+
+    unsigned fbits;
+    const auto *BT = DestTy->getAs<BuiltinType>();
+    switch (BT->getKind()) {
+      default: llvm_unreachable("Not a fixed point type!");
+      case BuiltinType::ShortAccum:   fbits = BUILTIN_SACCUM_FBIT; break;
+      case BuiltinType::Accum:        fbits = BUILTIN_ACCUM_FBIT; break;
+      case BuiltinType::LongAccum:    fbits = BUILTIN_LACCUM_FBIT; break;
+      case BuiltinType::UShortAccum:  fbits = BUILTIN_USACCUM_FBIT; break;
+      case BuiltinType::UAccum:       fbits = BUILTIN_UACCUM_FBIT; break;
+      case BuiltinType::ULongAccum:   fbits = BUILTIN_ULACCUM_FBIT; break;
+      case BuiltinType::ShortFract:   fbits = BUILTIN_SFRACT_FBIT; break;
+      case BuiltinType::Fract:        fbits = BUILTIN_FRACT_FBIT; break;
+      case BuiltinType::LongFract:    fbits = BUILTIN_LFRACT_FBIT; break;
+      case BuiltinType::UShortFract:  fbits = BUILTIN_USFRACT_FBIT; break;
+      case BuiltinType::UFract:       fbits = BUILTIN_UFRACT_FBIT; break;
+      case BuiltinType::ULongFract:   fbits = BUILTIN_ULFRACT_FBIT; break;
+    }
+
+    return Builder.CreateShl(EmitScalarConversion(Visit(E), E->getType(), DestTy, CE->getExprLoc()),
+                             fbits, "fixed_point_shl");
+  }
+
   case CK_IntegralCast:
   case CK_IntegralToFloating:
   case CK_FloatingToIntegral:
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -686,6 +686,7 @@
     Expr *subExpr = E->getSubExpr();
 
     switch (E->getCastKind()) {
+    case CK_IntegralToFixedPoint: llvm_unreachable("VisitCastExpr CK_IntegralToFixedPoint"); // TODO
     case CK_ToUnion: {
       // GCC cast to union extension
       assert(E->getType()->isUnionType() &&
Index: lib/CodeGen/CGExprComplex.cpp
===================================================================
--- lib/CodeGen/CGExprComplex.cpp
+++ lib/CodeGen/CGExprComplex.cpp
@@ -446,6 +446,7 @@
 ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
                                            QualType DestTy) {
   switch (CK) {
+  case CK_IntegralToFixedPoint: llvm_unreachable("ComplexExprEmitter::EmitCast CK_IntegralToFixedPoint"); // TODO
   case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
 
   // Atomic to non-atomic casts may be more than a no-op for some platforms and
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp
+++ lib/CodeGen/CGExprAgg.cpp
@@ -671,6 +671,7 @@
   if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E))
     CGF.CGM.EmitExplicitCastExprType(ECE, &CGF);
   switch (E->getCastKind()) {
+  case CK_IntegralToFixedPoint: llvm_unreachable("AggExprEmitter::VisitCastExpr CK_IntegralToFixedPoint"); // TODO
   case CK_Dynamic: {
     // FIXME: Can this actually happen? We have no test coverage for it.
     assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -4044,6 +4044,7 @@
 /// cast from scalar to union.
 LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
   switch (E->getCastKind()) {
+  case CK_IntegralToFixedPoint: llvm_unreachable("CodeGenFunction::EmitCastLValue CK_IntegralToFixedPoint"); // TODO
   case CK_ToVoid:
   case CK_BitCast:
   case CK_ArrayToPointerDecay:
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -1929,6 +1929,7 @@
     if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer;
     if (BT->isInteger()) return STK_Integral;
     if (BT->isFloatingPoint()) return STK_Floating;
+    if (BT->isFixedPointType()) return STK_FixedPoint;
     llvm_unreachable("unknown scalar builtin type");
   } else if (isa<PointerType>(T)) {
     return STK_CPointer;
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -1007,6 +1007,12 @@
   ID.AddInteger(S->getType()->castAs<BuiltinType>()->getKind());
 }
 
+void StmtProfiler::VisitFixedPointLiteral(const FixedPointLiteral *S) {
+  VisitExpr(S);
+  S->getValue().Profile(ID);
+  ID.AddInteger(S->getType()->castAs<BuiltinType>()->getKind());
+}
+
 void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) {
   VisitExpr(S);
   ID.AddInteger(S->getKind());
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1525,6 +1525,29 @@
   }
 }
 
+void StmtPrinter::VisitFixedPointLiteral(FixedPointLiteral *Node) {
+  if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context))
+    return;
+  bool isSigned = Node->getType()->isSignedFixedPointType();
+  OS << Node->getValue().toString(10, isSigned);
+
+  switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+  default: llvm_unreachable("Unexpected type for fixed point literal!");
+  case BuiltinType::ShortFract:   OS << "hr"; break;
+  case BuiltinType::ShortAccum:   OS << "hk"; break;
+  case BuiltinType::UShortFract:  OS << "uhr"; break;
+  case BuiltinType::UShortAccum:  OS << "uhk"; break;
+  case BuiltinType::Fract:   OS << "r"; break;
+  case BuiltinType::Accum:   OS << "k"; break;
+  case BuiltinType::UFract:  OS << "ur"; break;
+  case BuiltinType::UAccum:  OS << "uk"; break;
+  case BuiltinType::LongFract:   OS << "lr"; break;
+  case BuiltinType::LongAccum:   OS << "lk"; break;
+  case BuiltinType::ULongFract:  OS << "ulr"; break;
+  case BuiltinType::ULongAccum:  OS << "ulk"; break;
+  }
+}
+
 static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
                                  bool PrintSuffix) {
   SmallString<16> Str;
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3437,6 +3437,7 @@
   
 recurse:
   switch (E->getStmtClass()) {
+  case Expr::FixedPointLiteralClass: llvm_unreachable("Unknown mangling for FixedPointLiteralClass");
   case Expr::NoStmtClass:
 #define ABSTRACT_STMT(Type)
 #define EXPR(Type, Base)
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -1903,8 +1903,9 @@
     return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal);
   }
 
-  if (Value.isMemberPointer())
+  if (Value.isMemberPointer()){
     return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value);
+  }
 
   // Everything else is fine.
   return true;
@@ -7209,6 +7210,75 @@
 
   // FIXME: Missing: array subscript of vector, member of vector
 };
+
+class FixedPointExprEvaluator
+  : public ExprEvaluatorBase<FixedPointExprEvaluator> {
+  APValue &Result;
+public:
+  FixedPointExprEvaluator(EvalInfo &info, APValue &result)
+    : ExprEvaluatorBaseTy(info), Result(result) {}
+
+  bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) {
+    assert(E->getType()->isFixedPointType() &&
+           "Invalid evaluation result.");
+    assert(SI.isSigned() == E->getType()->isSignedFixedPointType() &&
+           "Invalid evaluation result.");
+    assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
+           "Invalid evaluation result.");
+    Result = APValue(SI);
+    return true;
+  }
+  bool Success(const llvm::APSInt &SI, const Expr *E) {
+    return Success(SI, E, Result);
+  }
+
+  bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) {
+    assert(E->getType()->isFixedPointType() && 
+           "Invalid evaluation result.");
+    assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
+           "Invalid evaluation result.");
+    Result = APValue(APSInt(I));
+    Result.getInt().setIsUnsigned(E->getType()->isUnsignedFixedPointType());
+    return true;
+  }
+  bool Success(const llvm::APInt &I, const Expr *E) {
+    return Success(I, E, Result);
+  }
+
+  bool Success(uint64_t Value, const Expr *E, APValue &Result) {
+    assert(E->getType()->isFixedPointType() && 
+           "Invalid evaluation result.");
+    Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType()));
+    return true;
+  }
+  bool Success(uint64_t Value, const Expr *E) {
+    return Success(Value, E, Result);
+  }
+
+  bool Success(CharUnits Size, const Expr *E) {
+    return Success(Size.getQuantity(), E);
+  }
+
+  bool Success(const APValue &V, const Expr *E) {
+    if (V.isLValue() || V.isAddrLabelDiff()) {
+      Result = V;
+      return true;
+    }
+    return Success(V.getInt(), E);
+  }
+
+  bool ZeroInitialization(const Expr *E) { return Success(0, E); }
+
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  bool VisitFixedPointLiteral(const FixedPointLiteral *E) {
+    return Success(E->getValue(), E);
+  }
+
+  bool VisitUnaryOperator(const UnaryOperator *E);
+};
 } // end anonymous namespace
 
 /// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and
@@ -9060,6 +9130,7 @@
   QualType SrcType = SubExpr->getType();
 
   switch (E->getCastKind()) {
+  case CK_IntegralToFixedPoint: llvm_unreachable("IntExprEvaluator::VisitCastExpr CK_IntegralToFixedPoint"); // TODO
   case CK_BaseToDerived:
   case CK_DerivedToBase:
   case CK_UncheckedDerivedToBase:
@@ -9236,6 +9307,41 @@
   return Success(E->getValue(), E);
 }
 
+bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+  switch (E->getOpcode()) {
+  default:
+    // Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
+    // See C99 6.6p3.
+    return Error(E);
+  case UO_Plus:
+    // The result is just the value.
+    return Visit(E->getSubExpr());
+  case UO_Minus: {
+    if (!Visit(E->getSubExpr()))
+      return false;
+    if (!Result.isInt()) return Error(E);
+    const APSInt &Value = Result.getInt();
+    if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow() &&
+        !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
+                        E->getType()))
+      return false;
+    return Success(-Value, E);
+  }
+  case UO_Not: {
+    if (!Visit(E->getSubExpr()))
+      return false;
+    if (!Result.isInt()) return Error(E);
+    return Success(~Result.getInt(), E);
+  }
+  case UO_LNot: {
+    bool bres;
+    if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
+      return false;
+    return Success(!bres, E);
+  }
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Float Evaluation
 //===----------------------------------------------------------------------===//
@@ -9553,6 +9659,7 @@
 bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
 
   switch (E->getCastKind()) {
+  case CK_IntegralToFixedPoint: llvm_unreachable("ComplexExprEvaluator::VisitCastExpr CK_IntegralToFixedPoint"); // TODO
   case CK_BitCast:
   case CK_BaseToDerived:
   case CK_DerivedToBase:
@@ -10087,6 +10194,9 @@
     if (!EvaluateComplex(E, C, Info))
       return false;
     C.moveInto(Result);
+  } else if (T->isFixedPointType()){
+    if (!FixedPointExprEvaluator(Info, Result).Visit(E))
+      return false;
   } else if (T->isMemberPointerType()) {
     MemberPtr P;
     if (!EvaluateMemberPointer(E, P, Info))
@@ -10523,6 +10633,7 @@
   case Expr::GenericSelectionExprClass:
     return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx);
   case Expr::IntegerLiteralClass:
+  case Expr::FixedPointLiteralClass:
   case Expr::CharacterLiteralClass:
   case Expr::ObjCBoolLiteralExprClass:
   case Expr::CXXBoolLiteralExprClass:
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -161,6 +161,7 @@
   case Expr::ShuffleVectorExprClass:
   case Expr::ConvertVectorExprClass:
   case Expr::IntegerLiteralClass:
+  case Expr::FixedPointLiteralClass:
   case Expr::CharacterLiteralClass:
   case Expr::AddrLabelExprClass:
   case Expr::CXXDeleteExprClass:
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -755,6 +755,48 @@
   return new (C) IntegerLiteral(Empty);
 }
 
+FixedPointLiteral::FixedPointLiteral(const ASTContext &C, const llvm::APInt &V,
+                                     QualType type, SourceLocation l)
+  : Expr(FixedPointLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
+         false, false),
+    Loc(l) {
+  assert(type->isFixedPointType() && "Illegal type in FixedPointLiteral");
+
+  const auto *BT = type->getAs<BuiltinType>();
+  assert(BT && "Not a fixed point type!");
+  switch (BT->getKind()) {
+    default: llvm_unreachable("Not a fixed point type!");
+    case BuiltinType::ShortAccum:
+    case BuiltinType::UShortAccum:
+    case BuiltinType::ShortFract:
+    case BuiltinType::UShortFract:
+      assert(V.getBitWidth() == C.getIntWidth(type) &&
+             "Short fixed point type is not the correct size for constant.");
+      break;
+    case BuiltinType::Accum:
+    case BuiltinType::UAccum:
+    case BuiltinType::Fract:
+    case BuiltinType::UFract:
+      assert(V.getBitWidth() == C.getIntWidth(type) &&
+             "Fixed point type is not the correct size for constant.");
+      break;
+    case BuiltinType::LongAccum:
+    case BuiltinType::ULongAccum:
+    case BuiltinType::LongFract:
+    case BuiltinType::ULongFract:
+      assert(V.getBitWidth() == C.getIntWidth(type) &&
+             "Long fixed point type is not the correct size for constant.");
+      break;
+  }
+  setValue(C, V);
+}
+
+FixedPointLiteral *
+FixedPointLiteral::CreateFromRawInt(const ASTContext &C, const llvm::APInt &V,
+                       QualType type, SourceLocation l) {
+  return new (C) FixedPointLiteral(C, V, type, l);
+}
+
 FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V,
                                  bool isexact, QualType Type, SourceLocation L)
   : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
@@ -1609,6 +1651,7 @@
   case CK_ZeroToOCLEvent:
   case CK_ZeroToOCLQueue:
   case CK_IntToOCLSampler:
+  case CK_IntegralToFixedPoint:
     assert(!getType()->isBooleanType() && "unheralded conversion to bool");
     goto CheckNoBasePath;
 
@@ -2990,6 +3033,7 @@
   case ObjCIvarRefExprClass:
   case PredefinedExprClass:
   case IntegerLiteralClass:
+  case FixedPointLiteralClass:
   case FloatingLiteralClass:
   case ImaginaryLiteralClass:
   case StringLiteralClass:
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -525,6 +525,7 @@
     void VisitPredefinedExpr(const PredefinedExpr *Node);
     void VisitCharacterLiteral(const CharacterLiteral *Node);
     void VisitIntegerLiteral(const IntegerLiteral *Node);
+    void VisitFixedPointLiteral(const FixedPointLiteral *Node);
     void VisitFloatingLiteral(const FloatingLiteral *Node);
     void VisitStringLiteral(const StringLiteral *Str);
     void VisitInitListExpr(const InitListExpr *ILE);
@@ -2177,6 +2178,14 @@
   OS << " " << Node->getValue().toString(10, isSigned);
 }
 
+void ASTDumper::VisitFixedPointLiteral(const FixedPointLiteral *Node) {
+  VisitExpr(Node);
+
+  bool isSigned = Node->getType()->isSignedFixedPointType();
+  ColorScope Color(*this, ValueColor);
+  OS << " " << Node->getValue().toString(10, isSigned);
+}
+
 void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) {
   VisitExpr(Node);
   ColorScope Color(*this, ValueColor);
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -60,6 +60,7 @@
 #include "clang/Basic/TargetCXXABI.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/XRayLists.h"
+#include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -1785,20 +1786,26 @@
     case BuiltinType::Short:
     case BuiltinType::ShortAccum:
     case BuiltinType::UShortAccum:
+    case BuiltinType::ShortFract:
+    case BuiltinType::UShortFract:
       Width = Target->getShortWidth();
       Align = Target->getShortAlign();
       break;
     case BuiltinType::UInt:
     case BuiltinType::Int:
     case BuiltinType::Accum:
     case BuiltinType::UAccum:
+    case BuiltinType::Fract:
+    case BuiltinType::UFract:
       Width = Target->getIntWidth();
       Align = Target->getIntAlign();
       break;
     case BuiltinType::ULong:
     case BuiltinType::Long:
     case BuiltinType::LongAccum:
     case BuiltinType::ULongAccum:
+    case BuiltinType::LongFract:
+    case BuiltinType::ULongFract:
       Width = Target->getLongWidth();
       Align = Target->getLongAlign();
       break;
Index: include/clang/Lex/LiteralSupport.h
===================================================================
--- include/clang/Lex/LiteralSupport.h
+++ include/clang/Lex/LiteralSupport.h
@@ -69,6 +69,23 @@
   bool isFloat128 : 1;      // 1.0q
   uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
 
+  enum FixedPointType {
+    FPT_UNSPECIFIED, FPT_ACCUM, FPT_FRACT
+  };
+
+  // We use separate fields for fixed point sizes b/c the isHalf/isLong booleans
+  // assume that this literal is an integral type instead of fixed point type.
+  enum FixedPointSize {
+    FPS_UNSPECIFIED, FPS_SHORT, FPS_LONG
+  };
+
+  enum FixedPointType fixedPointType;
+  enum FixedPointSize fixedPointSize;
+
+  bool isFixedPointLiteral() const {
+    return fixedPointType != FPT_UNSPECIFIED;
+  }
+
   bool isIntegerLiteral() const {
     return !saw_period && !saw_exponent;
   }
@@ -157,7 +174,6 @@
       ptr++;
     return ptr;
   }
-
 };
 
 /// CharLiteralParser - Perform interpretation and semantic analysis of a
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -57,6 +57,7 @@
 def PredefinedExpr : DStmt<Expr>;
 def DeclRefExpr : DStmt<Expr>;
 def IntegerLiteral : DStmt<Expr>;
+def FixedPointLiteral : DStmt<Expr>;
 def FloatingLiteral : DStmt<Expr>;
 def ImaginaryLiteral : DStmt<Expr>;
 def StringLiteral : DStmt<Expr>;
Index: include/clang/Basic/FixedPoint.h.in
===================================================================
--- /dev/null
+++ include/clang/Basic/FixedPoint.h.in
@@ -0,0 +1,28 @@
+#ifndef LLVM_CLANG_BASIC_FIXEDPOINT_H
+#define LLVM_CLANG_BASIC_FIXEDPOINT_H
+
+// Fractional bits of _Accum types
+#define BUILTIN_SACCUM_FBIT     @SACCUM_FBIT@
+#define BUILTIN_ACCUM_FBIT      @ACCUM_FBIT@
+#define BUILTIN_LACCUM_FBIT     @LACCUM_FBIT@
+#define BUILTIN_USACCUM_FBIT    @USACCUM_FBIT@
+#define BUILTIN_UACCUM_FBIT     @UACCUM_FBIT@
+#define BUILTIN_ULACCUM_FBIT    @ULACCUM_FBIT@
+
+// Fractional bits of _Fract types
+#define BUILTIN_SFRACT_FBIT     @SFRACT_FBIT@
+#define BUILTIN_FRACT_FBIT      @FRACT_FBIT@
+#define BUILTIN_LFRACT_FBIT     @LFRACT_FBIT@
+#define BUILTIN_USFRACT_FBIT    @USFRACT_FBIT@
+#define BUILTIN_UFRACT_FBIT     @UFRACT_FBIT@
+#define BUILTIN_ULFRACT_FBIT    @ULFRACT_FBIT@
+
+// Integral bits of _Accum types
+#define BUILTIN_SACCUM_IBIT     @SACCUM_IBIT@
+#define BUILTIN_ACCUM_IBIT      @ACCUM_IBIT@
+#define BUILTIN_LACCUM_IBIT     @LACCUM_IBIT@
+#define BUILTIN_USACCUM_IBIT    @USACCUM_IBIT@
+#define BUILTIN_UACCUM_IBIT     @UACCUM_IBIT@
+#define BUILTIN_ULACCUM_IBIT    @ULACCUM_IBIT@
+
+#endif
Index: include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- include/clang/Basic/DiagnosticCommonKinds.td
+++ include/clang/Basic/DiagnosticCommonKinds.td
@@ -168,6 +168,11 @@
                           InGroup<GccCompat>;
 def ext_clang_diagnose_if : Extension<"'diagnose_if' is a clang extension">,
                             InGroup<GccCompat>;
+def err_integral_part_on_fract : Error<"a _Fract type cannot have an "
+  "integral part">;
+def err_integral_part_of_accum_too_large : Error<
+  "the integral part of this literal is too large for this "
+  "%select{signed|unsigned}0 _Accum type">;
 def err_fixed_point_only_allowed_in_c : Error<
   "Fixed point types are only allowed in C">;
 
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1916,7 +1916,8 @@
     STK_Integral,
     STK_Floating,
     STK_IntegralComplex,
-    STK_FloatingComplex
+    STK_FloatingComplex,
+    STK_FixedPoint
   };
 
   /// Given that this is a scalar type, classify it.
@@ -2106,6 +2107,21 @@
   /// enumeration types whose underlying type is a unsigned integer type.
   bool isUnsignedIntegerOrEnumerationType() const;
 
+  // Return true if this is a fixed point type according to ISO/IEC JTC1 SC22 WG14 N1169.
+  bool isFixedPointType() const;
+
+  // Return true if this is a saturated fixed point type according to
+  // ISO/IEC JTC1 SC22 WG14 N1169.
+  bool isSaturatedFixedPointType() const;
+
+  // Return true if this is a fixed point type that is signed according
+  // to ISO/IEC JTC1 SC22 WG14 N1169. [short _Fract, _Accum, long _Fract...]
+  bool isSignedFixedPointType() const;
+
+  // Return true if this is a fixed point type that is unsigned according
+  // to ISO/IEC JTC1 SC22 WG14 N1169.
+  bool isUnsignedFixedPointType() const;
+
   /// Return true if this is not a variable sized type,
   /// according to the rules of C99 6.7.5p3.  It is not legal to call this on
   /// incomplete types.
@@ -6286,6 +6302,40 @@
   return false;
 }
 
+inline bool Type::isFixedPointType() const {
+  if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)){
+    return BT->getKind() >= BuiltinType::ShortAccum && BT->getKind() <= BuiltinType::SatULongFract;
+  }
+  return false;
+}
+
+inline bool Type::isSaturatedFixedPointType() const {
+  if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)){
+    return BT->getKind() >= BuiltinType::SatShortAccum && BT->getKind() <= BuiltinType::SatULongFract;
+  }
+  return false;
+}
+
+inline bool Type::isSignedFixedPointType() const {
+  if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)){
+    return ((BT->getKind() >= BuiltinType::ShortAccum && BT->getKind() <= BuiltinType::LongAccum) ||
+            (BT->getKind() >= BuiltinType::ShortFract && BT->getKind() <= BuiltinType::LongFract) ||
+            (BT->getKind() >= BuiltinType::SatShortAccum && BT->getKind() <= BuiltinType::SatLongAccum) ||
+            (BT->getKind() >= BuiltinType::SatShortFract && BT->getKind() <= BuiltinType::SatLongFract));
+  }
+  return false;
+}
+
+inline bool Type::isUnsignedFixedPointType() const {
+  if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)){
+    return ((BT->getKind() >= BuiltinType::UShortAccum && BT->getKind() <= BuiltinType::ULongAccum) ||
+            (BT->getKind() >= BuiltinType::UShortFract && BT->getKind() <= BuiltinType::ULongFract) ||
+            (BT->getKind() >= BuiltinType::SatUShortAccum && BT->getKind() <= BuiltinType::SatULongAccum) ||
+            (BT->getKind() >= BuiltinType::SatUShortFract && BT->getKind() <= BuiltinType::SatULongFract));
+  }
+  return false;
+}
+
 inline bool Type::isScalarType() const {
   if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
     return BT->getKind() > BuiltinType::Void &&
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2585,6 +2585,7 @@
 
 // These literals (all of them) do not need any action.
 DEF_TRAVERSE_STMT(IntegerLiteral, {})
+DEF_TRAVERSE_STMT(FixedPointLiteral, {})
 DEF_TRAVERSE_STMT(CharacterLiteral, {})
 DEF_TRAVERSE_STMT(FloatingLiteral, {})
 DEF_TRAVERSE_STMT(ImaginaryLiteral, {})
Index: include/clang/AST/OperationKinds.def
===================================================================
--- include/clang/AST/OperationKinds.def
+++ include/clang/AST/OperationKinds.def
@@ -197,6 +197,10 @@
 ///    float f = i;
 CAST_OPERATION(IntegralToFloating)
 
+/// CK_IntegralToFixedPoint - Integral to fixed point.
+///    (short _Accum) i;
+CAST_OPERATION(IntegralToFixedPoint)
+
 /// CK_FloatingToIntegral - Floating point to integral.  Rounds
 /// towards zero, discarding any fractional component.
 ///    (int) f
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -1344,6 +1344,42 @@
   }
 };
 
+class FixedPointLiteral : public Expr, public APIntStorage {
+  SourceLocation Loc;
+
+  /// \brief Construct an empty integer literal.
+  explicit FixedPointLiteral(EmptyShell Empty)
+    : Expr(FixedPointLiteralClass, Empty) { }
+
+public:
+  FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, QualType type,
+                    SourceLocation l);
+
+  // Store the int as is without any bit shifting.
+  static FixedPointLiteral *CreateFromRawInt(const ASTContext &C, const llvm::APInt &V,
+                                             QualType type, SourceLocation l);
+
+  SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+  SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
+
+  /// \brief Retrieve the location of the literal.
+  SourceLocation getLocation() const { return Loc; }
+
+  void setLocation(SourceLocation Location) { Loc = Location; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == FixedPointLiteralClass;
+  }
+
+  // Iterators
+  child_range children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+  const_child_range children() const {
+    return const_child_range(const_child_iterator(), const_child_iterator());
+  }
+};
+
 class CharacterLiteral : public Expr {
 public:
   enum CharacterKind {
Index: cmake/modules/InitFixedPointBits.cmake
===================================================================
--- /dev/null
+++ cmake/modules/InitFixedPointBits.cmake
@@ -0,0 +1,88 @@
+# Set default values of fixed point types for typical desktop processors i
+# described in ISO/IEC JTC1 SC22 WG14 N1169
+# Fractional bits of _Accum types
+if(NOT DEFINED SACCUM_FBIT)
+  set(SACCUM_FBIT 7)
+endif()
+if(NOT DEFINED ACCUM_FBIT)
+  set(ACCUM_FBIT 15)
+endif()
+if(NOT DEFINED LACCUM_FBIT)
+  set(LACCUM_FBIT 31)
+endif()
+if(NOT DEFINED USACCUM_FBIT)
+  set(USACCUM_FBIT 8)
+endif()
+if(NOT DEFINED UACCUM_FBIT)
+  set(UACCUM_FBIT 16)
+endif()
+if(NOT DEFINED ULACCUM_FBIT)
+  set(ULACCUM_FBIT 32)
+endif()
+
+# Fractional bits of _Fract types
+if(NOT DEFINED SFRACT_FBIT)
+  set(SFRACT_FBIT 7)
+endif()
+if(NOT DEFINED FRACT_FBIT)
+  set(FRACT_FBIT 15)
+endif()
+if(NOT DEFINED LFRACT_FBIT)
+  set(LFRACT_FBIT 31)
+endif()
+if(NOT DEFINED USFRACT_FBIT)
+  set(USFRACT_FBIT 8)
+endif()
+if(NOT DEFINED UFRACT_FBIT)
+  set(UFRACT_FBIT 16)
+endif()
+if(NOT DEFINED ULFRACT_FBIT)
+  set(ULFRACT_FBIT 32)
+endif()
+
+# Integral bits of _Accum types
+if(NOT DEFINED SACCUM_IBIT)
+  set(SACCUM_IBIT 8)
+endif()
+if(NOT DEFINED ACCUM_IBIT)
+  set(ACCUM_IBIT 16)
+endif()
+if(NOT DEFINED LACCUM_IBIT)
+  set(LACCUM_IBIT 32)
+endif()
+if(NOT DEFINED USACCUM_IBIT)
+  set(USACCUM_IBIT 8)
+endif()
+if(NOT DEFINED UACCUM_IBIT)
+  set(UACCUM_IBIT 16)
+endif()
+if(NOT DEFINED ULACCUM_IBIT)
+  set(ULACCUM_IBIT 32)
+endif()
+
+# Checks for each bit size
+# Each unsigned fract type has either the same number of fractional bits as,
+# or one more fractional bit than, its corresponding signed fract type.
+# TODO: Implement remaining checks in clause 6.2.6.3.
+function(check_diff_at_most_1 sfract_fbits ufract_fbits)
+  if(sfract_fbits EQUAL ufract_fbits)
+    return()
+  endif()
+  math(EXPR diff "${ufract_fbits} - ${sfract_fbits}")
+  if(diff EQUAL 1)
+    return()
+  endif()
+  message(FATAL_ERROR "Each unsigned fract type has either the same number of "
+	  "fractional bits as, or one more fractional bit than, its corresponding "
+	  "signed fract type.")
+endfunction()
+
+check_diff_at_most_1(${SFRACT_FBIT} ${USFRACT_FBIT})
+check_diff_at_most_1(${FRACT_FBIT} ${UFRACT_FBIT})
+check_diff_at_most_1(${LFRACT_FBIT} ${ULFRACT_FBIT})
+
+# Configure the FixedPoint.h file.
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/include/clang/Basic/FixedPoint.h.in
+  ${CMAKE_CURRENT_BINARY_DIR}/include/clang/Basic/FixedPoint.h)
+
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -324,6 +324,8 @@
   ${CMAKE_CURRENT_SOURCE_DIR}/include/clang/Basic/Version.inc.in
   ${CMAKE_CURRENT_BINARY_DIR}/include/clang/Basic/Version.inc)
 
+include(InitFixedPointBits)
+
 # Add appropriate flags for GCC
 if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to