Skip to content

Commit 79f8756

Browse files
committed
[clang][bytecode]
1 parent 28d4e33 commit 79f8756

File tree

6 files changed

+156
-81
lines changed

6 files changed

+156
-81
lines changed

clang/lib/AST/ByteCode/Descriptor.cpp

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
5252
template <typename T>
5353
static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
5454
const Descriptor *D) {
55-
new (Ptr) InitMapPtr(std::nullopt);
55+
new (Ptr) InitMapPtr();
5656

5757
if constexpr (needsCtor<T>()) {
5858
Ptr += sizeof(InitMapPtr);
@@ -64,10 +64,10 @@ static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
6464

6565
template <typename T>
6666
static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
67-
InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
67+
InitMapPtr IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
6868

69-
if (IMP)
70-
IMP = std::nullopt;
69+
if (IMP.hasInitMap())
70+
IMP.deleteInitMap();
7171

7272
if constexpr (needsCtor<T>()) {
7373
Ptr += sizeof(InitMapPtr);
@@ -467,21 +467,3 @@ bool Descriptor::hasTrivialDtor() const {
467467
}
468468

469469
bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
470-
471-
InitMap::InitMap(unsigned N)
472-
: UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
473-
474-
bool InitMap::initializeElement(unsigned I) {
475-
unsigned Bucket = I / PER_FIELD;
476-
T Mask = T(1) << (I % PER_FIELD);
477-
if (!(data()[Bucket] & Mask)) {
478-
data()[Bucket] |= Mask;
479-
UninitFields -= 1;
480-
}
481-
return UninitFields == 0;
482-
}
483-
484-
bool InitMap::isElementInitialized(unsigned I) const {
485-
unsigned Bucket = I / PER_FIELD;
486-
return data()[Bucket] & (T(1) << (I % PER_FIELD));
487-
}

clang/lib/AST/ByteCode/Descriptor.h

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
1414
#define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
1515

16+
#include "InitMap.h"
1617
#include "PrimType.h"
1718
#include "clang/AST/Decl.h"
1819
#include "clang/AST/Expr.h"
@@ -22,12 +23,10 @@ namespace interp {
2223
class Block;
2324
class Record;
2425
class SourceInfo;
25-
struct InitMap;
2626
struct Descriptor;
2727
enum PrimType : uint8_t;
2828

2929
using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
30-
using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>;
3130

3231
/// Invoked whenever a block is created. The constructor method fills in the
3332
/// inline descriptors of all fields and array elements. It also initializes
@@ -277,39 +276,6 @@ struct Descriptor final {
277276
void dumpFull(unsigned Offset = 0, unsigned Indent = 0) const;
278277
};
279278

280-
/// Bitfield tracking the initialisation status of elements of primitive arrays.
281-
struct InitMap final {
282-
private:
283-
/// Type packing bits.
284-
using T = uint64_t;
285-
/// Bits stored in a single field.
286-
static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT;
287-
288-
public:
289-
/// Initializes the map with no fields set.
290-
explicit InitMap(unsigned N);
291-
292-
private:
293-
friend class Pointer;
294-
295-
/// Returns a pointer to storage.
296-
T *data() { return Data.get(); }
297-
const T *data() const { return Data.get(); }
298-
299-
/// Initializes an element. Returns true when object if fully initialized.
300-
bool initializeElement(unsigned I);
301-
302-
/// Checks if an element was initialized.
303-
bool isElementInitialized(unsigned I) const;
304-
305-
static constexpr size_t numFields(unsigned N) {
306-
return (N + PER_FIELD - 1) / PER_FIELD;
307-
}
308-
/// Number of fields not initialized.
309-
unsigned UninitFields;
310-
std::unique_ptr<T[]> Data;
311-
};
312-
313279
} // namespace interp
314280
} // namespace clang
315281

clang/lib/AST/ByteCode/InitMap.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===----------------------- InitMap.cpp ------------------------*- 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+
#include "InitMap.h"
9+
10+
using namespace clang;
11+
using namespace clang::interp;
12+
13+
InitMap::InitMap(unsigned N)
14+
: UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
15+
16+
bool InitMap::initializeElement(unsigned I) {
17+
unsigned Bucket = I / PER_FIELD;
18+
T Mask = T(1) << (I % PER_FIELD);
19+
if (!(data()[Bucket] & Mask)) {
20+
data()[Bucket] |= Mask;
21+
UninitFields -= 1;
22+
}
23+
return UninitFields == 0;
24+
}
25+
26+
bool InitMap::isElementInitialized(unsigned I) const {
27+
if (UninitFields == 0)
28+
return true;
29+
unsigned Bucket = I / PER_FIELD;
30+
return data()[Bucket] & (T(1) << (I % PER_FIELD));
31+
}

clang/lib/AST/ByteCode/InitMap.h

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "Context.h"
1212
#include "Floating.h"
1313
#include "Function.h"
14+
#include "InitMap.h"
1415
#include "Integral.h"
1516
#include "InterpBlock.h"
1617
#include "MemberPointer.h"
@@ -477,14 +478,14 @@ bool Pointer::isElementInitialized(unsigned Index) const {
477478
}
478479

479480
if (Desc->isPrimitiveArray()) {
480-
InitMapPtr &IM = getInitMap();
481-
if (!IM)
481+
InitMapPtr IM = getInitMap();
482+
if (!IM.hasInitMap())
482483
return false;
483484

484-
if (IM->first)
485+
if (IM.allInitialized())
485486
return true;
486487

487-
return IM->second->isElementInitialized(Index);
488+
return IM->isElementInitialized(Index);
488489
}
489490
return isInitialized();
490491
}
@@ -523,34 +524,25 @@ void Pointer::initializeElement(unsigned Index) const {
523524
assert(Index < getFieldDesc()->getNumElems());
524525

525526
InitMapPtr &IM = getInitMap();
526-
if (!IM) {
527-
const Descriptor *Desc = getFieldDesc();
528-
IM = std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
529-
}
530527

531-
assert(IM);
532-
533-
// All initialized.
534-
if (IM->first)
528+
if (IM.allInitialized())
535529
return;
536530

537-
if (IM->second->initializeElement(Index)) {
538-
IM->first = true;
539-
IM->second.reset();
531+
if (!IM.hasInitMap()) {
532+
const Descriptor *Desc = getFieldDesc();
533+
IM.setInitMap(new InitMap(Desc->getNumElems()));
540534
}
535+
assert(IM.hasInitMap());
536+
537+
if (IM->initializeElement(Index))
538+
IM.noteAllInitialized();
541539
}
542540

543541
void Pointer::initializeAllElements() const {
544542
assert(getFieldDesc()->isPrimitiveArray());
545543
assert(isArrayRoot());
546544

547-
InitMapPtr &IM = getInitMap();
548-
if (!IM) {
549-
IM = std::make_pair(true, nullptr);
550-
} else {
551-
IM->first = true;
552-
IM->second.reset();
553-
}
545+
getInitMap().noteAllInitialized();
554546
}
555547

556548
bool Pointer::allElementsInitialized() const {
@@ -566,8 +558,8 @@ bool Pointer::allElementsInitialized() const {
566558
return GD.InitState == GlobalInitState::Initialized;
567559
}
568560

569-
InitMapPtr &IM = getInitMap();
570-
return IM && IM->first;
561+
InitMapPtr IM = getInitMap();
562+
return IM.allInitialized();
571563
}
572564

573565
void Pointer::activate() const {

clang/lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ add_clang_library(clangAST
8282
ByteCode/Floating.cpp
8383
ByteCode/EvaluationResult.cpp
8484
ByteCode/DynamicAllocator.cpp
85+
ByteCode/InitMap.cpp
8586
ByteCode/Interp.cpp
8687
ByteCode/InterpBlock.cpp
8788
ByteCode/InterpFrame.cpp

0 commit comments

Comments
 (0)