[clang] [clang][bytecode] Support overlapping regions in __builtin_memmove (PR #132523)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 21 22:18:48 PDT 2025


https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/132523

Unfortunately, a few circumstances make the implementation here less than ideal, but we need to handle overlapping regions anyway.

>From edec53dcbc6e340b9817c9f20fd0615ec6610e35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 22 Mar 2025 05:50:39 +0100
Subject: [PATCH] [clang][bytecode] Support overlapping regions in
 __builtin_memmove

Unfortunately, a few circumstances make the implementation here
less than ideal, but we need to handle overlapping regions anyway.
---
 .../lib/AST/ByteCode/InterpBuiltinBitCast.cpp | 41 +++++++++++++------
 clang/test/AST/ByteCode/builtin-functions.cpp |  3 +-
 2 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index 6b8860c09167c..239b3104e89f1 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -19,6 +19,8 @@
 #include "clang/AST/RecordLayout.h"
 #include "clang/Basic/TargetInfo.h"
 
+#include <variant>
+
 using namespace clang;
 using namespace clang::interp;
 
@@ -450,33 +452,48 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
   return Success;
 }
 
+using PrimTypeVariant =
+    std::variant<Pointer, FunctionPointer, MemberPointer, FixedPoint,
+                 Integral<8, false>, Integral<8, true>, Integral<16, false>,
+                 Integral<16, true>, Integral<32, false>, Integral<32, true>,
+                 Integral<64, false>, Integral<64, true>, IntegralAP<true>,
+                 IntegralAP<false>, Boolean, Floating>;
+
+// NB: This implementation isn't exactly ideal, but:
+//   1) We can't just do a bitcast here since we need to be able to
+//      copy pointers.
+//   2) This also needs to handle overlapping regions.
+//   3) We currently have no way of iterating over the fields of a pointer
+//      backwards.
 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();
-
+  llvm::SmallVector<PrimTypeVariant> Values;
   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, { Values.push_back(P.deref<T>()); });
+                           return true;
+                         });
 
+  unsigned ValueIndex = 0;
+  enumeratePointerFields(DestPtr, S.getContext(), Size,
+                         [&](const Pointer &P, PrimType T, Bits BitOffset,
+                             Bits FullBitWidth, bool PackedBools) -> bool {
                            TYPE_SWITCH(T, {
-                             DestP.deref<T>() = P.deref<T>();
-                             DestP.initialize();
+                             P.deref<T>() = std::get<T>(Values[ValueIndex]);
+                             P.initialize();
                            });
 
+                           ++ValueIndex;
                            return true;
                          });
 
+  // We should've read all the values into DestPtr.
+  assert(ValueIndex == Values.size());
+
   return true;
 }
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index 3dd348031fec1..13a34f71a6354 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -1276,7 +1276,6 @@ namespace BuiltinMemcpy {
   static_assert(test_incomplete_array_type() == 1234); // both-error {{constant}} both-note {{in call}}
 
 
-  /// FIXME: memmove needs to support overlapping memory regions.
   constexpr bool memmoveOverlapping() {
     char s1[] {1, 2, 3};
     __builtin_memmove(s1, s1 + 1, 2 * sizeof(char));
@@ -1289,7 +1288,7 @@ namespace BuiltinMemcpy {
 
     return Result1 && Result2;
   }
-  static_assert(memmoveOverlapping()); // expected-error {{failed}}
+  static_assert(memmoveOverlapping());
 }
 
 namespace Memcmp {



More information about the cfe-commits mailing list