From eea69691908d2ff59ef2614fc6f948d021d0ef07 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 28 May 2025 11:57:30 +0200 Subject: [PATCH] [LICM] Only check for provenance captures (#141731) When performing scalar promotions, only consider provenance captures, which may lead to non-thread-safe accesses. Address captures can be ignored. --- llvm/lib/Transforms/Scalar/LICM.cpp | 5 +- llvm/test/Transforms/LICM/promote-capture.ll | 52 ++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 006a09b38bc7..7965ed76a81b 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 5cbe158e47a3..eac670e6f3ed 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) {