diff options
author | Leonard Chan <leonardchan@google.com> | 2018-06-20 17:19:40 +0000 |
---|---|---|
committer | Leonard Chan <leonardchan@google.com> | 2018-06-20 17:19:40 +0000 |
commit | db01c3adc6f921a27e2bd39847140c401860aa56 (patch) | |
tree | c4c7e6ec5b92b188b7224b963c196fb5fccc9c6d /clang/lib/AST | |
parent | 7e067ab1afec1984e8c9d663a333d145f66c2adf (diff) | |
download | bcm5719-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/AST')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 89 | ||||
-rw-r--r-- | clang/lib/AST/ASTDumper.cpp | 8 | ||||
-rw-r--r-- | clang/lib/AST/Expr.cpp | 31 | ||||
-rw-r--r-- | clang/lib/AST/ExprClassification.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 101 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 22 | ||||
-rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 6 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 16 |
9 files changed, 275 insertions, 0 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()); +} |