|
| 1 | +//===----------------------- InitMap.h --------------------------*- C++ -*-===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +#ifndef LLVM_CLANG_AST_INTERP_INIT_MAP_H |
| 10 | +#define LLVM_CLANG_AST_INTERP_INIT_MAP_H |
| 11 | + |
| 12 | +#include <climits> |
| 13 | +#include <memory> |
| 14 | +#include <cassert> |
| 15 | + |
| 16 | +namespace clang { |
| 17 | +namespace interp { |
| 18 | + |
| 19 | +/// Bitfield tracking the initialisation status of elements of primitive arrays. |
| 20 | +struct InitMap final { |
| 21 | +private: |
| 22 | + /// Type packing bits. |
| 23 | + using T = uint64_t; |
| 24 | + /// Bits stored in a single field. |
| 25 | + static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT; |
| 26 | + /// Number of fields not initialized. |
| 27 | + unsigned UninitFields; |
| 28 | + std::unique_ptr<T[]> Data; |
| 29 | + |
| 30 | +public: |
| 31 | + /// Initializes the map with no fields set. |
| 32 | + explicit InitMap(unsigned N); |
| 33 | + |
| 34 | +private: |
| 35 | + friend class Pointer; |
| 36 | + |
| 37 | + /// Returns a pointer to storage. |
| 38 | + T *data() { return Data.get(); } |
| 39 | + const T *data() const { return Data.get(); } |
| 40 | + |
| 41 | + /// Initializes an element. Returns true when object if fully initialized. |
| 42 | + bool initializeElement(unsigned I); |
| 43 | + |
| 44 | + /// Checks if an element was initialized. |
| 45 | + bool isElementInitialized(unsigned I) const; |
| 46 | + |
| 47 | + static constexpr size_t numFields(unsigned N) { |
| 48 | + return ((N + PER_FIELD - 1) / PER_FIELD) * 2; |
| 49 | + } |
| 50 | +}; |
| 51 | + |
| 52 | +/// A pointer-sized struct we use to allocate into data storage. |
| 53 | +/// An InitMapPtr is either backed by an actual InitMap, or it |
| 54 | +/// hold information about the absence of the InitMap. |
| 55 | +struct InitMapPtr { |
| 56 | + /// V's value before an initmap has been created. |
| 57 | + static constexpr intptr_t NoInitMapValue = 0; |
| 58 | + /// V's value after the initmap has been destroyed because |
| 59 | + /// all its elements have already been initialized. |
| 60 | + static constexpr intptr_t AllInitializedValue = 1; |
| 61 | + uintptr_t V = 0; |
| 62 | + |
| 63 | + explicit InitMapPtr() = default; |
| 64 | + void deleteInitMap() { |
| 65 | + if (hasAllocatedInitMap()) { |
| 66 | + ((operator->)())->~InitMap(); |
| 67 | + delete (operator->)(); |
| 68 | + V = 0; |
| 69 | + } |
| 70 | + }; |
| 71 | + |
| 72 | + bool hasInitMap() const { return V != NoInitMapValue; } |
| 73 | + bool allInitialized() const { return V == AllInitializedValue; } |
| 74 | + |
| 75 | + void setInitMap(InitMap *IM) { |
| 76 | + assert(IM != nullptr); |
| 77 | + V = reinterpret_cast<uintptr_t>(IM); |
| 78 | + assert(hasInitMap()); |
| 79 | + assert(hasAllocatedInitMap()); |
| 80 | + } |
| 81 | + |
| 82 | + void noteAllInitialized() { |
| 83 | + if (hasAllocatedInitMap()) |
| 84 | + delete (operator->)(); |
| 85 | + V = AllInitializedValue; |
| 86 | + } |
| 87 | + |
| 88 | + InitMap *operator->() { |
| 89 | + assert(hasInitMap()); |
| 90 | + return reinterpret_cast<InitMap *>(V); |
| 91 | + } |
| 92 | + |
| 93 | +private: |
| 94 | + bool hasAllocatedInitMap() const { |
| 95 | + return V != NoInitMapValue && V != AllInitializedValue; |
| 96 | + } |
| 97 | +}; |
| 98 | +static_assert(sizeof(InitMapPtr) == sizeof(void *)); |
| 99 | + |
| 100 | +} // namespace interp |
| 101 | +} // namespace clang |
| 102 | + |
| 103 | +#endif |
0 commit comments