Skip to content

[LICM] Only check for provenance captures #141731

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 28, 2025
Merged

Conversation

nikic
Copy link
Contributor

@nikic nikic commented May 28, 2025

When performing scalar promotions, only consider provenance captures, which may lead to non-thread-safe accesses. Address captures can be ignored.

nikic added 2 commits May 28, 2025 10:47
When performing scalar promotions, only consider provenance
escapes, which may lead to non-thread-safe accesses. Address captures
can be ignored.
@llvmbot
Copy link
Member

llvmbot commented May 28, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Nikita Popov (nikic)

Changes

When performing scalar promotions, only consider provenance captures, which may lead to non-thread-safe accesses. Address captures can be ignored.


Full diff: https://github.com/llvm/llvm-project/pull/141731.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/LICM.cpp (+3-2)
  • (modified) llvm/test/Transforms/LICM/promote-capture.ll (+52)
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 006a09b38bc71..7965ed76a81b7 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -1928,8 +1928,9 @@ bool isNotCapturedBeforeOrInLoop(const Value *V, const Loop *L,
   // loop header, as the loop header is reachable from any instruction inside
   // the loop.
   // TODO: ReturnCaptures=true shouldn't be necessary here.
-  return !PointerMayBeCapturedBefore(V, /* ReturnCaptures */ true,
-                                     L->getHeader()->getTerminator(), DT);
+  return capturesNothing(PointerMayBeCapturedBefore(
+      V, /*ReturnCaptures=*/true, L->getHeader()->getTerminator(), DT,
+      /*IncludeI=*/false, CaptureComponents::Provenance));
 }
 
 /// Return true if we can prove that a caller cannot inspect the object if an
diff --git a/llvm/test/Transforms/LICM/promote-capture.ll b/llvm/test/Transforms/LICM/promote-capture.ll
index 5cbe158e47a3c..eac670e6f3edd 100644
--- a/llvm/test/Transforms/LICM/promote-capture.ll
+++ b/llvm/test/Transforms/LICM/promote-capture.ll
@@ -158,6 +158,58 @@ exit:
   ret void
 }
 
+define void @test_captured_before_loop_address_only(i32 %len) {
+; CHECK-LABEL: @test_captured_before_loop_address_only(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COUNT:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    store i32 0, ptr [[COUNT]], align 4
+; CHECK-NEXT:    call void @capture(ptr captures(address) [[COUNT]])
+; CHECK-NEXT:    [[COUNT_PROMOTED:%.*]] = load i32, ptr [[COUNT]], align 4
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[C_INC2:%.*]] = phi i32 [ [[COUNT_PROMOTED]], [[ENTRY:%.*]] ], [ [[C_INC1:%.*]], [[LATCH:%.*]] ]
+; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[I_NEXT:%.*]], [[LATCH]] ]
+; CHECK-NEXT:    [[COND:%.*]] = call i1 @cond(i32 [[I]])
+; CHECK-NEXT:    br i1 [[COND]], label [[IF:%.*]], label [[LATCH]]
+; CHECK:       if:
+; CHECK-NEXT:    [[C_INC:%.*]] = add i32 [[C_INC2]], 1
+; CHECK-NEXT:    br label [[LATCH]]
+; CHECK:       latch:
+; CHECK-NEXT:    [[C_INC1]] = phi i32 [ [[C_INC]], [[IF]] ], [ [[C_INC2]], [[LOOP]] ]
+; CHECK-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[I_NEXT]], [[LEN:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[C_INC1_LCSSA:%.*]] = phi i32 [ [[C_INC1]], [[LATCH]] ]
+; CHECK-NEXT:    store i32 [[C_INC1_LCSSA]], ptr [[COUNT]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %count = alloca i32
+  store i32 0, ptr %count
+  call void @capture(ptr captures(address) %count)
+  br label %loop
+
+loop:
+  %i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
+  %cond = call i1 @cond(i32 %i)
+  br i1 %cond, label %if, label %latch
+
+if:
+  %c = load i32, ptr %count
+  %c.inc = add i32 %c, 1
+  store i32 %c.inc, ptr %count
+  br label %latch
+
+latch:
+  %i.next = add nuw i32 %i, 1
+  %cmp = icmp eq i32 %i.next, %len
+  br i1 %cmp, label %exit, label %loop
+
+exit:
+  ret void
+}
+
 ; Should not get promoted, because the pointer is captured and may not
 ; be thread-local.
 define void @test_captured_before_loop_byval(ptr byval(i32) align 4 %count, i32 %len) {

Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nikic nikic merged commit eea6969 into llvm:main May 28, 2025
10 of 13 checks passed
@nikic nikic deleted the licm-provenance branch May 28, 2025 09:57
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
When performing scalar promotions, only consider provenance captures,
which may lead to non-thread-safe accesses. Address captures can be
ignored.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants