[clang] be1f53f - [clang][bytecode] Save a `Type*` in integral pointers instead of a descriptor (#202835)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 10 01:11:01 PDT 2026
Author: Timm Baeder
Date: 2026-06-10T10:10:57+02:00
New Revision: be1f53f568394ee7c1976a9a5785c8127dbcdf39
URL: https://github.com/llvm/llvm-project/commit/be1f53f568394ee7c1976a9a5785c8127dbcdf39
DIFF: https://github.com/llvm/llvm-project/commit/be1f53f568394ee7c1976a9a5785c8127dbcdf39.diff
LOG: [clang][bytecode] Save a `Type*` in integral pointers instead of a descriptor (#202835)
This way we don't need to allocate a descriptor via the `Program`, which
is for global data.
Added:
Modified:
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Interp.cpp
clang/lib/AST/ByteCode/Interp.h
clang/lib/AST/ByteCode/MemberPointer.h
clang/lib/AST/ByteCode/Opcodes.td
clang/lib/AST/ByteCode/Pointer.cpp
clang/lib/AST/ByteCode/Pointer.h
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index b89849b6983d8..8ea42fea03bee 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -434,18 +434,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
case CK_NullToMemberPointer: {
if (!this->discard(SubExpr))
return false;
- const Descriptor *Desc = nullptr;
- const QualType PointeeType = E->getType()->getPointeeType();
- if (!PointeeType.isNull()) {
- if (OptPrimType T = classify(PointeeType))
- Desc = P.createDescriptor(SubExpr, *T);
- else
- Desc = P.createDescriptor(SubExpr, PointeeType.getTypePtr(),
- std::nullopt, /*IsConst=*/true);
- }
-
uint64_t Val = Ctx.getASTContext().getTargetNullPointerValue(E->getType());
- return this->emitNull(classifyPrim(E->getType()), Val, Desc, E);
+ return this->emitNull(classifyPrim(E->getType()), Val,
+ E->getType().getTypePtr(), E);
}
case CK_PointerToIntegral: {
@@ -481,19 +472,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) {
// FIXME: I think the discard is wrong since the int->ptr cast might cause a
// diagnostic.
PrimType T = classifyPrim(IntType);
- QualType PtrType = E->getType();
- const Descriptor *Desc;
- if (OptPrimType T = classify(PtrType->getPointeeType()))
- Desc = P.createDescriptor(SubExpr, *T);
- else if (PtrType->getPointeeType()->isVoidType())
- Desc = nullptr;
- else
- Desc = P.createDescriptor(E, PtrType->getPointeeType().getTypePtr(),
- Descriptor::InlineDescMD, /*IsConst=*/true);
-
- if (!this->emitGetIntPtr(T, Desc, E))
+ if (!this->emitGetIntPtr(T, E->getType().getTypePtr(), E))
return false;
+ QualType PtrType = E->getType();
PrimType DestPtrT = classifyPrim(PtrType);
if (DestPtrT == PT_Ptr)
return true;
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index f6cac7aeb9fb5..f21dbb3d5246c 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1489,7 +1489,7 @@ static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if (Ptr.isIntegralPointer()) {
if (std::optional<IntPointer> IntPtr =
- Ptr.asIntPointer().atOffset(S.getASTContext(), Off)) {
+ Ptr.asIntPointer().atOffset(S.Ctx, Off)) {
S.Stk.push<Pointer>(std::move(*IntPtr));
return true;
}
@@ -1535,7 +1535,7 @@ static bool getBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if (!Ptr.isBlockPointer()) {
if (!Ptr.isIntegralPointer())
return false;
- S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
+ S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.Ctx, Off));
return true;
}
@@ -1895,7 +1895,7 @@ static bool getDynamicDecl(InterpState &S, CodePtr OpPC, Pointer TypePtr,
QualType DynamicType = TypePtr.getType();
if (TypePtr.isStatic() || TypePtr.isConst()) {
- if (const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();
+ if (const VarDecl *VD = TypePtr.getRootVarDecl();
VD && !VD->isConstexpr()) {
const Expr *E = S.Current->getExpr(OpPC);
APValue V = TypePtr.toAPValue(S.getASTContext());
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 4c0a7040f46aa..9d3d3b449bea3 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2503,11 +2503,16 @@ std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC,
// This is much simpler for integral pointers, so handle them first.
if (Ptr.isIntegralPointer()) {
uint64_t V = Ptr.getIntegerRepresentation();
- uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
- if constexpr (Op == ArithOp::Add)
- return Pointer(V + O, Ptr.asIntPointer().Desc);
- else
- return Pointer(V - O, Ptr.asIntPointer().Desc);
+ QualType ElemType = Ptr.asIntPointer().getPointeeType();
+ uint64_t ElemSize =
+ (ElemType.isNull() || ElemType->isVoidType())
+ ? 1u
+ : S.getASTContext().getTypeSizeInChars(ElemType).getQuantity();
+ uint64_t O = static_cast<uint64_t>(Offset) * ElemSize;
+ if constexpr (Op == ArithOp::Add) {
+ return Pointer(V + O, Ptr.asIntPointer().Ty);
+ } else
+ return Pointer(V - O, Ptr.asIntPointer().Ty);
} else if (Ptr.isFunctionPointer()) {
uint64_t O = static_cast<uint64_t>(Offset);
uint64_t N;
@@ -3119,11 +3124,10 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
}
template <PrimType Name, class T = typename PrimConv<Name>::T>
-inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
- const Descriptor *Desc) {
+inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Type *Ty) {
// FIXME(perf): This is a somewhat often-used function and the value of a
// null pointer is almost always 0.
- S.Stk.push<T>(Value, Desc);
+ S.Stk.push<T>(Value, Ty);
return true;
}
@@ -3563,7 +3567,7 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
}
template <PrimType Name, class T = typename PrimConv<Name>::T>
-inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
+inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Type *Ty) {
const T &IntVal = S.Stk.pop<T>();
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
@@ -3588,10 +3592,10 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
S.P.getFunction((const FunctionDecl *)IntVal.getPtr());
S.Stk.push<Pointer>(F, IntVal.getOffset());
} else {
- S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
+ S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Ty);
}
} else {
- S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
+ S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Ty);
}
return true;
@@ -3872,7 +3876,7 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
return false;
// If this failed and is nothrow, just return a null ptr.
- S.Stk.push<Pointer>(0, nullptr);
+ S.Stk.push<Pointer>();
return true;
}
if (NumElements.isNegative()) {
@@ -3881,7 +3885,7 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
<< NumElements.toDiagnosticString(S.getASTContext());
return false;
}
- S.Stk.push<Pointer>(0, nullptr);
+ S.Stk.push<Pointer>();
return true;
}
@@ -3915,7 +3919,7 @@ inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
return false;
// If this failed and is nothrow, just return a null ptr.
- S.Stk.push<Pointer>(0, ElementDesc);
+ S.Stk.push<Pointer>(0, ElementDesc->getType().getTypePtr());
return true;
}
if (NumElements.isNegative()) {
@@ -3924,7 +3928,7 @@ inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
<< NumElements.toDiagnosticString(S.getASTContext());
return false;
}
- S.Stk.push<Pointer>(0, nullptr);
+ S.Stk.push<Pointer>();
return true;
}
diff --git a/clang/lib/AST/ByteCode/MemberPointer.h b/clang/lib/AST/ByteCode/MemberPointer.h
index dbbf1fe85bada..b23acf7befc67 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.h
+++ b/clang/lib/AST/ByteCode/MemberPointer.h
@@ -44,7 +44,7 @@ class MemberPointer final {
MemberPointer() = default;
MemberPointer(Pointer Base, const ValueDecl *Dcl)
: Base(Base), DeclAndIsDerivedMember(Dcl) {}
- MemberPointer(uint32_t Address, const Descriptor *D) {
+ MemberPointer(uint32_t Address, const Type *) {
// We only reach this for Address == 0, when creating a null member pointer.
assert(Address == 0);
}
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 4bd61cdce658d..09c616aa2ff1d 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -311,7 +311,7 @@ def ZeroIntAPS : Opcode {
// [] -> [Pointer]
def Null : Opcode {
let Types = [PtrTypeClass];
- let Args = [ArgUint64, ArgDesc];
+ let Args = [ArgUint64, ArgTypePtr];
let HasGroup = 1;
}
@@ -596,7 +596,7 @@ def GetFnPtr : Opcode {
def GetIntPtr : Opcode {
let Types = [AluTypeClass];
- let Args = [ArgDesc];
+ let Args = [ArgTypePtr];
let HasGroup = 1;
}
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 96409faeb6929..1b15c59c9fbff 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -337,9 +337,7 @@ void Pointer::print(llvm::raw_ostream &OS) const {
OS << "}";
} break;
case Storage::Int:
- OS << "(Int) {";
- OS << Int.Value << " + " << Offset << ", " << Int.Desc;
- OS << "}";
+ OS << "(Int) {" << Int.Value << " + " << Offset << ", " << Int.Ty << "}";
break;
case Storage::Fn:
OS << "(Fn) { " << Fn.Func << " + " << Offset << " }";
@@ -994,11 +992,19 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
return Result;
}
-std::optional<IntPointer> IntPointer::atOffset(const ASTContext &ASTCtx,
+const VarDecl *Pointer::getRootVarDecl() const {
+ if (isBlockPointer())
+ return getDeclDesc()->asVarDecl();
+ return nullptr;
+}
+
+std::optional<IntPointer> IntPointer::atOffset(const interp::Context &Ctx,
unsigned Offset) const {
- if (!this->Desc)
- return *this;
- const Record *R = this->Desc->ElemRecord;
+ QualType CurType = getPointeeType();
+ if (CurType.isNull() || !CurType->isRecordType())
+ return std::nullopt;
+
+ const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
if (!R)
return *this;
@@ -1016,21 +1022,26 @@ std::optional<IntPointer> IntPointer::atOffset(const ASTContext &ASTCtx,
if (FD->getParent()->isInvalidDecl())
return std::nullopt;
+ const ASTContext &ASTCtx = Ctx.getASTContext();
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
unsigned FieldIndex = FD->getFieldIndex();
uint64_t FieldOffset =
ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
.getQuantity();
- return IntPointer{F->Desc, this->Value + FieldOffset};
+
+ return IntPointer{FD->getType().getTypePtr(), this->Value + FieldOffset};
}
-IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
+IntPointer IntPointer::baseCast(const interp::Context &Ctx,
unsigned BaseOffset) const {
- if (!Desc) {
- assert(Value == 0);
+ if (!Ty)
return *this;
- }
- const Record *R = Desc->ElemRecord;
+
+ QualType CurType = getPointeeType();
+ if (CurType.isNull() || !CurType->isRecordType())
+ return *this;
+
+ const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
const Descriptor *BaseDesc = nullptr;
// This iterates over bases and checks for the proper offset. That's
@@ -1044,9 +1055,13 @@ IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
assert(BaseDesc);
// Adjust the offset value based on the information from the record layout.
+ const ASTContext &ASTCtx = Ctx.getASTContext();
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
CharUnits BaseLayoutOffset =
Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
- return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
+ const RecordDecl *RD = BaseDesc->ElemRecord->getDecl();
+ QualType T = RD->getASTContext().getTagType(ElaboratedTypeKeyword::None,
+ std::nullopt, RD, false);
+ return {T.getTypePtr(), Value + BaseLayoutOffset.getQuantity()};
}
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index a77918f667fd3..2b455ebc5efb5 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -45,12 +45,24 @@ struct BlockPointer {
};
struct IntPointer {
- const Descriptor *Desc;
+ const Type *Ty;
uint64_t Value;
- std::optional<IntPointer> atOffset(const ASTContext &ASTCtx,
- unsigned Offset) const;
- IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const;
+ std::optional<IntPointer> atOffset(const Context &Ctx, unsigned Offset) const;
+ IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const;
+
+ QualType getPointeeType() const {
+ if (!Ty)
+ return QualType();
+
+ QualType QT(Ty, 0);
+ if (QT->isPointerOrReferenceType())
+ QT = QT->getPointeeType();
+ else if (QT->isArrayType())
+ QT = QT->getAsArrayTypeUnsafe()->getElementType();
+
+ return QT.IgnoreParens();
+ }
};
struct FunctionPointer {
@@ -107,8 +119,8 @@ class Pointer {
Pointer(Block *B, uint64_t BaseAndOffset);
Pointer(const Pointer &P);
Pointer(Pointer &&P);
- Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
- : Offset(Offset), StorageKind(Storage::Int), Int{Desc, Address} {}
+ Pointer(uint64_t Address, const Type *Ty, uint64_t Offset = 0)
+ : Offset(Offset), StorageKind(Storage::Int), Int{Ty, Address} {}
Pointer(const Function *F, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Fn), Fn{F} {}
Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)
@@ -127,7 +139,7 @@ class Pointer {
if (P.StorageKind != StorageKind)
return false;
if (isIntegralPointer())
- return P.Int.Value == Int.Value && P.Int.Desc == Int.Desc &&
+ return P.Int.Value == Int.Value && P.Int.Ty == Int.Ty &&
P.Offset == Offset;
if (isFunctionPointer())
@@ -161,7 +173,7 @@ class Pointer {
/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
if (isIntegralPointer())
- return Pointer(Int.Value, Int.Desc, Idx);
+ return Pointer(Int.Value, Int.Ty, Idx);
if (isFunctionPointer())
return Pointer(Fn.Func, Idx);
@@ -290,9 +302,7 @@ class Pointer {
/// Accessor for information about the declaration site.
const Descriptor *getDeclDesc() const {
- if (isIntegralPointer())
- return Int.Desc;
- if (isFunctionPointer() || isTypeidPointer())
+ if (!isBlockPointer())
return nullptr;
assert(isBlockPointer());
@@ -309,8 +319,8 @@ class Pointer {
const Function *F = Fn.Func;
return F ? F->getDecl() : DeclTy();
}
- assert(isIntegralPointer());
- return Int.Desc ? Int.Desc->getSource() : DeclTy();
+ llvm_unreachable("Unsupported pointer type in getSource()");
+ return DeclTy();
}
/// Returns a pointer to the object of which this pointer is a field.
@@ -335,7 +345,7 @@ class Pointer {
/// Accessors for information about the innermost field.
const Descriptor *getFieldDesc() const {
if (isIntegralPointer())
- return Int.Desc;
+ return nullptr;
if (isRoot())
return getDeclDesc();
@@ -348,6 +358,8 @@ class Pointer {
return QualType(Typeid.TypeInfoType, 0);
if (isFunctionPointer())
return Fn.Func->getDecl()->getType();
+ if (isIntegralPointer())
+ return Int.getPointeeType();
if (isRoot() && BS.Base == Offset) {
// If this pointer points to the root of a declaration, try to consult
@@ -372,14 +384,15 @@ class Pointer {
return getFieldDesc()->getType();
}
+ const VarDecl *getRootVarDecl() const;
+
[[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
/// Returns the element size of the innermost field.
size_t elemSize() const {
if (isIntegralPointer()) {
- if (!Int.Desc)
- return 1;
- return Int.Desc->getElemDataSize();
+ // FIXME: Remove this and handle int ptrs specially?
+ return 1;
}
if (BS.Base == RootPtrMark)
More information about the cfe-commits
mailing list