[LoadStoreVectorizer] Check for guaranteed-to-transfer (PR52950)

Rather than checking for nounwind in particular, make sure the
instruction is guaranteed to transfer execution, which will also
handle non-willreturn calls correctly.

Fixes https://github.com/llvm/llvm-project/issues/52950.
This commit is contained in:
Nikita Popov 2022-01-03 10:55:47 +01:00
parent 127d955441
commit 330cb03269
3 changed files with 79 additions and 8 deletions

View File

@ -698,8 +698,9 @@ Vectorizer::getVectorizablePrefix(ArrayRef<Instruction *> Chain) {
ChainInstrs.push_back(&I);
continue;
}
if (I.mayThrow()) {
LLVM_DEBUG(dbgs() << "LSV: Found may-throw operation: " << I << '\n');
if (!isGuaranteedToTransferExecutionToSuccessor(&I)) {
LLVM_DEBUG(dbgs() << "LSV: Found instruction may not transfer execution: "
<< I << '\n');
break;
}
if (I.mayReadOrWriteMemory())

View File

@ -200,10 +200,10 @@ define void @store_fn_readnone(i32* %p) #0 {
}
attributes #0 = { nounwind }
attributes #1 = { nounwind writeonly }
attributes #2 = { nounwind readonly }
attributes #0 = { nounwind willreturn }
attributes #1 = { nounwind willreturn writeonly }
attributes #2 = { nounwind readonly willreturn }
attributes #3 = { writeonly }
attributes #4 = { readonly }
; readnone implies nounwind, so no need to test separately
attributes #5 = { nounwind readnone }
attributes #5 = { nounwind willreturn readnone }

View File

@ -44,8 +44,8 @@ define void @test_sideeffect(float* %p) {
declare void @foo()
define void @test_inaccessiblememonly(float* %p) {
; CHECK-LABEL: @test_inaccessiblememonly(
define void @test_inaccessiblememonly_nounwind_willreturn(float* %p) {
; CHECK-LABEL: @test_inaccessiblememonly_nounwind_willreturn(
; CHECK-NEXT: [[P0:%.*]] = getelementptr float, float* [[P:%.*]], i64 0
; CHECK-NEXT: [[TMP1:%.*]] = bitcast float* [[P0]] to <4 x float>*
; CHECK-NEXT: [[TMP2:%.*]] = load <4 x float>, <4 x float>* [[TMP1]], align 16
@ -62,6 +62,41 @@ define void @test_inaccessiblememonly(float* %p) {
; CHECK-NEXT: [[TMP7:%.*]] = bitcast float* [[P0]] to <4 x float>*
; CHECK-NEXT: store <4 x float> [[TMP6]], <4 x float>* [[TMP7]], align 16
; CHECK-NEXT: ret void
;
%p0 = getelementptr float, float* %p, i64 0
%p1 = getelementptr float, float* %p, i64 1
%p2 = getelementptr float, float* %p, i64 2
%p3 = getelementptr float, float* %p, i64 3
%l0 = load float, float* %p0, align 16
%l1 = load float, float* %p1
%l2 = load float, float* %p2
call void @foo() inaccessiblememonly nounwind willreturn
%l3 = load float, float* %p3
store float %l0, float* %p0, align 16
call void @foo() inaccessiblememonly nounwind willreturn
store float %l1, float* %p1
store float %l2, float* %p2
store float %l3, float* %p3
ret void
}
define void @test_inaccessiblememonly_not_willreturn(float* %p) {
; CHECK-LABEL: @test_inaccessiblememonly_not_willreturn(
; CHECK-NEXT: [[P0:%.*]] = getelementptr float, float* [[P:%.*]], i64 0
; CHECK-NEXT: [[P1:%.*]] = getelementptr float, float* [[P]], i64 1
; CHECK-NEXT: [[P2:%.*]] = getelementptr float, float* [[P]], i64 2
; CHECK-NEXT: [[P3:%.*]] = getelementptr float, float* [[P]], i64 3
; CHECK-NEXT: [[L0:%.*]] = load float, float* [[P0]], align 16
; CHECK-NEXT: [[L1:%.*]] = load float, float* [[P1]], align 4
; CHECK-NEXT: [[L2:%.*]] = load float, float* [[P2]], align 4
; CHECK-NEXT: call void @foo() #[[ATTR2:[0-9]+]]
; CHECK-NEXT: [[L3:%.*]] = load float, float* [[P3]], align 4
; CHECK-NEXT: store float [[L0]], float* [[P0]], align 16
; CHECK-NEXT: call void @foo() #[[ATTR2]]
; CHECK-NEXT: store float [[L1]], float* [[P1]], align 4
; CHECK-NEXT: store float [[L2]], float* [[P2]], align 4
; CHECK-NEXT: store float [[L3]], float* [[P3]], align 4
; CHECK-NEXT: ret void
;
%p0 = getelementptr float, float* %p, i64 0
%p1 = getelementptr float, float* %p, i64 1
@ -79,3 +114,38 @@ define void @test_inaccessiblememonly(float* %p) {
store float %l3, float* %p3
ret void
}
define void @test_inaccessiblememonly_not_nounwind(float* %p) {
; CHECK-LABEL: @test_inaccessiblememonly_not_nounwind(
; CHECK-NEXT: [[P0:%.*]] = getelementptr float, float* [[P:%.*]], i64 0
; CHECK-NEXT: [[P1:%.*]] = getelementptr float, float* [[P]], i64 1
; CHECK-NEXT: [[P2:%.*]] = getelementptr float, float* [[P]], i64 2
; CHECK-NEXT: [[P3:%.*]] = getelementptr float, float* [[P]], i64 3
; CHECK-NEXT: [[L0:%.*]] = load float, float* [[P0]], align 16
; CHECK-NEXT: [[L1:%.*]] = load float, float* [[P1]], align 4
; CHECK-NEXT: [[L2:%.*]] = load float, float* [[P2]], align 4
; CHECK-NEXT: call void @foo() #[[ATTR3:[0-9]+]]
; CHECK-NEXT: [[L3:%.*]] = load float, float* [[P3]], align 4
; CHECK-NEXT: store float [[L0]], float* [[P0]], align 16
; CHECK-NEXT: call void @foo() #[[ATTR3]]
; CHECK-NEXT: store float [[L1]], float* [[P1]], align 4
; CHECK-NEXT: store float [[L2]], float* [[P2]], align 4
; CHECK-NEXT: store float [[L3]], float* [[P3]], align 4
; CHECK-NEXT: ret void
;
%p0 = getelementptr float, float* %p, i64 0
%p1 = getelementptr float, float* %p, i64 1
%p2 = getelementptr float, float* %p, i64 2
%p3 = getelementptr float, float* %p, i64 3
%l0 = load float, float* %p0, align 16
%l1 = load float, float* %p1
%l2 = load float, float* %p2
call void @foo() inaccessiblememonly willreturn
%l3 = load float, float* %p3
store float %l0, float* %p0, align 16
call void @foo() inaccessiblememonly willreturn
store float %l1, float* %p1
store float %l2, float* %p2
store float %l3, float* %p3
ret void
}