diff options
author | Gauthier Harnisch <tyker1@outlook.com> | 2019-06-15 10:24:47 +0000 |
---|---|---|
committer | Gauthier Harnisch <tyker1@outlook.com> | 2019-06-15 10:24:47 +0000 |
commit | ce5b229c3eb42bd896aa1534a29739a3fbec06fe (patch) | |
tree | d4e5190389f986e7b930db76b188509f2cfe438a /lib | |
parent | 68614bff657fc84425b5b6a93fec455ebaea74cb (diff) | |
download | clang-ce5b229c3eb42bd896aa1534a29739a3fbec06fe.tar.gz |
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@363493 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/APValue.cpp | 5 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 3 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 7 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 141 | ||||
-rw-r--r-- | lib/AST/TextNodeDumper.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 2 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 56 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 21 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 55 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 10 |
10 files changed, 268 insertions, 41 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 5d5e67a890..1993bba9bd 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -456,7 +456,8 @@ void APValue::dump(raw_ostream &OS) const { llvm_unreachable("Unknown APValue kind!"); } -void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ +void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, + QualType Ty) const { switch (getKind()) { case APValue::None: Out << "<out of lifetime>"; @@ -675,7 +676,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ llvm_unreachable("Unknown APValue kind!"); } -std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const { +std::string APValue::getAsString(const ASTContext &Ctx, QualType Ty) const { std::string Result; llvm::raw_string_ostream Out(Result); printPretty(Out, Ctx, Ty); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 0657528dc1..b3c9c20d2b 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -827,6 +827,9 @@ ASTContext::~ASTContext() { for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); + + for (APValue *Value : APValueCleanups) + Value->~APValue(); } class ASTContext::ParentMap { diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index b43491d061..d3c79eac90 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -6376,6 +6376,13 @@ ExpectedStmt ASTNodeImporter::VisitConstantExpr(ConstantExpr *E) { Expr *ToSubExpr; std::tie(ToSubExpr) = *Imp; + // TODO : Handle APValue::ValueKind that require importing. + APValue::ValueKind Kind = E->getResultAPValueKind(); + if (Kind == APValue::Int || Kind == APValue::Float || + Kind == APValue::FixedPoint || Kind == APValue::ComplexFloat || + Kind == APValue::ComplexInt) + return ConstantExpr::Create(Importer.getToContext(), ToSubExpr, + E->getAPValueResult()); return ConstantExpr::Create(Importer.getToContext(), ToSubExpr); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 72e1119851..f5714d9378 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -229,6 +229,110 @@ SourceLocation Expr::getExprLoc() const { // Primary Expressions. //===----------------------------------------------------------------------===// +static void AssertResultStorageKind(ConstantExpr::ResultStorageKind Kind) { + assert((Kind == ConstantExpr::RSK_APValue || + Kind == ConstantExpr::RSK_Int64 || Kind == ConstantExpr::RSK_None) && + "Invalid StorageKind Value"); +} + +ConstantExpr::ResultStorageKind +ConstantExpr::getStorageKind(const APValue &Value) { + switch (Value.getKind()) { + case APValue::None: + return ConstantExpr::RSK_None; + case APValue::Int: + if (!Value.getInt().needsCleanup()) + return ConstantExpr::RSK_Int64; + LLVM_FALLTHROUGH; + default: + return ConstantExpr::RSK_APValue; + } +} + +void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) { + ConstantExprBits.ResultKind = StorageKind; + if (StorageKind == RSK_APValue) + ::new (getTrailingObjects<APValue>()) APValue(); +} + +ConstantExpr::ConstantExpr(Expr *subexpr, ResultStorageKind StorageKind) + : FullExpr(ConstantExprClass, subexpr) { + DefaultInit(StorageKind); +} + +ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E, + ResultStorageKind StorageKind) { + assert(!isa<ConstantExpr>(E)); + AssertResultStorageKind(StorageKind); + unsigned Size = totalSizeToAlloc<APValue, uint64_t>( + StorageKind == ConstantExpr::RSK_APValue, + StorageKind == ConstantExpr::RSK_Int64); + void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); + ConstantExpr *Self = new (Mem) ConstantExpr(E, StorageKind); + if (StorageKind == ConstantExpr::RSK_APValue) + Context.AddAPValueCleanup(&Self->APValueResult()); + return Self; +} + +ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E, + const APValue &Result) { + ResultStorageKind StorageKind = getStorageKind(Result); + ConstantExpr *Self = Create(Context, E, StorageKind); + Self->SetResult(Result); + return Self; +} + +ConstantExpr::ConstantExpr(ResultStorageKind StorageKind, EmptyShell Empty) + : FullExpr(ConstantExprClass, Empty) { + DefaultInit(StorageKind); +} + +ConstantExpr *ConstantExpr::CreateEmpty(const ASTContext &Context, + ResultStorageKind StorageKind, + EmptyShell Empty) { + AssertResultStorageKind(StorageKind); + unsigned Size = totalSizeToAlloc<APValue, uint64_t>( + StorageKind == ConstantExpr::RSK_APValue, + StorageKind == ConstantExpr::RSK_Int64); + void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); + ConstantExpr *Self = new (Mem) ConstantExpr(StorageKind, Empty); + if (StorageKind == ConstantExpr::RSK_APValue) + Context.AddAPValueCleanup(&Self->APValueResult()); + return Self; +} + +void ConstantExpr::MoveIntoResult(APValue &Value) { + assert(getStorageKind(Value) == ConstantExprBits.ResultKind && + "Invalid storage for this value kind"); + switch (ConstantExprBits.ResultKind) { + case RSK_None: + return; + case RSK_Int64: + Int64Result() = *Value.getInt().getRawData(); + ConstantExprBits.BitWidth = Value.getInt().getBitWidth(); + ConstantExprBits.IsUnsigned = Value.getInt().isUnsigned(); + return; + case RSK_APValue: + APValueResult() = std::move(Value); + return; + } + llvm_unreachable("Invalid ResultKind Bits"); +} + +APValue ConstantExpr::getAPValueResult() const { + switch (ConstantExprBits.ResultKind) { + case ConstantExpr::RSK_APValue: + return APValueResult(); + case ConstantExpr::RSK_Int64: + return APValue( + llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()), + ConstantExprBits.IsUnsigned)); + case ConstantExpr::RSK_None: + return APValue(); + } + llvm_unreachable("invalid ResultKind"); +} + /// Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. @@ -840,7 +944,7 @@ FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty) : Expr(FloatingLiteralClass, Empty) { - setRawSemantics(IEEEhalf); + setRawSemantics(llvm::APFloatBase::S_IEEEhalf); FloatingLiteralBits.IsExact = false; } @@ -855,41 +959,6 @@ FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) FloatingLiteral(C, Empty); } -const llvm::fltSemantics &FloatingLiteral::getSemantics() const { - switch(FloatingLiteralBits.Semantics) { - case IEEEhalf: - return llvm::APFloat::IEEEhalf(); - case IEEEsingle: - return llvm::APFloat::IEEEsingle(); - case IEEEdouble: - return llvm::APFloat::IEEEdouble(); - case x87DoubleExtended: - return llvm::APFloat::x87DoubleExtended(); - case IEEEquad: - return llvm::APFloat::IEEEquad(); - case PPCDoubleDouble: - return llvm::APFloat::PPCDoubleDouble(); - } - llvm_unreachable("Unrecognised floating semantics"); -} - -void FloatingLiteral::setSemantics(const llvm::fltSemantics &Sem) { - if (&Sem == &llvm::APFloat::IEEEhalf()) - FloatingLiteralBits.Semantics = IEEEhalf; - else if (&Sem == &llvm::APFloat::IEEEsingle()) - FloatingLiteralBits.Semantics = IEEEsingle; - else if (&Sem == &llvm::APFloat::IEEEdouble()) - FloatingLiteralBits.Semantics = IEEEdouble; - else if (&Sem == &llvm::APFloat::x87DoubleExtended()) - FloatingLiteralBits.Semantics = x87DoubleExtended; - else if (&Sem == &llvm::APFloat::IEEEquad()) - FloatingLiteralBits.Semantics = IEEEquad; - else if (&Sem == &llvm::APFloat::PPCDoubleDouble()) - FloatingLiteralBits.Semantics = PPCDoubleDouble; - else - llvm_unreachable("Unknown floating semantics"); -} - /// getValueAsApproximateDouble - This returns the value as an inaccurate /// double. Note that this may cause loss of precision, but is useful for /// debugging dumps, etc. diff --git a/lib/AST/TextNodeDumper.cpp b/lib/AST/TextNodeDumper.cpp index 1998cfaec0..81b3b74f93 100644 --- a/lib/AST/TextNodeDumper.cpp +++ b/lib/AST/TextNodeDumper.cpp @@ -223,6 +223,7 @@ void TextNodeDumper::Visit(const Decl *D) { return; } + Context = &D->getASTContext(); { ColorScope Color(OS, ShowColors, DeclKindNameColor); OS << D->getDeclKindName() << "Decl"; @@ -689,6 +690,14 @@ void TextNodeDumper::VisitCaseStmt(const CaseStmt *Node) { OS << " gnu_range"; } +void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) { + if (Node->getResultAPValueKind() != APValue::None) { + ColorScope Color(OS, ShowColors, ValueColor); + OS << " "; + Node->getAPValueResult().printPretty(OS, *Context, Node->getType()); + } +} + void TextNodeDumper::VisitCallExpr(const CallExpr *Node) { if (Node->usesADL()) OS << " adl"; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 4bc725f4cf..70bb757607 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -5514,7 +5514,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, if (Notes.empty()) { // It's a constant expression. - return ConstantExpr::Create(S.Context, Result.get()); + return ConstantExpr::Create(S.Context, Result.get(), Value); } } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 55e1f132c5..fa4a4b38a0 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -9102,6 +9102,62 @@ ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record, return SourceRange(beg, end); } +static FixedPointSemantics +ReadFixedPointSemantics(const SmallVectorImpl<uint64_t> &Record, + unsigned &Idx) { + unsigned Width = Record[Idx++]; + unsigned Scale = Record[Idx++]; + uint64_t Tmp = Record[Idx++]; + bool IsSigned = Tmp & 0x1; + bool IsSaturated = Tmp & 0x2; + bool HasUnsignedPadding = Tmp & 0x4; + return FixedPointSemantics(Width, Scale, IsSigned, IsSaturated, + HasUnsignedPadding); +} + +APValue ASTReader::ReadAPValue(const RecordData &Record, unsigned &Idx) { + unsigned Kind = Record[Idx++]; + switch (Kind) { + case APValue::None: + return APValue(); + case APValue::Indeterminate: + return APValue::IndeterminateValue(); + case APValue::Int: + return APValue(ReadAPSInt(Record, Idx)); + case APValue::Float: { + const llvm::fltSemantics &FloatSema = llvm::APFloatBase::EnumToSemantics( + static_cast<llvm::APFloatBase::Semantics>(Record[Idx++])); + return APValue(ReadAPFloat(Record, FloatSema, Idx)); + } + case APValue::FixedPoint: { + FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, Idx); + return APValue(APFixedPoint(ReadAPInt(Record, Idx), FPSema)); + } + case APValue::ComplexInt: { + llvm::APSInt First = ReadAPSInt(Record, Idx); + return APValue(std::move(First), ReadAPSInt(Record, Idx)); + } + case APValue::ComplexFloat: { + const llvm::fltSemantics &FloatSema1 = llvm::APFloatBase::EnumToSemantics( + static_cast<llvm::APFloatBase::Semantics>(Record[Idx++])); + llvm::APFloat First = ReadAPFloat(Record, FloatSema1, Idx); + const llvm::fltSemantics &FloatSema2 = llvm::APFloatBase::EnumToSemantics( + static_cast<llvm::APFloatBase::Semantics>(Record[Idx++])); + return APValue(std::move(First), ReadAPFloat(Record, FloatSema2, Idx)); + } + case APValue::LValue: + case APValue::Vector: + case APValue::Array: + case APValue::Struct: + case APValue::Union: + case APValue::MemberPointer: + case APValue::AddrLabelDiff: + // TODO : Handle all these APValue::ValueKind. + return APValue(); + } + llvm_unreachable("Invalid APValue::ValueKind"); +} + /// Read an integral value llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) { unsigned BitWidth = Record[Idx++]; diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 4955343a42..e94a9125b7 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -533,6 +533,18 @@ void ASTStmtReader::VisitExpr(Expr *E) { void ASTStmtReader::VisitConstantExpr(ConstantExpr *E) { VisitExpr(E); + E->ConstantExprBits.ResultKind = Record.readInt(); + switch (E->ConstantExprBits.ResultKind) { + case ConstantExpr::RSK_Int64: { + E->Int64Result() = Record.readInt(); + uint64_t tmp = Record.readInt(); + E->ConstantExprBits.IsUnsigned = tmp & 0x1; + E->ConstantExprBits.BitWidth = tmp >> 1; + break; + } + case ConstantExpr::RSK_APValue: + E->APValueResult() = Record.readAPValue(); + } E->setSubExpr(Record.readSubExpr()); } @@ -590,7 +602,8 @@ void ASTStmtReader::VisitFixedPointLiteral(FixedPointLiteral *E) { void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) { VisitExpr(E); - E->setRawSemantics(static_cast<Stmt::APFloatSemantics>(Record.readInt())); + E->setRawSemantics( + static_cast<llvm::APFloatBase::Semantics>(Record.readInt())); E->setExact(Record.readInt()); E->setValue(Record.getContext(), Record.readAPFloat(E->getSemantics())); E->setLocation(ReadSourceLocation()); @@ -2510,7 +2523,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case EXPR_CONSTANT: - S = new (Context) ConstantExpr(Empty); + S = ConstantExpr::CreateEmpty( + Context, + static_cast<ConstantExpr::ResultStorageKind>( + Record[ASTStmtReader::NumExprFields]), + Empty); break; case EXPR_PREDEFINED: diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index a6950e490f..60187379bf 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -5399,6 +5399,61 @@ void ASTRecordWriter::AddAPFloat(const llvm::APFloat &Value) { AddAPInt(Value.bitcastToAPInt()); } +static void WriteFixedPointSemantics(ASTRecordWriter &Record, + FixedPointSemantics FPSema) { + Record.push_back(FPSema.getWidth()); + Record.push_back(FPSema.getScale()); + Record.push_back(FPSema.isSigned() | FPSema.isSaturated() << 1 | + FPSema.hasUnsignedPadding() << 2); +} + +void ASTRecordWriter::AddAPValue(const APValue &Value) { + APValue::ValueKind Kind = Value.getKind(); + push_back(static_cast<uint64_t>(Kind)); + switch (Kind) { + case APValue::None: + case APValue::Indeterminate: + return; + case APValue::Int: + AddAPSInt(Value.getInt()); + return; + case APValue::Float: + push_back(static_cast<uint64_t>( + llvm::APFloatBase::SemanticsToEnum(Value.getFloat().getSemantics()))); + AddAPFloat(Value.getFloat()); + return; + case APValue::FixedPoint: { + WriteFixedPointSemantics(*this, Value.getFixedPoint().getSemantics()); + AddAPSInt(Value.getFixedPoint().getValue()); + return; + } + case APValue::ComplexInt: { + AddAPSInt(Value.getComplexIntReal()); + AddAPSInt(Value.getComplexIntImag()); + return; + } + case APValue::ComplexFloat: { + push_back(static_cast<uint64_t>(llvm::APFloatBase::SemanticsToEnum( + Value.getComplexFloatReal().getSemantics()))); + AddAPFloat(Value.getComplexFloatReal()); + push_back(static_cast<uint64_t>(llvm::APFloatBase::SemanticsToEnum( + Value.getComplexFloatImag().getSemantics()))); + AddAPFloat(Value.getComplexFloatImag()); + return; + } + case APValue::LValue: + case APValue::Vector: + case APValue::Array: + case APValue::Struct: + case APValue::Union: + case APValue::MemberPointer: + case APValue::AddrLabelDiff: + // TODO : Handle all these APValue::ValueKind. + return; + } + llvm_unreachable("Invalid APValue::ValueKind"); +} + void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record) { Record.push_back(getIdentifierRef(II)); } diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index bd715461cb..20a6b7d74c 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -432,6 +432,16 @@ void ASTStmtWriter::VisitExpr(Expr *E) { void ASTStmtWriter::VisitConstantExpr(ConstantExpr *E) { VisitExpr(E); + Record.push_back(static_cast<uint64_t>(E->ConstantExprBits.ResultKind)); + switch (E->ConstantExprBits.ResultKind) { + case ConstantExpr::RSK_Int64: + Record.push_back(E->Int64Result()); + Record.push_back(E->ConstantExprBits.IsUnsigned | + E->ConstantExprBits.BitWidth << 1); + break; + case ConstantExpr::RSK_APValue: + Record.AddAPValue(E->APValueResult()); + } Record.AddStmt(E->getSubExpr()); Code = serialization::EXPR_CONSTANT; } |