[clang] [clang][bytecode] Reintroduce Pointer::elem() (PR #149693)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 20 00:04:45 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
As a way of writing atIndex(I).deref<T>(), which creates an intermediate Pointer, which in turn adds (and removes) that pointer from the pointer list of the Block. This way we can avoid that.
---
Full diff: https://github.com/llvm/llvm-project/pull/149693.diff
8 Files Affected:
- (modified) clang/lib/AST/ByteCode/Context.cpp (+1-1)
- (modified) clang/lib/AST/ByteCode/EvaluationResult.cpp (+1-1)
- (modified) clang/lib/AST/ByteCode/Interp.h (+26-26)
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+10-11)
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+6-7)
- (modified) clang/lib/AST/ByteCode/Pointer.h (+19)
- (modified) clang/lib/AST/ByteCode/Program.cpp (+4-6)
- (modified) clang/lib/AST/ExprConstant.cpp (+3-12)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 9e683d71f83bc..12b8ab5da1d1d 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -254,7 +254,7 @@ bool Context::evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result) {
Result = 0;
for (unsigned I = Ptr.getIndex(); I != N; ++I) {
INT_TYPE_SWITCH(ElemT, {
- auto Elem = Ptr.atIndex(I).deref<T>();
+ auto Elem = Ptr.elem<T>(I);
if (Elem.isZero())
return true;
++Result;
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index f59612bf00015..b11531f4296a2 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -204,7 +204,7 @@ static void collectBlocks(const Pointer &Ptr,
} else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
- const Pointer &ElemPointee = Ptr.atIndex(I).deref<Pointer>();
+ const Pointer &ElemPointee = Ptr.elem<Pointer>(I);
if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
collectBlocks(ElemPointee, Blocks);
}
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 7ba6e21bd5d82..7f29200f8617f 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -468,10 +468,10 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) {
const Pointer &Result = S.Stk.peek<Pointer>();
if constexpr (std::is_same_v<T, Floating>) {
- APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
- APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
- APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
- APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
+ APFloat A = LHS.elem<Floating>(0).getAPFloat();
+ APFloat B = LHS.elem<Floating>(1).getAPFloat();
+ APFloat C = RHS.elem<Floating>(0).getAPFloat();
+ APFloat D = RHS.elem<Floating>(1).getAPFloat();
APFloat ResR(A.getSemantics());
APFloat ResI(A.getSemantics());
@@ -480,20 +480,20 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) {
// Copy into the result.
Floating RA = S.allocFloat(A.getSemantics());
RA.copy(ResR);
- Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR);
+ Result.elem<Floating>(0) = RA; // Floating(ResR);
Result.atIndex(0).initialize();
Floating RI = S.allocFloat(A.getSemantics());
RI.copy(ResI);
- Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI);
+ Result.elem<Floating>(1) = RI; // Floating(ResI);
Result.atIndex(1).initialize();
Result.initialize();
} else {
// Integer element type.
- const T &LHSR = LHS.atIndex(0).deref<T>();
- const T &LHSI = LHS.atIndex(1).deref<T>();
- const T &RHSR = RHS.atIndex(0).deref<T>();
- const T &RHSI = RHS.atIndex(1).deref<T>();
+ const T &LHSR = LHS.elem<T>(0);
+ const T &LHSI = LHS.elem<T>(1);
+ const T &RHSR = RHS.elem<T>(0);
+ const T &RHSI = RHS.elem<T>(1);
unsigned Bits = LHSR.bitWidth();
// real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
@@ -503,7 +503,7 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) {
T B;
if (T::mul(LHSI, RHSI, Bits, &B))
return false;
- if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))
+ if (T::sub(A, B, Bits, &Result.elem<T>(0)))
return false;
Result.atIndex(0).initialize();
@@ -512,7 +512,7 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) {
return false;
if (T::mul(LHSI, RHSR, Bits, &B))
return false;
- if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))
+ if (T::add(A, B, Bits, &Result.elem<T>(1)))
return false;
Result.atIndex(1).initialize();
Result.initialize();
@@ -528,10 +528,10 @@ inline bool Divc(InterpState &S, CodePtr OpPC) {
const Pointer &Result = S.Stk.peek<Pointer>();
if constexpr (std::is_same_v<T, Floating>) {
- APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
- APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
- APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
- APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
+ APFloat A = LHS.elem<Floating>(0).getAPFloat();
+ APFloat B = LHS.elem<Floating>(1).getAPFloat();
+ APFloat C = RHS.elem<Floating>(0).getAPFloat();
+ APFloat D = RHS.elem<Floating>(1).getAPFloat();
APFloat ResR(A.getSemantics());
APFloat ResI(A.getSemantics());
@@ -540,21 +540,21 @@ inline bool Divc(InterpState &S, CodePtr OpPC) {
// Copy into the result.
Floating RA = S.allocFloat(A.getSemantics());
RA.copy(ResR);
- Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR);
+ Result.elem<Floating>(0) = RA; // Floating(ResR);
Result.atIndex(0).initialize();
Floating RI = S.allocFloat(A.getSemantics());
RI.copy(ResI);
- Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI);
+ Result.elem<Floating>(1) = RI; // Floating(ResI);
Result.atIndex(1).initialize();
Result.initialize();
} else {
// Integer element type.
- const T &LHSR = LHS.atIndex(0).deref<T>();
- const T &LHSI = LHS.atIndex(1).deref<T>();
- const T &RHSR = RHS.atIndex(0).deref<T>();
- const T &RHSI = RHS.atIndex(1).deref<T>();
+ const T &LHSR = LHS.elem<T>(0);
+ const T &LHSI = LHS.elem<T>(1);
+ const T &RHSR = RHS.elem<T>(0);
+ const T &RHSI = RHS.elem<T>(1);
unsigned Bits = LHSR.bitWidth();
const T Zero = T::from(0, Bits);
@@ -581,8 +581,8 @@ inline bool Divc(InterpState &S, CodePtr OpPC) {
}
// real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
- T &ResultR = Result.atIndex(0).deref<T>();
- T &ResultI = Result.atIndex(1).deref<T>();
+ T &ResultR = Result.elem<T>(0);
+ T &ResultI = Result.elem<T>(1);
if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
return false;
@@ -3103,7 +3103,7 @@ inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
return false;
assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
- S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
+ S.Stk.push<T>(Ptr.elem<T>(Index));
return true;
}
@@ -3115,7 +3115,7 @@ inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
return false;
assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
- S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
+ S.Stk.push<T>(Ptr.elem<T>(Index));
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 462b9a11e0a5c..f86d26edbb526 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1098,9 +1098,9 @@ static bool interp__builtin_complex(InterpState &S, CodePtr OpPC,
const Floating &Arg1 = S.Stk.pop<Floating>();
Pointer &Result = S.Stk.peek<Pointer>();
- Result.atIndex(0).deref<Floating>() = Arg1;
+ Result.elem<Floating>(0) = Arg1;
Result.atIndex(0).initialize();
- Result.atIndex(1).deref<Floating>() = Arg2;
+ Result.elem<Floating>(1) = Arg2;
Result.atIndex(1).initialize();
Result.initialize();
@@ -1644,10 +1644,10 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
unsigned NumElems = Arg.getNumElems();
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
- T Result = Arg.atIndex(0).deref<T>();
+ T Result = Arg.elem<T>(0);
unsigned BitWidth = Result.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
- T Elem = Arg.atIndex(I).deref<T>();
+ T Elem = Arg.elem<T>(I);
T PrevResult = Result;
if (ID == Builtin::BI__builtin_reduce_add) {
@@ -1723,11 +1723,10 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
for (unsigned I = 0; I != NumElems; ++I) {
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
if (BuiltinID == Builtin::BI__builtin_elementwise_popcount) {
- Dst.atIndex(I).deref<T>() =
- T::from(Arg.atIndex(I).deref<T>().toAPSInt().popcount());
+ Dst.elem<T>(I) = T::from(Arg.elem<T>(I).toAPSInt().popcount());
} else {
- Dst.atIndex(I).deref<T>() = T::from(
- Arg.atIndex(I).deref<T>().toAPSInt().reverseBits().getZExtValue());
+ Dst.elem<T>(I) =
+ T::from(Arg.elem<T>(I).toAPSInt().reverseBits().getZExtValue());
}
Dst.atIndex(I).initialize();
});
@@ -2296,8 +2295,8 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
APSInt Elem1;
APSInt Elem2;
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
- Elem1 = LHS.atIndex(I).deref<T>().toAPSInt();
- Elem2 = RHS.atIndex(I).deref<T>().toAPSInt();
+ Elem1 = LHS.elem<T>(I).toAPSInt();
+ Elem2 = RHS.elem<T>(I).toAPSInt();
});
APSInt Result;
@@ -2942,7 +2941,7 @@ static bool copyComposite(InterpState &S, CodePtr OpPC, const Pointer &Src,
for (unsigned I = 0, N = DestDesc->getNumElems(); I != N; ++I) {
Pointer DestElem = Dest.atIndex(I);
TYPE_SWITCH(ET, {
- DestElem.deref<T>() = Src.atIndex(I).deref<T>();
+ DestElem.deref<T>() = Src.elem<T>(I);
DestElem.initialize();
});
}
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 2f9ecf98e558e..c4d06d6a430d3 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -760,14 +760,14 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
assert(ElemT);
INT_TYPE_SWITCH(*ElemT, {
- auto V1 = Ptr.atIndex(0).deref<T>();
- auto V2 = Ptr.atIndex(1).deref<T>();
+ auto V1 = Ptr.elem<T>(0);
+ auto V2 = Ptr.elem<T>(1);
R = APValue(V1.toAPSInt(), V2.toAPSInt());
return true;
});
} else if (ElemTy->isFloatingType()) {
- R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
- Ptr.atIndex(1).deref<Floating>().getAPFloat());
+ R = APValue(Ptr.elem<Floating>(0).getAPFloat(),
+ Ptr.elem<Floating>(1).getAPFloat());
return true;
}
return false;
@@ -782,9 +782,8 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
SmallVector<APValue> Values;
Values.reserve(VT->getNumElements());
for (unsigned I = 0; I != VT->getNumElements(); ++I) {
- TYPE_SWITCH(ElemT, {
- Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
- });
+ TYPE_SWITCH(ElemT,
+ { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
}
assert(Values.size() == VT->getNumElements());
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index da74013cf83a6..d17eba5da9ca6 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -693,6 +693,25 @@ class Pointer {
return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset);
}
+ /// Dereferences the element at index \p I.
+ /// This is equivalent to atIndex(I).deref<T>().
+ template <typename T> T &elem(unsigned I) const {
+ assert(isLive() && "Invalid pointer");
+ assert(isBlockPointer());
+ assert(asBlockPointer().Pointee);
+ assert(isDereferencable());
+ assert(getFieldDesc()->isPrimitiveArray());
+
+ unsigned ElemByteOffset = I * getFieldDesc()->getElemSize();
+ if (isArrayRoot())
+ return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +
+ asBlockPointer().Base + sizeof(InitMapPtr) +
+ ElemByteOffset);
+
+ return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset +
+ ElemByteOffset);
+ }
+
/// Whether this block can be read from at all. This is only true for
/// block pointers that point to a valid location inside that block.
bool isDereferencable() const {
diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp
index 5ac0f59f32d4e..af6d7c7110629 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -74,27 +74,25 @@ unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) {
const Pointer Ptr(G->block());
if (CharWidth == 1) {
- std::memcpy(&Ptr.atIndex(0).deref<char>(), S->getString().data(),
- StringLength);
+ std::memcpy(&Ptr.elem<char>(0), S->getString().data(), StringLength);
} else {
// Construct the string in storage.
for (unsigned I = 0; I <= StringLength; ++I) {
- Pointer Field = Ptr.atIndex(I);
const uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
switch (CharType) {
case PT_Sint8: {
using T = PrimConv<PT_Sint8>::T;
- Field.deref<T>() = T::from(CodePoint, BitWidth);
+ Ptr.elem<T>(I) = T::from(CodePoint, BitWidth);
break;
}
case PT_Uint16: {
using T = PrimConv<PT_Uint16>::T;
- Field.deref<T>() = T::from(CodePoint, BitWidth);
+ Ptr.elem<T>(I) = T::from(CodePoint, BitWidth);
break;
}
case PT_Uint32: {
using T = PrimConv<PT_Uint32>::T;
- Field.deref<T>() = T::from(CodePoint, BitWidth);
+ Ptr.elem<T>(I) = T::from(CodePoint, BitWidth);
break;
}
default:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 0d12161756467..2ab94362f9aa5 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9346,13 +9346,9 @@ bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
// [C++26][expr.unary.op]
// If the operand points to an object or function, the result
// denotes that object or function; otherwise, the behavior is undefined.
- // Because &(*(type*)0) is a common pattern, we do not fail the evaluation
- // immediately.
- if (!Success || !E->getType().getNonReferenceType()->isObjectType())
- return Success;
- return bool(findCompleteObject(Info, E, AK_Dereference, Result,
- E->getType())) ||
- Info.noteUndefinedBehavior();
+ return Success &&
+ (!E->getType().getNonReferenceType()->isObjectType() ||
+ findCompleteObject(Info, E, AK_Dereference, Result, E->getType()));
}
bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -18022,11 +18018,6 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
Info.InConstantContext = true;
Info.CheckingPotentialConstantExpression = true;
- if (Info.EnableNewConstInterp) {
- Info.Ctx.getInterpContext().isPotentialConstantExprUnevaluated(Info, E, FD);
- return Diags.empty();
- }
-
// Fabricate a call stack frame to give the arguments a plausible cover story.
CallStackFrame Frame(Info, SourceLocation(), FD, /*This=*/nullptr,
/*CallExpr=*/nullptr, CallRef());
``````````
</details>
https://github.com/llvm/llvm-project/pull/149693
More information about the cfe-commits
mailing list