Skip to content

Commit ab78cf1

Browse files
committed
[MemCpyOpt] Fix the invalid code modification for GEP
Relocate the GEP modification to a later stage of the function performCallSlotOption, ensuring that the code remains unchanged if the optimization fails.
1 parent 7b93611 commit ab78cf1

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,12 +1043,13 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
10431043

10441044
// Since we're changing the parameter to the callsite, we need to make sure
10451045
// that what would be the new parameter dominates the callsite.
1046+
bool NeedMoveGEP = false;
10461047
if (!DT->dominates(cpyDest, C)) {
10471048
// Support moving a constant index GEP before the call.
10481049
auto *GEP = dyn_cast<GetElementPtrInst>(cpyDest);
10491050
if (GEP && GEP->hasAllConstantIndices() &&
10501051
DT->dominates(GEP->getPointerOperand(), C))
1051-
GEP->moveBefore(C);
1052+
NeedMoveGEP = true;
10521053
else
10531054
return false;
10541055
}
@@ -1101,6 +1102,11 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
11011102
cast<AllocaInst>(cpyDest)->setAlignment(srcAlign);
11021103
}
11031104

1105+
if (NeedMoveGEP) {
1106+
auto *GEP = dyn_cast<GetElementPtrInst>(cpyDest);
1107+
GEP->moveBefore(C);
1108+
}
1109+
11041110
if (SkippedLifetimeStart) {
11051111
SkippedLifetimeStart->moveBefore(C);
11061112
MSSAU->moveBefore(MSSA->getMemoryAccess(SkippedLifetimeStart),
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -S -passes=memcpyopt < %s -verify-memoryssa | FileCheck %s
3+
4+
%struct.MaskedType = type { i8, i8 }
5+
6+
declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #0
7+
declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #0
8+
declare void @MaskedFunction1(ptr, ptr addrspace(1))
9+
declare void @MaskedFunction2(ptr, ptr)
10+
11+
define i8 @test_gep_not_modified(ptr %in0, ptr %in1) {
12+
; CHECK-LABEL: @test_gep_not_modified(
13+
; CHECK-NEXT: entry:
14+
; CHECK-NEXT: [[FUNCALLOC:%.*]] = alloca [[STRUCT_MASKEDTYPE:%.*]], align 4
15+
; CHECK-NEXT: [[PTRALLOC:%.*]] = alloca i8, align 1
16+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[PTRALLOC]])
17+
; CHECK-NEXT: [[ADDRSPACECAST:%.*]] = addrspacecast ptr [[PTRALLOC]] to ptr addrspace(1)
18+
; CHECK-NEXT: call void @MaskedFunction1(ptr [[IN1:%.*]], ptr addrspace(1) [[ADDRSPACECAST]])
19+
; CHECK-NEXT: [[LOAD1:%.*]] = load i8, ptr [[PTRALLOC]], align 1
20+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[PTRALLOC]])
21+
; CHECK-NEXT: [[GETELEMPTR1:%.*]] = getelementptr inbounds [[STRUCT_MASKEDTYPE]], ptr [[FUNCALLOC]], i32 0, i32 1
22+
; CHECK-NEXT: store i8 [[LOAD1]], ptr [[GETELEMPTR1]], align 1
23+
; CHECK-NEXT: ret i8 0
24+
;
25+
entry:
26+
%funcAlloc = alloca %struct.MaskedType, align 4
27+
%ptrAlloc = alloca i8, align 1
28+
call void @llvm.lifetime.start.p0(i64 4, ptr %ptrAlloc) #0
29+
%addrspaceCast = addrspacecast ptr %ptrAlloc to ptr addrspace(1)
30+
call void @MaskedFunction1(ptr %in1, ptr addrspace(1) %addrspaceCast)
31+
%load1 = load i8, ptr %ptrAlloc, align 1
32+
call void @llvm.lifetime.end.p0(i64 4, ptr %ptrAlloc) #0
33+
%getElemPtr1 = getelementptr inbounds %struct.MaskedType, ptr %funcAlloc, i32 0, i32 1
34+
store i8 %load1, ptr %getElemPtr1, align 1
35+
ret i8 0
36+
}
37+
38+
define i8 @test_gep_modified(ptr %in0, ptr %in1) {
39+
; CHECK-LABEL: @test_gep_modified(
40+
; CHECK-NEXT: entry:
41+
; CHECK-NEXT: [[FUNCALLOC:%.*]] = alloca [[STRUCT_MASKEDTYPE:%.*]], align 4
42+
; CHECK-NEXT: [[PTRALLOC:%.*]] = alloca i8, align 1
43+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[PTRALLOC]])
44+
; CHECK-NEXT: [[GETELEMPTR1:%.*]] = getelementptr inbounds [[STRUCT_MASKEDTYPE]], ptr [[FUNCALLOC]], i32 0, i32 1
45+
; CHECK-NEXT: call void @MaskedFunction2(ptr [[IN1:%.*]], ptr [[GETELEMPTR1]])
46+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[PTRALLOC]])
47+
; CHECK-NEXT: ret i8 0
48+
;
49+
entry:
50+
%funcAlloc = alloca %struct.MaskedType, align 4
51+
%ptrAlloc = alloca i8, align 1
52+
call void @llvm.lifetime.start.p0(i64 4, ptr %ptrAlloc) #0
53+
call void @MaskedFunction2(ptr %in1, ptr %ptrAlloc)
54+
%load1 = load i8, ptr %ptrAlloc, align 1
55+
call void @llvm.lifetime.end.p0(i64 4, ptr %ptrAlloc) #0
56+
%getElemPtr1 = getelementptr inbounds %struct.MaskedType, ptr %funcAlloc, i32 0, i32 1
57+
store i8 %load1, ptr %getElemPtr1, align 1
58+
ret i8 0
59+
}
60+

0 commit comments

Comments
 (0)