https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/172665

>From 03745b5e9123f2bf89f1cc4cf174e0082d89e7df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Wed, 17 Dec 2025 14:05:23 +0100
Subject: [PATCH] [clang][bytecode]

---
 clang/lib/AST/ByteCode/Descriptor.cpp | 24 +------
 clang/lib/AST/ByteCode/Descriptor.h   | 36 +---------
 clang/lib/AST/ByteCode/InitMap.cpp    | 31 +++++++++
 clang/lib/AST/ByteCode/InitMap.h      | 97 +++++++++++++++++++++++++++
 clang/lib/AST/ByteCode/Pointer.cpp    | 42 +++++-------
 clang/lib/AST/CMakeLists.txt          |  1 +
 clang/test/AST/ByteCode/const-eval.c  |  2 +-
 7 files changed, 151 insertions(+), 82 deletions(-)
 create mode 100644 clang/lib/AST/ByteCode/InitMap.cpp
 create mode 100644 clang/lib/AST/ByteCode/InitMap.h

diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp 
b/clang/lib/AST/ByteCode/Descriptor.cpp
index 0a819599287ee..487e5ae4f6ad0 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -52,7 +52,7 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor 
*) {
 template <typename T>
 static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
                         const Descriptor *D) {
-  new (Ptr) InitMapPtr(std::nullopt);
+  new (Ptr) InitMapPtr();
 
   if constexpr (needsCtor<T>()) {
     Ptr += sizeof(InitMapPtr);
@@ -66,8 +66,8 @@ template <typename T>
 static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
   InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
 
-  if (IMP)
-    IMP = std::nullopt;
+  if (IMP.hasInitMap())
+    IMP.deleteInitMap();
 
   if constexpr (needsCtor<T>()) {
     Ptr += sizeof(InitMapPtr);
@@ -467,21 +467,3 @@ bool Descriptor::hasTrivialDtor() const {
 }
 
 bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); 
}
-
-InitMap::InitMap(unsigned N)
-    : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
-
-bool InitMap::initializeElement(unsigned I) {
-  unsigned Bucket = I / PER_FIELD;
-  T Mask = T(1) << (I % PER_FIELD);
-  if (!(data()[Bucket] & Mask)) {
-    data()[Bucket] |= Mask;
-    UninitFields -= 1;
-  }
-  return UninitFields == 0;
-}
-
-bool InitMap::isElementInitialized(unsigned I) const {
-  unsigned Bucket = I / PER_FIELD;
-  return data()[Bucket] & (T(1) << (I % PER_FIELD));
-}
diff --git a/clang/lib/AST/ByteCode/Descriptor.h 
b/clang/lib/AST/ByteCode/Descriptor.h
index 90dc2b4aa3111..057f40f8f1f69 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
 #define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
 
+#include "InitMap.h"
 #include "PrimType.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
@@ -22,12 +23,10 @@ namespace interp {
 class Block;
 class Record;
 class SourceInfo;
-struct InitMap;
 struct Descriptor;
 enum PrimType : uint8_t;
 
 using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
-using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>;
 
 /// Invoked whenever a block is created. The constructor method fills in the
 /// inline descriptors of all fields and array elements. It also initializes
@@ -277,39 +276,6 @@ struct Descriptor final {
   void dumpFull(unsigned Offset = 0, unsigned Indent = 0) const;
 };
 
-/// 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;
-
-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;
-  }
-  /// Number of fields not initialized.
-  unsigned UninitFields;
-  std::unique_ptr<T[]> Data;
-};
-
 } // namespace interp
 } // namespace clang
 
diff --git a/clang/lib/AST/ByteCode/InitMap.cpp 
b/clang/lib/AST/ByteCode/InitMap.cpp
new file mode 100644
index 0000000000000..ae841dd6df189
--- /dev/null
+++ b/clang/lib/AST/ByteCode/InitMap.cpp
@@ -0,0 +1,31 @@
+//===----------------------- InitMap.cpp ------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+#include "InitMap.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+InitMap::InitMap(unsigned N)
+    : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
+
+bool InitMap::initializeElement(unsigned I) {
+  unsigned Bucket = I / PER_FIELD;
+  T Mask = T(1) << (I % PER_FIELD);
+  if (!(data()[Bucket] & Mask)) {
+    data()[Bucket] |= Mask;
+    UninitFields -= 1;
+  }
+  return UninitFields == 0;
+}
+
+bool InitMap::isElementInitialized(unsigned I) const {
+  if (UninitFields == 0)
+    return true;
+  unsigned Bucket = I / PER_FIELD;
+  return data()[Bucket] & (T(1) << (I % PER_FIELD));
+}
diff --git a/clang/lib/AST/ByteCode/InitMap.h b/clang/lib/AST/ByteCode/InitMap.h
new file mode 100644
index 0000000000000..7a5f744748403
--- /dev/null
+++ b/clang/lib/AST/ByteCode/InitMap.h
@@ -0,0 +1,97 @@
+//===----------------------- 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>
+
+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 {
+  /// 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;
+  }
+  bool allInitialized() const { return V == AllInitializedValue; }
+
+  void setInitMap(InitMap *IM) {
+    assert(IM != nullptr);
+    V = reinterpret_cast<uintptr_t>(IM);
+    assert(hasInitMap());
+  }
+
+  void noteAllInitialized() {
+    if (hasInitMap())
+      delete (operator->)();
+    V = AllInitializedValue;
+  }
+
+  InitMap *operator->() {
+    assert(hasInitMap());
+    return reinterpret_cast<InitMap *>(V);
+  }
+
+  void deleteInitMap() {
+    if (hasInitMap())
+      delete (operator->)();
+    V = NoInitMapValue;
+  };
+};
+static_assert(sizeof(InitMapPtr) == sizeof(void *));
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp 
b/clang/lib/AST/ByteCode/Pointer.cpp
index 90f41bed39440..5fb6ccc92c7bf 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -11,6 +11,7 @@
 #include "Context.h"
 #include "Floating.h"
 #include "Function.h"
+#include "InitMap.h"
 #include "Integral.h"
 #include "InterpBlock.h"
 #include "MemberPointer.h"
@@ -477,14 +478,14 @@ bool Pointer::isElementInitialized(unsigned Index) const {
   }
 
   if (Desc->isPrimitiveArray()) {
-    InitMapPtr &IM = getInitMap();
-    if (!IM)
-      return false;
+    InitMapPtr IM = getInitMap();
 
-    if (IM->first)
+    if (IM.allInitialized())
       return true;
 
-    return IM->second->isElementInitialized(Index);
+    if (!IM.hasInitMap())
+      return false;
+    return IM->isElementInitialized(Index);
   }
   return isInitialized();
 }
@@ -523,34 +524,25 @@ void Pointer::initializeElement(unsigned Index) const {
   assert(Index < getFieldDesc()->getNumElems());
 
   InitMapPtr &IM = getInitMap();
-  if (!IM) {
-    const Descriptor *Desc = getFieldDesc();
-    IM = std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
-  }
-
-  assert(IM);
 
-  // All initialized.
-  if (IM->first)
+  if (IM.allInitialized())
     return;
 
-  if (IM->second->initializeElement(Index)) {
-    IM->first = true;
-    IM->second.reset();
+  if (!IM.hasInitMap()) {
+    const Descriptor *Desc = getFieldDesc();
+    IM.setInitMap(new InitMap(Desc->getNumElems()));
   }
+  assert(IM.hasInitMap());
+
+  if (IM->initializeElement(Index))
+    IM.noteAllInitialized();
 }
 
 void Pointer::initializeAllElements() const {
   assert(getFieldDesc()->isPrimitiveArray());
   assert(isArrayRoot());
 
-  InitMapPtr &IM = getInitMap();
-  if (!IM) {
-    IM = std::make_pair(true, nullptr);
-  } else {
-    IM->first = true;
-    IM->second.reset();
-  }
+  getInitMap().noteAllInitialized();
 }
 
 bool Pointer::allElementsInitialized() const {
@@ -566,8 +558,8 @@ bool Pointer::allElementsInitialized() const {
     return GD.InitState == GlobalInitState::Initialized;
   }
 
-  InitMapPtr &IM = getInitMap();
-  return IM && IM->first;
+  InitMapPtr IM = getInitMap();
+  return IM.allInitialized();
 }
 
 void Pointer::activate() const {
diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index fd50e956bb865..f9a5f4f0e7ecd 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -82,6 +82,7 @@ add_clang_library(clangAST
   ByteCode/Floating.cpp
   ByteCode/EvaluationResult.cpp
   ByteCode/DynamicAllocator.cpp
+  ByteCode/InitMap.cpp
   ByteCode/Interp.cpp
   ByteCode/InterpBlock.cpp
   ByteCode/InterpFrame.cpp
diff --git a/clang/test/AST/ByteCode/const-eval.c 
b/clang/test/AST/ByteCode/const-eval.c
index d6cf600b378a8..70b2a4dbd86e4 100644
--- a/clang/test/AST/ByteCode/const-eval.c
+++ b/clang/test/AST/ByteCode/const-eval.c
@@ -127,7 +127,7 @@ EVAL_EXPR(43, varfloat && constfloat) // both-error {{not 
an integer constant ex
 EVAL_EXPR(45, ((char*)-1) + 1 == 0 ? 1 : -1)
 EVAL_EXPR(46, ((char*)-1) + 1 < (char*) -1 ? 1 : -1)
 EVAL_EXPR(47, &x < &x + 1 ? 1 : -1)
-EVAL_EXPR(48, &x != &x - 1 ? 1 : -1)
+EVAL_EXPR(48, &x != &x - 1 ? 1 : -1) // expected-error {{declared as an array 
with a negative size}}
 EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // ref-error {{not an integer constant 
expression}}
 
 extern struct Test50S Test50;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to