[LoadStoreVectorizer] Check for guaranteed-to-transfer (PR52950)
authorNikita Popov <npopov@redhat.com>
Mon, 3 Jan 2022 09:55:47 +0000 (10:55 +0100)
committerNikita Popov <npopov@redhat.com>
Mon, 3 Jan 2022 09:55:47 +0000 (10:55 +0100)
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.

llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp
llvm/test/Transforms/LoadStoreVectorizer/NVPTX/merge-across-side-effects.ll
llvm/test/Transforms/LoadStoreVectorizer/int_sideeffect.ll

index 5a4a2f0..d2e0d1d 100644 (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())
index 72c13b4..73623da 100644 (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 }
index 23108e3..bd47d66 100644 (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
@@ -70,6 +70,41 @@ define void @test_inaccessiblememonly(float* %p) {
   %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
+  %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
   %l3 = load float, float* %p3
   store float %l0, float* %p0, align 16
@@ -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
+}