Skip to content

Commit 1f2d934

Browse files
authored
[clang][bytecode] Support pointers in __builtin_mem{move,cpy} (#120560)
Unfortunately, that means we can't use the __builtin_bit_cast implementation for this.
1 parent 6f8afaf commit 1f2d934

File tree

5 files changed

+75
-7
lines changed

5 files changed

+75
-7
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

+17-5
Original file line numberDiff line numberDiff line change
@@ -1862,10 +1862,10 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18621862
}
18631863

18641864
QualType ElemType;
1865-
if (SrcPtr.getFieldDesc()->isArray())
1866-
ElemType = SrcPtr.getFieldDesc()->getElemQualType();
1865+
if (DestPtr.getFieldDesc()->isArray())
1866+
ElemType = DestPtr.getFieldDesc()->getElemQualType();
18671867
else
1868-
ElemType = SrcPtr.getType();
1868+
ElemType = DestPtr.getType();
18691869

18701870
unsigned ElemSize =
18711871
S.getASTContext().getTypeSizeInChars(ElemType).getQuantity();
@@ -1876,6 +1876,18 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18761876
return false;
18771877
}
18781878

1879+
QualType SrcElemType;
1880+
if (SrcPtr.getFieldDesc()->isArray())
1881+
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
1882+
else
1883+
SrcElemType = SrcPtr.getType();
1884+
1885+
if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) {
1886+
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun)
1887+
<< Move << SrcElemType << ElemType;
1888+
return false;
1889+
}
1890+
18791891
// Check for overlapping memory regions.
18801892
if (!Move && Pointer::pointToSameBlock(SrcPtr, DestPtr)) {
18811893
unsigned SrcIndex = SrcPtr.getIndex() * SrcPtr.elemSize();
@@ -1893,8 +1905,8 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18931905
// As a last resort, reject dummy pointers.
18941906
if (DestPtr.isDummy() || SrcPtr.isDummy())
18951907
return false;
1896-
1897-
if (!DoBitCastPtr(S, OpPC, SrcPtr, DestPtr, Size.getZExtValue()))
1908+
assert(Size.getZExtValue() % ElemSize == 0);
1909+
if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits()))
18981910
return false;
18991911

19001912
S.Stk.push<Pointer>(DestPtr);

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,34 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
448448

449449
return Success;
450450
}
451+
452+
bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC,
453+
const Pointer &SrcPtr, const Pointer &DestPtr,
454+
Bits Size) {
455+
assert(SrcPtr.isBlockPointer());
456+
assert(DestPtr.isBlockPointer());
457+
458+
unsigned SrcStartOffset = SrcPtr.getByteOffset();
459+
unsigned DestStartOffset = DestPtr.getByteOffset();
460+
461+
enumeratePointerFields(SrcPtr, S.getContext(), Size,
462+
[&](const Pointer &P, PrimType T, Bits BitOffset,
463+
Bits FullBitWidth, bool PackedBools) -> bool {
464+
unsigned SrcOffsetDiff =
465+
P.getByteOffset() - SrcStartOffset;
466+
467+
Pointer DestP =
468+
Pointer(DestPtr.asBlockPointer().Pointee,
469+
DestPtr.asBlockPointer().Base,
470+
DestStartOffset + SrcOffsetDiff);
471+
472+
TYPE_SWITCH(T, {
473+
DestP.deref<T>() = P.deref<T>();
474+
DestP.initialize();
475+
});
476+
477+
return true;
478+
});
479+
480+
return true;
481+
}

clang/lib/AST/ByteCode/InterpBuiltinBitCast.h

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr,
3333
Pointer &ToPtr, size_t Size);
3434
bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
3535
BitcastBuffer &Buffer, bool ReturnOnUninit);
36+
37+
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &SrcPtr,
38+
const Pointer &DestPtr, Bits Size);
39+
3640
} // namespace interp
3741
} // namespace clang
3842

clang/lib/AST/ByteCode/Pointer.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class Pointer {
107107
: Offset(Offset), StorageKind(Storage::Fn) {
108108
PointeeStorage.Fn = FunctionPointer(F);
109109
}
110+
Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
110111
~Pointer();
111112

112113
void operator=(const Pointer &P);
@@ -706,8 +707,6 @@ class Pointer {
706707
friend struct InitMap;
707708
friend class DynamicAllocator;
708709

709-
Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
710-
711710
/// Returns the embedded descriptor preceding a field.
712711
InlineDescriptor *getInlineDesc() const {
713712
assert(isBlockPointer());

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

+22
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,28 @@ namespace BuiltinMemcpy {
12221222
static_assert(test_memcpy(1, 2, sizeof(int)) == 1334);
12231223
static_assert(test_memcpy(0, 1, sizeof(int) * 2) == 2334); // both-error {{not an integral constant expression}} \
12241224
// both-note {{in call}}
1225+
1226+
/// Both memcpy and memmove must support pointers.
1227+
constexpr bool moveptr() {
1228+
int a = 0;
1229+
void *x = &a;
1230+
void *z = nullptr;
1231+
1232+
__builtin_memmove(&z, &x, sizeof(void*));
1233+
return z == x;
1234+
}
1235+
static_assert(moveptr());
1236+
1237+
constexpr bool cpyptr() {
1238+
int a = 0;
1239+
void *x = &a;
1240+
void *z = nullptr;
1241+
1242+
__builtin_memcpy(&z, &x, sizeof(void*));
1243+
return z == x;
1244+
}
1245+
static_assert(cpyptr());
1246+
12251247
}
12261248

12271249
namespace Memcmp {

0 commit comments

Comments
 (0)