
This brings our tree to NetBSD 7.0, as found on -current on the 10-10-2015. This updates: - LLVM to 3.6.1 - GCC to GCC 5.1 - Replace minix/commands/zdump with usr.bin/zdump - external/bsd/libelf has moved to /external/bsd/elftoolchain/ - Import ctwm - Drop sprintf from libminc Change-Id: I149836ac18e9326be9353958bab9b266efb056f0
453 lines
15 KiB
C++
453 lines
15 KiB
C++
//===--- APValue.h - Union class for APFloat/APSInt/Complex -----*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the APValue class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_AST_APVALUE_H
|
|
#define LLVM_CLANG_AST_APVALUE_H
|
|
|
|
#include "clang/Basic/LLVM.h"
|
|
#include "llvm/ADT/APFloat.h"
|
|
#include "llvm/ADT/APSInt.h"
|
|
#include "llvm/ADT/PointerIntPair.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
|
|
namespace clang {
|
|
class AddrLabelExpr;
|
|
class ASTContext;
|
|
class CharUnits;
|
|
class DiagnosticBuilder;
|
|
class Expr;
|
|
class FieldDecl;
|
|
class Decl;
|
|
class ValueDecl;
|
|
class CXXRecordDecl;
|
|
class QualType;
|
|
|
|
/// APValue - This class implements a discriminated union of [uninitialized]
|
|
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
|
|
/// [Vector: N * APValue], [Array: N * APValue]
|
|
class APValue {
|
|
typedef llvm::APSInt APSInt;
|
|
typedef llvm::APFloat APFloat;
|
|
public:
|
|
enum ValueKind {
|
|
Uninitialized,
|
|
Int,
|
|
Float,
|
|
ComplexInt,
|
|
ComplexFloat,
|
|
LValue,
|
|
Vector,
|
|
Array,
|
|
Struct,
|
|
Union,
|
|
MemberPointer,
|
|
AddrLabelDiff
|
|
};
|
|
typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase;
|
|
typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType;
|
|
union LValuePathEntry {
|
|
/// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item
|
|
/// in the path. An opaque value of type BaseOrMemberType.
|
|
void *BaseOrMember;
|
|
/// ArrayIndex - The array index of the next item in the path.
|
|
uint64_t ArrayIndex;
|
|
};
|
|
struct NoLValuePath {};
|
|
struct UninitArray {};
|
|
struct UninitStruct {};
|
|
private:
|
|
ValueKind Kind;
|
|
|
|
struct ComplexAPSInt {
|
|
APSInt Real, Imag;
|
|
ComplexAPSInt() : Real(1), Imag(1) {}
|
|
};
|
|
struct ComplexAPFloat {
|
|
APFloat Real, Imag;
|
|
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
|
|
};
|
|
struct LV;
|
|
struct Vec {
|
|
APValue *Elts;
|
|
unsigned NumElts;
|
|
Vec() : Elts(nullptr), NumElts(0) {}
|
|
~Vec() { delete[] Elts; }
|
|
};
|
|
struct Arr {
|
|
APValue *Elts;
|
|
unsigned NumElts, ArrSize;
|
|
Arr(unsigned NumElts, unsigned ArrSize);
|
|
~Arr();
|
|
};
|
|
struct StructData {
|
|
APValue *Elts;
|
|
unsigned NumBases;
|
|
unsigned NumFields;
|
|
StructData(unsigned NumBases, unsigned NumFields);
|
|
~StructData();
|
|
};
|
|
struct UnionData {
|
|
const FieldDecl *Field;
|
|
APValue *Value;
|
|
UnionData();
|
|
~UnionData();
|
|
};
|
|
struct AddrLabelDiffData {
|
|
const AddrLabelExpr* LHSExpr;
|
|
const AddrLabelExpr* RHSExpr;
|
|
};
|
|
struct MemberPointerData;
|
|
|
|
// We ensure elsewhere that Data is big enough for LV and MemberPointerData.
|
|
typedef llvm::AlignedCharArrayUnion<void *, APSInt, APFloat, ComplexAPSInt,
|
|
ComplexAPFloat, Vec, Arr, StructData,
|
|
UnionData, AddrLabelDiffData> DataType;
|
|
static const size_t DataSize = sizeof(DataType);
|
|
|
|
DataType Data;
|
|
|
|
public:
|
|
APValue() : Kind(Uninitialized) {}
|
|
explicit APValue(APSInt I) : Kind(Uninitialized) {
|
|
MakeInt(); setInt(std::move(I));
|
|
}
|
|
explicit APValue(APFloat F) : Kind(Uninitialized) {
|
|
MakeFloat(); setFloat(std::move(F));
|
|
}
|
|
explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) {
|
|
MakeVector(); setVector(E, N);
|
|
}
|
|
APValue(APSInt R, APSInt I) : Kind(Uninitialized) {
|
|
MakeComplexInt(); setComplexInt(std::move(R), std::move(I));
|
|
}
|
|
APValue(APFloat R, APFloat I) : Kind(Uninitialized) {
|
|
MakeComplexFloat(); setComplexFloat(std::move(R), std::move(I));
|
|
}
|
|
APValue(const APValue &RHS);
|
|
APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); }
|
|
APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex)
|
|
: Kind(Uninitialized) {
|
|
MakeLValue(); setLValue(B, O, N, CallIndex);
|
|
}
|
|
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
|
|
bool OnePastTheEnd, unsigned CallIndex)
|
|
: Kind(Uninitialized) {
|
|
MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex);
|
|
}
|
|
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
|
|
MakeArray(InitElts, Size);
|
|
}
|
|
APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) {
|
|
MakeStruct(B, M);
|
|
}
|
|
explicit APValue(const FieldDecl *D, const APValue &V = APValue())
|
|
: Kind(Uninitialized) {
|
|
MakeUnion(); setUnion(D, V);
|
|
}
|
|
APValue(const ValueDecl *Member, bool IsDerivedMember,
|
|
ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) {
|
|
MakeMemberPointer(Member, IsDerivedMember, Path);
|
|
}
|
|
APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr)
|
|
: Kind(Uninitialized) {
|
|
MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr);
|
|
}
|
|
|
|
~APValue() {
|
|
MakeUninit();
|
|
}
|
|
|
|
/// \brief Returns whether the object performed allocations.
|
|
///
|
|
/// If APValues are constructed via placement new, \c needsCleanup()
|
|
/// indicates whether the destructor must be called in order to correctly
|
|
/// free all allocated memory.
|
|
bool needsCleanup() const;
|
|
|
|
/// \brief Swaps the contents of this and the given APValue.
|
|
void swap(APValue &RHS);
|
|
|
|
ValueKind getKind() const { return Kind; }
|
|
bool isUninit() const { return Kind == Uninitialized; }
|
|
bool isInt() const { return Kind == Int; }
|
|
bool isFloat() const { return Kind == Float; }
|
|
bool isComplexInt() const { return Kind == ComplexInt; }
|
|
bool isComplexFloat() const { return Kind == ComplexFloat; }
|
|
bool isLValue() const { return Kind == LValue; }
|
|
bool isVector() const { return Kind == Vector; }
|
|
bool isArray() const { return Kind == Array; }
|
|
bool isStruct() const { return Kind == Struct; }
|
|
bool isUnion() const { return Kind == Union; }
|
|
bool isMemberPointer() const { return Kind == MemberPointer; }
|
|
bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; }
|
|
|
|
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;
|
|
|
|
APSInt &getInt() {
|
|
assert(isInt() && "Invalid accessor");
|
|
return *(APSInt*)(char*)Data.buffer;
|
|
}
|
|
const APSInt &getInt() const {
|
|
return const_cast<APValue*>(this)->getInt();
|
|
}
|
|
|
|
APFloat &getFloat() {
|
|
assert(isFloat() && "Invalid accessor");
|
|
return *(APFloat*)(char*)Data.buffer;
|
|
}
|
|
const APFloat &getFloat() const {
|
|
return const_cast<APValue*>(this)->getFloat();
|
|
}
|
|
|
|
APSInt &getComplexIntReal() {
|
|
assert(isComplexInt() && "Invalid accessor");
|
|
return ((ComplexAPSInt*)(char*)Data.buffer)->Real;
|
|
}
|
|
const APSInt &getComplexIntReal() const {
|
|
return const_cast<APValue*>(this)->getComplexIntReal();
|
|
}
|
|
|
|
APSInt &getComplexIntImag() {
|
|
assert(isComplexInt() && "Invalid accessor");
|
|
return ((ComplexAPSInt*)(char*)Data.buffer)->Imag;
|
|
}
|
|
const APSInt &getComplexIntImag() const {
|
|
return const_cast<APValue*>(this)->getComplexIntImag();
|
|
}
|
|
|
|
APFloat &getComplexFloatReal() {
|
|
assert(isComplexFloat() && "Invalid accessor");
|
|
return ((ComplexAPFloat*)(char*)Data.buffer)->Real;
|
|
}
|
|
const APFloat &getComplexFloatReal() const {
|
|
return const_cast<APValue*>(this)->getComplexFloatReal();
|
|
}
|
|
|
|
APFloat &getComplexFloatImag() {
|
|
assert(isComplexFloat() && "Invalid accessor");
|
|
return ((ComplexAPFloat*)(char*)Data.buffer)->Imag;
|
|
}
|
|
const APFloat &getComplexFloatImag() const {
|
|
return const_cast<APValue*>(this)->getComplexFloatImag();
|
|
}
|
|
|
|
const LValueBase getLValueBase() const;
|
|
CharUnits &getLValueOffset();
|
|
const CharUnits &getLValueOffset() const {
|
|
return const_cast<APValue*>(this)->getLValueOffset();
|
|
}
|
|
bool isLValueOnePastTheEnd() const;
|
|
bool hasLValuePath() const;
|
|
ArrayRef<LValuePathEntry> getLValuePath() const;
|
|
unsigned getLValueCallIndex() const;
|
|
|
|
APValue &getVectorElt(unsigned I) {
|
|
assert(isVector() && "Invalid accessor");
|
|
assert(I < getVectorLength() && "Index out of range");
|
|
return ((Vec*)(char*)Data.buffer)->Elts[I];
|
|
}
|
|
const APValue &getVectorElt(unsigned I) const {
|
|
return const_cast<APValue*>(this)->getVectorElt(I);
|
|
}
|
|
unsigned getVectorLength() const {
|
|
assert(isVector() && "Invalid accessor");
|
|
return ((const Vec*)(const void *)Data.buffer)->NumElts;
|
|
}
|
|
|
|
APValue &getArrayInitializedElt(unsigned I) {
|
|
assert(isArray() && "Invalid accessor");
|
|
assert(I < getArrayInitializedElts() && "Index out of range");
|
|
return ((Arr*)(char*)Data.buffer)->Elts[I];
|
|
}
|
|
const APValue &getArrayInitializedElt(unsigned I) const {
|
|
return const_cast<APValue*>(this)->getArrayInitializedElt(I);
|
|
}
|
|
bool hasArrayFiller() const {
|
|
return getArrayInitializedElts() != getArraySize();
|
|
}
|
|
APValue &getArrayFiller() {
|
|
assert(isArray() && "Invalid accessor");
|
|
assert(hasArrayFiller() && "No array filler");
|
|
return ((Arr*)(char*)Data.buffer)->Elts[getArrayInitializedElts()];
|
|
}
|
|
const APValue &getArrayFiller() const {
|
|
return const_cast<APValue*>(this)->getArrayFiller();
|
|
}
|
|
unsigned getArrayInitializedElts() const {
|
|
assert(isArray() && "Invalid accessor");
|
|
return ((const Arr*)(const void *)Data.buffer)->NumElts;
|
|
}
|
|
unsigned getArraySize() const {
|
|
assert(isArray() && "Invalid accessor");
|
|
return ((const Arr*)(const void *)Data.buffer)->ArrSize;
|
|
}
|
|
|
|
unsigned getStructNumBases() const {
|
|
assert(isStruct() && "Invalid accessor");
|
|
return ((const StructData*)(const char*)Data.buffer)->NumBases;
|
|
}
|
|
unsigned getStructNumFields() const {
|
|
assert(isStruct() && "Invalid accessor");
|
|
return ((const StructData*)(const char*)Data.buffer)->NumFields;
|
|
}
|
|
APValue &getStructBase(unsigned i) {
|
|
assert(isStruct() && "Invalid accessor");
|
|
return ((StructData*)(char*)Data.buffer)->Elts[i];
|
|
}
|
|
APValue &getStructField(unsigned i) {
|
|
assert(isStruct() && "Invalid accessor");
|
|
return ((StructData*)(char*)Data.buffer)->Elts[getStructNumBases() + i];
|
|
}
|
|
const APValue &getStructBase(unsigned i) const {
|
|
return const_cast<APValue*>(this)->getStructBase(i);
|
|
}
|
|
const APValue &getStructField(unsigned i) const {
|
|
return const_cast<APValue*>(this)->getStructField(i);
|
|
}
|
|
|
|
const FieldDecl *getUnionField() const {
|
|
assert(isUnion() && "Invalid accessor");
|
|
return ((const UnionData*)(const char*)Data.buffer)->Field;
|
|
}
|
|
APValue &getUnionValue() {
|
|
assert(isUnion() && "Invalid accessor");
|
|
return *((UnionData*)(char*)Data.buffer)->Value;
|
|
}
|
|
const APValue &getUnionValue() const {
|
|
return const_cast<APValue*>(this)->getUnionValue();
|
|
}
|
|
|
|
const ValueDecl *getMemberPointerDecl() const;
|
|
bool isMemberPointerToDerivedMember() const;
|
|
ArrayRef<const CXXRecordDecl*> getMemberPointerPath() const;
|
|
|
|
const AddrLabelExpr* getAddrLabelDiffLHS() const {
|
|
assert(isAddrLabelDiff() && "Invalid accessor");
|
|
return ((const AddrLabelDiffData*)(const char*)Data.buffer)->LHSExpr;
|
|
}
|
|
const AddrLabelExpr* getAddrLabelDiffRHS() const {
|
|
assert(isAddrLabelDiff() && "Invalid accessor");
|
|
return ((const AddrLabelDiffData*)(const char*)Data.buffer)->RHSExpr;
|
|
}
|
|
|
|
void setInt(APSInt I) {
|
|
assert(isInt() && "Invalid accessor");
|
|
*(APSInt *)(char *)Data.buffer = std::move(I);
|
|
}
|
|
void setFloat(APFloat F) {
|
|
assert(isFloat() && "Invalid accessor");
|
|
*(APFloat *)(char *)Data.buffer = std::move(F);
|
|
}
|
|
void setVector(const APValue *E, unsigned N) {
|
|
assert(isVector() && "Invalid accessor");
|
|
((Vec*)(char*)Data.buffer)->Elts = new APValue[N];
|
|
((Vec*)(char*)Data.buffer)->NumElts = N;
|
|
for (unsigned i = 0; i != N; ++i)
|
|
((Vec*)(char*)Data.buffer)->Elts[i] = E[i];
|
|
}
|
|
void setComplexInt(APSInt R, APSInt I) {
|
|
assert(R.getBitWidth() == I.getBitWidth() &&
|
|
"Invalid complex int (type mismatch).");
|
|
assert(isComplexInt() && "Invalid accessor");
|
|
((ComplexAPSInt *)(char *)Data.buffer)->Real = std::move(R);
|
|
((ComplexAPSInt *)(char *)Data.buffer)->Imag = std::move(I);
|
|
}
|
|
void setComplexFloat(APFloat R, APFloat I) {
|
|
assert(&R.getSemantics() == &I.getSemantics() &&
|
|
"Invalid complex float (type mismatch).");
|
|
assert(isComplexFloat() && "Invalid accessor");
|
|
((ComplexAPFloat *)(char *)Data.buffer)->Real = std::move(R);
|
|
((ComplexAPFloat *)(char *)Data.buffer)->Imag = std::move(I);
|
|
}
|
|
void setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
|
|
unsigned CallIndex);
|
|
void setLValue(LValueBase B, const CharUnits &O,
|
|
ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,
|
|
unsigned CallIndex);
|
|
void setUnion(const FieldDecl *Field, const APValue &Value) {
|
|
assert(isUnion() && "Invalid accessor");
|
|
((UnionData*)(char*)Data.buffer)->Field = Field;
|
|
*((UnionData*)(char*)Data.buffer)->Value = Value;
|
|
}
|
|
void setAddrLabelDiff(const AddrLabelExpr* LHSExpr,
|
|
const AddrLabelExpr* RHSExpr) {
|
|
((AddrLabelDiffData*)(char*)Data.buffer)->LHSExpr = LHSExpr;
|
|
((AddrLabelDiffData*)(char*)Data.buffer)->RHSExpr = RHSExpr;
|
|
}
|
|
|
|
/// Assign by swapping from a copy of the RHS.
|
|
APValue &operator=(APValue RHS) {
|
|
swap(RHS);
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
void DestroyDataAndMakeUninit();
|
|
void MakeUninit() {
|
|
if (Kind != Uninitialized)
|
|
DestroyDataAndMakeUninit();
|
|
}
|
|
void MakeInt() {
|
|
assert(isUninit() && "Bad state change");
|
|
new ((void*)Data.buffer) APSInt(1);
|
|
Kind = Int;
|
|
}
|
|
void MakeFloat() {
|
|
assert(isUninit() && "Bad state change");
|
|
new ((void*)(char*)Data.buffer) APFloat(0.0);
|
|
Kind = Float;
|
|
}
|
|
void MakeVector() {
|
|
assert(isUninit() && "Bad state change");
|
|
new ((void*)(char*)Data.buffer) Vec();
|
|
Kind = Vector;
|
|
}
|
|
void MakeComplexInt() {
|
|
assert(isUninit() && "Bad state change");
|
|
new ((void*)(char*)Data.buffer) ComplexAPSInt();
|
|
Kind = ComplexInt;
|
|
}
|
|
void MakeComplexFloat() {
|
|
assert(isUninit() && "Bad state change");
|
|
new ((void*)(char*)Data.buffer) ComplexAPFloat();
|
|
Kind = ComplexFloat;
|
|
}
|
|
void MakeLValue();
|
|
void MakeArray(unsigned InitElts, unsigned Size);
|
|
void MakeStruct(unsigned B, unsigned M) {
|
|
assert(isUninit() && "Bad state change");
|
|
new ((void*)(char*)Data.buffer) StructData(B, M);
|
|
Kind = Struct;
|
|
}
|
|
void MakeUnion() {
|
|
assert(isUninit() && "Bad state change");
|
|
new ((void*)(char*)Data.buffer) UnionData();
|
|
Kind = Union;
|
|
}
|
|
void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
|
|
ArrayRef<const CXXRecordDecl*> Path);
|
|
void MakeAddrLabelDiff() {
|
|
assert(isUninit() && "Bad state change");
|
|
new ((void*)(char*)Data.buffer) AddrLabelDiffData();
|
|
Kind = AddrLabelDiff;
|
|
}
|
|
};
|
|
|
|
} // end namespace clang.
|
|
|
|
#endif
|