Skip to content

Commit d679516

Browse files
authored
[clang][bytecode] Support overlapping regions in __builtin_memmove (#132523)
Unfortunately, a few circumstances make the implementation here less than ideal, but we need to handle overlapping regions anyway.
1 parent 1edefc3 commit d679516

File tree

2 files changed

+30
-14
lines changed

2 files changed

+30
-14
lines changed

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "clang/AST/RecordLayout.h"
2020
#include "clang/Basic/TargetInfo.h"
2121

22+
#include <variant>
23+
2224
using namespace clang;
2325
using namespace clang::interp;
2426

@@ -450,33 +452,48 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
450452
return Success;
451453
}
452454

455+
using PrimTypeVariant =
456+
std::variant<Pointer, FunctionPointer, MemberPointer, FixedPoint,
457+
Integral<8, false>, Integral<8, true>, Integral<16, false>,
458+
Integral<16, true>, Integral<32, false>, Integral<32, true>,
459+
Integral<64, false>, Integral<64, true>, IntegralAP<true>,
460+
IntegralAP<false>, Boolean, Floating>;
461+
462+
// NB: This implementation isn't exactly ideal, but:
463+
// 1) We can't just do a bitcast here since we need to be able to
464+
// copy pointers.
465+
// 2) This also needs to handle overlapping regions.
466+
// 3) We currently have no way of iterating over the fields of a pointer
467+
// backwards.
453468
bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC,
454469
const Pointer &SrcPtr, const Pointer &DestPtr,
455470
Bits Size) {
456471
assert(SrcPtr.isBlockPointer());
457472
assert(DestPtr.isBlockPointer());
458473

459-
unsigned SrcStartOffset = SrcPtr.getByteOffset();
460-
unsigned DestStartOffset = DestPtr.getByteOffset();
461-
474+
llvm::SmallVector<PrimTypeVariant> Values;
462475
enumeratePointerFields(SrcPtr, S.getContext(), Size,
463476
[&](const Pointer &P, PrimType T, Bits BitOffset,
464477
Bits FullBitWidth, bool PackedBools) -> bool {
465-
unsigned SrcOffsetDiff =
466-
P.getByteOffset() - SrcStartOffset;
467-
468-
Pointer DestP =
469-
Pointer(DestPtr.asBlockPointer().Pointee,
470-
DestPtr.asBlockPointer().Base,
471-
DestStartOffset + SrcOffsetDiff);
478+
TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); });
479+
return true;
480+
});
472481

482+
unsigned ValueIndex = 0;
483+
enumeratePointerFields(DestPtr, S.getContext(), Size,
484+
[&](const Pointer &P, PrimType T, Bits BitOffset,
485+
Bits FullBitWidth, bool PackedBools) -> bool {
473486
TYPE_SWITCH(T, {
474-
DestP.deref<T>() = P.deref<T>();
475-
DestP.initialize();
487+
P.deref<T>() = std::get<T>(Values[ValueIndex]);
488+
P.initialize();
476489
});
477490

491+
++ValueIndex;
478492
return true;
479493
});
480494

495+
// We should've read all the values into DestPtr.
496+
assert(ValueIndex == Values.size());
497+
481498
return true;
482499
}

clang/test/AST/ByteCode/builtin-functions.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,6 @@ namespace BuiltinMemcpy {
12761276
static_assert(test_incomplete_array_type() == 1234); // both-error {{constant}} both-note {{in call}}
12771277

12781278

1279-
/// FIXME: memmove needs to support overlapping memory regions.
12801279
constexpr bool memmoveOverlapping() {
12811280
char s1[] {1, 2, 3};
12821281
__builtin_memmove(s1, s1 + 1, 2 * sizeof(char));
@@ -1289,7 +1288,7 @@ namespace BuiltinMemcpy {
12891288

12901289
return Result1 && Result2;
12911290
}
1292-
static_assert(memmoveOverlapping()); // expected-error {{failed}}
1291+
static_assert(memmoveOverlapping());
12931292
}
12941293

12951294
namespace Memcmp {

0 commit comments

Comments
 (0)