Home | History | Annotate | Line # | Download | only in Interp
      1  1.1  joerg //===--- Descriptor.h - Types for the constexpr VM --------------*- C++ -*-===//
      2  1.1  joerg //
      3  1.1  joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  1.1  joerg // See https://llvm.org/LICENSE.txt for license information.
      5  1.1  joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  1.1  joerg //
      7  1.1  joerg //===----------------------------------------------------------------------===//
      8  1.1  joerg //
      9  1.1  joerg // Defines descriptors which characterise allocations.
     10  1.1  joerg //
     11  1.1  joerg //===----------------------------------------------------------------------===//
     12  1.1  joerg 
     13  1.1  joerg #ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
     14  1.1  joerg #define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
     15  1.1  joerg 
     16  1.1  joerg #include "clang/AST/Decl.h"
     17  1.1  joerg #include "clang/AST/Expr.h"
     18  1.1  joerg 
     19  1.1  joerg namespace clang {
     20  1.1  joerg namespace interp {
     21  1.1  joerg class Block;
     22  1.1  joerg class Record;
     23  1.1  joerg struct Descriptor;
     24  1.1  joerg enum PrimType : unsigned;
     25  1.1  joerg 
     26  1.1  joerg using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
     27  1.1  joerg 
     28  1.1  joerg /// Invoked whenever a block is created. The constructor method fills in the
     29  1.1  joerg /// inline descriptors of all fields and array elements. It also initializes
     30  1.1  joerg /// all the fields which contain non-trivial types.
     31  1.1  joerg using BlockCtorFn = void (*)(Block *Storage, char *FieldPtr, bool IsConst,
     32  1.1  joerg                              bool IsMutable, bool IsActive,
     33  1.1  joerg                              Descriptor *FieldDesc);
     34  1.1  joerg 
     35  1.1  joerg /// Invoked when a block is destroyed. Invokes the destructors of all
     36  1.1  joerg /// non-trivial nested fields of arrays and records.
     37  1.1  joerg using BlockDtorFn = void (*)(Block *Storage, char *FieldPtr,
     38  1.1  joerg                              Descriptor *FieldDesc);
     39  1.1  joerg 
     40  1.1  joerg /// Invoked when a block with pointers referencing it goes out of scope. Such
     41  1.1  joerg /// blocks are persisted: the move function copies all inline descriptors and
     42  1.1  joerg /// non-trivial fields, as existing pointers might need to reference those
     43  1.1  joerg /// descriptors. Data is not copied since it cannot be legally read.
     44  1.1  joerg using BlockMoveFn = void (*)(Block *Storage, char *SrcFieldPtr,
     45  1.1  joerg                              char *DstFieldPtr, Descriptor *FieldDesc);
     46  1.1  joerg 
     47  1.1  joerg /// Object size as used by the interpreter.
     48  1.1  joerg using InterpSize = unsigned;
     49  1.1  joerg 
     50  1.1  joerg /// Describes a memory block created by an allocation site.
     51  1.1  joerg struct Descriptor {
     52  1.1  joerg private:
     53  1.1  joerg   /// Original declaration, used to emit the error message.
     54  1.1  joerg   const DeclTy Source;
     55  1.1  joerg   /// Size of an element, in host bytes.
     56  1.1  joerg   const InterpSize ElemSize;
     57  1.1  joerg   /// Size of the storage, in host bytes.
     58  1.1  joerg   const InterpSize Size;
     59  1.1  joerg   /// Size of the allocation (storage + metadata), in host bytes.
     60  1.1  joerg   const InterpSize AllocSize;
     61  1.1  joerg 
     62  1.1  joerg   /// Value to denote arrays of unknown size.
     63  1.1  joerg   static constexpr unsigned UnknownSizeMark = (unsigned)-1;
     64  1.1  joerg 
     65  1.1  joerg public:
     66  1.1  joerg   /// Token to denote structures of unknown size.
     67  1.1  joerg   struct UnknownSize {};
     68  1.1  joerg 
     69  1.1  joerg   /// Pointer to the record, if block contains records.
     70  1.1  joerg   Record *const ElemRecord = nullptr;
     71  1.1  joerg   /// Descriptor of the array element.
     72  1.1  joerg   Descriptor *const ElemDesc = nullptr;
     73  1.1  joerg   /// Flag indicating if the block is mutable.
     74  1.1  joerg   const bool IsConst = false;
     75  1.1  joerg   /// Flag indicating if a field is mutable.
     76  1.1  joerg   const bool IsMutable = false;
     77  1.1  joerg   /// Flag indicating if the block is a temporary.
     78  1.1  joerg   const bool IsTemporary = false;
     79  1.1  joerg   /// Flag indicating if the block is an array.
     80  1.1  joerg   const bool IsArray = false;
     81  1.1  joerg 
     82  1.1  joerg   /// Storage management methods.
     83  1.1  joerg   const BlockCtorFn CtorFn = nullptr;
     84  1.1  joerg   const BlockDtorFn DtorFn = nullptr;
     85  1.1  joerg   const BlockMoveFn MoveFn = nullptr;
     86  1.1  joerg 
     87  1.1  joerg   /// Allocates a descriptor for a primitive.
     88  1.1  joerg   Descriptor(const DeclTy &D, PrimType Type, bool IsConst, bool IsTemporary,
     89  1.1  joerg              bool IsMutable);
     90  1.1  joerg 
     91  1.1  joerg   /// Allocates a descriptor for an array of primitives.
     92  1.1  joerg   Descriptor(const DeclTy &D, PrimType Type, size_t NumElems, bool IsConst,
     93  1.1  joerg              bool IsTemporary, bool IsMutable);
     94  1.1  joerg 
     95  1.1  joerg   /// Allocates a descriptor for an array of primitives of unknown size.
     96  1.1  joerg   Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary, UnknownSize);
     97  1.1  joerg 
     98  1.1  joerg   /// Allocates a descriptor for an array of composites.
     99  1.1  joerg   Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems, bool IsConst,
    100  1.1  joerg              bool IsTemporary, bool IsMutable);
    101  1.1  joerg 
    102  1.1  joerg   /// Allocates a descriptor for an array of composites of unknown size.
    103  1.1  joerg   Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, UnknownSize);
    104  1.1  joerg 
    105  1.1  joerg   /// Allocates a descriptor for a record.
    106  1.1  joerg   Descriptor(const DeclTy &D, Record *R, bool IsConst, bool IsTemporary,
    107  1.1  joerg              bool IsMutable);
    108  1.1  joerg 
    109  1.1  joerg   QualType getType() const;
    110  1.1  joerg   SourceLocation getLocation() const;
    111  1.1  joerg 
    112  1.1  joerg   const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
    113  1.1  joerg   const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
    114  1.1  joerg 
    115  1.1  joerg   const ValueDecl *asValueDecl() const {
    116  1.1  joerg     return dyn_cast_or_null<ValueDecl>(asDecl());
    117  1.1  joerg   }
    118  1.1  joerg 
    119  1.1  joerg   const FieldDecl *asFieldDecl() const {
    120  1.1  joerg     return dyn_cast_or_null<FieldDecl>(asDecl());
    121  1.1  joerg   }
    122  1.1  joerg 
    123  1.1  joerg   const RecordDecl *asRecordDecl() const {
    124  1.1  joerg     return dyn_cast_or_null<RecordDecl>(asDecl());
    125  1.1  joerg   }
    126  1.1  joerg 
    127  1.1  joerg   /// Returns the size of the object without metadata.
    128  1.1  joerg   unsigned getSize() const {
    129  1.1  joerg     assert(!isUnknownSizeArray() && "Array of unknown size");
    130  1.1  joerg     return Size;
    131  1.1  joerg   }
    132  1.1  joerg 
    133  1.1  joerg   /// Returns the allocated size, including metadata.
    134  1.1  joerg   unsigned getAllocSize() const { return AllocSize; }
    135  1.1  joerg   /// returns the size of an element when the structure is viewed as an array.
    136  1.1  joerg   unsigned getElemSize()  const { return ElemSize; }
    137  1.1  joerg 
    138  1.1  joerg   /// Returns the number of elements stored in the block.
    139  1.1  joerg   unsigned getNumElems() const {
    140  1.1  joerg     return Size == UnknownSizeMark ? 0 : (getSize() / getElemSize());
    141  1.1  joerg   }
    142  1.1  joerg 
    143  1.1  joerg   /// Checks if the descriptor is of an array of primitives.
    144  1.1  joerg   bool isPrimitiveArray() const { return IsArray && !ElemDesc; }
    145  1.1  joerg   /// Checks if the descriptor is of an array of zero size.
    146  1.1  joerg   bool isZeroSizeArray() const { return Size == 0; }
    147  1.1  joerg   /// Checks if the descriptor is of an array of unknown size.
    148  1.1  joerg   bool isUnknownSizeArray() const { return Size == UnknownSizeMark; }
    149  1.1  joerg 
    150  1.1  joerg   /// Checks if the descriptor is of a primitive.
    151  1.1  joerg   bool isPrimitive() const { return !IsArray && !ElemRecord; }
    152  1.1  joerg 
    153  1.1  joerg   /// Checks if the descriptor is of an array.
    154  1.1  joerg   bool isArray() const { return IsArray; }
    155  1.1  joerg };
    156  1.1  joerg 
    157  1.1  joerg /// Inline descriptor embedded in structures and arrays.
    158  1.1  joerg ///
    159  1.1  joerg /// Such descriptors precede all composite array elements and structure fields.
    160  1.1  joerg /// If the base of a pointer is not zero, the base points to the end of this
    161  1.1  joerg /// structure. The offset field is used to traverse the pointer chain up
    162  1.1  joerg /// to the root structure which allocated the object.
    163  1.1  joerg struct InlineDescriptor {
    164  1.1  joerg   /// Offset inside the structure/array.
    165  1.1  joerg   unsigned Offset;
    166  1.1  joerg 
    167  1.1  joerg   /// Flag indicating if the storage is constant or not.
    168  1.1  joerg   /// Relevant for primitive fields.
    169  1.1  joerg   unsigned IsConst : 1;
    170  1.1  joerg   /// For primitive fields, it indicates if the field was initialized.
    171  1.1  joerg   /// Primitive fields in static storage are always initialized.
    172  1.1  joerg   /// Arrays are always initialized, even though their elements might not be.
    173  1.1  joerg   /// Base classes are initialized after the constructor is invoked.
    174  1.1  joerg   unsigned IsInitialized : 1;
    175  1.1  joerg   /// Flag indicating if the field is an embedded base class.
    176  1.1  joerg   unsigned IsBase : 1;
    177  1.1  joerg   /// Flag indicating if the field is the active member of a union.
    178  1.1  joerg   unsigned IsActive : 1;
    179  1.1  joerg   /// Flag indicating if the field is mutable (if in a record).
    180  1.1  joerg   unsigned IsMutable : 1;
    181  1.1  joerg 
    182  1.1  joerg   Descriptor *Desc;
    183  1.1  joerg };
    184  1.1  joerg 
    185  1.1  joerg /// Bitfield tracking the initialisation status of elements of primitive arrays.
    186  1.1  joerg /// A pointer to this is embedded at the end of all primitive arrays.
    187  1.1  joerg /// If the map was not yet created and nothing was initialied, the pointer to
    188  1.1  joerg /// this structure is 0. If the object was fully initialized, the pointer is -1.
    189  1.1  joerg struct InitMap {
    190  1.1  joerg private:
    191  1.1  joerg   /// Type packing bits.
    192  1.1  joerg   using T = uint64_t;
    193  1.1  joerg   /// Bits stored in a single field.
    194  1.1  joerg   static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT;
    195  1.1  joerg 
    196  1.1  joerg   /// Initializes the map with no fields set.
    197  1.1  joerg   InitMap(unsigned N);
    198  1.1  joerg 
    199  1.1  joerg   /// Returns a pointer to storage.
    200  1.1  joerg   T *data();
    201  1.1  joerg 
    202  1.1  joerg public:
    203  1.1  joerg   /// Initializes an element. Returns true when object if fully initialized.
    204  1.1  joerg   bool initialize(unsigned I);
    205  1.1  joerg 
    206  1.1  joerg   /// Checks if an element was initialized.
    207  1.1  joerg   bool isInitialized(unsigned I);
    208  1.1  joerg 
    209  1.1  joerg   /// Allocates a map holding N elements.
    210  1.1  joerg   static InitMap *allocate(unsigned N);
    211  1.1  joerg 
    212  1.1  joerg private:
    213  1.1  joerg   /// Number of fields initialized.
    214  1.1  joerg   unsigned UninitFields;
    215  1.1  joerg };
    216  1.1  joerg 
    217  1.1  joerg } // namespace interp
    218  1.1  joerg } // namespace clang
    219  1.1  joerg 
    220  1.1  joerg #endif
    221