Skip to content

Commit 2e57c8f

Browse files
committed
Improve handling of memmove when Lenght > size of the type to move
It is possible that for a single element Src type size doesn't match memory size to move (for example we copy N elements of one integer array to an address of a first element of another integer array). Signed-off-by: Dmitry Sidorov <[email protected]>
1 parent b5441a4 commit 2e57c8f

File tree

2 files changed

+47
-19
lines changed

2 files changed

+47
-19
lines changed

lib/SPIRV/SPIRVLowerMemmove.cpp

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,34 +63,31 @@ class SPIRVLowerMemmoveBase {
6363
if (isa<PHINode>(Src))
6464
report_fatal_error("llvm.memmove of PHI instruction result not supported",
6565
false);
66-
auto *SrcTy = Src->getType();
67-
auto *Length = cast<ConstantInt>(I.getLength());
68-
auto *S = Src;
6966
// The source could be bit-cast or addrspacecast from another type,
7067
// need the original type for the allocation of the temporary variable
71-
while (isa<BitCastInst>(S) || isa<AddrSpaceCastInst>(S))
72-
S = cast<CastInst>(S)->getOperand(0);
73-
SrcTy = S->getType();
68+
auto *SrcTy = Src->stripPointerCasts()->getType();
69+
auto *Length = cast<ConstantInt>(I.getLength());
7470
MaybeAlign Align = I.getSourceAlign();
7571
auto Volatile = I.isVolatile();
7672
Value *NumElements = nullptr;
7773
uint64_t ElementsCount = 1;
7874
if (SrcTy->isArrayTy()) {
79-
NumElements = Builder.getInt32(SrcTy->getArrayNumElements());
8075
ElementsCount = SrcTy->getArrayNumElements();
76+
NumElements = Builder.getInt32(ElementsCount);
8177
}
82-
if (((ElementsCount > 1) && (Mod->getDataLayout().getTypeSizeInBits(
83-
SrcTy->getPointerElementType()) *
84-
ElementsCount !=
85-
Length->getZExtValue() * 8)) ||
86-
((ElementsCount == 1) &&
87-
(Mod->getDataLayout().getTypeSizeInBits(
88-
SrcTy->getPointerElementType()) < Length->getZExtValue() * 8)))
89-
report_fatal_error("Size of the memcpy should match the allocated memory",
90-
false);
91-
92-
auto *Alloca =
93-
Builder.CreateAlloca(SrcTy->getPointerElementType(), NumElements);
78+
// Get number of bits to move and allocate memory appropriately:
79+
// if lenght is bigger than a pointer base type size, then create an
80+
// alloca of an array type with the same base type.
81+
const uint64_t LenBits = Length->getZExtValue();
82+
const uint64_t LayoutTypeBites =
83+
Mod->getDataLayout().getTypeSizeInBits(SrcTy->getPointerElementType()) *
84+
ElementsCount;
85+
auto *AllocaTy = SrcTy->getPointerElementType();
86+
if (LenBits > LayoutTypeBites) {
87+
const uint64_t ArraySize = LenBits / LayoutTypeBites;
88+
AllocaTy = ArrayType::get(SrcTy->getPointerElementType(), ArraySize);
89+
}
90+
auto *Alloca = Builder.CreateAlloca(AllocaTy, NumElements);
9491
if (Align.hasValue()) {
9592
Alloca->setAlignment(Align.getValue());
9693
}

test/llvm-intrinsics/memmove.ll

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
; CHECK-SPIRV-NOT: llvm.memmove
99

10+
; CHECK-SPIRV: TypeInt [[#TYPEINT:]] 32
11+
; CHECK-SPIRV: Constant [[#TYPEINT]] [[#ARRSIZE:]] 128
12+
1013
; CHECK-SPIRV: Variable {{[0-9]+}} [[mem:[0-9]+]] 7
1114
; CHECK-SPIRV: Bitcast [[i8Ty:[0-9]+]] [[tmp0:[0-9]+]] [[mem]]
1215
; CHECK-SPIRV: LifetimeStart [[tmp0]] [[size:[0-9]+]]
@@ -28,6 +31,16 @@
2831
; CHECK-SPIRV: Bitcast [[i8Ty]] [[tmp3:[0-9]+]] [[mem]]
2932
; CHECK-SPIRV: LifetimeStop [[tmp3]] [[size]]
3033

34+
; CHECK-SPIRV: Variable [[#]] [[#VAR:]]
35+
; CHECK-SPIRV: Bitcast [[i8Ty:[0-9]+]] [[#TMP0:]] [[#VAR]]
36+
; CHECK-SPIRV: LifetimeStart [[#TMP0]]
37+
; CHECK-SPIRV: Bitcast [[i8Ty]] [[#TMP1:]] [[#VAR]]
38+
; CHECK-SPIRV: CopyMemorySized [[#TMP1]] [[#]] [[#ARRSIZE]]
39+
; CHECK-SPIRV: Bitcast [[i8Ty]] [[#TMP2:]] [[#VAR]]
40+
; CHECK-SPIRV: CopyMemorySized [[#]] [[#TMP2]] [[#ARRSIZE]]
41+
; CHECK-SPIRV: Bitcast [[i8Ty]] [[#TMP3:]] [[#VAR]]
42+
; CHECK-SPIRV: LifetimeStop [[#TMP3]]
43+
3144
; CHECK-LLVM-NOT: llvm.memmove
3245

3346
; CHECK-LLVM-LABEL: @test_struct
@@ -60,6 +73,18 @@
6073
; CHECK-LLVM: [[tmp4:%[0-9]+]] = bitcast %struct.SomeStruct* [[local]] to [[type]]
6174
; CHECK-LLVM: call void @llvm.lifetime.end.p0i8({{i[0-9]+}} {{-?[0-9]+}}, [[type]] [[tmp4]])
6275

76+
; CHECK-LLVM-LABEL: @test_array
77+
; CHECK-LLVM: %[[#ALLOCA:]] = alloca [16 x i8], align 1
78+
; CHECK-LLVM: %[[#TMP0:]] = bitcast [16 x i8]* %[[#ALLOCA]] to i8*
79+
; CHECK-LLVM: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %[[#TMP0]])
80+
; CHECK-LLVM: %[[#TMP1:]] = bitcast [16 x i8]* %[[#ALLOCA]] to i8*
81+
; CHECK-LLVM: call void @llvm.memcpy.p0i8.p1i8.i32(i8* %[[#TMP1]], i8 addrspace(1)* %out, i32 128, i1 false)
82+
; CHECK-LLVM: %[[#TMP2:]] = bitcast [16 x i8]* %[[#ALLOCA]] to i8*
83+
; CHECK-LLVM: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)* %in, i8* %[[#TMP2]], i32 128, i1 false)
84+
; CHECK-LLVM: %[[#TMP3:]] = bitcast [16 x i8]* %[[#ALLOCA]] to i8*
85+
; CHECK-LLVM: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %[[#TMP3]])
86+
87+
6388
target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
6489
target triple = "spir-unknown-unknown"
6590

@@ -81,6 +106,12 @@ define spir_func void @copy_struct(%struct.SomeStruct addrspace(1)* nocapture re
81106
ret void
82107
}
83108

109+
; Function Attrs: nounwind
110+
define spir_kernel void @test_array(i8 addrspace(1)* %in, i8 addrspace(1)* %out) {
111+
call void @llvm.memmove.p1i8.p1i8.i32(i8 addrspace(1)* %in, i8 addrspace(1)* %out, i32 128, i1 false)
112+
ret void
113+
}
114+
84115
; Function Attrs: nounwind
85116
declare void @llvm.memmove.p1i8.p1i8.i32(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i32, i1) #1
86117

0 commit comments

Comments
 (0)