[clang] [clang][bytecode] Optimize InitElem{,Pop} (PR #159084)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 16 05:57:29 PDT 2025
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/159084
Try harder to avoid creating a new `Pointer` for the element.
>From c4f2102e9fb8335c7d5f19c93753650970ce5e14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 16 Sep 2025 12:39:04 +0200
Subject: [PATCH] InitElem
---
clang/lib/AST/ByteCode/Interp.h | 39 +++++++++++++++-----
clang/lib/AST/ByteCode/Pointer.cpp | 59 +++++++++++++++++-------------
clang/lib/AST/ByteCode/Pointer.h | 2 +
3 files changed, 64 insertions(+), 36 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index d8362ee3176a0..5b097d6f062b7 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2127,19 +2127,28 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
if (Ptr.isUnknownSizeArray())
return false;
+ const Descriptor *Desc = Ptr.getFieldDesc();
// In the unlikely event that we're initializing the first item of
// a non-array, skip the atIndex().
- if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
+ if (Idx == 0 && !Desc->isArray()) {
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
}
- const Pointer &ElemPtr = Ptr.atIndex(Idx);
- if (!CheckInit(S, OpPC, ElemPtr))
+ if (!CheckLive(S, OpPC, Ptr, AK_Assign))
return false;
- ElemPtr.initialize();
- new (&ElemPtr.deref<T>()) T(Value);
+ if (Idx >= Desc->getNumElems()) {
+ // CheckRange.
+ if (S.getLangOpts().CPlusPlus) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_access_past_end)
+ << AK_Assign << S.Current->getRange(OpPC);
+ }
+ return false;
+ }
+ Ptr.initializeElement(Idx);
+ new (&Ptr.elem<T>(Idx)) T(Value);
return true;
}
@@ -2148,22 +2157,32 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
const T &Value = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();
+
if (Ptr.isUnknownSizeArray())
return false;
+ const Descriptor *Desc = Ptr.getFieldDesc();
// In the unlikely event that we're initializing the first item of
// a non-array, skip the atIndex().
- if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
+ if (Idx == 0 && !Desc->isArray()) {
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
}
- const Pointer &ElemPtr = Ptr.atIndex(Idx);
- if (!CheckInit(S, OpPC, ElemPtr))
+ if (!CheckLive(S, OpPC, Ptr, AK_Assign))
return false;
- ElemPtr.initialize();
- new (&ElemPtr.deref<T>()) T(Value);
+ if (Idx >= Desc->getNumElems()) {
+ // CheckRange.
+ if (S.getLangOpts().CPlusPlus) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_access_past_end)
+ << AK_Assign << S.Current->getRange(OpPC);
+ }
+ return false;
+ }
+ Ptr.initializeElement(Idx);
+ new (&Ptr.elem<T>(Idx)) T(Value);
return true;
}
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index ef75b0ded4f1f..f9e402d43e2da 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -433,7 +433,8 @@ bool Pointer::isInitialized() const {
if (!isBlockPointer())
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
+ Offset == BS.Base) {
const GlobalInlineDescriptor &GD =
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
return GD.InitState == GlobalInitState::Initialized;
@@ -461,7 +462,8 @@ bool Pointer::isElementInitialized(unsigned Index) const {
if (isStatic() && BS.Base == 0)
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
+ Offset == BS.Base) {
const GlobalInlineDescriptor &GD =
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
return GD.InitState == GlobalInitState::Initialized;
@@ -486,7 +488,8 @@ void Pointer::initialize() const {
assert(BS.Pointee && "Cannot initialize null pointer");
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
+ Offset == BS.Base) {
GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
asBlockPointer().Pointee->rawData());
GD.InitState = GlobalInitState::Initialized;
@@ -496,35 +499,38 @@ void Pointer::initialize() const {
const Descriptor *Desc = getFieldDesc();
assert(Desc);
if (Desc->isPrimitiveArray()) {
- // Primitive global arrays don't have an initmap.
- if (isStatic() && BS.Base == 0)
- return;
+ initializeElement(getIndex());
+ return;
+ }
- // Nothing to do for these.
- if (Desc->getNumElems() == 0)
- return;
+ // Field has its bit in an inline descriptor.
+ assert(BS.Base != 0 && "Only composite fields can be initialised");
+ getInlineDesc()->IsInitialized = true;
+}
- InitMapPtr &IM = getInitMap();
- if (!IM)
- IM =
- std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
+void Pointer::initializeElement(unsigned Index) const {
+ // Primitive global arrays don't have an initmap.
+ if (isStatic() && BS.Base == 0)
+ return;
- assert(IM);
+ assert(Index < getFieldDesc()->getNumElems());
- // All initialized.
- if (IM->first)
- return;
+ InitMapPtr &IM = getInitMap();
+ if (!IM) {
+ const Descriptor *Desc = getFieldDesc();
+ IM = std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
+ }
- if (IM->second->initializeElement(getIndex())) {
- IM->first = true;
- IM->second.reset();
- }
+ assert(IM);
+
+ // All initialized.
+ if (IM->first)
return;
- }
- // Field has its bit in an inline descriptor.
- assert(BS.Base != 0 && "Only composite fields can be initialised");
- getInlineDesc()->IsInitialized = true;
+ if (IM->second->initializeElement(Index)) {
+ IM->first = true;
+ IM->second.reset();
+ }
}
void Pointer::initializeAllElements() const {
@@ -547,7 +553,8 @@ bool Pointer::allElementsInitialized() const {
if (isStatic() && BS.Base == 0)
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
+ Offset == BS.Base) {
const GlobalInlineDescriptor &GD =
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
return GD.InitState == GlobalInitState::Initialized;
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 9e67374c3354f..bbf20801ce923 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -702,6 +702,8 @@ class Pointer {
/// Initializes a field.
void initialize() const;
+ /// Initialized the given element of a primitive array.
+ void initializeElement(unsigned Index) const;
/// Initialize all elements of a primitive array at once. This can be
/// used in situations where we *know* we have initialized *all* elements
/// of a primtive array.
More information about the cfe-commits
mailing list