[clang] 1f2d934 - [clang][bytecode] Support pointers in __builtin_mem{move,cpy} (#120560)

via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 19 07:39:02 PST 2024


Author: Timm Baeder
Date: 2024-12-19T16:38:58+01:00
New Revision: 1f2d934525833c4aae5f0436fd99551c776fd246

URL: https://github.com/llvm/llvm-project/commit/1f2d934525833c4aae5f0436fd99551c776fd246
DIFF: https://github.com/llvm/llvm-project/commit/1f2d934525833c4aae5f0436fd99551c776fd246.diff

LOG: [clang][bytecode] Support pointers in __builtin_mem{move,cpy} (#120560)

Unfortunately, that means we can't use the __builtin_bit_cast
implementation for this.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/InterpBuiltin.cpp
    clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
    clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
    clang/lib/AST/ByteCode/Pointer.h
    clang/test/AST/ByteCode/builtin-functions.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index d6b33c8aeeaac3..2ae91feb2d9e8e 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1862,10 +1862,10 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
   }
 
   QualType ElemType;
-  if (SrcPtr.getFieldDesc()->isArray())
-    ElemType = SrcPtr.getFieldDesc()->getElemQualType();
+  if (DestPtr.getFieldDesc()->isArray())
+    ElemType = DestPtr.getFieldDesc()->getElemQualType();
   else
-    ElemType = SrcPtr.getType();
+    ElemType = DestPtr.getType();
 
   unsigned ElemSize =
       S.getASTContext().getTypeSizeInChars(ElemType).getQuantity();
@@ -1876,6 +1876,18 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
     return false;
   }
 
+  QualType SrcElemType;
+  if (SrcPtr.getFieldDesc()->isArray())
+    SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
+  else
+    SrcElemType = SrcPtr.getType();
+
+  if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) {
+    S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun)
+        << Move << SrcElemType << ElemType;
+    return false;
+  }
+
   // Check for overlapping memory regions.
   if (!Move && Pointer::pointToSameBlock(SrcPtr, DestPtr)) {
     unsigned SrcIndex = SrcPtr.getIndex() * SrcPtr.elemSize();
@@ -1893,8 +1905,8 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
   // As a last resort, reject dummy pointers.
   if (DestPtr.isDummy() || SrcPtr.isDummy())
     return false;
-
-  if (!DoBitCastPtr(S, OpPC, SrcPtr, DestPtr, Size.getZExtValue()))
+  assert(Size.getZExtValue() % ElemSize == 0);
+  if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits()))
     return false;
 
   S.Stk.push<Pointer>(DestPtr);

diff  --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index 07f76943708216..0fc94e1694822a 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -448,3 +448,34 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
 
   return Success;
 }
+
+bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC,
+                             const Pointer &SrcPtr, const Pointer &DestPtr,
+                             Bits Size) {
+  assert(SrcPtr.isBlockPointer());
+  assert(DestPtr.isBlockPointer());
+
+  unsigned SrcStartOffset = SrcPtr.getByteOffset();
+  unsigned DestStartOffset = DestPtr.getByteOffset();
+
+  enumeratePointerFields(SrcPtr, S.getContext(), Size,
+                         [&](const Pointer &P, PrimType T, Bits BitOffset,
+                             Bits FullBitWidth, bool PackedBools) -> bool {
+                           unsigned SrcOffsetDiff =
+                               P.getByteOffset() - SrcStartOffset;
+
+                           Pointer DestP =
+                               Pointer(DestPtr.asBlockPointer().Pointee,
+                                       DestPtr.asBlockPointer().Base,
+                                       DestStartOffset + SrcOffsetDiff);
+
+                           TYPE_SWITCH(T, {
+                             DestP.deref<T>() = P.deref<T>();
+                             DestP.initialize();
+                           });
+
+                           return true;
+                         });
+
+  return true;
+}

diff  --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
index b45613b2f21e20..a0191bab693c45 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
@@ -33,6 +33,10 @@ bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr,
                   Pointer &ToPtr, size_t Size);
 bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
                          BitcastBuffer &Buffer, bool ReturnOnUninit);
+
+bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &SrcPtr,
+              const Pointer &DestPtr, Bits Size);
+
 } // namespace interp
 } // namespace clang
 

diff  --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 457fe93b278175..0d467c2abf0838 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -107,6 +107,7 @@ class Pointer {
       : Offset(Offset), StorageKind(Storage::Fn) {
     PointeeStorage.Fn = FunctionPointer(F);
   }
+  Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
   ~Pointer();
 
   void operator=(const Pointer &P);
@@ -706,8 +707,6 @@ class Pointer {
   friend struct InitMap;
   friend class DynamicAllocator;
 
-  Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
-
   /// Returns the embedded descriptor preceding a field.
   InlineDescriptor *getInlineDesc() const {
     assert(isBlockPointer());

diff  --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index 5906cb970f06c4..c1fd1bc1381503 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -1222,6 +1222,28 @@ namespace BuiltinMemcpy {
   static_assert(test_memcpy(1, 2, sizeof(int)) == 1334);
   static_assert(test_memcpy(0, 1, sizeof(int) * 2) == 2334); // both-error {{not an integral constant expression}} \
                                                              // both-note {{in call}}
+
+  /// Both memcpy and memmove must support pointers.
+  constexpr bool moveptr() {
+    int a = 0;
+    void *x = &a;
+    void *z = nullptr;
+
+    __builtin_memmove(&z, &x, sizeof(void*));
+    return z == x;
+  }
+  static_assert(moveptr());
+
+  constexpr bool cpyptr() {
+    int a = 0;
+    void *x = &a;
+    void *z = nullptr;
+
+    __builtin_memcpy(&z, &x, sizeof(void*));
+    return z == x;
+  }
+  static_assert(cpyptr());
+
 }
 
 namespace Memcmp {


        


More information about the cfe-commits mailing list