[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
llvm-svn: 363493
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index 5d5e67a..1993bba 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -456,7 +456,8 @@
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 @@
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/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 0657528..b3c9c20 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -827,6 +827,9 @@
for (const auto &Value : ModuleInitializers)
Value.second->~PerModuleInitializers();
+
+ for (APValue *Value : APValueCleanups)
+ Value->~APValue();
}
class ASTContext::ParentMap {
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index b43491d..d3c79ea 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -6376,6 +6376,13 @@
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/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 72e1119..f5714d9 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -229,6 +229,110 @@
// 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, EmptyShell Empty)
: Expr(FloatingLiteralClass, Empty) {
- setRawSemantics(IEEEhalf);
+ setRawSemantics(llvm::APFloatBase::S_IEEEhalf);
FloatingLiteralBits.IsExact = false;
}
@@ -855,41 +959,6 @@
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/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 1998cfa..81b3b74 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -223,6 +223,7 @@
return;
}
+ Context = &D->getASTContext();
{
ColorScope Color(OS, ShowColors, DeclKindNameColor);
OS << D->getDeclKindName() << "Decl";
@@ -689,6 +690,14 @@
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";