varungandhi-apple created this revision.
varungandhi-apple added a reviewer: rjmccall.
varungandhi-apple requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The implementation for (de)serialization of APValues can be shared
between Clang and Swift, so we prefer pushing the methods up
the inheritance hierarchy, instead of having the methods live in
ASTReader/ASTWriter. Fixes rdar://72592937.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D94196

Files:
  clang/include/clang/AST/APValue.h
  clang/include/clang/AST/AbstractBasicReader.h
  clang/include/clang/AST/AbstractBasicWriter.h
  clang/include/clang/AST/PropertiesBase.td
  clang/include/clang/Serialization/ASTRecordReader.h
  clang/include/clang/Serialization/ASTRecordWriter.h
  clang/include/clang/Serialization/ASTWriter.h
  clang/lib/AST/APValue.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/utils/TableGen/ClangASTPropertiesEmitter.cpp

Index: clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
===================================================================
--- clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
+++ clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
@@ -708,15 +708,13 @@
   // Emit the Basic{Reader,Writer}Base template.
   Out << "template <class Impl>\n"
          "class Basic" << info.ClassSuffix << "Base {\n";
-  if (info.IsReader)
-    Out << "  ASTContext &C;\n";
+  Out << "  ASTContext &C;\n";
   Out << "protected:\n"
-         "  Basic" << info.ClassSuffix << "Base"
-                   << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
-                   << " {}\n"
+         "  Basic"
+      << info.ClassSuffix << "Base" << ("(ASTContext &ctx) : C(ctx)")
+      << " {}\n"
          "public:\n";
-  if (info.IsReader)
-    Out << "  ASTContext &getASTContext() { return C; }\n";
+  Out << "  ASTContext &getASTContext() { return C; }\n";
   Out << "  Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
 
   auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -5121,144 +5121,6 @@
   AddAPInt(Value.bitcastToAPInt());
 }
 
-static void WriteFixedPointSemantics(ASTRecordWriter &Record,
-                                     llvm::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: {
-    assert(llvm::APFloatBase::SemanticsToEnum(
-               Value.getComplexFloatImag().getSemantics()) ==
-           llvm::APFloatBase::SemanticsToEnum(
-               Value.getComplexFloatReal().getSemantics()));
-    push_back(static_cast<uint64_t>(llvm::APFloatBase::SemanticsToEnum(
-        Value.getComplexFloatReal().getSemantics())));
-    AddAPFloat(Value.getComplexFloatReal());
-    AddAPFloat(Value.getComplexFloatImag());
-    return;
-  }
-  case APValue::Vector:
-    push_back(Value.getVectorLength());
-    for (unsigned Idx = 0; Idx < Value.getVectorLength(); Idx++)
-      AddAPValue(Value.getVectorElt(Idx));
-    return;
-  case APValue::Array:
-    push_back(Value.getArrayInitializedElts());
-    push_back(Value.getArraySize());
-    for (unsigned Idx = 0; Idx < Value.getArrayInitializedElts(); Idx++)
-      AddAPValue(Value.getArrayInitializedElt(Idx));
-    if (Value.hasArrayFiller())
-      AddAPValue(Value.getArrayFiller());
-    return;
-  case APValue::Struct:
-    push_back(Value.getStructNumBases());
-    push_back(Value.getStructNumFields());
-    for (unsigned Idx = 0; Idx < Value.getStructNumBases(); Idx++)
-      AddAPValue(Value.getStructBase(Idx));
-    for (unsigned Idx = 0; Idx < Value.getStructNumFields(); Idx++)
-      AddAPValue(Value.getStructField(Idx));
-    return;
-  case APValue::Union:
-    AddDeclRef(Value.getUnionField());
-    AddAPValue(Value.getUnionValue());
-    return;
-  case APValue::AddrLabelDiff:
-    AddStmt(const_cast<AddrLabelExpr *>(Value.getAddrLabelDiffLHS()));
-    AddStmt(const_cast<AddrLabelExpr *>(Value.getAddrLabelDiffRHS()));
-    return;
-  case APValue::MemberPointer: {
-    push_back(Value.isMemberPointerToDerivedMember());
-    AddDeclRef(Value.getMemberPointerDecl());
-    ArrayRef<const CXXRecordDecl *> RecordPath = Value.getMemberPointerPath();
-    push_back(RecordPath.size());
-    for (auto Elem : RecordPath)
-      AddDeclRef(Elem);
-    return;
-  }
-  case APValue::LValue: {
-    push_back(Value.hasLValuePath() | Value.isLValueOnePastTheEnd() << 1 |
-              Value.getLValueBase().is<const Expr *>() << 2 |
-              Value.getLValueBase().is<TypeInfoLValue>() << 3 |
-              Value.isNullPointer() << 4 |
-              static_cast<bool>(Value.getLValueBase()) << 5);
-    QualType ElemTy;
-    if (Value.getLValueBase()) {
-      assert(!Value.getLValueBase().is<DynamicAllocLValue>() &&
-             "in C++20 dynamic allocation are transient so they shouldn't "
-             "appear in the AST");
-      if (!Value.getLValueBase().is<TypeInfoLValue>()) {
-        push_back(Value.getLValueBase().getCallIndex());
-        push_back(Value.getLValueBase().getVersion());
-        if (const auto *E = Value.getLValueBase().dyn_cast<const Expr *>()) {
-          AddStmt(const_cast<Expr *>(E));
-          ElemTy = E->getType();
-        } else {
-          AddDeclRef(Value.getLValueBase().get<const ValueDecl *>());
-          ElemTy = Value.getLValueBase().get<const ValueDecl *>()->getType();
-        }
-      } else {
-        AddTypeRef(
-            QualType(Value.getLValueBase().get<TypeInfoLValue>().getType(), 0));
-        AddTypeRef(Value.getLValueBase().getTypeInfoType());
-        ElemTy = Value.getLValueBase().getTypeInfoType();
-      }
-    }
-    push_back(Value.getLValueOffset().getQuantity());
-    push_back(Value.getLValuePath().size());
-    if (Value.hasLValuePath()) {
-      ArrayRef<APValue::LValuePathEntry> Path = Value.getLValuePath();
-      for (auto Elem : Path) {
-        if (ElemTy->getAs<RecordType>()) {
-          push_back(Elem.getAsBaseOrMember().getInt());
-          const Decl *BaseOrMember = Elem.getAsBaseOrMember().getPointer();
-          if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
-            AddDeclRef(RD);
-            ElemTy = Writer->Context->getRecordType(RD);
-          } else {
-            const auto *VD = cast<ValueDecl>(BaseOrMember);
-            AddDeclRef(VD);
-            ElemTy = VD->getType();
-          }
-        } else {
-          push_back(Elem.getAsArrayIndex());
-          ElemTy = Writer->Context->getAsArrayType(ElemTy)->getElementType();
-        }
-      }
-    }
-  }
-    return;
-  }
-  llvm_unreachable("Invalid APValue::ValueKind");
-}
-
 void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record) {
   Record.push_back(getIdentifierRef(II));
 }
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -8941,165 +8941,6 @@
   return SourceRange(beg, end);
 }
 
-static llvm::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 llvm::FixedPointSemantics(Width, Scale, IsSigned, IsSaturated,
-                                   HasUnsignedPadding);
-}
-
-APValue ASTRecordReader::readAPValue() {
-  auto Kind = static_cast<APValue::ValueKind>(asImpl().readUInt32());
-  switch (Kind) {
-  case APValue::None:
-    return APValue();
-  case APValue::Indeterminate:
-    return APValue::IndeterminateValue();
-  case APValue::Int:
-    return APValue(asImpl().readAPSInt());
-  case APValue::Float: {
-    const llvm::fltSemantics &FloatSema = llvm::APFloatBase::EnumToSemantics(
-        static_cast<llvm::APFloatBase::Semantics>(asImpl().readUInt32()));
-    return APValue(asImpl().readAPFloat(FloatSema));
-  }
-  case APValue::FixedPoint: {
-    llvm::FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, Idx);
-    return APValue(llvm::APFixedPoint(readAPInt(), FPSema));
-  }
-  case APValue::ComplexInt: {
-    llvm::APSInt First = asImpl().readAPSInt();
-    return APValue(std::move(First), asImpl().readAPSInt());
-  }
-  case APValue::ComplexFloat: {
-    const llvm::fltSemantics &FloatSema = llvm::APFloatBase::EnumToSemantics(
-        static_cast<llvm::APFloatBase::Semantics>(asImpl().readUInt32()));
-    llvm::APFloat First = readAPFloat(FloatSema);
-    return APValue(std::move(First), asImpl().readAPFloat(FloatSema));
-  }
-  case APValue::Vector: {
-    APValue Result;
-    Result.MakeVector();
-    unsigned Length = asImpl().readUInt32();
-    (void)Result.setVectorUninit(Length);
-    for (unsigned LoopIdx = 0; LoopIdx < Length; LoopIdx++)
-      Result.getVectorElt(LoopIdx) = asImpl().readAPValue();
-    return Result;
-  }
-  case APValue::Array: {
-    APValue Result;
-    unsigned InitLength = asImpl().readUInt32();
-    unsigned TotalLength = asImpl().readUInt32();
-    Result.MakeArray(InitLength, TotalLength);
-    for (unsigned LoopIdx = 0; LoopIdx < InitLength; LoopIdx++)
-      Result.getArrayInitializedElt(LoopIdx) = asImpl().readAPValue();
-    if (Result.hasArrayFiller())
-      Result.getArrayFiller() = asImpl().readAPValue();
-    return Result;
-  }
-  case APValue::Struct: {
-    APValue Result;
-    unsigned BasesLength = asImpl().readUInt32();
-    unsigned FieldsLength = asImpl().readUInt32();
-    Result.MakeStruct(BasesLength, FieldsLength);
-    for (unsigned LoopIdx = 0; LoopIdx < BasesLength; LoopIdx++)
-      Result.getStructBase(LoopIdx) = asImpl().readAPValue();
-    for (unsigned LoopIdx = 0; LoopIdx < FieldsLength; LoopIdx++)
-      Result.getStructField(LoopIdx) = asImpl().readAPValue();
-    return Result;
-  }
-  case APValue::Union: {
-    auto *FDecl = asImpl().readDeclAs<FieldDecl>();
-    APValue Value = asImpl().readAPValue();
-    return APValue(FDecl, std::move(Value));
-  }
-  case APValue::AddrLabelDiff: {
-    auto *LHS = cast<AddrLabelExpr>(asImpl().readExpr());
-    auto *RHS = cast<AddrLabelExpr>(asImpl().readExpr());
-    return APValue(LHS, RHS);
-  }
-  case APValue::MemberPointer: {
-    APValue Result;
-    bool IsDerived = asImpl().readUInt32();
-    auto *Member = asImpl().readDeclAs<ValueDecl>();
-    unsigned PathSize = asImpl().readUInt32();
-    const CXXRecordDecl **PathArray =
-        Result.setMemberPointerUninit(Member, IsDerived, PathSize).data();
-    for (unsigned LoopIdx = 0; LoopIdx < PathSize; LoopIdx++)
-      PathArray[LoopIdx] =
-          asImpl().readDeclAs<const CXXRecordDecl>()->getCanonicalDecl();
-    return Result;
-  }
-  case APValue::LValue: {
-    uint64_t Bits = asImpl().readUInt32();
-    bool HasLValuePath = Bits & 0x1;
-    bool IsLValueOnePastTheEnd = Bits & 0x2;
-    bool IsExpr = Bits & 0x4;
-    bool IsTypeInfo = Bits & 0x8;
-    bool IsNullPtr = Bits & 0x10;
-    bool HasBase = Bits & 0x20;
-    APValue::LValueBase Base;
-    QualType ElemTy;
-    assert((!IsExpr || !IsTypeInfo) && "LValueBase cannot be both");
-    if (HasBase) {
-      if (!IsTypeInfo) {
-        unsigned CallIndex = asImpl().readUInt32();
-        unsigned Version = asImpl().readUInt32();
-        if (IsExpr) {
-          Base = APValue::LValueBase(asImpl().readExpr(), CallIndex, Version);
-          ElemTy = Base.get<const Expr *>()->getType();
-        } else {
-          Base = APValue::LValueBase(asImpl().readDeclAs<const ValueDecl>(),
-                                     CallIndex, Version);
-          ElemTy = Base.get<const ValueDecl *>()->getType();
-        }
-      } else {
-        QualType TypeInfo = asImpl().readType();
-        QualType Type = asImpl().readType();
-        Base = APValue::LValueBase::getTypeInfo(
-            TypeInfoLValue(TypeInfo.getTypePtr()), Type);
-        Base.getTypeInfoType();
-      }
-    }
-    CharUnits Offset = CharUnits::fromQuantity(asImpl().readUInt32());
-    unsigned PathLength = asImpl().readUInt32();
-    APValue Result;
-    Result.MakeLValue();
-    if (HasLValuePath) {
-      APValue::LValuePathEntry *Path =
-          Result
-              .setLValueUninit(Base, Offset, PathLength, IsLValueOnePastTheEnd,
-                               IsNullPtr)
-              .data();
-      for (unsigned LoopIdx = 0; LoopIdx < PathLength; LoopIdx++) {
-        if (ElemTy->getAs<RecordType>()) {
-          unsigned Int = asImpl().readUInt32();
-          Decl *D = asImpl().readDeclAs<Decl>();
-          if (auto *RD = dyn_cast<CXXRecordDecl>(D))
-            ElemTy = getASTContext().getRecordType(RD);
-          else
-            ElemTy = cast<ValueDecl>(D)->getType();
-          Path[LoopIdx] =
-              APValue::LValuePathEntry(APValue::BaseOrMemberType(D, Int));
-        } else {
-          ElemTy = getASTContext().getAsArrayType(ElemTy)->getElementType();
-          Path[LoopIdx] =
-              APValue::LValuePathEntry::ArrayIndex(asImpl().readUInt32());
-        }
-      }
-    } else
-      Result.setLValue(Base, Offset, APValue::NoLValuePath{}, IsNullPtr);
-    return Result;
-  }
-  }
-  llvm_unreachable("Invalid APValue::ValueKind");
-}
-
 /// Read a floating-point value
 llvm::APFloat ASTRecordReader::readAPFloat(const llvm::fltSemantics &Sem) {
   return llvm::APFloat(Sem, readAPInt());
Index: clang/lib/AST/APValue.cpp
===================================================================
--- clang/lib/AST/APValue.cpp
+++ clang/lib/AST/APValue.cpp
@@ -154,6 +154,14 @@
   ID.AddInteger(Value);
 }
 
+APValue::LValuePathSerializationHelper::LValuePathSerializationHelper(
+    ArrayRef<LValuePathEntry> Path, QualType ElemTy)
+    : ElemTy((const void *)ElemTy.getTypePtrOrNull()), Path(Path) {}
+
+QualType APValue::LValuePathSerializationHelper::getType() {
+  return QualType::getFromOpaquePtr(ElemTy);
+}
+
 namespace {
   struct LVBase {
     APValue::LValueBase Base;
Index: clang/include/clang/Serialization/ASTWriter.h
===================================================================
--- clang/include/clang/Serialization/ASTWriter.h
+++ clang/include/clang/Serialization/ASTWriter.h
@@ -555,6 +555,11 @@
             bool IncludeTimestamps = true);
   ~ASTWriter() override;
 
+  ASTContext &getASTContext() const {
+    assert(Context && "requested AST context when not writing AST");
+    return *Context;
+  }
+
   const LangOptions &getLangOpts() const;
 
   /// Get a timestamp for output into the AST file. The actual timestamp
Index: clang/include/clang/Serialization/ASTRecordWriter.h
===================================================================
--- clang/include/clang/Serialization/ASTRecordWriter.h
+++ clang/include/clang/Serialization/ASTRecordWriter.h
@@ -55,13 +55,14 @@
 
 public:
   /// Construct a ASTRecordWriter that uses the default encoding scheme.
-  ASTRecordWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record)
-      : Writer(&Writer), Record(&Record) {}
+  ASTRecordWriter(ASTWriter &W, ASTWriter::RecordDataImpl &Record)
+      : DataStreamBasicWriter(W.getASTContext()), Writer(&W), Record(&Record) {}
 
   /// Construct a ASTRecordWriter that uses the same encoding scheme as another
   /// ASTRecordWriter.
   ASTRecordWriter(ASTRecordWriter &Parent, ASTWriter::RecordDataImpl &Record)
-      : Writer(Parent.Writer), Record(&Record) {}
+      : DataStreamBasicWriter(Parent.getASTContext()), Writer(Parent.Writer),
+        Record(&Record) {}
 
   /// Copying an ASTRecordWriter is almost certainly a bug.
   ASTRecordWriter(const ASTRecordWriter &) = delete;
@@ -165,7 +166,7 @@
   void AddAPFloat(const llvm::APFloat &Value);
 
   /// Emit an APvalue.
-  void AddAPValue(const APValue &Value);
+  void AddAPValue(const APValue &Value) { writeAPValue(Value); }
 
   /// Emit a reference to an identifier.
   void AddIdentifierRef(const IdentifierInfo *II) {
Index: clang/include/clang/Serialization/ASTRecordReader.h
===================================================================
--- clang/include/clang/Serialization/ASTRecordReader.h
+++ clang/include/clang/Serialization/ASTRecordReader.h
@@ -281,7 +281,7 @@
   }
 
   /// Read an arbitrary constant value, advancing Idx.
-  APValue readAPValue();
+  // APValue readAPValue(); (inherited)
 
   /// Read an integral value, advancing Idx.
   // llvm::APInt readAPInt(); (inherited)
Index: clang/include/clang/AST/PropertiesBase.td
===================================================================
--- clang/include/clang/AST/PropertiesBase.td
+++ clang/include/clang/AST/PropertiesBase.td
@@ -72,6 +72,8 @@
 
 def APInt : PropertyType<"llvm::APInt"> { let PassByReference = 1; }
 def APSInt : PropertyType<"llvm::APSInt"> { let PassByReference = 1; }
+def APValue : PropertyType { let PassByReference = 1; }
+def APValueKind : EnumPropertyType<"APValue::ValueKind">;
 def ArraySizeModifier : EnumPropertyType<"ArrayType::ArraySizeModifier">;
 def AttrKind : EnumPropertyType<"attr::Kind">;
 def AutoTypeKeyword : EnumPropertyType;
@@ -109,7 +111,15 @@
     SubclassPropertyType<"ValueDecl", DeclRef>;
 def ElaboratedTypeKeyword : EnumPropertyType;
 def ExtParameterInfo : PropertyType<"FunctionProtoType::ExtParameterInfo">;
+def FixedPointSemantics : PropertyType<"llvm::FixedPointSemantics"> {
+  let PassByReference = 1;
+}
 def Identifier : RefPropertyType<"IdentifierInfo"> { let ConstWhenWriting = 1; }
+def LValuePathEntry : PropertyType<"APValue::LValuePathEntry">;
+def LValuePathSerializationHelper :
+    PropertyType<"APValue::LValuePathSerializationHelper"> {
+  let BufferElementTypes = [ LValuePathEntry ];
+}
 def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">;
 def NestedNameSpecifierKind :
   EnumPropertyType<"NestedNameSpecifier::SpecifierKind">;
@@ -237,6 +247,304 @@
   string Name = name;
 }
 
+// Type cases for APValue.
+def : PropertyTypeKind<APValue, APValueKind,
+                       "node.getKind()">;
+let Class = PropertyTypeCase<APValue, "None"> in {
+  def : Creator<[{ return APValue(); }]>;
+}
+let Class = PropertyTypeCase<APValue, "Indeterminate"> in {
+  def : Creator<[{ return APValue::IndeterminateValue(); }]>;
+}
+let Class = PropertyTypeCase<APValue, "Int"> in {
+  def : Property<"value", APSInt> {
+    let Read = [{ node.getInt() }];
+  }
+  def : Creator<[{ return APValue(value); }]>;
+}
+let Class = PropertyTypeCase<APValue, "Float"> in {
+  def : Property<"semantics", UInt32> {
+    let Read = [{
+      static_cast<uint32_t>(
+        llvm::APFloatBase::SemanticsToEnum(node.getFloat().getSemantics()))
+    }];
+  }
+  def : Property<"value", APInt> {
+    let Read = [{ node.getFloat().bitcastToAPInt() }];
+  }
+  def : Creator<[{
+    const llvm::fltSemantics &floatSema = llvm::APFloatBase::EnumToSemantics(
+        static_cast<llvm::APFloatBase::Semantics>(semantics));
+    return APValue(llvm::APFloat(floatSema, value));
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "FixedPoint"> in {
+  def : Property<"semantics", FixedPointSemantics> {
+    let Read = [{ node.getFixedPoint().getSemantics() }];
+  }
+  def : Property<"value", APSInt> {
+    let Read = [{ node.getFixedPoint().getValue() }];
+  }
+  def : Creator<[{
+    return APValue(llvm::APFixedPoint(std::move(value), semantics));
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "ComplexInt"> in {
+  def : Property<"real", APSInt> {
+    let Read = [{ node.getComplexIntReal() }];
+  }
+  def : Property<"imag", APSInt> {
+    let Read = [{ node.getComplexIntImag() }];
+  }
+  def : Creator<[{ return APValue(real, imag); }]>;
+}
+let Class = PropertyTypeCase<APValue, "ComplexFloat"> in {
+  def : ReadHelper<[{
+    auto sema = llvm::APFloatBase::SemanticsToEnum(
+        node.getComplexFloatReal().getSemantics());
+    assert(sema == llvm::APFloatBase::SemanticsToEnum(
+        node.getComplexFloatImag().getSemantics()));
+  }]>;
+  def : Property<"semantics", UInt32> {
+    let Read = [{ static_cast<uint32_t>(sema) }];
+  }
+  def : Property<"real", APInt> {
+    let Read = [{ node.getComplexFloatReal().bitcastToAPInt() }];
+  }
+  def : Property<"imag", APInt> {
+    let Read = [{ node.getComplexFloatImag().bitcastToAPInt() }];
+  }
+  def : Creator<[{
+    const llvm::fltSemantics &sema = llvm::APFloatBase::EnumToSemantics(
+        static_cast<llvm::APFloatBase::Semantics>(semantics));
+    return APValue(llvm::APFloat(sema, real),
+                   llvm::APFloat(sema, imag));
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "Vector"> in {
+  def : ReadHelper<[{
+    SmallVector<APValue, 4> buffer;
+    unsigned len = node.getVectorLength();
+    for (unsigned i = 0; i < len; ++i)
+      buffer.push_back(node.getVectorElt(i));
+  }]>;
+  def : Property<"elements", Array<APValue>> {
+    let Read = [{ buffer }];
+  }
+  def : Creator<[{
+    APValue result;
+    result.MakeVector();
+    unsigned length = elements.size();
+    (void)result.setVectorUninit(length);
+    for (unsigned i = 0; i < length; i++)
+      result.getVectorElt(i) = elements[i];
+    return result;
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "Array"> in {
+  def : ReadHelper<[{
+    SmallVector<APValue, 4> buffer{};
+    unsigned initLength = node.getArrayInitializedElts();
+    for (unsigned i = 0; i < initLength; ++i)
+      buffer.push_back(node.getArrayInitializedElt(i));
+    if (node.hasArrayFiller())
+      buffer.push_back(node.getArrayFiller());
+  }]>;
+  def : Property<"totalLength", UInt32> {
+    let Read = [{ node.getArraySize() }];
+  }
+  def : Property<"hasFiller", Bool> {
+    let Read = [{ node.hasArrayFiller() }];
+  }
+  def : Property<"elements", Array<APValue>> {
+    let Read = [{ buffer }];
+  }
+  def : Creator<[{
+    APValue result;
+    unsigned initLength = elements.size() - (hasFiller ? 1 : 0);
+    result.MakeArray(initLength, totalLength);
+    for (unsigned i = 0; i < initLength; ++i)
+      result.getArrayInitializedElt(i) = elements[i];
+    if (hasFiller)
+      result.getArrayFiller() = elements.back();
+    return result;
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "Struct"> in {
+  def : ReadHelper<[{
+    SmallVector<APValue, 4> structBases;
+    unsigned numBases = node.getStructNumBases();
+    for (unsigned i = 0; i < numBases; ++i)
+      structBases.push_back(node.getStructBase(i));
+    SmallVector<APValue, 4> structFields;
+    unsigned numFields = node.getStructNumFields();
+    for (unsigned i = 0; i < numFields; ++i)
+      structFields.push_back(node.getStructField(i));
+  }]>;
+  def : Property<"bases", Array<APValue>> {
+    let Read = [{ structBases }];
+  }
+  def : Property<"fields", Array<APValue>> {
+    let Read = [{ structFields }];
+  }
+  def : Creator<[{
+    APValue result;
+    result.MakeStruct(bases.size(), fields.size());
+    for (unsigned i = 0; i < bases.size(); ++i)
+      result.getStructBase(i) = bases[i];
+    for (unsigned i = 0; i < fields.size(); ++i)
+      result.getStructField(i) = fields[i];
+    return result;
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "Union"> in {
+  def : Property<"fieldDecl", DeclRef> {
+    let Read = [{ node.getUnionField() }];
+  }
+  def : Property<"value", APValue> {
+    let Read = [{ node.getUnionValue() }];
+  }
+  def : Creator<[{
+    return APValue(cast<clang::FieldDecl>(fieldDecl), std::move(value));
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "AddrLabelDiff"> in {
+  def : Property<"lhs", StmtRef> {
+    let Read = [{ const_cast<AddrLabelExpr *>(node.getAddrLabelDiffLHS()) }];
+  }
+  def : Property<"rhs", StmtRef> {
+    let Read = [{ const_cast<AddrLabelExpr *>(node.getAddrLabelDiffRHS()) }];
+  }
+  def : Creator<[{
+    return APValue(cast<AddrLabelExpr>(lhs), cast<AddrLabelExpr>(rhs));
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "MemberPointer"> in {
+  def : Property<"isDerived", Bool> {
+    let Read = [{ node.isMemberPointerToDerivedMember() }];
+  }
+  def : Property<"member", ValueDeclRef> {
+    let Read = [{ node.getMemberPointerDecl() }];
+  }
+  def : Property<"memberPath", Array<CXXRecordDeclRef>> {
+    let Read = [{ node.getMemberPointerPath() }];
+  }
+  def : Creator<[{
+    APValue result;
+    unsigned pathSize = memberPath.size();
+    const CXXRecordDecl **pathArray =
+        result.setMemberPointerUninit(member, isDerived, pathSize).data();
+    for (unsigned i = 0; i < pathSize; ++i)
+      pathArray[i] = memberPath[i]->getCanonicalDecl();
+    return result;
+  }]>;
+}
+let Class = PropertyTypeCase<APValue, "LValue"> in {
+  def : ReadHelper<[{
+    auto lvalueBase = node.getLValueBase();
+    const Expr *expr =
+        lvalueBase ? lvalueBase.dyn_cast<const Expr *>() : nullptr;
+    bool lvalueBaseIsExpr = (bool) expr;
+    bool lvalueBaseIsTypeInfo = lvalueBase.is<TypeInfoLValue>();
+    QualType elemTy;
+    if (lvalueBase) {
+      if (lvalueBaseIsTypeInfo) {
+        elemTy = lvalueBase.getTypeInfoType();
+      } else if (lvalueBaseIsExpr) {
+        elemTy = expr->getType();
+      } else {
+        elemTy = lvalueBase.get<const ValueDecl *>()->getType();
+      }
+    }
+  }]>;
+  def : Property<"hasLValuePath", Bool> {
+    let Read = [{ node.hasLValuePath() }];
+  }
+  def : Property<"isLValueOnePastTheEnd", Bool> {
+    let Read = [{ node.isLValueOnePastTheEnd() }];
+  }
+  def : Property<"isExpr", Bool> {
+    let Read = [{ lvalueBaseIsExpr }];
+  }
+  def : Property<"isTypeInfo", Bool> {
+    let Read = [{ lvalueBaseIsTypeInfo }];
+  }
+  def : Property<"hasBase", Bool> {
+    let Read = [{ static_cast<bool>(lvalueBase) }];
+  }
+  def : Property<"isNullPtr", Bool> {
+    let Read = [{ node.isNullPointer() }];
+  }
+  def : Property<"typeInfo", QualType> {
+    let Conditional = [{ hasBase && isTypeInfo }];
+    let Read = [{
+      QualType(node.getLValueBase().get<TypeInfoLValue>().getType(), 0)
+    }];
+  }
+  def : Property<"type", QualType> {
+    let Conditional = [{ hasBase && isTypeInfo }];
+    let Read = [{ node.getLValueBase().getTypeInfoType() }];
+  }
+  def : Property<"callIndex", UInt32> {
+    let Conditional = [{ hasBase && !isTypeInfo }];
+    let Read = [{ node.getLValueBase().getCallIndex() }];
+  }
+  def : Property<"version", UInt32> {
+    let Conditional = [{ hasBase && !isTypeInfo }];
+    let Read = [{ node.getLValueBase().getVersion() }];
+  }
+  def : Property<"stmt", StmtRef> {
+    let Conditional = [{ hasBase && !isTypeInfo && isExpr }];
+    let Read = [{ const_cast<Expr *>(expr) }];
+  }
+  def : Property<"decl", DeclRef> {
+    let Conditional = [{ hasBase && !isTypeInfo && !isExpr }];
+    let Read = [{ lvalueBase.get<const ValueDecl *>() }];
+  }
+  def : Property<"offsetQuantity", UInt32> {
+    let Read = [{ node.getLValueOffset().getQuantity() }];
+  }
+  def : Property<"lvaluePath", LValuePathSerializationHelper> {
+    let Conditional = [{ hasLValuePath }];
+    let Read = [{
+      APValue::LValuePathSerializationHelper(node.getLValuePath(), elemTy)
+    }];
+  }
+  def : Creator<[{
+    (void)ctx;
+    APValue::LValueBase base;
+    QualType elemTy;
+    if (hasBase) {
+      if (isTypeInfo) {
+        base = APValue::LValueBase::getTypeInfo(
+            TypeInfoLValue(typeInfo.getValue().getTypePtr()), type.getValue());
+        elemTy = base.getTypeInfoType();
+      } else if (isExpr) {
+        base = APValue::LValueBase(cast<Expr>(stmt.getValue()),
+                                   callIndex.getValue(), version.getValue());
+        elemTy = base.get<const Expr *>()->getType();
+      } else {
+        base = APValue::LValueBase(cast<ValueDecl>(decl.getValue()),
+                                   callIndex.getValue(), version.getValue());
+        elemTy = base.get<const ValueDecl *>()->getType();
+      }
+    }
+    CharUnits offset = CharUnits::fromQuantity(offsetQuantity);
+    APValue result;
+    result.MakeLValue();
+    if (!hasLValuePath) {
+      result.setLValue(base, offset, APValue::NoLValuePath{}, isNullPtr);
+      return result;
+    }
+    auto pathLength = lvaluePath->Path.size();
+    APValue::LValuePathEntry *path = result.setLValueUninit(
+        base, offset, pathLength, isLValueOnePastTheEnd, isNullPtr).data();
+    assert(lvaluePath->getType() == elemTy && "Unexpected type reference!");
+    llvm::copy(lvaluePath->Path, path);
+    return result;
+  }]>;
+}
+
 // Type cases for DeclarationName.
 def : PropertyTypeKind<DeclarationName, DeclarationNameKind,
                        "node.getNameKind()">;
Index: clang/include/clang/AST/AbstractBasicWriter.h
===================================================================
--- clang/include/clang/AST/AbstractBasicWriter.h
+++ clang/include/clang/AST/AbstractBasicWriter.h
@@ -121,6 +121,7 @@
 class DataStreamBasicWriter : public BasicWriterBase<Impl> {
 protected:
   using BasicWriterBase<Impl>::asImpl;
+  DataStreamBasicWriter(ASTContext &ctx) : BasicWriterBase<Impl>(ctx) {}
 
 public:
   /// Implement property-find by ignoring it.  We rely on properties being
@@ -163,6 +164,39 @@
       asImpl().writeUInt64(words[i]);
   }
 
+  void writeFixedPointSemantics(const llvm::FixedPointSemantics &sema) {
+    asImpl().writeUInt32(sema.getWidth());
+    asImpl().writeUInt32(sema.getScale());
+    asImpl().writeUInt32(sema.isSigned() | sema.isSaturated() << 1 |
+                         sema.hasUnsignedPadding() << 2);
+  }
+
+  void writeLValuePathSerializationHelper(
+      APValue::LValuePathSerializationHelper lvaluePath) {
+    ArrayRef<APValue::LValuePathEntry> path = lvaluePath.Path;
+    QualType elemTy = lvaluePath.getType();
+    asImpl().writeQualType(elemTy);
+    asImpl().writeUInt32(path.size());
+    auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext();
+    for (auto elem : path) {
+      if (elemTy->getAs<RecordType>()) {
+        asImpl().writeUInt32(elem.getAsBaseOrMember().getInt());
+        const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
+        if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
+          asImpl().writeDeclRef(recordDecl);
+          elemTy = ctx.getRecordType(recordDecl);
+        } else {
+          const auto *valueDecl = cast<ValueDecl>(baseOrMember);
+          asImpl().writeDeclRef(valueDecl);
+          elemTy = valueDecl->getType();
+        }
+      } else {
+        asImpl().writeUInt32(elem.getAsArrayIndex());
+        elemTy = ctx.getAsArrayType(elemTy)->getElementType();
+      }
+    }
+  }
+
   void writeQualifiers(Qualifiers value) {
     static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
                   "update this if the value size changes");
Index: clang/include/clang/AST/AbstractBasicReader.h
===================================================================
--- clang/include/clang/AST/AbstractBasicReader.h
+++ clang/include/clang/AST/AbstractBasicReader.h
@@ -177,6 +177,40 @@
     return llvm::APInt(bitWidth, numWords, &data[0]);
   }
 
+  llvm::FixedPointSemantics readFixedPointSemantics() {
+    unsigned width = asImpl().readUInt32();
+    unsigned scale = asImpl().readUInt32();
+    unsigned tmp = asImpl().readUInt32();
+    bool isSigned = tmp & 0x1;
+    bool isSaturated = tmp & 0x2;
+    bool hasUnsignedPadding = tmp & 0x4;
+    return llvm::FixedPointSemantics(width, scale, isSigned, isSaturated,
+                                     hasUnsignedPadding);
+  }
+
+  APValue::LValuePathSerializationHelper readLValuePathSerializationHelper(
+      SmallVectorImpl<APValue::LValuePathEntry> &path) {
+    auto elemTy = asImpl().readQualType();
+    unsigned pathLength = asImpl().readUInt32();
+    for (unsigned i = 0; i < pathLength; ++i) {
+      if (elemTy->template getAs<RecordType>()) {
+        unsigned int_ = asImpl().readUInt32();
+        Decl *decl = asImpl().template readDeclAs<Decl>();
+        if (auto *recordDecl = dyn_cast<CXXRecordDecl>(decl))
+          elemTy = getASTContext().getRecordType(recordDecl);
+        else
+          elemTy = cast<ValueDecl>(decl)->getType();
+        path.push_back(
+            APValue::LValuePathEntry(APValue::BaseOrMemberType(decl, int_)));
+      } else {
+        elemTy = getASTContext().getAsArrayType(elemTy)->getElementType();
+        path.push_back(
+            APValue::LValuePathEntry::ArrayIndex(asImpl().readUInt32()));
+      }
+    }
+    return APValue::LValuePathSerializationHelper(path, elemTy);
+  }
+
   Qualifiers readQualifiers() {
     static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint32_t),
                   "update this if the value size changes");
Index: clang/include/clang/AST/APValue.h
===================================================================
--- clang/include/clang/AST/APValue.h
+++ clang/include/clang/AST/APValue.h
@@ -23,6 +23,10 @@
 #include "llvm/Support/AlignOf.h"
 
 namespace clang {
+namespace serialization {
+template <typename T> class BasicReaderBase;
+}
+
   class AddrLabelExpr;
   class ASTContext;
   class CharUnits;
@@ -233,12 +237,20 @@
       return llvm::hash_value(A.Value);
     }
   };
+  class LValuePathSerializationHelper {
+    const void *ElemTy;
+
+  public:
+    ArrayRef<LValuePathEntry> Path;
+
+    LValuePathSerializationHelper(ArrayRef<LValuePathEntry>, QualType);
+    QualType getType();
+  };
   struct NoLValuePath {};
   struct UninitArray {};
   struct UninitStruct {};
 
-  friend class ASTRecordReader;
-  friend class ASTWriter;
+  template <typename Impl> friend class clang::serialization::BasicReaderBase;
   friend class ASTImporter;
   friend class ASTNodeImporter;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to