summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorLeonard Chan <leonardchan@google.com>2018-06-20 17:19:40 +0000
committerLeonard Chan <leonardchan@google.com>2018-06-20 17:19:40 +0000
commitdb01c3adc6f921a27e2bd39847140c401860aa56 (patch)
treec4c7e6ec5b92b188b7224b963c196fb5fccc9c6d /clang/lib
parent7e067ab1afec1984e8c9d663a333d145f66c2adf (diff)
downloadbcm5719-llvm-db01c3adc6f921a27e2bd39847140c401860aa56.tar.gz
bcm5719-llvm-db01c3adc6f921a27e2bd39847140c401860aa56.zip
[Fixed Point Arithmetic] Fixed Point Precision Bits and Fixed Point Literals
This diff includes the logic for setting the precision bits for each primary fixed point type in the target info and logic for initializing a fixed point literal. 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 illegal literal values ``` unsigned short _Accum u_short_accum = 256.0uhk; // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}} ``` Differential Revision: https://reviews.llvm.org/D46915 llvm-svn: 335148
Diffstat (limited to 'clang/lib')
-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
22 files changed, 590 insertions, 9 deletions
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:
OpenPOWER on IntegriCloud