Skip to content

Commit bc7ea63

Browse files
authored
[MemCpyOpt] handle memcpy from memset for non-constant sizes (#143727)
Allows forwarding memset to memcpy for mismatching unknown sizes if overread has undef contents. In that case we can refine the undef bytes to the memset value. Refs #140954 which laid some of the groundwork for this.
1 parent 6c72084 commit bc7ea63

File tree

2 files changed

+22
-22
lines changed

2 files changed

+22
-22
lines changed

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,7 +1440,7 @@ bool MemCpyOptPass::performMemCpyToMemSetOptzn(MemCpyInst *MemCpy,
14401440
int64_t MOffset = 0;
14411441
const DataLayout &DL = MemCpy->getModule()->getDataLayout();
14421442
// We can only transforms memcpy's where the dest of one is the source of the
1443-
// other, or the memory transfer has a known offset from the memset.
1443+
// other, or they have a known offset.
14441444
if (MemCpy->getSource() != MemSet->getDest()) {
14451445
std::optional<int64_t> Offset =
14461446
MemCpy->getSource()->getPointerOffsetFrom(MemSet->getDest(), DL);
@@ -1451,28 +1451,28 @@ bool MemCpyOptPass::performMemCpyToMemSetOptzn(MemCpyInst *MemCpy,
14511451

14521452
if (MOffset != 0 || MemSetSize != CopySize) {
14531453
// Make sure the memcpy doesn't read any more than what the memset wrote,
1454-
// other than undef. Don't worry about sizes larger than i64. A known memset
1455-
// size is required.
1454+
// other than undef. Don't worry about sizes larger than i64.
14561455
auto *CMemSetSize = dyn_cast<ConstantInt>(MemSetSize);
1457-
if (!CMemSetSize)
1458-
return false;
1459-
1460-
// A known memcpy size is also required.
14611456
auto *CCopySize = dyn_cast<ConstantInt>(CopySize);
1462-
if (!CCopySize)
1463-
return false;
1464-
if (CCopySize->getZExtValue() + MOffset > CMemSetSize->getZExtValue()) {
1457+
if (!CMemSetSize || !CCopySize ||
1458+
CCopySize->getZExtValue() + MOffset > CMemSetSize->getZExtValue()) {
14651459
if (!overreadUndefContents(MSSA, MemCpy, MemSet, BAA))
14661460
return false;
1467-
// Clip the memcpy to the bounds of the memset
1468-
if (MOffset == 0)
1469-
CopySize = MemSetSize;
1470-
else
1471-
CopySize =
1472-
ConstantInt::get(CopySize->getType(),
1473-
CMemSetSize->getZExtValue() <= (uint64_t)MOffset
1474-
? 0
1475-
: CMemSetSize->getZExtValue() - MOffset);
1461+
1462+
if (CMemSetSize && CCopySize) {
1463+
// If both have constant sizes and offsets, clip the memcpy to the
1464+
// bounds of the memset if applicable.
1465+
assert(CCopySize->getZExtValue() + MOffset >
1466+
CMemSetSize->getZExtValue());
1467+
if (MOffset == 0)
1468+
CopySize = MemSetSize;
1469+
else
1470+
CopySize =
1471+
ConstantInt::get(CopySize->getType(),
1472+
CMemSetSize->getZExtValue() <= (uint64_t)MOffset
1473+
? 0
1474+
: CMemSetSize->getZExtValue() - MOffset);
1475+
}
14761476
}
14771477
}
14781478

llvm/test/Transforms/MemCpyOpt/variable-sized-memset-memcpy.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ define void @test(ptr %src, i8 %c, i64 %size) {
1919
}
2020

2121
; Differing sizes, but would be UB if size1 < size2 since the memcpy would reference outside of the first alloca
22-
define void @negative_test(ptr %src, i8 %c, i64 %size1, i64 %size2) {
23-
; CHECK-LABEL: @negative_test(
22+
define void @dynsize_test(ptr %src, i8 %c, i64 %size1, i64 %size2) {
23+
; CHECK-LABEL: @dynsize_test(
2424
; CHECK-NEXT: [[DST1:%.*]] = alloca i8, i64 [[SIZE1:%.*]], align 1
2525
; CHECK-NEXT: [[DST2:%.*]] = alloca i8, i64 [[SIZE2:%.*]], align 1
2626
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[DST1]], i8 [[C:%.*]], i64 [[SIZE1]], i1 false)
27-
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[DST2]], ptr align 8 [[DST1]], i64 [[SIZE2]], i1 false)
27+
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[DST2]], i8 [[C]], i64 [[SIZE2]], i1 false)
2828
; CHECK-NEXT: ret void
2929
;
3030
%dst1 = alloca i8, i64 %size1

0 commit comments

Comments
 (0)