Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 2 additions & 22 deletions clang/lib/AST/ByteCode/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -65,9 +65,7 @@ static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
template <typename T>
static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);

if (IMP)
IMP = std::nullopt;
IMP.deleteInitMap();

if constexpr (needsCtor<T>()) {
Ptr += sizeof(InitMapPtr);
Expand Down Expand Up @@ -467,21 +465,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));
}
36 changes: 1 addition & 35 deletions clang/lib/AST/ByteCode/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down
31 changes: 31 additions & 0 deletions clang/lib/AST/ByteCode/InitMap.cpp
Original file line number Diff line number Diff line change
@@ -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));
}
100 changes: 100 additions & 0 deletions clang/lib/AST/ByteCode/InitMap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//===----------------------- 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 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
42 changes: 17 additions & 25 deletions clang/lib/AST/ByteCode/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/ByteCode/const-eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down