Skip to content

Commit d606d63

Browse files
committed
Add support for mismatched array sizes
1 parent a761a05 commit d606d63

File tree

2 files changed

+45
-19
lines changed

2 files changed

+45
-19
lines changed

llvm/lib/Target/DirectX/DXILLegalizePass.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -268,36 +268,41 @@ static void emitMemcpyExpansion(IRBuilder<> &Builder, Value *Dst, Value *Src,
268268
return nullptr;
269269
};
270270

271-
ArrayType *ArrTy = GetArrTyFromVal(Dst);
272-
assert(ArrTy && "Expected Dst of memcpy to be a Pointer to an Array Type");
271+
ArrayType *DstArrTy = GetArrTyFromVal(Dst);
272+
assert(DstArrTy && "Expected Dst of memcpy to be a Pointer to an Array Type");
273273
if (auto *DstGlobalVar = dyn_cast<GlobalVariable>(Dst))
274274
assert(!DstGlobalVar->isConstant() &&
275275
"The Dst of memcpy must not be a constant Global Variable");
276-
277276
[[maybe_unused]] ArrayType *SrcArrTy = GetArrTyFromVal(Src);
278277
assert(SrcArrTy && "Expected Src of memcpy to be a Pointer to an Array Type");
279278

279+
Type *DstElemTy = DstArrTy->getElementType();
280+
uint64_t DstElemByteSize = DL.getTypeStoreSize(DstElemTy);
281+
assert(DstElemByteSize > 0 && "Dst element type store size must be set");
282+
Type *SrcElemTy = SrcArrTy->getElementType();
283+
[[maybe_unused]] uint64_t SrcElemByteSize = DL.getTypeStoreSize(SrcElemTy);
284+
assert(SrcElemByteSize > 0 && "Src element type store size must be set");
285+
280286
// This assumption simplifies implementation and covers currently-known
281287
// use-cases for DXIL. It may be relaxed in the future if required.
282-
assert(ArrTy == SrcArrTy &&
283-
"Array Types of Src and Dst in memcpy must match");
284-
285-
Type *ElemTy = ArrTy->getElementType();
286-
uint64_t ElemSize = DL.getTypeStoreSize(ElemTy);
287-
assert(ElemSize > 0 && "Size must be set");
288-
289-
[[maybe_unused]] uint64_t Size = ArrTy->getArrayNumElements();
290-
assert(ElemSize * Size >= ByteLength &&
291-
"Array size must be at least as large as the memcpy length");
292-
293-
uint64_t NumElemsToCopy = ByteLength / ElemSize;
294-
assert(ByteLength % ElemSize == 0 &&
288+
assert(DstElemTy == SrcElemTy &&
289+
"The element types of Src and Dst arrays must match");
290+
291+
[[maybe_unused]] uint64_t DstArrNumElems = DstArrTy->getArrayNumElements();
292+
assert(DstElemByteSize * DstArrNumElems >= ByteLength &&
293+
"Dst array size must be at least as large as the memcpy length");
294+
[[maybe_unused]] uint64_t SrcArrNumElems = SrcArrTy->getArrayNumElements();
295+
assert(SrcElemByteSize * SrcArrNumElems >= ByteLength &&
296+
"Src array size must be at least as large as the memcpy length");
297+
298+
uint64_t NumElemsToCopy = ByteLength / DstElemByteSize;
299+
assert(ByteLength % DstElemByteSize == 0 &&
295300
"memcpy length must be divisible by array element type");
296301
for (uint64_t I = 0; I < NumElemsToCopy; ++I) {
297302
Value *Offset = ConstantInt::get(Type::getInt32Ty(Ctx), I);
298-
Value *SrcPtr = Builder.CreateInBoundsGEP(ElemTy, Src, Offset, "gep");
299-
Value *SrcVal = Builder.CreateLoad(ElemTy, SrcPtr);
300-
Value *DstPtr = Builder.CreateInBoundsGEP(ElemTy, Dst, Offset, "gep");
303+
Value *SrcPtr = Builder.CreateInBoundsGEP(SrcElemTy, Src, Offset, "gep");
304+
Value *SrcVal = Builder.CreateLoad(SrcElemTy, SrcPtr);
305+
Value *DstPtr = Builder.CreateInBoundsGEP(DstElemTy, Dst, Offset, "gep");
301306
Builder.CreateStore(SrcVal, DstPtr);
302307
}
303308
}

llvm/test/CodeGen/DirectX/legalize-memcpy.ll

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,27 @@ define void @replace_3int_memcpy_test() #0 {
4343
ret void
4444
}
4545

46+
define void @replace_mismatched_size_int_memcpy_test() #0 {
47+
; CHECK-LABEL: define void @replace_mismatched_size_int_memcpy_test(
48+
; CHECK-SAME: ) #[[ATTR0]] {
49+
; CHECK-NEXT: [[TMP1:%.*]] = alloca [2 x i32], align 4
50+
; CHECK-NEXT: [[TMP2:%.*]] = alloca [3 x i32], align 4
51+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i32 0
52+
; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[GEP]], align 4
53+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i32 0
54+
; CHECK-NEXT: store i32 [[TMP3]], ptr [[GEP1]], align 4
55+
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i32 1
56+
; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[GEP2]], align 4
57+
; CHECK-NEXT: [[GEP3:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i32 1
58+
; CHECK-NEXT: store i32 [[TMP4]], ptr [[GEP3]], align 4
59+
; CHECK-NEXT: ret void
60+
;
61+
%1 = alloca [2 x i32], align 4
62+
%2 = alloca [3 x i32], align 4
63+
call void @llvm.memcpy.p0.p0.i32(ptr nonnull align 4 dereferenceable(12) %2, ptr align 4 dereferenceable(8) %1, i32 8, i1 false)
64+
ret void
65+
}
66+
4667
define void @replace_int16_memcpy_test() #0 {
4768
; CHECK-LABEL: define void @replace_int16_memcpy_test(
4869
; CHECK-SAME: ) #[[ATTR0]] {

0 commit comments

Comments
 (0)