| //===----------------------- InitMap.h --------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_INTERP_INIT_MAP_H |
| #define LLVM_CLANG_AST_INTERP_INIT_MAP_H |
| |
| #include <cassert> |
| #include <climits> |
| #include <memory> |
| #include <cstdint> |
| |
| namespace clang { |
| namespace interp { |
| |
| /// Bitfield tracking the initialisation status of elements of primitive arrays. |
| struct InitMap final { |
| private: |
| /// Type packing bits. |
| using T = uint64_t; |
| /// Bits stored in a single field. |
| static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT; |
| /// Number of fields not initialized. |
| unsigned UninitFields; |
| std::unique_ptr<T[]> Data; |
| |
| public: |
| /// Initializes the map with no fields set. |
| explicit InitMap(unsigned N); |
| |
| private: |
| friend class Pointer; |
| |
| /// Returns a pointer to storage. |
| T *data() { return Data.get(); } |
| const T *data() const { return Data.get(); } |
| |
| /// Initializes an element. Returns true when object if fully initialized. |
| bool initializeElement(unsigned I); |
| |
| /// Checks if an element was initialized. |
| bool isElementInitialized(unsigned I) const; |
| |
| static constexpr size_t numFields(unsigned N) { |
| return ((N + PER_FIELD - 1) / PER_FIELD) * 2; |
| } |
| }; |
| |
| /// A pointer-sized struct we use to allocate into data storage. |
| /// An InitMapPtr is either backed by an actual InitMap, or it |
| /// hold information about the absence of the InitMap. |
| struct InitMapPtr final { |
| /// V's value before an initmap has been created. |
| static constexpr intptr_t NoInitMapValue = 0; |
| /// V's value after the initmap has been destroyed because |
| /// all its elements have already been initialized. |
| static constexpr intptr_t AllInitializedValue = 1; |
| uintptr_t V = 0; |
| |
| explicit InitMapPtr() = default; |
| bool hasInitMap() const { |
| return V != NoInitMapValue && V != AllInitializedValue; |
| } |
| /// Are all elements in the array already initialized? |
| bool allInitialized() const { return V == AllInitializedValue; } |
| |
| void setInitMap(const InitMap *IM) { |
| assert(IM != nullptr); |
| V = reinterpret_cast<uintptr_t>(IM); |
| assert(hasInitMap()); |
| } |
| |
| void noteAllInitialized() { |
| if (hasInitMap()) |
| delete (operator->)(); |
| V = AllInitializedValue; |
| } |
| |
| /// Access the underlying InitMap directly. |
| InitMap *operator->() { |
| assert(hasInitMap()); |
| return reinterpret_cast<InitMap *>(V); |
| } |
| |
| /// Delete the InitMap if one exists. |
| void deleteInitMap() { |
| if (hasInitMap()) |
| delete (operator->)(); |
| V = NoInitMapValue; |
| }; |
| }; |
| static_assert(sizeof(InitMapPtr) == sizeof(void *)); |
| |
| } // namespace interp |
| } // namespace clang |
| |
| #endif |