summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang-c/Index.h7
-rw-r--r--clang/include/clang/AST/ASTContext.h3
-rw-r--r--clang/include/clang/AST/Expr.h41
-rw-r--r--clang/include/clang/AST/RecursiveASTVisitor.h1
-rw-r--r--clang/include/clang/AST/Type.h7
-rw-r--r--clang/include/clang/Basic/DiagnosticCommonKinds.td2
-rw-r--r--clang/include/clang/Basic/LangOptions.def2
-rw-r--r--clang/include/clang/Basic/StmtNodes.td1
-rw-r--r--clang/include/clang/Basic/TargetInfo.h103
-rw-r--r--clang/include/clang/Driver/Options.td4
-rw-r--r--clang/include/clang/Lex/LiteralSupport.h17
-rw-r--r--clang/lib/AST/ASTContext.cpp89
-rw-r--r--clang/lib/AST/ASTDumper.cpp8
-rw-r--r--clang/lib/AST/Expr.cpp31
-rw-r--r--clang/lib/AST/ExprClassification.cpp1
-rw-r--r--clang/lib/AST/ExprConstant.cpp101
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp1
-rw-r--r--clang/lib/AST/StmtPrinter.cpp22
-rw-r--r--clang/lib/AST/StmtProfile.cpp6
-rw-r--r--clang/lib/AST/Type.cpp16
-rw-r--r--clang/lib/Basic/TargetInfo.cpp83
-rw-r--r--clang/lib/Basic/Targets.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp4
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp3
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp5
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp4
-rw-r--r--clang/lib/Lex/LiteralSupport.cpp153
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--clang/lib/Sema/SemaExpr.cpp49
-rw-r--r--clang/lib/Sema/TreeTransform.h6
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp6
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp1
-rw-r--r--clang/test/Frontend/fixed_point.c162
-rw-r--r--clang/test/Frontend/fixed_point_bit_widths.c72
-rw-r--r--clang/test/Frontend/fixed_point_declarations.c113
-rw-r--r--clang/test/Frontend/fixed_point_errors.c57
-rw-r--r--clang/test/Frontend/fixed_point_same_fbits.c28
-rw-r--r--clang/tools/libclang/CIndex.cpp2
-rw-r--r--clang/tools/libclang/CXCursor.cpp4
40 files changed, 1175 insertions, 50 deletions
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 4afcd2b1e38..0ad90010ccd 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -2170,7 +2170,12 @@ enum CXCursorKind {
*/
CXCursor_ObjCAvailabilityCheckExpr = 148,
- CXCursor_LastExpr = CXCursor_ObjCAvailabilityCheckExpr,
+ /**
+ * Fixed point literal
+ */
+ CXCursor_FixedPointLiteral = 149,
+
+ CXCursor_LastExpr = CXCursor_FixedPointLiteral,
/* Statements */
CXCursor_FirstStmt = 200,
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index a488ff0cedc..ac317a77695 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1947,6 +1947,9 @@ public:
return getQualifiedType(type.getUnqualifiedType(), Qs);
}
+ unsigned char getFixedPointScale(QualType Ty) const;
+ unsigned char getFixedPointIBits(QualType Ty) const;
+
DeclarationNameInfo getNameForTemplate(TemplateName Name,
SourceLocation NameLoc) const;
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index c51ba8ddc09..d71fda74301 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -1351,6 +1351,47 @@ public:
}
};
+class FixedPointLiteral : public Expr, public APIntStorage {
+ SourceLocation Loc;
+ unsigned Scale;
+
+ /// \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, unsigned Scale);
+
+ // Store the int as is without any bit shifting.
+ static FixedPointLiteral *CreateFromRawInt(const ASTContext &C,
+ const llvm::APInt &V,
+ QualType type, SourceLocation l,
+ unsigned Scale);
+
+ 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;
+ }
+
+ std::string getValueAsString(unsigned Radix) const;
+
+ // 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 {
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 1858de8e58e..3e6090d3126 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2585,6 +2585,7 @@ DEF_TRAVERSE_STMT(CoyieldExpr, {
// 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, {})
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index ff26757b435..5e1fc372a02 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -30,6 +30,7 @@
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/None.h"
@@ -6546,6 +6547,12 @@ QualType DecayedType::getPointeeType() const {
return cast<PointerType>(Decayed)->getPointeeType();
}
+// Get the decimal string representation of a fixed point type, represented
+// as a scaled integer.
+void FixedPointValueToString(SmallVectorImpl<char> &Str,
+ const llvm::APSInt &Val,
+ unsigned Scale, unsigned Radix);
+
} // namespace clang
#endif // LLVM_CLANG_AST_TYPE_H
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 93f262361c8..61a73541d0b 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -168,6 +168,8 @@ def ext_clang_enable_if : Extension<"'enable_if' is a clang extension">,
InGroup<GccCompat>;
def ext_clang_diagnose_if : Extension<"'diagnose_if' is a clang extension">,
InGroup<GccCompat>;
+def err_too_large_for_fixed_point : Error<
+ "this value is too large for this fixed point type">;
def err_fixed_point_not_enabled : Error<"compile with "
"'-ffixed-point' to enable fixed point types">;
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index f9246bd8935..d7d66be32de 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -305,6 +305,8 @@ ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest,
COMPATIBLE_VALUE_LANGOPT(FunctionAlignment, 5, 0, "Default alignment for functions")
LANGOPT(FixedPoint, 1, 0, "fixed point types")
+LANGOPT(SameFBits, 1, 0,
+ "unsigned and signed fixed point type having the same number of fractional bits")
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 0d21845fbf8..506da072033 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -57,6 +57,7 @@ def Expr : Stmt<1>;
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>;
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 24eb67af41b..9bb4db7205d 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -74,12 +74,32 @@ protected:
unsigned char LargeArrayMinWidth, LargeArrayAlign;
unsigned char LongWidth, LongAlign;
unsigned char LongLongWidth, LongLongAlign;
+
+ // Fixed point bit widths
unsigned char ShortAccumWidth, ShortAccumAlign;
unsigned char AccumWidth, AccumAlign;
unsigned char LongAccumWidth, LongAccumAlign;
unsigned char ShortFractWidth, ShortFractAlign;
unsigned char FractWidth, FractAlign;
unsigned char LongFractWidth, LongFractAlign;
+
+ // If true, unsigned fixed point types have the same number of fractional bits
+ // as their signed counterparts. Otherwise, unsigned fixed point types have
+ // one more fractional bit than its corresponding signed type. This is false
+ // by default.
+ bool SameFBits;
+
+ // Fixed point integral and fractional bit sizes
+ // Saturated types share the same integral/fractional bits as their
+ // corresponding unsaturated types.
+ // For simplicity, the fractional bits in a _Fract type will be one less the
+ // width of that _Fract type. This leaves all signed _Fract types having no
+ // padding and unsigned _Fract types will only have 1 bit of padding after the
+ // sign if SameFBits is set.
+ unsigned char ShortAccumScale;
+ unsigned char AccumScale;
+ unsigned char LongAccumScale;
+
unsigned char SuitableAlign;
unsigned char DefaultAlignForAttributeAligned;
unsigned char MinGlobalAlign;
@@ -394,6 +414,84 @@ public:
unsigned getLongFractWidth() const { return LongFractWidth; }
unsigned getLongFractAlign() const { return LongFractAlign; }
+ /// getShortAccumScale/IBits - Return the number of fractional/integral bits
+ /// in a 'signed short _Accum' type.
+ unsigned getShortAccumScale() const { return ShortAccumScale; }
+ unsigned getShortAccumIBits() const {
+ return ShortAccumWidth - ShortAccumScale - 1;
+ }
+
+ /// getAccumScale/IBits - Return the number of fractional/integral bits
+ /// in a 'signed _Accum' type.
+ unsigned getAccumScale() const { return AccumScale; }
+ unsigned getAccumIBits() const { return AccumWidth - AccumScale - 1; }
+
+ /// getLongAccumScale/IBits - Return the number of fractional/integral bits
+ /// in a 'signed long _Accum' type.
+ unsigned getLongAccumScale() const { return LongAccumScale; }
+ unsigned getLongAccumIBits() const {
+ return LongAccumWidth - LongAccumScale - 1;
+ }
+
+ /// getUnsignedShortAccumScale/IBits - Return the number of
+ /// fractional/integral bits in a 'unsigned short _Accum' type.
+ unsigned getUnsignedShortAccumScale() const {
+ return SameFBits ? ShortAccumScale : ShortAccumScale + 1;
+ }
+ unsigned getUnsignedShortAccumIBits() const {
+ return SameFBits ? getShortAccumIBits()
+ : ShortAccumWidth - getUnsignedShortAccumScale();
+ }
+
+ /// getUnsignedAccumScale/IBits - Return the number of fractional/integral
+ /// bits in a 'unsigned _Accum' type.
+ unsigned getUnsignedAccumScale() const {
+ return SameFBits ? AccumScale : AccumScale + 1;
+ }
+ unsigned getUnsignedAccumIBits() const {
+ return SameFBits ? getAccumIBits() : AccumWidth - getUnsignedAccumScale();
+ }
+
+ /// getUnsignedLongAccumScale/IBits - Return the number of fractional/integral
+ /// bits in a 'unsigned long _Accum' type.
+ unsigned getUnsignedLongAccumScale() const {
+ return SameFBits ? LongAccumScale : LongAccumScale + 1;
+ }
+ unsigned getUnsignedLongAccumIBits() const {
+ return SameFBits ? getLongAccumIBits()
+ : LongAccumWidth - getUnsignedLongAccumScale();
+ }
+
+ /// getShortFractScale - Return the number of fractional bits
+ /// in a 'signed short _Fract' type.
+ unsigned getShortFractScale() const { return ShortFractWidth - 1; }
+
+ /// getFractScale - Return the number of fractional bits
+ /// in a 'signed _Fract' type.
+ unsigned getFractScale() const { return FractWidth - 1; }
+
+ /// getLongFractScale - Return the number of fractional bits
+ /// in a 'signed long _Fract' type.
+ unsigned getLongFractScale() const { return LongFractWidth - 1; }
+
+ /// getUnsignedShortFractScale - Return the number of fractional bits
+ /// in a 'unsigned short _Fract' type.
+ unsigned getUnsignedShortFractScale() const {
+ return SameFBits ? getShortFractScale() : getShortFractScale() + 1;
+ }
+
+ /// getUnsignedFractScale - Return the number of fractional bits
+ /// in a 'unsigned _Fract' type.
+ unsigned getUnsignedFractScale() const {
+ return SameFBits ? getFractScale() : getFractScale() + 1;
+ }
+
+ /// getUnsignedLongFractScale - Return the number of fractional bits
+ /// in a 'unsigned long _Fract' type.
+ unsigned getUnsignedLongFractScale() const {
+ return SameFBits ? getLongFractScale() : getLongFractScale() + 1;
+ }
+
/// Determine whether the __int128 type is supported on this target.
virtual bool hasInt128Type() const {
return (getPointerWidth(0) >= 64) || getTargetOpts().ForceEnableInt128;
@@ -1189,6 +1287,11 @@ protected:
virtual ArrayRef<AddlRegName> getGCCAddlRegNames() const {
return None;
}
+
+ private:
+ // Assert the values for the fractional and integral bits for each fixed point
+ // type follow the restrictions given in clause 6.2.6.3 of N1169.
+ void CheckFixedPointBits() const;
};
} // end namespace clang
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index cd02a5ab5bd..089a9b3649a 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -893,6 +893,10 @@ def ffixed_point : Flag<["-"], "ffixed-point">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Enable fixed point types">;
def fno_fixed_point : Flag<["-"], "fno-fixed-point">, Group<f_Group>,
HelpText<"Disable fixed point types">;
+def fsame_fbits : Flag<["-"], "fsame-fbits">, Group<f_Group>,
+ Flags<[CC1Option]>,
+ HelpText<"Force each unsigned fixed point type to have the same number of fractional bits as its corresponding signed type">;
+def fno_same_fbits : Flag<["-"], "fno-same-fbits">, Group<f_Group>;
// Begin sanitizer flags. These should all be core options exposed in all driver
// modes.
diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h
index 4f32fa8e738..1b6bf6bcffb 100644
--- a/clang/include/clang/Lex/LiteralSupport.h
+++ b/clang/include/clang/Lex/LiteralSupport.h
@@ -50,7 +50,7 @@ class NumericLiteralParser {
unsigned radix;
- bool saw_exponent, saw_period, saw_ud_suffix;
+ bool saw_exponent, saw_period, saw_ud_suffix, saw_fixed_point_suffix;
SmallString<32> UDSuffixBuf;
@@ -69,11 +69,16 @@ public:
bool isFloat128 : 1; // 1.0q
uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
+ bool isFract : 1; // 1.0hr/r/lr/uhr/ur/ulr
+ bool isAccum : 1; // 1.0hk/k/lk/uhk/uk/ulk
+
+ bool isFixedPointLiteral() const { return saw_fixed_point_suffix; }
+
bool isIntegerLiteral() const {
- return !saw_period && !saw_exponent;
+ return !saw_period && !saw_exponent && !isFixedPointLiteral();
}
bool isFloatingLiteral() const {
- return saw_period || saw_exponent;
+ return (saw_period || saw_exponent) && !isFixedPointLiteral();
}
bool hasUDSuffix() const {
@@ -105,6 +110,12 @@ public:
/// literal exactly, and false otherwise.
llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result);
+ /// GetFixedPointValue - Convert this numeric literal value into a
+ /// scaled integer that represents this value. Returns true if an overflow
+ /// occurred when calculating the integral part of the scaled integer or
+ /// calculating the digit sequence of the exponent.
+ bool GetFixedPointValue(llvm::APInt &StoreVal, unsigned Scale);
+
private:
void ParseNumberStartingWithZero(SourceLocation TokLoc);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index de32de5dca6..96b7b56c1c7 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -10162,3 +10162,92 @@ clang::LazyGenerationalUpdatePtr<
clang::LazyGenerationalUpdatePtr<
const Decl *, Decl *, &ExternalASTSource::CompleteRedeclChain>::makeValue(
const clang::ASTContext &Ctx, Decl *Value);
+
+unsigned char ASTContext::getFixedPointScale(QualType Ty) const {
+ assert(Ty->isFixedPointType());
+
+ const auto *BT = Ty->getAs<BuiltinType>();
+ const TargetInfo &Target = getTargetInfo();
+ switch (BT->getKind()) {
+ default:
+ llvm_unreachable("Not a fixed point type!");
+ case BuiltinType::ShortAccum:
+ case BuiltinType::SatShortAccum:
+ return Target.getShortAccumScale();
+ case BuiltinType::Accum:
+ case BuiltinType::SatAccum:
+ return Target.getAccumScale();
+ case BuiltinType::LongAccum:
+ case BuiltinType::SatLongAccum:
+ return Target.getLongAccumScale();
+ case BuiltinType::UShortAccum:
+ case BuiltinType::SatUShortAccum:
+ return Target.getUnsignedShortAccumScale();
+ case BuiltinType::UAccum:
+ case BuiltinType::SatUAccum:
+ return Target.getUnsignedAccumScale();
+ case BuiltinType::ULongAccum:
+ case BuiltinType::SatULongAccum:
+ return Target.getUnsignedLongAccumScale();
+ case BuiltinType::ShortFract:
+ case BuiltinType::SatShortFract:
+ return Target.getShortFractScale();
+ case BuiltinType::Fract:
+ case BuiltinType::SatFract:
+ return Target.getFractScale();
+ case BuiltinType::LongFract:
+ case BuiltinType::SatLongFract:
+ return Target.getLongFractScale();
+ case BuiltinType::UShortFract:
+ case BuiltinType::SatUShortFract:
+ return Target.getUnsignedShortFractScale();
+ case BuiltinType::UFract:
+ case BuiltinType::SatUFract:
+ return Target.getUnsignedFractScale();
+ case BuiltinType::ULongFract:
+ case BuiltinType::SatULongFract:
+ return Target.getUnsignedLongFractScale();
+ }
+}
+
+unsigned char ASTContext::getFixedPointIBits(QualType Ty) const {
+ assert(Ty->isFixedPointType());
+
+ const auto *BT = Ty->getAs<BuiltinType>();
+ const TargetInfo &Target = getTargetInfo();
+ switch (BT->getKind()) {
+ default:
+ llvm_unreachable("Not a fixed point type!");
+ case BuiltinType::ShortAccum:
+ case BuiltinType::SatShortAccum:
+ return Target.getShortAccumIBits();
+ case BuiltinType::Accum:
+ case BuiltinType::SatAccum:
+ return Target.getAccumIBits();
+ case BuiltinType::LongAccum:
+ case BuiltinType::SatLongAccum:
+ return Target.getLongAccumIBits();
+ case BuiltinType::UShortAccum:
+ case BuiltinType::SatUShortAccum:
+ return Target.getUnsignedShortAccumIBits();
+ case BuiltinType::UAccum:
+ case BuiltinType::SatUAccum:
+ return Target.getUnsignedAccumIBits();
+ case BuiltinType::ULongAccum:
+ case BuiltinType::SatULongAccum:
+ return Target.getUnsignedLongAccumIBits();
+ case BuiltinType::ShortFract:
+ case BuiltinType::SatShortFract:
+ case BuiltinType::Fract:
+ case BuiltinType::SatFract:
+ case BuiltinType::LongFract:
+ case BuiltinType::SatLongFract:
+ case BuiltinType::UShortFract:
+ case BuiltinType::SatUShortFract:
+ case BuiltinType::UFract:
+ case BuiltinType::SatUFract:
+ case BuiltinType::ULongFract:
+ case BuiltinType::SatULongFract:
+ return 0;
+ }
+}
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index cf512b9bd3f..6d9f24020fe 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -525,6 +525,7 @@ namespace {
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,13 @@ void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) {
OS << " " << Node->getValue().toString(10, isSigned);
}
+void ASTDumper::VisitFixedPointLiteral(const FixedPointLiteral *Node) {
+ VisitExpr(Node);
+
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValueAsString(/*Radix=*/10);
+}
+
void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) {
VisitExpr(Node);
ColorScope Color(*this, ValueColor);
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index b2593ef4675..47cf026e28e 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -755,6 +755,36 @@ IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) IntegerLiteral(Empty);
}
+FixedPointLiteral::FixedPointLiteral(const ASTContext &C, const llvm::APInt &V,
+ QualType type, SourceLocation l,
+ unsigned Scale)
+ : Expr(FixedPointLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
+ false, false),
+ Loc(l), Scale(Scale) {
+ assert(type->isFixedPointType() && "Illegal type in FixedPointLiteral");
+ assert(V.getBitWidth() == C.getTypeInfo(type).Width &&
+ "Fixed point type is not the correct size for constant.");
+ setValue(C, V);
+}
+
+FixedPointLiteral *FixedPointLiteral::CreateFromRawInt(const ASTContext &C,
+ const llvm::APInt &V,
+ QualType type,
+ SourceLocation l,
+ unsigned Scale) {
+ return new (C) FixedPointLiteral(C, V, type, l, Scale);
+}
+
+std::string FixedPointLiteral::getValueAsString(unsigned Radix) const {
+ // Currently the longest decimal number that can be printed is the max for an
+ // unsigned long _Accum: 4294967295.99999999976716935634613037109375
+ // which is 43 characters.
+ SmallString<64> S;
+ FixedPointValueToString(
+ S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale, Radix);
+ return S.str();
+}
+
FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L)
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
@@ -2991,6 +3021,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ObjCIvarRefExprClass:
case PredefinedExprClass:
case IntegerLiteralClass:
+ case FixedPointLiteralClass:
case FloatingLiteralClass:
case ImaginaryLiteralClass:
case StringLiteralClass:
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index 297267b521b..c5b3b361a0a 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -161,6 +161,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ShuffleVectorExprClass:
case Expr::ConvertVectorExprClass:
case Expr::IntegerLiteralClass:
+ case Expr::FixedPointLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::AddrLabelExprClass:
case Expr::CXXDeleteExprClass:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 2079f901ed3..c700da635b7 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -7220,6 +7220,73 @@ public:
// 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
@@ -9460,6 +9527,37 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
return Success(E->getValue(), E);
}
+bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+ switch (E->getOpcode()) {
+ default:
+ // Invalid unary operators
+ 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()) {
+ SmallString<64> S;
+ FixedPointValueToString(S, Value,
+ Info.Ctx.getTypeInfo(E->getType()).Width,
+ /*Radix=*/10);
+ Info.CCEDiag(E, diag::note_constexpr_overflow) << S << E->getType();
+ if (Info.noteUndefinedBehavior()) return false;
+ }
+ return Success(-Value, E);
+ }
+ case UO_LNot: {
+ bool bres;
+ if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
+ return false;
+ return Success(!bres, E);
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// Float Evaluation
//===----------------------------------------------------------------------===//
@@ -10311,6 +10409,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
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))
@@ -10759,6 +10859,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
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:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 54ceffa026d..86b9fb5d6ab 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3501,6 +3501,7 @@ recurse:
case Expr::AsTypeExprClass:
case Expr::PseudoObjectExprClass:
case Expr::AtomicExprClass:
+ case Expr::FixedPointLiteralClass:
{
if (!NullOut) {
// As bad as this diagnostic is, it's better than crashing.
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 38ec6632e78..dad57de8940 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1529,6 +1529,28 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
}
}
+void StmtPrinter::VisitFixedPointLiteral(FixedPointLiteral *Node) {
+ if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context))
+ return;
+ OS << Node->getValueAsString(/*Radix=*/10);
+
+ 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;
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 91c7aa9f2fa..791ec569cc4 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1007,6 +1007,12 @@ void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) {
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());
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 5c37c100028..eb65220bc15 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3986,3 +3986,19 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const {
return getClass()->getAsCXXRecordDecl()->getMostRecentNonInjectedDecl();
}
+
+void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
+ const llvm::APSInt &Val, unsigned Scale,
+ unsigned Radix) {
+ llvm::APSInt ScaleVal = llvm::APSInt::getUnsigned(1ULL << Scale);
+ llvm::APSInt IntPart = Val / ScaleVal;
+ llvm::APSInt FractPart = Val % ScaleVal;
+ llvm::APSInt RadixInt = llvm::APSInt::getUnsigned(Radix);
+
+ IntPart.toString(Str, Radix);
+ Str.push_back('.');
+ do {
+ (FractPart * RadixInt / ScaleVal).toString(Str, Radix);
+ FractPart = (FractPart * RadixInt) % ScaleVal;
+ } while (FractPart.getExtValue());
+}
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 8dfcbcc8e26..31bc7a44f81 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -40,12 +40,24 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
LongLongWidth = LongLongAlign = 64;
+
+ // Fixed point default bit widths
ShortAccumWidth = ShortAccumAlign = 16;
AccumWidth = AccumAlign = 32;
LongAccumWidth = LongAccumAlign = 64;
- ShortFractWidth = ShortFractAlign = 16;
- FractWidth = FractAlign = 32;
- LongFractWidth = LongFractAlign = 64;
+ ShortFractWidth = ShortFractAlign = 8;
+ FractWidth = FractAlign = 16;
+ LongFractWidth = LongFractAlign = 32;
+
+ // Fixed point default integral and fractional bit sizes
+ // We give the _Accum 1 fewer fractional bits than their corresponding _Fract
+ // types by default to have the same number of fractional bits between _Accum
+ // and _Fract types.
+ SameFBits = false;
+ ShortAccumScale = 7;
+ AccumScale = 15;
+ LongAccumScale = 31;
+
SuitableAlign = 64;
DefaultAlignForAttributeAligned = 128;
MinGlobalAlign = 0;
@@ -362,6 +374,11 @@ void TargetInfo::adjust(LangOptions &Opts) {
if (Opts.NewAlignOverride)
NewAlign = Opts.NewAlignOverride * getCharWidth();
+
+ // Each unsigned fixed point type has the same number of fractional bits as
+ // its corresponding signed type.
+ SameFBits |= Opts.SameFBits;
+ CheckFixedPointBits();
}
bool TargetInfo::initFeatureMap(
@@ -716,3 +733,63 @@ bool TargetInfo::validateInputConstraint(
return true;
}
+
+void TargetInfo::CheckFixedPointBits() const {
+ // Check that the number of fractional and integral bits (and maybe sign) can
+ // fit into the bits given for a fixed point type.
+ assert(ShortAccumScale + getShortAccumIBits() + 1 <= ShortAccumWidth);
+ assert(AccumScale + getAccumIBits() + 1 <= AccumWidth);
+ assert(LongAccumScale + getLongAccumIBits() + 1 <= LongAccumWidth);
+ assert(getUnsignedShortAccumScale() + getUnsignedShortAccumIBits() <=
+ ShortAccumWidth);
+ assert(getUnsignedAccumScale() + getUnsignedAccumIBits() <= AccumWidth);
+ assert(getUnsignedLongAccumScale() + getUnsignedLongAccumIBits() <=
+ LongAccumWidth);
+
+ assert(getShortFractScale() + 1 <= ShortFractWidth);
+ assert(getFractScale() + 1 <= FractWidth);
+ assert(getLongFractScale() + 1 <= LongFractWidth);
+ assert(getUnsignedShortFractScale() <= ShortFractWidth);
+ assert(getUnsignedFractScale() <= FractWidth);
+ assert(getUnsignedLongFractScale() <= LongFractWidth);
+
+ // Each unsigned fract type has either the same number of fractional bits
+ // as, or one more fractional bit than, its corresponding signed fract type.
+ assert(getShortFractScale() == getUnsignedShortFractScale() ||
+ getShortFractScale() == getUnsignedShortFractScale() - 1);
+ assert(getFractScale() == getUnsignedFractScale() ||
+ getFractScale() == getUnsignedFractScale() - 1);
+ assert(getLongFractScale() == getUnsignedLongFractScale() ||
+ getLongFractScale() == getUnsignedLongFractScale() - 1);
+
+ // When arranged in order of increasing rank (see 6.3.1.3a), the number of
+ // fractional bits is nondecreasing for each of the following sets of
+ // fixed-point types:
+ // - signed fract types
+ // - unsigned fract types
+ // - signed accum types
+ // - unsigned accum types.
+ assert(getLongFractScale() >= getFractScale() &&
+ getFractScale() >= getShortFractScale());
+ assert(getUnsignedLongFractScale() >= getUnsignedFractScale() &&
+ getUnsignedFractScale() >= getUnsignedShortFractScale());
+ assert(LongAccumScale >= AccumScale && AccumScale >= ShortAccumScale);
+ assert(getUnsignedLongAccumScale() >= getUnsignedAccumScale() &&
+ getUnsignedAccumScale() >= getUnsignedShortAccumScale());
+
+ // When arranged in order of increasing rank (see 6.3.1.3a), the number of
+ // integral bits is nondecreasing for each of the following sets of
+ // fixed-point types:
+ // - signed accum types
+ // - unsigned accum types
+ assert(getLongAccumIBits() >= getAccumIBits() &&
+ getAccumIBits() >= getShortAccumIBits());
+ assert(getUnsignedLongAccumIBits() >= getUnsignedAccumIBits() &&
+ getUnsignedAccumIBits() >= getUnsignedShortAccumIBits());
+
+ // Each signed accum type has at least as many integral bits as its
+ // corresponding unsigned accum type.
+ assert(getShortAccumIBits() >= getUnsignedShortAccumIBits());
+ assert(getAccumIBits() >= getUnsignedAccumIBits());
+ assert(getLongAccumIBits() >= getUnsignedLongAccumIBits());
+}
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index 2e4b722b852..1ef2fe3b814 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -652,5 +652,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
if (!Target->validateTarget(Diags))
return nullptr;
+ Target->CheckFixedPointBits();
+
return Target.release();
}
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index d350a86a117..29174047832 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -684,12 +684,12 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E));
else
CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast");
-
+
if (!Dest.isIgnored())
CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination");
break;
}
-
+
case CK_ToUnion: {
// Evaluate even if the destination is ignored.
if (Dest.isIgnored()) {
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 0edd1cbdaff..f4c0c75c256 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -387,6 +387,9 @@ public:
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());
}
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index a5943de9930..bce2083051e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3766,6 +3766,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
/*Default=*/false))
Args.AddLastArg(CmdArgs, options::OPT_ffixed_point);
+ if (Args.hasFlag(options::OPT_fsame_fbits,
+ options::OPT_fno_same_fbits,
+ /*Default=*/false))
+ Args.AddLastArg(CmdArgs, options::OPT_fsame_fbits);
+
// Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi}
// (-ansi is equivalent to -std=c89 or -std=c++98).
//
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 2aa74c38e2b..1f9d6b0d7f5 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2338,6 +2338,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.FixedPoint =
Args.hasFlag(OPT_ffixed_point, OPT_fno_fixed_point, /*Default=*/false) &&
!Opts.CPlusPlus;
+ Opts.SameFBits =
+ Args.hasFlag(OPT_fsame_fbits, OPT_fno_same_fbits,
+ /*Default=*/false) &&
+ Opts.FixedPoint;
// Handle exception personalities
Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions,
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index af64ffef6c0..e414f85e021 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -538,6 +538,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
saw_exponent = false;
saw_period = false;
saw_ud_suffix = false;
+ saw_fixed_point_suffix = false;
isLong = false;
isUnsigned = false;
isLongLong = false;
@@ -547,6 +548,8 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isFloat16 = false;
isFloat128 = false;
MicrosoftInteger = 0;
+ isFract = false;
+ isAccum = false;
hadError = false;
if (*s == '0') { // parse radix
@@ -568,6 +571,14 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
SuffixBegin = s;
checkSeparator(TokLoc, s, CSK_AfterDigits);
+ // Initial scan to lookahead for fixed point suffix.
+ for (const char *c = s; c != ThisTokEnd; ++c) {
+ if (*c == 'r' || *c == 'k' || *c == 'R' || *c == 'K') {
+ saw_fixed_point_suffix = true;
+ break;
+ }
+ }
+
// Parse the suffix. At this point we can classify whether we have an FP or
// integer constant.
bool isFPConstant = isFloatingLiteral();
@@ -576,11 +587,21 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// we break out of the loop.
for (; s != ThisTokEnd; ++s) {
switch (*s) {
+ case 'R':
+ case 'r':
+ if (isFract || isAccum) break;
+ isFract = true;
+ continue;
+ case 'K':
+ case 'k':
+ if (isFract || isAccum) break;
+ isAccum = true;
+ continue;
case 'h': // FP Suffix for "half".
case 'H':
// 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.
+ if (!(PP.getLangOpts().Half || PP.getLangOpts().FixedPoint)) break;
+ if (isIntegerLiteral()) break; // Error for integer constant.
if (isHalf || isFloat || isLong) break; // HH, FH, LH invalid.
isHalf = true;
continue; // Success.
@@ -693,6 +714,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isHalf = false;
isImaginary = false;
MicrosoftInteger = 0;
+ saw_fixed_point_suffix = false;
+ isFract = false;
+ isAccum = false;
}
saw_ud_suffix = true;
@@ -707,6 +731,11 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
hadError = true;
}
}
+
+ if (!hadError && saw_fixed_point_suffix) {
+ assert(isFract || isAccum);
+ assert(radix == 16 || radix == 10);
+ }
}
/// ParseDecimalOrOctalCommon - This method is called for decimal or octal
@@ -1012,6 +1041,126 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
return Result.convertFromString(Str, APFloat::rmNearestTiesToEven);
}
+static inline bool IsExponentPart(char c) {
+ return c == 'p' || c == 'P' || c == 'e' || c == 'E';
+}
+
+bool NumericLiteralParser::GetFixedPointValue(llvm::APInt &StoreVal, unsigned Scale) {
+ assert(radix == 16 || radix == 10);
+
+ // Find how many digits are needed to store the whole literal.
+ unsigned NumDigits = SuffixBegin - DigitsBegin;
+ if (saw_period) --NumDigits;
+
+ // Initial scan of the exponent if it exists
+ bool ExpOverflowOccurred = false;
+ bool NegativeExponent = false;
+ const char *ExponentBegin;
+ uint64_t Exponent = 0;
+ int64_t BaseShift = 0;
+ if (saw_exponent) {
+ const char *Ptr = DigitsBegin;
+
+ while (!IsExponentPart(*Ptr)) ++Ptr;
+ ExponentBegin = Ptr;
+ ++Ptr;
+ NegativeExponent = *Ptr == '-';
+ if (NegativeExponent) ++Ptr;
+
+ unsigned NumExpDigits = SuffixBegin - Ptr;
+ if (alwaysFitsInto64Bits(radix, NumExpDigits)) {
+ llvm::StringRef ExpStr(Ptr, NumExpDigits);
+ llvm::APInt ExpInt(/*numBits=*/64, ExpStr, /*radix=*/10);
+ Exponent = ExpInt.getZExtValue();
+ } else {
+ ExpOverflowOccurred = true;
+ }
+
+ if (NegativeExponent) BaseShift -= Exponent;
+ else BaseShift += Exponent;
+ }
+
+ // Number of bits needed for decimal literal is
+ // ceil(NumDigits * log2(10)) Integral part
+ // + Scale Fractional part
+ // + ceil(Exponent * log2(10)) Exponent
+ // --------------------------------------------------
+ // ceil((NumDigits + Exponent) * log2(10)) + Scale
+ //
+ // But for simplicity in handling integers, we can round up log2(10) to 4,
+ // making:
+ // 4 * (NumDigits + Exponent) + Scale
+ //
+ // Number of digits needed for hexadecimal literal is
+ // 4 * NumDigits Integral part
+ // + Scale Fractional part
+ // + Exponent Exponent
+ // --------------------------------------------------
+ // (4 * NumDigits) + Scale + Exponent
+ uint64_t NumBitsNeeded;
+ if (radix == 10)
+ NumBitsNeeded = 4 * (NumDigits + Exponent) + Scale;
+ else
+ NumBitsNeeded = 4 * NumDigits + Exponent + Scale;
+
+ if (NumBitsNeeded > std::numeric_limits<unsigned>::max())
+ ExpOverflowOccurred = true;
+ llvm::APInt Val(static_cast<unsigned>(NumBitsNeeded), 0, /*isSigned=*/false);
+
+ bool FoundDecimal = false;
+
+ int64_t FractBaseShift = 0;
+ const char *End = saw_exponent ? ExponentBegin : SuffixBegin;
+ for (const char *Ptr = DigitsBegin; Ptr < End; ++Ptr) {
+ if (*Ptr == '.') {
+ FoundDecimal = true;
+ continue;
+ }
+
+ // Normal reading of an integer
+ unsigned C = llvm::hexDigitValue(*Ptr);
+ assert(C < radix && "NumericLiteralParser ctor should have rejected this");
+
+ Val *= radix;
+ Val += C;
+
+ if (FoundDecimal)
+ // Keep track of how much we will need to adjust this value by from the
+ // number of digits past the radix point.
+ --FractBaseShift;
+ }
+
+ // For a radix of 16, we will be multiplying by 2 instead of 16.
+ if (radix == 16) FractBaseShift *= 4;
+ BaseShift += FractBaseShift;
+
+ Val <<= Scale;
+
+ uint64_t Base = (radix == 16) ? 2 : 10;
+ if (BaseShift > 0) {
+ for (int64_t i = 0; i < BaseShift; ++i) {
+ Val *= Base;
+ }
+ } else if (BaseShift < 0) {
+ for (int64_t i = BaseShift; i < 0 && !Val.isNullValue(); ++i)
+ Val = Val.udiv(Base);
+ }
+
+ bool IntOverflowOccurred = false;
+ auto MaxVal = llvm::APInt::getMaxValue(StoreVal.getBitWidth());
+ if (Val.getBitWidth() > StoreVal.getBitWidth()) {
+ IntOverflowOccurred |= Val.ugt(MaxVal.zext(Val.getBitWidth()));
+ StoreVal = Val.trunc(StoreVal.getBitWidth());
+ } else if (Val.getBitWidth() < StoreVal.getBitWidth()) {
+ IntOverflowOccurred |= Val.zext(MaxVal.getBitWidth()).ugt(MaxVal);
+ StoreVal = Val.zext(StoreVal.getBitWidth());
+ } else {
+ StoreVal = Val;
+ }
+
+ return IntOverflowOccurred || ExpOverflowOccurred;
+}
+
/// \verbatim
/// user-defined-character-literal: [C++11 lex.ext]
/// character-literal ud-suffix
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index a81c17bb7fa..8dce6d59c60 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1258,6 +1258,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ImaginaryLiteralClass:
case Expr::ImplicitValueInitExprClass:
case Expr::IntegerLiteralClass:
+ case Expr::FixedPointLiteralClass:
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::ObjCEncodeExprClass:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index aeedd6b1691..88059e94667 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3326,7 +3326,52 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Expr *Res;
- if (Literal.isFloatingLiteral()) {
+ if (Literal.isFixedPointLiteral()) {
+ QualType Ty;
+
+ if (Literal.isAccum) {
+ if (Literal.isHalf) {
+ Ty = Context.ShortAccumTy;
+ } else if (Literal.isLong) {
+ Ty = Context.LongAccumTy;
+ } else {
+ Ty = Context.AccumTy;
+ }
+ } else if (Literal.isFract) {
+ if (Literal.isHalf) {
+ Ty = Context.ShortFractTy;
+ } else if (Literal.isLong) {
+ Ty = Context.LongFractTy;
+ } else {
+ Ty = Context.FractTy;
+ }
+ }
+
+ if (Literal.isUnsigned) Ty = Context.getCorrespondingUnsignedType(Ty);
+
+ 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);
+
+ // Do not use bit_width since some types may have padding like _Fract or
+ // unsigned _Accums if SameFBits is set.
+ auto MaxVal = llvm::APInt::getMaxValue(ibits + scale).zextOrSelf(bit_width);
+ if (Literal.isFract && Val == MaxVal + 1)
+ // 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
+ // the maximal value for the type.
+ --Val;
+ else if (Val.ugt(MaxVal) || Overflowed)
+ Diag(Tok.getLocation(), diag::err_too_large_for_fixed_point);
+
+ Res = FixedPointLiteral::CreateFromRawInt(Context, Val, Ty,
+ Tok.getLocation(), scale);
+ } else if (Literal.isFloatingLiteral()) {
QualType Ty;
if (Literal.isHalf){
if (getOpenCLOptions().isEnabled("cl_khr_fp16"))
@@ -13122,7 +13167,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
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();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index cdf7dc419f8..66c947abb31 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -8888,6 +8888,12 @@ TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) {
return E;
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformFixedPointLiteral(
+ FixedPointLiteral *E) {
+ return E;
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 62d8cd088ee..2b7de79841d 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -533,6 +533,12 @@ void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
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()));
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 665b87961d1..b79e80e122a 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -444,6 +444,13 @@ void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
Code = serialization::EXPR_INTEGER_LITERAL;
}
+void ASTStmtWriter::VisitFixedPointLiteral(FixedPointLiteral *E) {
+ VisitExpr(E);
+ Record.AddSourceLocation(E->getLocation());
+ Record.AddAPInt(E->getValue());
+ Code = serialization::EXPR_INTEGER_LITERAL;
+}
+
void ASTStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) {
VisitExpr(E);
Record.push_back(E->getRawSemantics());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 939b21944d9..8ec78cf8109 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1297,6 +1297,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::AddrLabelExprClass:
case Stmt::AttributedStmtClass:
case Stmt::IntegerLiteralClass:
+ case Stmt::FixedPointLiteralClass:
case Stmt::CharacterLiteralClass:
case Stmt::ImplicitValueInitExprClass:
case Stmt::CXXScalarValueInitExprClass:
diff --git a/clang/test/Frontend/fixed_point.c b/clang/test/Frontend/fixed_point.c
index bc8cf2dcd7b..3a67718fba8 100644
--- a/clang/test/Frontend/fixed_point.c
+++ b/clang/test/Frontend/fixed_point.c
@@ -236,4 +236,164 @@ SatlF_t SatlF_type;
//CHECK-NEXT: |-VarDecl {{.*}} SatlA_type 'SatlA_t':'_Sat long _Accum'
//CHECK-NEXT: |-VarDecl {{.*}} SatsF_type 'SatsF_t':'_Sat short _Fract'
//CHECK-NEXT: |-VarDecl {{.*}} SatF_type 'SatF_t':'_Sat _Fract'
-//CHECK-NEXT: `-VarDecl {{.*}} SatlF_type 'SatlF_t':'_Sat long _Fract'
+//CHECK-NEXT: |-VarDecl {{.*}} SatlF_type 'SatlF_t':'_Sat long _Fract'
+
+// Fixed point literal exponent syntax
+_Accum decexp1 = 1.575e1k;
+_Accum decexp2 = 1.575E1k;
+_Accum decexp3 = 1575e-2k;
+_Accum decexp4 = 1575E-2k;
+
+_Accum hexexp1 = 0x0.3p10k;
+_Accum hexexp2 = 0x0.3P10k;
+_Accum hexexp3 = 0x30000p-10k;
+_Accum hexexp4 = 0x30000P-10k;
+
+_Accum zeroexp1 = 1e0k;
+_Accum zeroexp2 = 1e-0k;
+
+//CHECK-NEXT: |-VarDecl {{.*}} decexp1 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 15.75
+//CHECK-NEXT: |-VarDecl {{.*}} decexp2 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 15.75
+//CHECK-NEXT: |-VarDecl {{.*}} decexp3 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 15.75
+//CHECK-NEXT: |-VarDecl {{.*}} decexp4 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 15.75
+
+//CHECK-NEXT: |-VarDecl {{.*}} hexexp1 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 192.0
+//CHECK-NEXT: |-VarDecl {{.*}} hexexp2 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 192.0
+//CHECK-NEXT: |-VarDecl {{.*}} hexexp3 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 192.0
+//CHECK-NEXT: |-VarDecl {{.*}} hexexp4 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 192.0
+
+//CHECK-NEXT: |-VarDecl {{.*}} zeroexp1 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.0
+//CHECK-NEXT: |-VarDecl {{.*}} zeroexp2 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.0
+
+// Fixed point literal values
+_Accum literal1 = 2.5k; // Precise decimal
+_Accum literal2 = 0.0k; // Zero
+_Accum literal3 = 1.1k; // Imprecise decimal
+_Accum literal4 = 1.11k;
+_Accum literal5 = 1.111k;
+_Accum literal6 = 1.1111k;
+_Accum literal7 = 1.11111k; // After some point after the radix, adding any more
+ // digits to the literal will not result in any
+ // further precision since the nth digit added may
+ // be less than the precision that can be
+ // represented by the fractional bits of the type.
+ // This results in the same value being stored for
+ // the type.
+
+//CHECK-NEXT: |-VarDecl {{.*}} literal1 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 2.5
+//CHECK-NEXT: |-VarDecl {{.*}} literal2 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 0.0
+//CHECK-NEXT: |-VarDecl {{.*}} literal3 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.0999755859375
+//CHECK-NEXT: |-VarDecl {{.*}} literal4 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.1099853515625
+//CHECK-NEXT: |-VarDecl {{.*}} literal5 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.110992431640625
+//CHECK-NEXT: |-VarDecl {{.*}} literal6 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.111083984375
+//CHECK-NEXT: |-VarDecl {{.*}} literal7 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.111083984375
+
+long _Accum longaccumliteral = 0.99999999lk;
+long _Accum longaccumliteral2 = 0.999999999lk;
+long _Accum verylongaccumliteral = 0.99999999999999999999999999lk;
+long _Fract longfractliteral = 0.99999999lr;
+long _Fract longfractliteral2 = 0.999999999lr;
+long _Fract verylongfractliteral = 0.99999999999999999999999999lr;
+
+//CHECK-NEXT: |-VarDecl {{.*}} longaccumliteral 'long _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.999999989755451679229736328125
+//CHECK-NEXT: |-VarDecl {{.*}} longaccumliteral2 'long _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.9999999986030161380767822265625
+//CHECK-NEXT: |-VarDecl {{.*}} verylongaccumliteral 'long _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.9999999995343387126922607421875
+//CHECK-NEXT: |-VarDecl {{.*}} longfractliteral 'long _Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Fract' 0.999999989755451679229736328125
+//CHECK-NEXT: |-VarDecl {{.*}} longfractliteral2 'long _Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Fract' 0.9999999986030161380767822265625
+//CHECK-NEXT: |-VarDecl {{.*}} verylongfractliteral 'long _Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Fract' 0.9999999995343387126922607421875
+
+unsigned _Accum uliteral1 = 2.5uk; // Unsigned
+_Accum literal8 = -2.5k; // Negative
+
+//CHECK-NEXT: |-VarDecl {{.*}} uliteral1 'unsigned _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'unsigned _Accum' 2.5
+//CHECK-NEXT: |-VarDecl {{.*}} literal8 '_Accum' cinit
+//CHECK-NEXT: `-UnaryOperator {{.*}} '_Accum' prefix '-'
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 2.5
+
+short _Accum literalexact1 = 0.9921875hk; // Exact value
+_Accum literalexact2 = 0.999969482421875k;
+
+//CHECK-NEXT: |-VarDecl {{.*}} literalexact1 'short _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Accum' 0.9921875
+//CHECK-NEXT: |-VarDecl {{.*}} literalexact2 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 0.999969482421875
+
+// Unfortunately we do not have enough space to store the exact decimal value of
+// 0.9999999995343387126922607421875 ((1 << 31) - 1), but we can still use a
+// large number of 9s to get the max fractional value.
+long _Accum long_accum_max = 0.999999999999999999999999999lk;
+
+//CHECK-NEXT: |-VarDecl {{.*}} long_accum_max 'long _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.9999999995343387126922607421875
+
+// Epsilon
+short _Accum short_accum_eps = 0.0078125hk;
+short _Accum short_accum_eps2 = 0.0078124hk; // Less than epsilon floors to zero
+_Accum accum_eps = 0.000030517578125k;
+_Accum accum_eps2 = 0.000030517578124k;
+long _Accum long_accum_eps = 0x1p-31lk;
+long _Accum long_accum_eps2 = 0x0.99999999p-31lk;
+
+//CHECK-NEXT: |-VarDecl {{.*}} short_accum_eps 'short _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Accum' 0.0078125
+//CHECK-NEXT: |-VarDecl {{.*}} short_accum_eps2 'short _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Accum' 0.0
+//CHECK-NEXT: |-VarDecl {{.*}} accum_eps '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 0.000030517578125
+//CHECK-NEXT: |-VarDecl {{.*}} accum_eps2 '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 0.0
+//CHECK-NEXT: |-VarDecl {{.*}} long_accum_eps 'long _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.0000000004656612873077392578125
+//CHECK-NEXT: |-VarDecl {{.*}} long_accum_eps2 'long _Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.0
+
+// Fract literals can be one but evaluate to the respective Fract max
+short _Fract short_fract_one = 1.0hr;
+_Fract fract_one = 1.0r;
+long _Fract long_fract_one = 1.0lr;
+unsigned short _Fract u_short_fract_one = 1.0uhr;
+unsigned _Fract u_fract_one = 1.0ur;
+unsigned long _Fract u_long_fract_one = 1.0ulr;
+
+//CHECK-NEXT: |-VarDecl {{.*}} short_fract_one 'short _Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Fract' 0.9921875
+//CHECK-NEXT: |-VarDecl {{.*}} fract_one '_Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Fract' 0.999969482421875
+//CHECK-NEXT: |-VarDecl {{.*}} long_fract_one 'long _Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Fract' 0.9999999995343387126922607421875
+
+//CHECK-NEXT: |-VarDecl {{.*}} u_short_fract_one 'unsigned short _Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'unsigned short _Fract' 0.99609375
+//CHECK-NEXT: |-VarDecl {{.*}} u_fract_one 'unsigned _Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'unsigned _Fract' 0.9999847412109375
+//CHECK-NEXT: |-VarDecl {{.*}} u_long_fract_one 'unsigned long _Fract' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'unsigned long _Fract' 0.99999999976716935634613037109375
+
+_Accum literallast = 1.0k; // One
+
+//CHECK-NEXT: `-VarDecl {{.*}} literallast '_Accum' cinit
+//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.0
diff --git a/clang/test/Frontend/fixed_point_bit_widths.c b/clang/test/Frontend/fixed_point_bit_widths.c
index 8973a336660..ac8db49ed51 100644
--- a/clang/test/Frontend/fixed_point_bit_widths.c
+++ b/clang/test/Frontend/fixed_point_bit_widths.c
@@ -44,12 +44,12 @@ int align_SsF = __alignof(signed short _Fract);
int align_SF = __alignof(signed _Fract);
int align_SlF = __alignof(signed long _Fract);
-// CHECK-NEXT: @size_SsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @size_SF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @size_SlF = {{.*}}global i{{[0-9]+}} 8
-// CHECK-NEXT: @align_SsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @align_SF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @align_SlF = {{.*}}global i{{[0-9]+}} 8
+// CHECK-NEXT: @size_SsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @size_SF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @size_SlF = {{.*}}global i{{[0-9]+}} 4
+// CHECK-NEXT: @align_SsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @align_SF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @align_SlF = {{.*}}global i{{[0-9]+}} 4
/* Primary unsigned _Fract */
@@ -60,12 +60,12 @@ int align_UsF = __alignof(unsigned short _Fract);
int align_UF = __alignof(unsigned _Fract);
int align_UlF = __alignof(unsigned long _Fract);
-// CHECK-NEXT: @size_UsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @size_UF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @size_UlF = {{.*}}global i{{[0-9]+}} 8
-// CHECK-NEXT: @align_UsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @align_UF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @align_UlF = {{.*}}global i{{[0-9]+}} 8
+// CHECK-NEXT: @size_UsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @size_UF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @size_UlF = {{.*}}global i{{[0-9]+}} 4
+// CHECK-NEXT: @align_UsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @align_UF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @align_UlF = {{.*}}global i{{[0-9]+}} 4
/* Aliased _Accum */
@@ -92,12 +92,12 @@ int align_sF = __alignof(short _Fract);
int align_F = __alignof(_Fract);
int align_lF = __alignof(long _Fract);
-// CHECK-NEXT: @size_sF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @size_F = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @size_lF = {{.*}}global i{{[0-9]+}} 8
-// CHECK-NEXT: @align_sF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @align_F = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @align_lF = {{.*}}global i{{[0-9]+}} 8
+// CHECK-NEXT: @size_sF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @size_F = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @size_lF = {{.*}}global i{{[0-9]+}} 4
+// CHECK-NEXT: @align_sF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @align_F = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @align_lF = {{.*}}global i{{[0-9]+}} 4
/* Saturated signed _Accum */
@@ -140,12 +140,12 @@ int align_SatSsF = __alignof(_Sat signed short _Fract);
int align_SatSF = __alignof(_Sat signed _Fract);
int align_SatSlF = __alignof(_Sat signed long _Fract);
-// CHECK-NEXT: @size_SatSsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @size_SatSF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @size_SatSlF = {{.*}}global i{{[0-9]+}} 8
-// CHECK-NEXT: @align_SatSsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @align_SatSF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @align_SatSlF = {{.*}}global i{{[0-9]+}} 8
+// CHECK-NEXT: @size_SatSsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @size_SatSF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @size_SatSlF = {{.*}}global i{{[0-9]+}} 4
+// CHECK-NEXT: @align_SatSsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @align_SatSF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @align_SatSlF = {{.*}}global i{{[0-9]+}} 4
/* Saturated unsigned _Fract */
@@ -156,12 +156,12 @@ int align_SatUsF = __alignof(_Sat unsigned short _Fract);
int align_SatUF = __alignof(_Sat unsigned _Fract);
int align_SatUlF = __alignof(_Sat unsigned long _Fract);
-// CHECK-NEXT: @size_SatUsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @size_SatUF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @size_SatUlF = {{.*}}global i{{[0-9]+}} 8
-// CHECK-NEXT: @align_SatUsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @align_SatUF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @align_SatUlF = {{.*}}global i{{[0-9]+}} 8
+// CHECK-NEXT: @size_SatUsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @size_SatUF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @size_SatUlF = {{.*}}global i{{[0-9]+}} 4
+// CHECK-NEXT: @align_SatUsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @align_SatUF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @align_SatUlF = {{.*}}global i{{[0-9]+}} 4
/* Aliased saturated signed _Accum */
@@ -188,9 +188,9 @@ int align_SatsF = __alignof(_Sat short _Fract);
int align_SatF = __alignof(_Sat _Fract);
int align_SatlF = __alignof(_Sat long _Fract);
-// CHECK-NEXT: @size_SatsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @size_SatF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @size_SatlF = {{.*}}global i{{[0-9]+}} 8
-// CHECK-NEXT: @align_SatsF = {{.*}}global i{{[0-9]+}} 2
-// CHECK-NEXT: @align_SatF = {{.*}}global i{{[0-9]+}} 4
-// CHECK-NEXT: @align_SatlF = {{.*}}global i{{[0-9]+}} 8
+// CHECK-NEXT: @size_SatsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @size_SatF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @size_SatlF = {{.*}}global i{{[0-9]+}} 4
+// CHECK-NEXT: @align_SatsF = {{.*}}global i{{[0-9]+}} 1
+// CHECK-NEXT: @align_SatF = {{.*}}global i{{[0-9]+}} 2
+// CHECK-NEXT: @align_SatlF = {{.*}}global i{{[0-9]+}} 4
diff --git a/clang/test/Frontend/fixed_point_declarations.c b/clang/test/Frontend/fixed_point_declarations.c
new file mode 100644
index 00000000000..47f7e9f8035
--- /dev/null
+++ b/clang/test/Frontend/fixed_point_declarations.c
@@ -0,0 +1,113 @@
+// RUN: %clang -ffixed-point -S -emit-llvm %s -o - | 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
+signed _Accum s_accum; // CHECK-DAG: @s_accum = {{.*}}global i32 0, align 4
+signed long _Accum s_long_accum; // CHECK-DAG: @s_long_accum = {{.*}}global i64 0, align 8
+unsigned short _Accum u_short_accum; // CHECK-DAG: @u_short_accum = {{.*}}global i16 0, align 2
+unsigned _Accum u_accum; // CHECK-DAG: @u_accum = {{.*}}global i32 0, align 4
+unsigned long _Accum u_long_accum; // CHECK-DAG: @u_long_accum = {{.*}}global i64 0, align 8
+signed short _Fract s_short_fract; // CHECK-DAG: @s_short_fract = {{.*}}global i8 0, align 1
+signed _Fract s_fract; // CHECK-DAG: @s_fract = {{.*}}global i16 0, align 2
+signed long _Fract s_long_fract; // CHECK-DAG: @s_long_fract = {{.*}}global i32 0, align 4
+unsigned short _Fract u_short_fract; // CHECK-DAG: @u_short_fract = {{.*}}global i8 0, align 1
+unsigned _Fract u_fract; // CHECK-DAG: @u_fract = {{.*}}global i16 0, align 2
+unsigned long _Fract u_long_fract; // CHECK-DAG: @u_long_fract = {{.*}}global i32 0, align 4
+
+// Aliased
+short _Accum short_accum; // CHECK-DAG: @short_accum = {{.*}}global i16 0, align 2
+_Accum accum; // CHECK-DAG: @accum = {{.*}}global i32 0, align 4
+long _Accum long_accum; // CHECK-DAG: @long_accum = {{.*}}global i64 0, align 8
+short _Fract short_fract; // CHECK-DAG: @short_fract = {{.*}}global i8 0, align 1
+_Fract fract; // CHECK-DAG: @fract = {{.*}}global i16 0, align 2
+long _Fract long_fract; // CHECK-DAG: @long_fract = {{.*}}global i32 0, align 4
+
+// Primary saturated
+_Sat signed short _Accum sat_s_short_accum; // CHECK-DAG: @sat_s_short_accum = {{.*}}global i16 0, align 2
+_Sat signed _Accum sat_s_accum; // CHECK-DAG: @sat_s_accum = {{.*}}global i32 0, align 4
+_Sat signed long _Accum sat_s_long_accum; // CHECK-DAG: @sat_s_long_accum = {{.*}}global i64 0, align 8
+_Sat unsigned short _Accum sat_u_short_accum; // CHECK-DAG: @sat_u_short_accum = {{.*}}global i16 0, align 2
+_Sat unsigned _Accum sat_u_accum; // CHECK-DAG: @sat_u_accum = {{.*}}global i32 0, align 4
+_Sat unsigned long _Accum sat_u_long_accum; // CHECK-DAG: @sat_u_long_accum = {{.*}}global i64 0, align 8
+_Sat signed short _Fract sat_s_short_fract; // CHECK-DAG: @sat_s_short_fract = {{.*}}global i8 0, align 1
+_Sat signed _Fract sat_s_fract; // CHECK-DAG: @sat_s_fract = {{.*}}global i16 0, align 2
+_Sat signed long _Fract sat_s_long_fract; // CHECK-DAG: @sat_s_long_fract = {{.*}}global i32 0, align 4
+_Sat unsigned short _Fract sat_u_short_fract; // CHECK-DAG: @sat_u_short_fract = {{.*}}global i8 0, align 1
+_Sat unsigned _Fract sat_u_fract; // CHECK-DAG: @sat_u_fract = {{.*}}global i16 0, align 2
+_Sat unsigned long _Fract sat_u_long_fract; // CHECK-DAG: @sat_u_long_fract = {{.*}}global i32 0, align 4
+
+// Aliased saturated
+_Sat short _Accum sat_short_accum; // CHECK-DAG: @sat_short_accum = {{.*}}global i16 0, align 2
+_Sat _Accum sat_accum; // CHECK-DAG: @sat_accum = {{.*}}global i32 0, align 4
+_Sat long _Accum sat_long_accum; // CHECK-DAG: @sat_long_accum = {{.*}}global i64 0, align 8
+_Sat short _Fract sat_short_fract; // CHECK-DAG: @sat_short_fract = {{.*}}global i8 0, align 1
+_Sat _Fract sat_fract; // CHECK-DAG: @sat_fract = {{.*}}global i16 0, align 2
+_Sat long _Fract sat_long_fract; // CHECK-DAG: @sat_long_fract = {{.*}}global i32 0, align 4
+
+/* Fixed point literals */
+short _Accum short_accum_literal = 2.5hk; // CHECK-DAG: @short_accum_literal = {{.*}}global i16 320, align 2
+_Accum accum_literal = 2.5k; // CHECK-DAG: @accum_literal = {{.*}}global i32 81920, align 4
+long _Accum long_accum_literal = 2.5lk; // CHECK-DAG: @long_accum_literal = {{.*}}global i64 5368709120, align 8
+short _Fract short_fract_literal = 0.5hr; // CHECK-DAG: @short_fract_literal = {{.*}}global i8 64, align 1
+_Fract fract_literal = 0.5r; // CHECK-DAG: @fract_literal = {{.*}}global i16 16384, align 2
+long _Fract long_fract_literal = 0.5lr; // CHECK-DAG: @long_fract_literal = {{.*}}global i32 1073741824, align 4
+
+unsigned short _Accum u_short_accum_literal = 2.5uhk; // CHECK-DAG: @u_short_accum_literal = {{.*}}global i16 640, align 2
+unsigned _Accum u_accum_literal = 2.5uk; // CHECK-DAG: @u_accum_literal = {{.*}}global i32 163840, align 4
+unsigned long _Accum u_long_accum_literal = 2.5ulk; // CHECK-DAG: @u_long_accum_literal = {{.*}}global i64 10737418240, align 8
+unsigned short _Fract u_short_fract_literal = 0.5uhr; // CHECK-DAG: @u_short_fract_literal = {{.*}}global i8 -128, align 1
+unsigned _Fract u_fract_literal = 0.5ur; // CHECK-DAG: @u_fract_literal = {{.*}}global i16 -32768, align 2
+unsigned long _Fract u_long_fract_literal = 0.5ulr; // CHECK-DAG: @u_long_fract_literal = {{.*}}global i32 -2147483648, align 4
+
+// Max literal values
+short _Accum short_accum_max = 255.9999999999999999hk; // CHECK-DAG: @short_accum_max = {{.*}}global i16 32767, align 2
+_Accum accum_max = 65535.9999999999999999k; // CHECK-DAG: @accum_max = {{.*}}global i32 2147483647, align 4
+long _Accum long_accum_max = 4294967295.9999999999999999lk; // CHECK-DAG: @long_accum_max = {{.*}}global i64 9223372036854775807, align 8
+unsigned short _Accum u_short_accum_max = 255.9999999999999999uhk; // CHECK-DAG: @u_short_accum_max = {{.*}}global i16 -1, align 2
+unsigned _Accum u_accum_max = 65535.9999999999999999uk; // CHECK-DAG: @u_accum_max = {{.*}}global i32 -1, align 4
+unsigned long _Accum u_long_accum_max = 4294967295.9999999999999999ulk; // CHECK-DAG: @u_long_accum_max = {{.*}}global i64 -1, align 8
+
+short _Fract short_fract_max = 0.9999999999999999hr; // CHECK-DAG: @short_fract_max = {{.*}}global i8 127, align 1
+_Fract fract_max = 0.9999999999999999r; // CHECK-DAG: @fract_max = {{.*}}global i16 32767, align 2
+long _Fract long_fract_max = 0.9999999999999999lr; // CHECK-DAG: @long_fract_max = {{.*}}global i32 2147483647, align 4
+unsigned short _Fract u_short_fract_max = 0.9999999999999999uhr; // CHECK-DAG: @u_short_fract_max = {{.*}}global i8 -1, align 1
+unsigned _Fract u_fract_max = 0.9999999999999999ur; // CHECK-DAG: @u_fract_max = {{.*}}global i16 -1, align 2
+unsigned long _Fract u_long_fract_max = 0.9999999999999999ulr; // CHECK-DAG: @u_long_fract_max = {{.*}}global i32 -1, align 4
+
+// Fracts may be exactly one but evaluate to the Fract max
+short _Fract short_fract_one = 1.0hr; // CHECK-DAG: @short_fract_one = {{.*}}global i8 127, align 1
+_Fract fract_one = 1.0r; // CHECK-DAG: @fract_one = {{.*}}global i16 32767, align 2
+long _Fract long_fract_one = 1.0lr; // CHECK-DAG: @long_fract_one = {{.*}}global i32 2147483647, align 4
+unsigned short _Fract u_short_fract_one = 1.0uhr; // CHECK-DAG: @u_short_fract_one = {{.*}}global i8 -1, align 1
+unsigned _Fract u_fract_one = 1.0ur; // CHECK-DAG: @u_fract_one = {{.*}}global i16 -1, align 2
+unsigned long _Fract u_long_fract_one = 1.0ulr; // CHECK-DAG: @u_long_fract_one = {{.*}}global i32 -1, align 4
+
+short _Fract short_fract_exp_one = 0.1e1hr; // CHECK-DAG: @short_fract_exp_one = {{.*}}global i8 127, align 1
+_Fract fract_exp_one = 0.1e1r; // CHECK-DAG: @fract_exp_one = {{.*}}global i16 32767, align 2
+long _Fract long_fract_exp_one = 0.1e1lr; // CHECK-DAG: @long_fract_exp_one = {{.*}}global i32 2147483647, align 4
+unsigned short _Fract u_short_fract_exp_one = 0.1e1uhr; // CHECK-DAG: @u_short_fract_exp_one = {{.*}}global i8 -1, align 1
+unsigned _Fract u_fract_exp_one = 0.1e1ur; // CHECK-DAG: @u_fract_exp_one = {{.*}}global i16 -1, align 2
+unsigned long _Fract u_long_fract_exp_one = 0.1e1ulr; // CHECK-DAG: @u_long_fract_exp_one = {{.*}}global i32 -1, align 4
+
+short _Fract short_fract_hex_exp_one = 0x0.8p1hr; // CHECK-DAG: @short_fract_hex_exp_one = {{.*}}global i8 127, align 1
+_Fract fract_hex_exp_one = 0x0.8p1r; // CHECK-DAG: @fract_hex_exp_one = {{.*}}global i16 32767, align 2
+long _Fract long_fract_hex_exp_one = 0x0.8p1lr; // CHECK-DAG: @long_fract_hex_exp_one = {{.*}}global i32 2147483647, align 4
+unsigned short _Fract u_short_fract_hex_exp_one = 0x0.8p1uhr; // CHECK-DAG: @u_short_fract_hex_exp_one = {{.*}}global i8 -1, align 1
+unsigned _Fract u_fract_hex_exp_one = 0x0.8p1ur; // CHECK-DAG: @u_fract_hex_exp_one = {{.*}}global i16 -1, align 2
+unsigned long _Fract u_long_fract_hex_exp_one = 0x0.8p1ulr; // CHECK-DAG: @u_long_fract_hex_exp_one = {{.*}}global i32 -1, align 4
+
+// Expsilon values
+short _Accum short_accum_eps = 0x1p-7hk; // CHECK-DAG: @short_accum_eps = {{.*}}global i16 1, align 2
+_Accum accum_eps = 0x1p-15k; // CHECK-DAG: @accum_eps = {{.*}}global i32 1, align 4
+long _Accum long_accum_eps = 0x1p-31lk; // CHECK-DAG: @long_accum_eps = {{.*}}global i64 1, align 8
+unsigned short _Accum u_short_accum_eps = 0x1p-8uhk; // CHECK-DAG: @u_short_accum_eps = {{.*}}global i16 1, align 2
+unsigned _Accum u_accum_eps = 0x1p-16uk; // CHECK-DAG: @u_accum_eps = {{.*}}global i32 1, align 4
+unsigned long _Accum u_long_accum_eps = 0x1p-32ulk; // CHECK-DAG: @u_long_accum_eps = {{.*}}global i64 1, align 8
+
+short _Fract short_fract_eps = 0x1p-7hr; // CHECK-DAG: @short_fract_eps = {{.*}}global i8 1, align 1
+_Fract fract_eps = 0x1p-15r; // CHECK-DAG: @fract_eps = {{.*}}global i16 1, align 2
+long _Fract long_fract_eps = 0x1p-31lr; // CHECK-DAG: @long_fract_eps = {{.*}}global i32 1, align 4
+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
diff --git a/clang/test/Frontend/fixed_point_errors.c b/clang/test/Frontend/fixed_point_errors.c
index 7f0e0099576..f55fc82f917 100644
--- a/clang/test/Frontend/fixed_point_errors.c
+++ b/clang/test/Frontend/fixed_point_errors.c
@@ -78,6 +78,50 @@ _Sat char c; // expected-error{{'_Sat' specifier is only valid on '
_Sat int i; // expected-error{{'_Sat' specifier is only valid on '_Fract' or '_Accum', not 'int'}}
_Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}}
+
+/* Literals that cannot fit into types */
+signed short _Accum s_short_accum = 256.0hk; // expected-error{{this value is too large for this fixed point type}}
+unsigned short _Accum u_short_accum = 256.0uhk; // expected-error{{this value is too large for this fixed point type}}
+signed _Accum s_accum = 65536.0k; // expected-error{{this value is too large for this fixed point type}}
+unsigned _Accum u_accum = 65536.0uk; // expected-error{{this value is too large for this fixed point type}}
+signed long _Accum s_long_accum = 4294967296.0lk; // expected-error{{this value is too large for this fixed point type}}
+unsigned long _Accum u_long_accum = 4294967296.0ulk; // expected-error{{this value is too large for this fixed point type}}
+
+// Large values from decimal exponents
+short _Accum short_accum_exp = 2.56e2hk; // expected-error{{this value is too large for this fixed point type}}
+_Accum accum_exp = 6.5536e4k; // expected-error{{this value is too large for this fixed point type}}
+long _Accum long_accum_exp = 4.294967296e9lk; // expected-error{{this value is too large for this fixed point type}}
+unsigned short _Accum u_short_accum_exp = 2.56e2uhk; // expected-error{{this value is too large for this fixed point type}}
+unsigned _Accum u_accum_exp = 6.5536e4uk; // expected-error{{this value is too large for this fixed point type}}
+unsigned long _Accum u_long_accum_exp = 4.294967296e9ulk; // expected-error{{this value is too large for this fixed point type}}
+
+// Large value from hexidecimal exponents
+short _Accum short_accum_hex_exp = 0x1p8hk; // expected-error{{this value is too large for this fixed point type}}
+_Accum accum_hex_exp = 0x1p16k; // expected-error{{this value is too large for this fixed point type}}
+long _Accum long_accum_hex_exp = 0x1p32lk; // expected-error{{this value is too large for this fixed point type}}
+unsigned short _Accum u_short_accum_hex_exp = 0x1p8uhk; // expected-error{{this value is too large for this fixed point type}}
+unsigned _Accum u_accum_hex_exp = 0x1p16uk; // expected-error{{this value is too large for this fixed point type}}
+unsigned long _Accum u_long_accum_hex_exp = 0x1p32ulk; // expected-error{{this value is too large for this fixed point type}}
+
+// Very large exponent
+_Accum x = 1e1000000000000000000000000000000000k; // expected-error{{this value is too large for this fixed point type}}
+
+/* Although _Fract's cannot equal 1, _Fract literals written as 1 are allowed
+ * and the underlying value represents the max value for that _Fract type. */
+short _Fract short_fract_above_1 = 1.1hr; // expected-error{{this value is too large for this fixed point type}}
+_Fract fract_above_1 = 1.1r; // expected-error{{this value is too large for this fixed point type}}
+long _Fract long_fract_above_1 = 1.1lr; // expected-error{{this value is too large for this fixed point type}}
+unsigned short _Fract u_short_fract_above_1 = 1.1uhr; // expected-error{{this value is too large for this fixed point type}}
+unsigned _Fract u_fract_above_1 = 1.1ur; // expected-error{{this value is too large for this fixed point type}}
+unsigned long _Fract u_long_fract_above_1 = 1.1ulr; // expected-error{{this value is too large for this fixed point type}}
+
+short _Fract short_fract_hex_exp = 0x0.fp1hr; // expected-error{{this value is too large for this fixed point type}}
+_Fract fract_hex_exp = 0x0.fp1r; // expected-error{{this value is too large for this fixed point type}}
+long _Fract long_fract_hex_exp = 0x0.fp1lr; // expected-error{{this value is too large for this fixed point type}}
+unsigned short _Fract u_short_fract_hex_exp = 0x0.fp1uhr; // expected-error{{this value is too large for this fixed point type}}
+unsigned _Fract u_fract_hex_exp = 0x0.fp1ur; // expected-error{{this value is too large for this fixed point type}}
+unsigned long _Fract u_long_fract_hex_exp = 0x0.fp1ulr; // expected-error{{this value is too large for this fixed point type}}
+
/* Do not allow typedef to be used with typedef'd types */
typedef short _Fract shortfract_t;
typedef short _Accum shortaccum_t;
@@ -91,3 +135,16 @@ _Sat fract_t td_sat_fract; // expected-error{{'_Sat' specifier
_Sat accum_t td_sat_accum; // expected-error{{'_Sat' specifier is only valid on '_Fract' or '_Accum', not 'type-name'}}
_Sat longfract_t td_sat_long_fract; // expected-error{{'_Sat' specifier is only valid on '_Fract' or '_Accum', not 'type-name'}}
_Sat longaccum_t td_sat_long_accum; // expected-error{{'_Sat' specifier is only valid on '_Fract' or '_Accum', not 'type-name'}}
+
+/* Bad suffixes */
+_Accum fk = 1.0fk; // expected-error{{invalid suffix 'fk' on integer constant}}
+_Accum kk = 1.0kk; // expected-error{{invalid suffix 'kk' on integer constant}}
+_Accum rk = 1.0rk; // expected-error{{invalid suffix 'rk' on integer constant}}
+_Accum rk = 1.0rr; // expected-error{{invalid suffix 'rr' on integer constant}}
+_Accum qk = 1.0qr; // expected-error{{invalid suffix 'qr' on integer constant}}
+
+/* Using wrong exponent notation */
+_Accum dec_with_hex_exp1 = 0.1p10k; // expected-error{{invalid suffix 'p10k' on integer constant}}
+_Accum dec_with_hex_exp2 = 0.1P10k; // expected-error{{invalid suffix 'P10k' on integer constant}}
+_Accum hex_with_dex_exp1 = 0x0.1e10k; // expected-error{{hexadecimal floating constant requires an exponent}}
+_Accum hex_with_dex_exp2 = 0x0.1E10k; // expected-error{{hexadecimal floating constant requires an exponent}}
diff --git a/clang/test/Frontend/fixed_point_same_fbits.c b/clang/test/Frontend/fixed_point_same_fbits.c
new file mode 100644
index 00000000000..ad88d1a73b7
--- /dev/null
+++ b/clang/test/Frontend/fixed_point_same_fbits.c
@@ -0,0 +1,28 @@
+// RUN: %clang -ffixed-point -S -emit-llvm -o - %s | FileCheck %s -check-prefix=DEFAULT
+// RUN: %clang -ffixed-point -fsame-fbits -S -emit-llvm -o - %s | FileCheck %s -check-prefix=SAME
+
+/* The scale for unsigned fixed point types should be the same as that of signed
+ * fixed point types when -fsame-fbits is enabled. */
+
+void func() {
+ unsigned short _Accum u_short_accum = 0.5uhk;
+ unsigned _Accum u_accum = 0.5uk;
+ unsigned long _Accum u_long_accum = 0.5ulk;
+ unsigned short _Fract u_short_fract = 0.5uhr;
+ unsigned _Fract u_fract = 0.5ur;
+ unsigned long _Fract u_long_fract = 0.5ulr;
+
+// DEFAULT: store i16 128, i16* %u_short_accum, align 2
+// DEFAULT: store i32 32768, i32* %u_accum, align 4
+// DEFAULT: store i64 2147483648, i64* %u_long_accum, align 8
+// DEFAULT: store i8 -128, i8* %u_short_fract, align 1
+// DEFAULT: store i16 -32768, i16* %u_fract, align 2
+// DEFAULT: store i32 -2147483648, i32* %u_long_fract, align 4
+
+// SAME: store i16 64, i16* %u_short_accum, align 2
+// SAME: store i32 16384, i32* %u_accum, align 4
+// SAME: store i64 1073741824, i64* %u_long_accum, align 8
+// SAME: store i8 64, i8* %u_short_fract, align 1
+// SAME: store i16 16384, i16* %u_fract, align 2
+// SAME: store i32 1073741824, i32* %u_long_fract, align 4
+}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 1c291d73320..c2aac1f1024 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -5061,6 +5061,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("VariableRef");
case CXCursor_IntegerLiteral:
return cxstring::createRef("IntegerLiteral");
+ case CXCursor_FixedPointLiteral:
+ return cxstring::createRef("FixedPointLiteral");
case CXCursor_FloatingLiteral:
return cxstring::createRef("FloatingLiteral");
case CXCursor_ImaginaryLiteral:
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index bce9351b948..b4ad0595cc5 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -305,6 +305,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
K = CXCursor_IntegerLiteral;
break;
+ case Stmt::FixedPointLiteralClass:
+ K = CXCursor_FixedPointLiteral;
+ break;
+
case Stmt::FloatingLiteralClass:
K = CXCursor_FloatingLiteral;
break;
OpenPOWER on IntegriCloud