Skip to content

Commit c4184ff

Browse files
authored
Implement support for dynamic memmove (#1060)
* Implement support for dynamic memmove Use LLVM expandMemMoveAsLoop function in case memmove intrinsic use has non-constant length.
1 parent 75e0b0e commit c4184ff

File tree

2 files changed

+58
-12
lines changed

2 files changed

+58
-12
lines changed

lib/SPIRV/SPIRVLowerMemmove.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,21 @@
4141
#include "libSPIRV/SPIRVDebug.h"
4242

4343
#include "llvm/IR/IRBuilder.h"
44-
#include "llvm/IR/InstVisitor.h"
4544
#include "llvm/IR/IntrinsicInst.h"
4645
#include "llvm/IR/Module.h"
4746
#include "llvm/IR/PassManager.h"
4847
#include "llvm/Pass.h"
48+
#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
4949

5050
using namespace llvm;
5151
using namespace SPIRV;
5252

5353
namespace SPIRV {
5454

55-
class SPIRVLowerMemmoveBase : public InstVisitor<SPIRVLowerMemmoveBase> {
55+
class SPIRVLowerMemmoveBase {
5656
public:
57-
SPIRVLowerMemmoveBase() : Context(nullptr) {}
58-
virtual ~SPIRVLowerMemmoveBase() {}
59-
virtual void visitMemMoveInst(MemMoveInst &I) {
57+
SPIRVLowerMemmoveBase() : Context(nullptr), Mod(nullptr) {}
58+
void LowerMemMoveInst(MemMoveInst &I) {
6059
IRBuilder<> Builder(I.getParent());
6160
Builder.SetInsertPoint(&I);
6261
auto *Dest = I.getRawDest();
@@ -65,11 +64,6 @@ class SPIRVLowerMemmoveBase : public InstVisitor<SPIRVLowerMemmoveBase> {
6564
report_fatal_error("llvm.memmove of PHI instruction result not supported",
6665
false);
6766
auto *SrcTy = Src->getType();
68-
if (!isa<ConstantInt>(I.getLength()))
69-
// ToDo: for non-constant length, could use a loop to copy a
70-
// fixed length chunk at a time. For now simply fail
71-
report_fatal_error("llvm.memmove of non-constant length not supported",
72-
false);
7367
auto *Length = cast<ConstantInt>(I.getLength());
7468
auto *S = Src;
7569
// The source could be bit-cast or addrspacecast from another type,
@@ -111,13 +105,36 @@ class SPIRVLowerMemmoveBase : public InstVisitor<SPIRVLowerMemmoveBase> {
111105
I.dropAllReferences();
112106
I.eraseFromParent();
113107
}
108+
bool expandMemMoveIntrinsicUses(Function &F) {
109+
bool Changed = false;
110+
111+
for (User *U : make_early_inc_range(F.users())) {
112+
MemMoveInst *Inst = cast<MemMoveInst>(U);
113+
if (!isa<ConstantInt>(Inst->getLength())) {
114+
expandMemMoveAsLoop(Inst);
115+
Inst->eraseFromParent();
116+
} else {
117+
LowerMemMoveInst(*Inst);
118+
}
119+
Changed = true;
120+
}
121+
return Changed;
122+
}
114123
bool runLowerMemmove(Module &M) {
115124
Context = &M.getContext();
116125
Mod = &M;
117-
visit(M);
126+
bool Changed = false;
127+
128+
for (Function &F : M) {
129+
if (!F.isDeclaration())
130+
continue;
131+
132+
if (F.getIntrinsicID() == Intrinsic::memmove)
133+
Changed |= expandMemMoveIntrinsicUses(F);
134+
}
118135

119136
verifyRegularizationPass(M, "SPIRVLowerMemmove");
120-
return true;
137+
return Changed;
121138
}
122139

123140
private:
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt
3+
; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV
4+
; RUN: llvm-spirv %t.bc -o %t.spv
5+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
6+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
7+
8+
; CHECK-SPIRV-NOT: llvm.memmove
9+
10+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
11+
target triple = "spir64-unknown-unknown"
12+
13+
declare void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i64, i1)
14+
15+
define spir_func void @memmove_caller(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 %n) {
16+
entry:
17+
call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 %n, i1 false)
18+
call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 %n, i1 false)
19+
call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 %n, i1 false)
20+
ret void
21+
22+
; CHECK-LLVM: @memmove_caller(i8 addrspace(1)* [[DST:%.*]], i8 addrspace(1)* [[SRC:%.*]], i64 [[N:%.*]])
23+
; CHECK-LLVM: [[SRC_CMP:%.*]] = ptrtoint i8 addrspace(1)* [[SRC]] to i64
24+
; CHECK-LLVM: [[DST_CMP:%.*]] = ptrtoint i8 addrspace(1)* [[DST]] to i64
25+
; CHECK-LLVM: [[COMPARE_SRC_DST:%.*]] = icmp ult i64 [[SRC_CMP]], [[DST_CMP]]
26+
; CHECK-LLVM-NEXT: [[COMPARE_N_TO_0:%.*]] = icmp eq i64 [[N]], 0
27+
; CHECK-LLVM-NEXT: br i1 [[COMPARE_SRC_DST]], label %[[COPY_BACKWARDS:.*]], label %[[COPY_FORWARD:.*]]
28+
; CHECK-LLVM: [[COPY_BACKWARDS]]:
29+
}

0 commit comments

Comments
 (0)