[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:
Gauthier Harnisch 2019-06-15 10:24:47 +00:00
parent b6dc09e725
commit 83c7b61052
20 changed files with 443 additions and 68 deletions

View File

@ -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");

View File

@ -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.

View File

@ -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; }

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -827,6 +827,9 @@ ASTContext::~ASTContext() {
for (const auto &Value : ModuleInitializers)
Value.second->~PerModuleInitializers();
for (APValue *Value : APValueCleanups)
Value->~APValue();
}
class ASTContext::ParentMap {

View File

@ -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);
}

View File

@ -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.

View File

@ -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";

View File

@ -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);
}
}

View File

@ -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++];

View File

@ -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:

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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]]>{{$}}

View File

@ -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;

View File

@ -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;
}