Skip to content

Commit ab7e0c0

Browse files
authored
[clang][bytecode] Implement __builtin_wmem{cpy,move} (#135969)
1 parent 99c08ff commit ab7e0c0

File tree

2 files changed

+84
-8
lines changed

2 files changed

+84
-8
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,14 +1788,18 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
17881788
Pointer DestPtr = getParam<Pointer>(Frame, 0);
17891789
const ASTContext &ASTCtx = S.getASTContext();
17901790
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
1791-
const APSInt &Size =
1792-
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
1791+
APSInt Size = peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
17931792
assert(!Size.isSigned() && "memcpy and friends take an unsigned size");
17941793

17951794
if (ID == Builtin::BImemcpy || ID == Builtin::BImemmove)
17961795
diagnoseNonConstexprBuiltin(S, OpPC, ID);
17971796

1798-
bool Move = (ID == Builtin::BI__builtin_memmove || ID == Builtin::BImemmove);
1797+
bool Move =
1798+
(ID == Builtin::BI__builtin_memmove || ID == Builtin::BImemmove ||
1799+
ID == Builtin::BI__builtin_wmemmove || ID == Builtin::BIwmemmove);
1800+
bool WChar = ID == Builtin::BIwmemcpy || ID == Builtin::BIwmemmove ||
1801+
ID == Builtin::BI__builtin_wmemcpy ||
1802+
ID == Builtin::BI__builtin_wmemmove;
17991803

18001804
// If the size is zero, we treat this as always being a valid no-op.
18011805
if (Size.isZero()) {
@@ -1806,7 +1810,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18061810
if (SrcPtr.isZero() || DestPtr.isZero()) {
18071811
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
18081812
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
1809-
<< /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero()
1813+
<< /*IsMove=*/Move << /*IsWchar=*/WChar << !SrcPtr.isZero()
18101814
<< DiagPtr.toDiagnosticString(ASTCtx);
18111815
return false;
18121816
}
@@ -1818,7 +1822,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18181822
? std::to_string(SrcPtr.getIntegerRepresentation())
18191823
: std::to_string(DestPtr.getIntegerRepresentation());
18201824
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
1821-
<< Move << false << DestPtr.isIntegralPointer() << DiagVal;
1825+
<< Move << WChar << DestPtr.isIntegralPointer() << DiagVal;
18221826
return false;
18231827
}
18241828

@@ -1837,11 +1841,17 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18371841
}
18381842
unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity();
18391843

1844+
if (WChar) {
1845+
uint64_t WCharSize =
1846+
ASTCtx.getTypeSizeInChars(ASTCtx.getWCharType()).getQuantity();
1847+
Size *= APSInt(APInt(Size.getBitWidth(), WCharSize, /*IsSigned=*/false),
1848+
/*IsUnsigend=*/true);
1849+
}
1850+
18401851
if (Size.urem(DestElemSize) != 0) {
18411852
S.FFDiag(S.Current->getSource(OpPC),
18421853
diag::note_constexpr_memcpy_unsupported)
1843-
<< Move << /*IsWchar=*/false << 0 << DestElemType << Size
1844-
<< DestElemSize;
1854+
<< Move << WChar << 0 << DestElemType << Size << DestElemSize;
18451855
return false;
18461856
}
18471857

@@ -1869,7 +1879,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18691879
APInt N = Size.udiv(DestElemSize);
18701880
S.FFDiag(S.Current->getSource(OpPC),
18711881
diag::note_constexpr_memcpy_unsupported)
1872-
<< Move << /*IsWChar*/ false << (Size.ugt(RemainingSrcBytes) ? 1 : 2)
1882+
<< Move << WChar << (Size.ugt(RemainingSrcBytes) ? 1 : 2)
18731883
<< DestElemType << toString(N, 10, /*Signed=*/false);
18741884
return false;
18751885
}
@@ -2587,8 +2597,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
25872597

25882598
case Builtin::BI__builtin_memcpy:
25892599
case Builtin::BImemcpy:
2600+
case Builtin::BI__builtin_wmemcpy:
2601+
case Builtin::BIwmemcpy:
25902602
case Builtin::BI__builtin_memmove:
25912603
case Builtin::BImemmove:
2604+
case Builtin::BI__builtin_wmemmove:
2605+
case Builtin::BIwmemmove:
25922606
if (!interp__builtin_memcpy(S, OpPC, Frame, F, Call))
25932607
return false;
25942608
break;

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

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extern "C" {
3030
extern wchar_t *wcschr(const wchar_t *s, wchar_t c);
3131
extern int wcscmp(const wchar_t *s1, const wchar_t *s2);
3232
extern int wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n);
33+
extern wchar_t *wmemcpy(wchar_t *d, const wchar_t *s, size_t n);
3334
}
3435

3536
namespace strcmp {
@@ -1592,6 +1593,67 @@ namespace WMemChr {
15921593
// both-note {{non-constexpr function 'wcschr' cannot be used in a constant expression}}
15931594
}
15941595

1596+
namespace WMemCpy {
1597+
template<typename T>
1598+
constexpr T result(T (&arr)[4]) {
1599+
return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
1600+
}
1601+
constexpr int test_wmemcpy(int a, int b, int n) {
1602+
wchar_t arr[4] = {1, 2, 3, 4};
1603+
__builtin_wmemcpy(arr + a, arr + b, n);
1604+
// both-note@-1 2{{overlapping memory regions}}
1605+
// both-note@-2 {{source is not a contiguous array of at least 2 elements of type 'wchar_t'}}
1606+
// both-note@-3 {{destination is not a contiguous array of at least 3 elements of type 'wchar_t'}}
1607+
return result(arr);
1608+
}
1609+
static_assert(test_wmemcpy(1, 2, 1) == 1334);
1610+
static_assert(test_wmemcpy(2, 1, 1) == 1224);
1611+
static_assert(test_wmemcpy(0, 1, 2) == 2334); // both-error {{constant}} both-note {{in call}}
1612+
static_assert(test_wmemcpy(1, 0, 2) == 1124); // both-error {{constant}} both-note {{in call}}
1613+
static_assert(test_wmemcpy(1, 2, 1) == 1334);
1614+
static_assert(test_wmemcpy(0, 3, 1) == 4234);
1615+
static_assert(test_wmemcpy(0, 3, 2) == 4234); // both-error {{constant}} both-note {{in call}}
1616+
static_assert(test_wmemcpy(2, 0, 3) == 4234); // both-error {{constant}} both-note {{in call}}
1617+
1618+
wchar_t global;
1619+
constexpr wchar_t *null = 0;
1620+
static_assert(__builtin_wmemcpy(&global, null, sizeof(wchar_t))); // both-error {{}} \
1621+
// both-note {{source of 'wmemcpy' is nullptr}}
1622+
static_assert(__builtin_wmemcpy(null, &global, sizeof(wchar_t))); // both-error {{}} \
1623+
// both-note {{destination of 'wmemcpy' is nullptr}}
1624+
}
1625+
1626+
namespace WMemMove {
1627+
template<typename T>
1628+
constexpr T result(T (&arr)[4]) {
1629+
return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
1630+
}
1631+
1632+
constexpr int test_wmemmove(int a, int b, int n) {
1633+
wchar_t arr[4] = {1, 2, 3, 4};
1634+
__builtin_wmemmove(arr + a, arr + b, n);
1635+
// both-note@-1 {{source is not a contiguous array of at least 2 elements of type 'wchar_t'}}
1636+
// both-note@-2 {{destination is not a contiguous array of at least 3 elements of type 'wchar_t'}}
1637+
return result(arr);
1638+
}
1639+
1640+
static_assert(test_wmemmove(1, 2, 1) == 1334);
1641+
static_assert(test_wmemmove(2, 1, 1) == 1224);
1642+
static_assert(test_wmemmove(0, 1, 2) == 2334);
1643+
static_assert(test_wmemmove(1, 0, 2) == 1124);
1644+
static_assert(test_wmemmove(1, 2, 1) == 1334);
1645+
static_assert(test_wmemmove(0, 3, 1) == 4234);
1646+
static_assert(test_wmemmove(0, 3, 2) == 4234); // both-error {{constant}} both-note {{in call}}
1647+
static_assert(test_wmemmove(2, 0, 3) == 4234); // both-error {{constant}} both-note {{in call}}
1648+
1649+
wchar_t global;
1650+
constexpr wchar_t *null = 0;
1651+
static_assert(__builtin_wmemmove(&global, null, sizeof(wchar_t))); // both-error {{}} \
1652+
// both-note {{source of 'wmemmove' is nullptr}}
1653+
static_assert(__builtin_wmemmove(null, &global, sizeof(wchar_t))); // both-error {{}} \
1654+
// both-note {{destination of 'wmemmove' is nullptr}}
1655+
}
1656+
15951657
namespace Invalid {
15961658
constexpr int test() { // both-error {{never produces a constant expression}}
15971659
__builtin_abort(); // both-note 2{{subexpression not valid in a constant expression}}

0 commit comments

Comments
 (0)