https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/202356
>From ca6e26a828df55c3432e3fbf2d1f3f269cac52d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Mon, 8 Jun 2026 15:05:35 +0200 Subject: [PATCH] as --- clang/lib/AST/ByteCode/Compiler.cpp | 24 ++++++++++++++++++++++-- clang/lib/AST/ByteCode/Interp.h | 28 ++++++++++++++++++++++------ clang/lib/AST/ByteCode/Opcodes.td | 6 +++++- clang/lib/AST/ByteCode/Pointer.cpp | 14 +++++++++----- clang/lib/AST/ByteCode/Pointer.h | 23 +++++++++++++++-------- clang/test/AST/ByteCode/codegen.cl | 17 +++++++++++++++++ 6 files changed, 90 insertions(+), 22 deletions(-) create mode 100644 clang/test/AST/ByteCode/codegen.cl diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 38a095f8a1164..450ecf991570b 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -716,7 +716,8 @@ 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); - if (!this->emitGetIntPtr(T, E->getType().getTypePtr(), E)) + uint64_t Val = Ctx.getASTContext().getTargetNullPointerValue(E->getType()); + if (!this->emitGetIntPtr(T, E->getType().getTypePtr(), Val, E)) return false; QualType PtrType = E->getType(); @@ -734,10 +735,29 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) { case CK_NonAtomicToAtomic: case CK_NoOp: case CK_UserDefinedConversion: - case CK_AddressSpaceConversion: case CK_CPointerToObjCPointerCast: return this->delegate(SubExpr); + case CK_AddressSpaceConversion: { + if (E->containsErrors()) + return false; + + if (!this->visit(SubExpr)) + return false; + + uint64_t Val; + if (E->getType()->isPointerType()) + Val = Ctx.getASTContext().getTargetNullPointerValue(E->getType()); + else + Val = 0; + + if (!this->emitCastAddressSpace(Val, E->getType().getTypePtr(), E)) + return false; + if (DiscardResult) + return this->emitPopPtr(E); + return true; + } + case CK_BitCast: { if (E->containsErrors()) return false; diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index f7d396b720767..06a05054108c9 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2581,9 +2581,9 @@ std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC, : 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); + return Pointer(V + O, Ptr.asIntPointer().getType()); } else - return Pointer(V - O, Ptr.asIntPointer().Ty); + return Pointer(V - O, Ptr.asIntPointer().getType()); } else if (Ptr.isFunctionPointer()) { uint64_t O = static_cast<uint64_t>(Offset); uint64_t N; @@ -3202,7 +3202,20 @@ template <PrimType Name, class T = typename PrimConv<Name>::T> inline bool Null(InterpState &S, 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, Ty); + if constexpr (std::is_same_v<T, Pointer>) + S.Stk.push<T>(Value, Ty, /*Offset=*/0, /*IsNull=*/true); + else + S.Stk.push<T>(Value, Ty); + return true; +} + +inline bool CastAddressSpace(InterpState &S, CodePtr OpPC, uint64_t Value, + const Type *Ty) { + const Pointer Ptr = S.Stk.pop<Pointer>(); + if (Ptr.isZero()) + S.Stk.push<Pointer>(Value, Ty); + else + S.Stk.push<Pointer>(Ptr); return true; } @@ -3648,7 +3661,8 @@ inline bool GetFnPtr(InterpState &S, const Function *Func) { } template <PrimType Name, class T = typename PrimConv<Name>::T> -inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Type *Ty) { +inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Type *Ty, + uint64_t NullValue) { const T &IntVal = S.Stk.pop<T>(); S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast) @@ -3673,7 +3687,8 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Type *Ty) { S.P.getFunction((const FunctionDecl *)IntVal.getPtr()); S.Stk.push<Pointer>(F, IntVal.getOffset()); } else { - S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Ty); + S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Ty, 0, + static_cast<uint64_t>(IntVal) == NullValue); } } else { S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Ty); @@ -4003,7 +4018,8 @@ 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->getType().getTypePtr()); + S.Stk.push<Pointer>(0, ElementDesc->getType().getTypePtr(), 0, + /*IsNull=*/true); return true; } if (NumElements.isNegative()) { diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index afed0014c1a10..1ec241b1fe974 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -324,6 +324,10 @@ def Null : SuccessOpcode { let HasGroup = 1; } +def CastAddressSpace : Opcode { + let Args = [ArgUint64, ArgTypePtr]; +} + //===----------------------------------------------------------------------===// // Pointer generation //===----------------------------------------------------------------------===// @@ -654,7 +658,7 @@ def GetFnPtr : SuccessOpcode { def GetIntPtr : Opcode { let Types = [AluTypeClass]; - let Args = [ArgTypePtr]; + let Args = [ArgTypePtr, ArgUint64]; let HasGroup = 1; } diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index dca2630138a4e..29bba15650ffc 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -212,7 +212,8 @@ bool Pointer::operator==(const Pointer &P) const { switch (StorageKind) { case Storage::Int: - return P.Int.Value == Int.Value && P.Int.Ty == Int.Ty && P.Offset == Offset; + return P.Int.Value == Int.Value && P.Int.getType() == Int.getType() && + P.Offset == Offset; case Storage::Block: return P.view() == view(); case Storage::Fn: @@ -477,7 +478,8 @@ void Pointer::print(llvm::raw_ostream &OS) const { OS << "}"; } break; case Storage::Int: - OS << "(Int) {" << Int.Value << " + " << Offset << ", " << Int.Ty << "}"; + OS << "(Int) {" << Int.Value << " + " << Offset << ", " << Int.getType() + << ", " << (Int.isNull() ? "null" : "nonnull") << '}'; break; case Storage::Fn: OS << "(Fn) { " << Fn.Func << " + " << Offset << " }"; @@ -1361,12 +1363,13 @@ std::optional<IntPointer> IntPointer::atOffset(const interp::Context &Ctx, ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)) .getQuantity(); - return IntPointer{FD->getType().getTypePtr(), this->Value + FieldOffset}; + uint64_t NewValue = this->Value + FieldOffset; + return IntPointer{{FD->getType().getTypePtr(), NewValue == 0}, NewValue}; } IntPointer IntPointer::baseCast(const interp::Context &Ctx, unsigned BaseOffset) const { - if (!Ty) + if (!getType()) return *this; QualType CurType = getPointeeType(); @@ -1391,7 +1394,8 @@ IntPointer IntPointer::baseCast(const interp::Context &Ctx, const RecordDecl *RD = BaseDesc->ElemRecord->getDecl(); QualType T = RD->getASTContext().getTagType(ElaboratedTypeKeyword::None, std::nullopt, RD, false); - return {T.getTypePtr(), Value + BaseLayoutOffset.getQuantity()}; + uint64_t NewValue = Value + BaseLayoutOffset.getQuantity(); + return {{T.getTypePtr(), NewValue == 0}, NewValue}; } std::optional<size_t> diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 54e0f858b4fa0..4f67e668e4786 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -353,17 +353,22 @@ struct BlockPointer { }; struct IntPointer { - const Type *Ty; + llvm::PointerIntPair<const Type *, 1, bool> TypeAndIsNull; + // const Type *Ty; uint64_t Value; + // bool IsNull = false; std::optional<IntPointer> atOffset(const Context &Ctx, unsigned Offset) const; IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const; + const Type *getType() const { return TypeAndIsNull.getPointer(); } + bool isNull() const { return TypeAndIsNull.getInt(); } + QualType getPointeeType() const { - if (!Ty) + if (!getType()) return QualType(); - QualType QT(Ty, 0); + QualType QT(getType(), 0); if (QT->isPointerOrReferenceType()) QT = QT->getPointeeType(); else if (QT->isArrayType()) @@ -535,15 +540,17 @@ enum class Storage { Int, Block, Fn, Typeid, String, Opaque }; /// \endverbatim class Pointer { public: - Pointer() : StorageKind(Storage::Int), Int{nullptr, 0} {} + Pointer() : StorageKind(Storage::Int), Int{{nullptr, true}, 0} {} Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int), Int(std::move(IntPtr)) {} Pointer(Block *B); Pointer(Block *B, uint64_t BaseAndOffset); Pointer(const Pointer &P); Pointer(Pointer &&P); - Pointer(uint64_t Address, const Type *Ty, uint64_t Offset = 0) - : Offset(Offset), StorageKind(Storage::Int), Int{Ty, Address} {} + Pointer(uint64_t Address, const Type *Ty, uint64_t Offset = 0, + std::optional<bool> IsNull = std::nullopt) + : Offset(Offset), StorageKind(Storage::Int), + Int{{Ty, IsNull.value_or(Address == 0)}, 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) @@ -603,7 +610,7 @@ class Pointer { [[nodiscard]] Pointer atIndex(uint64_t Idx) const { switch (StorageKind) { case Storage::Int: - return Pointer(Int.Value, Int.Ty, Idx); + return Pointer(Int.Value, Int.getType(), Idx); case Storage::Block: return Pointer(view().atIndex(Idx)); case Storage::Fn: @@ -646,7 +653,7 @@ class Pointer { bool isZero() const { switch (StorageKind) { case Storage::Int: - return Int.Value == 0 && Offset == 0; + return Int.isNull(); case Storage::Block: return BS.Pointee == nullptr; case Storage::Fn: diff --git a/clang/test/AST/ByteCode/codegen.cl b/clang/test/AST/ByteCode/codegen.cl new file mode 100644 index 0000000000000..d2e331905e02d --- /dev/null +++ b/clang/test/AST/ByteCode/codegen.cl @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -no-enable-noundef-analysis %s -cl-std=CL2.0 -triple amdgcn -fcommon -O0 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -no-enable-noundef-analysis %s -cl-std=CL2.0 -triple amdgcn -fcommon -O0 -emit-llvm -o - -fexperimental-new-constant-interpreter | FileCheck %s + +// CHECK: @fold_int_local ={{.*}} addrspace(1) global i32 13, align 4 +int fold_int_local = (int)(local void*)(generic char*)(global int*)0 + 14; + +// CHECK: @fold_int ={{.*}} addrspace(1) global i32 13, align 4 +int fold_int = (int)(private void*)(generic char*)(global int*)0 + 14; + +// CHECK: @test_static_var_private.sp4 = internal addrspace(1) global ptr addrspace(5) null, align 4 +// CHECK: @test_static_var_private.sp5 = internal addrspace(1) global ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), align 4 + +void test_static_var_private(void) { + static private char *sp4 = (private char*)((void)0, 0); + const int x = 0; + static private char *sp5 = (private char*)x; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
