[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
This commit is contained in:
parent
b6dc09e725
commit
83c7b61052
|
@ -182,6 +182,10 @@ public:
|
|||
struct NoLValuePath {};
|
||||
struct UninitArray {};
|
||||
struct UninitStruct {};
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTWriter;
|
||||
|
||||
private:
|
||||
ValueKind Kind;
|
||||
|
||||
|
@ -326,8 +330,8 @@ public:
|
|||
void dump() const;
|
||||
void dump(raw_ostream &OS) const;
|
||||
|
||||
void printPretty(raw_ostream &OS, ASTContext &Ctx, QualType Ty) const;
|
||||
std::string getAsString(ASTContext &Ctx, QualType Ty) const;
|
||||
void printPretty(raw_ostream &OS, const ASTContext &Ctx, QualType Ty) const;
|
||||
std::string getAsString(const ASTContext &Ctx, QualType Ty) const;
|
||||
|
||||
APSInt &getInt() {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
|
|
|
@ -271,6 +271,9 @@ private:
|
|||
llvm::DenseMap<const MaterializeTemporaryExpr *, APValue *>
|
||||
MaterializedTemporaryValues;
|
||||
|
||||
/// Used to cleanups APValues stored in the AST.
|
||||
mutable llvm::SmallVector<APValue *, 0> APValueCleanups;
|
||||
|
||||
/// A cache mapping a string value to a StringLiteral object with the same
|
||||
/// value.
|
||||
///
|
||||
|
@ -2816,6 +2819,10 @@ public:
|
|||
APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
|
||||
bool MayCreate);
|
||||
|
||||
/// Adds an APValue that will be destructed during the destruction of the
|
||||
/// ASTContext.
|
||||
void AddAPValueCleanup(APValue *Ptr) const { APValueCleanups.push_back(Ptr); }
|
||||
|
||||
/// Return a string representing the human readable name for the specified
|
||||
/// function declaration or file name. Used by SourceLocExpr and
|
||||
/// PredefinedExpr to cache evaluated results.
|
||||
|
|
|
@ -943,21 +943,61 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// ConstantExpr - An expression that occurs in a constant context.
|
||||
class ConstantExpr : public FullExpr {
|
||||
ConstantExpr(Expr *subexpr)
|
||||
: FullExpr(ConstantExprClass, subexpr) {}
|
||||
/// ConstantExpr - An expression that occurs in a constant context and
|
||||
/// optionally the result of evaluating the expression.
|
||||
class ConstantExpr final
|
||||
: public FullExpr,
|
||||
private llvm::TrailingObjects<ConstantExpr, APValue, uint64_t> {
|
||||
static_assert(std::is_same<uint64_t, llvm::APInt::WordType>::value,
|
||||
"this class assumes llvm::APInt::WordType is uint64_t for "
|
||||
"trail-allocated storage");
|
||||
|
||||
public:
|
||||
static ConstantExpr *Create(const ASTContext &Context, Expr *E) {
|
||||
assert(!isa<ConstantExpr>(E));
|
||||
return new (Context) ConstantExpr(E);
|
||||
/// Describes the kind of result that can be trail-allocated.
|
||||
enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue };
|
||||
|
||||
private:
|
||||
size_t numTrailingObjects(OverloadToken<APValue>) const {
|
||||
return ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue;
|
||||
}
|
||||
size_t numTrailingObjects(OverloadToken<uint64_t>) const {
|
||||
return ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64;
|
||||
}
|
||||
|
||||
/// Build an empty constant expression wrapper.
|
||||
explicit ConstantExpr(EmptyShell Empty)
|
||||
: FullExpr(ConstantExprClass, Empty) {}
|
||||
void DefaultInit(ResultStorageKind StorageKind);
|
||||
uint64_t &Int64Result() {
|
||||
assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64 &&
|
||||
"invalid accessor");
|
||||
return *getTrailingObjects<uint64_t>();
|
||||
}
|
||||
const uint64_t &Int64Result() const {
|
||||
return const_cast<ConstantExpr *>(this)->Int64Result();
|
||||
}
|
||||
APValue &APValueResult() {
|
||||
assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue &&
|
||||
"invalid accessor");
|
||||
return *getTrailingObjects<APValue>();
|
||||
}
|
||||
const APValue &APValueResult() const {
|
||||
return const_cast<ConstantExpr *>(this)->APValueResult();
|
||||
}
|
||||
|
||||
ConstantExpr(Expr *subexpr, ResultStorageKind StorageKind);
|
||||
ConstantExpr(ResultStorageKind StorageKind, EmptyShell Empty);
|
||||
|
||||
public:
|
||||
friend TrailingObjects;
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
static ConstantExpr *Create(const ASTContext &Context, Expr *E,
|
||||
const APValue &Result);
|
||||
static ConstantExpr *Create(const ASTContext &Context, Expr *E,
|
||||
ResultStorageKind Storage = RSK_None);
|
||||
static ConstantExpr *CreateEmpty(const ASTContext &Context,
|
||||
ResultStorageKind StorageKind,
|
||||
EmptyShell Empty);
|
||||
|
||||
static ResultStorageKind getStorageKind(const APValue &Value);
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY {
|
||||
return SubExpr->getBeginLoc();
|
||||
}
|
||||
|
@ -969,6 +1009,25 @@ public:
|
|||
return T->getStmtClass() == ConstantExprClass;
|
||||
}
|
||||
|
||||
void SetResult(APValue Value) { MoveIntoResult(Value); }
|
||||
void MoveIntoResult(APValue &Value);
|
||||
|
||||
APValue::ValueKind getResultAPValueKind() const {
|
||||
switch (ConstantExprBits.ResultKind) {
|
||||
case ConstantExpr::RSK_APValue:
|
||||
return APValueResult().getKind();
|
||||
case ConstantExpr::RSK_Int64:
|
||||
return APValue::Int;
|
||||
case ConstantExpr::RSK_None:
|
||||
return APValue::None;
|
||||
}
|
||||
llvm_unreachable("invalid ResultKind");
|
||||
}
|
||||
ResultStorageKind getResultStorageKind() const {
|
||||
return static_cast<const ResultStorageKind>(ConstantExprBits.ResultKind);
|
||||
}
|
||||
APValue getAPValueResult() const;
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
|
||||
const_child_range children() const {
|
||||
|
@ -1517,21 +1576,28 @@ public:
|
|||
|
||||
/// Get a raw enumeration value representing the floating-point semantics of
|
||||
/// this literal (32-bit IEEE, x87, ...), suitable for serialisation.
|
||||
APFloatSemantics getRawSemantics() const {
|
||||
return static_cast<APFloatSemantics>(FloatingLiteralBits.Semantics);
|
||||
llvm::APFloatBase::Semantics getRawSemantics() const {
|
||||
return static_cast<llvm::APFloatBase::Semantics>(
|
||||
FloatingLiteralBits.Semantics);
|
||||
}
|
||||
|
||||
/// Set the raw enumeration value representing the floating-point semantics of
|
||||
/// this literal (32-bit IEEE, x87, ...), suitable for serialisation.
|
||||
void setRawSemantics(APFloatSemantics Sem) {
|
||||
void setRawSemantics(llvm::APFloatBase::Semantics Sem) {
|
||||
FloatingLiteralBits.Semantics = Sem;
|
||||
}
|
||||
|
||||
/// Return the APFloat semantics this literal uses.
|
||||
const llvm::fltSemantics &getSemantics() const;
|
||||
const llvm::fltSemantics &getSemantics() const {
|
||||
return llvm::APFloatBase::EnumToSemantics(
|
||||
static_cast<llvm::APFloatBase::Semantics>(
|
||||
FloatingLiteralBits.Semantics));
|
||||
}
|
||||
|
||||
/// Set the APFloat semantics this literal uses.
|
||||
void setSemantics(const llvm::fltSemantics &Sem);
|
||||
void setSemantics(const llvm::fltSemantics &Sem) {
|
||||
FloatingLiteralBits.Semantics = llvm::APFloatBase::SemanticsToEnum(Sem);
|
||||
}
|
||||
|
||||
bool isExact() const { return FloatingLiteralBits.IsExact; }
|
||||
void setExact(bool E) { FloatingLiteralBits.IsExact = E; }
|
||||
|
|
|
@ -322,6 +322,26 @@ protected:
|
|||
};
|
||||
enum { NumExprBits = NumStmtBits + 9 };
|
||||
|
||||
class ConstantExprBitfields {
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
friend class ConstantExpr;
|
||||
|
||||
unsigned : NumExprBits;
|
||||
|
||||
/// The kind of result that is trail-allocated.
|
||||
unsigned ResultKind : 2;
|
||||
|
||||
/// When ResultKind == RSK_Int64. whether the trail-allocated integer is
|
||||
/// signed.
|
||||
unsigned IsUnsigned : 1;
|
||||
|
||||
/// When ResultKind == RSK_Int64. the BitWidth of the trail-allocated
|
||||
/// integer. 7 bits because it is the minimal number of bit to represent a
|
||||
/// value from 0 to 64 (the size of the trail-allocated number).
|
||||
unsigned BitWidth : 7;
|
||||
};
|
||||
|
||||
class PredefinedExprBitfields {
|
||||
friend class ASTStmtReader;
|
||||
friend class PredefinedExpr;
|
||||
|
@ -357,14 +377,6 @@ protected:
|
|||
SourceLocation Loc;
|
||||
};
|
||||
|
||||
enum APFloatSemantics {
|
||||
IEEEhalf,
|
||||
IEEEsingle,
|
||||
IEEEdouble,
|
||||
x87DoubleExtended,
|
||||
IEEEquad,
|
||||
PPCDoubleDouble
|
||||
};
|
||||
|
||||
class FloatingLiteralBitfields {
|
||||
friend class FloatingLiteral;
|
||||
|
@ -938,6 +950,7 @@ protected:
|
|||
|
||||
// Expressions
|
||||
ExprBitfields ExprBits;
|
||||
ConstantExprBitfields ConstantExprBits;
|
||||
PredefinedExprBitfields PredefinedExprBits;
|
||||
DeclRefExprBitfields DeclRefExprBits;
|
||||
FloatingLiteralBitfields FloatingLiteralBits;
|
||||
|
|
|
@ -146,6 +146,8 @@ class TextNodeDumper
|
|||
|
||||
const comments::CommandTraits *Traits;
|
||||
|
||||
const ASTContext *Context;
|
||||
|
||||
const char *getCommandName(unsigned CommandID);
|
||||
|
||||
public:
|
||||
|
@ -228,6 +230,7 @@ public:
|
|||
void VisitLabelStmt(const LabelStmt *Node);
|
||||
void VisitGotoStmt(const GotoStmt *Node);
|
||||
void VisitCaseStmt(const CaseStmt *Node);
|
||||
void VisitConstantExpr(const ConstantExpr *Node);
|
||||
void VisitCallExpr(const CallExpr *Node);
|
||||
void VisitCastExpr(const CastExpr *Node);
|
||||
void VisitImplicitCastExpr(const ImplicitCastExpr *Node);
|
||||
|
|
|
@ -2220,6 +2220,9 @@ public:
|
|||
llvm::APFloat ReadAPFloat(const RecordData &Record,
|
||||
const llvm::fltSemantics &Sem, unsigned &Idx);
|
||||
|
||||
/// Read an APValue
|
||||
APValue ReadAPValue(const RecordData &Record, unsigned &Idx);
|
||||
|
||||
// Read a string
|
||||
static std::string ReadString(const RecordData &Record, unsigned &Idx);
|
||||
|
||||
|
@ -2612,6 +2615,8 @@ public:
|
|||
return Reader->ReadSourceRange(*F, Record, Idx);
|
||||
}
|
||||
|
||||
APValue readAPValue() { return Reader->ReadAPValue(Record, Idx); }
|
||||
|
||||
/// Read an integral value, advancing Idx.
|
||||
llvm::APInt readAPInt() {
|
||||
return Reader->ReadAPInt(Record, Idx);
|
||||
|
|
|
@ -863,6 +863,9 @@ public:
|
|||
/// Emit a floating-point value.
|
||||
void AddAPFloat(const llvm::APFloat &Value);
|
||||
|
||||
/// Emit an APvalue.
|
||||
void AddAPValue(const APValue &Value);
|
||||
|
||||
/// Emit a reference to an identifier.
|
||||
void AddIdentifierRef(const IdentifierInfo *II) {
|
||||
return Writer->AddIdentifierRef(II, *Record);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -827,6 +827,9 @@ ASTContext::~ASTContext() {
|
|||
|
||||
for (const auto &Value : ModuleInitializers)
|
||||
Value.second->~PerModuleInitializers();
|
||||
|
||||
for (APValue *Value : APValueCleanups)
|
||||
Value->~APValue();
|
||||
}
|
||||
|
||||
class ASTContext::ParentMap {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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++];
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -49,13 +49,13 @@ struct Invalid {
|
|||
//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:10:11[[RESET]]> [[Green]]'int'[[RESET]][[Cyan:.\[0;36m]][[RESET]][[Cyan]][[RESET]][[CYAN]] 1[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:14[[RESET]], [[Yellow]]line:15:3[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]CaseStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:11:3[[RESET]], [[Yellow]]line:12:27[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[MAGENTA]]ConstantExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:11:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[MAGENTA]]ConstantExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:11:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 1[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | | | `-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 1[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[MAGENTA]]AttributedStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:12:5[[RESET]], [[Yellow]]col:27[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[BLUE]]FallThroughAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:7[[RESET]], [[Yellow]]col:14[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[MAGENTA]]NullStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:27[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CaseStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:13:3[[RESET]], [[Yellow]]line:14:5[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]ConstantExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:13:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]ConstantExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:13:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 2[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 2[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]NullStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:14:5[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:8:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}}
|
||||
|
|
|
@ -147,6 +147,17 @@ struct APFloatBase {
|
|||
|
||||
/// \name Floating Point Semantics.
|
||||
/// @{
|
||||
enum Semantics {
|
||||
S_IEEEhalf,
|
||||
S_IEEEsingle,
|
||||
S_IEEEdouble,
|
||||
S_x87DoubleExtended,
|
||||
S_IEEEquad,
|
||||
S_PPCDoubleDouble
|
||||
};
|
||||
|
||||
static const llvm::fltSemantics &EnumToSemantics(Semantics S);
|
||||
static Semantics SemanticsToEnum(const llvm::fltSemantics &Sem);
|
||||
|
||||
static const fltSemantics &IEEEhalf() LLVM_READNONE;
|
||||
static const fltSemantics &IEEEsingle() LLVM_READNONE;
|
||||
|
|
|
@ -113,6 +113,42 @@ namespace llvm {
|
|||
static const fltSemantics semPPCDoubleDoubleLegacy = {1023, -1022 + 53,
|
||||
53 + 53, 128};
|
||||
|
||||
const llvm::fltSemantics &APFloatBase::EnumToSemantics(Semantics S) {
|
||||
switch (S) {
|
||||
case S_IEEEhalf:
|
||||
return IEEEhalf();
|
||||
case S_IEEEsingle:
|
||||
return IEEEsingle();
|
||||
case S_IEEEdouble:
|
||||
return IEEEdouble();
|
||||
case S_x87DoubleExtended:
|
||||
return x87DoubleExtended();
|
||||
case S_IEEEquad:
|
||||
return IEEEquad();
|
||||
case S_PPCDoubleDouble:
|
||||
return PPCDoubleDouble();
|
||||
}
|
||||
llvm_unreachable("Unrecognised floating semantics");
|
||||
}
|
||||
|
||||
APFloatBase::Semantics
|
||||
APFloatBase::SemanticsToEnum(const llvm::fltSemantics &Sem) {
|
||||
if (&Sem == &llvm::APFloat::IEEEhalf())
|
||||
return S_IEEEhalf;
|
||||
else if (&Sem == &llvm::APFloat::IEEEsingle())
|
||||
return S_IEEEsingle;
|
||||
else if (&Sem == &llvm::APFloat::IEEEdouble())
|
||||
return S_IEEEdouble;
|
||||
else if (&Sem == &llvm::APFloat::x87DoubleExtended())
|
||||
return S_x87DoubleExtended;
|
||||
else if (&Sem == &llvm::APFloat::IEEEquad())
|
||||
return S_IEEEquad;
|
||||
else if (&Sem == &llvm::APFloat::PPCDoubleDouble())
|
||||
return S_PPCDoubleDouble;
|
||||
else
|
||||
llvm_unreachable("Unknown floating semantics");
|
||||
}
|
||||
|
||||
const fltSemantics &APFloatBase::IEEEhalf() {
|
||||
return semIEEEhalf;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue