[clang] 1e64ea9 - Revert "[CaptureTracking][FunctionAttrs] Add support for CaptureInfo (#125880)"
Nikita Popov via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 13 05:56:23 PST 2025
Author: Nikita Popov
Date: 2025-02-13T14:56:12+01:00
New Revision: 1e64ea9914d3cc839b52e50d2d497600e03c8b6e
URL: https://github.com/llvm/llvm-project/commit/1e64ea9914d3cc839b52e50d2d497600e03c8b6e
DIFF: https://github.com/llvm/llvm-project/commit/1e64ea9914d3cc839b52e50d2d497600e03c8b6e.diff
LOG: Revert "[CaptureTracking][FunctionAttrs] Add support for CaptureInfo (#125880)"
This reverts commit ee655ca27aad466bcc54f6eba03f7e564940ad5a.
A miscompilation has been reported at:
https://github.com/llvm/llvm-project/pull/125880#issuecomment-2656632577
Added:
Modified:
clang/test/CodeGen/allow-ubsan-check.c
clang/test/CodeGenCXX/RelativeVTablesABI/dynamic-cast.cpp
clang/test/CodeGenCXX/RelativeVTablesABI/type-info.cpp
clang/test/CodeGenOpenCL/amdgcn-buffer-rsrc-type.cl
clang/test/CodeGenOpenCL/as_type.cl
llvm/include/llvm/Analysis/CaptureTracking.h
llvm/include/llvm/Support/ModRef.h
llvm/lib/Analysis/CaptureTracking.cpp
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/lib/Transforms/IPO/AttributorAttributes.cpp
llvm/lib/Transforms/IPO/FunctionAttrs.cpp
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
llvm/test/Transforms/FunctionAttrs/arg_returned.ll
llvm/test/Transforms/FunctionAttrs/nocapture.ll
llvm/test/Transforms/FunctionAttrs/nonnull.ll
llvm/test/Transforms/FunctionAttrs/noundef.ll
llvm/test/Transforms/FunctionAttrs/readattrs.ll
llvm/test/Transforms/FunctionAttrs/stats.ll
llvm/test/Transforms/PhaseOrdering/AArch64/block_scaling_decompr_8bit.ll
llvm/test/Transforms/PhaseOrdering/bitcast-store-branch.ll
llvm/test/Transforms/PhaseOrdering/dce-after-argument-promotion-loads.ll
llvm/test/Transforms/PhaseOrdering/enable-loop-header-duplication-oz.ll
llvm/unittests/Analysis/CaptureTrackingTest.cpp
Removed:
################################################################################
diff --git a/clang/test/CodeGen/allow-ubsan-check.c b/clang/test/CodeGen/allow-ubsan-check.c
index c116604288546..0cd81a77f5cc5 100644
--- a/clang/test/CodeGen/allow-ubsan-check.c
+++ b/clang/test/CodeGen/allow-ubsan-check.c
@@ -86,7 +86,7 @@ int div(int x, int y) {
}
// CHECK-LABEL: define dso_local i32 @null(
-// CHECK-SAME: ptr noundef readonly captures(address_is_null) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]]
//
@@ -102,7 +102,7 @@ int div(int x, int y) {
// CHECK-NEXT: ret i32 [[TMP2]]
//
// TR-LABEL: define dso_local i32 @null(
-// TR-SAME: ptr noundef readonly captures(address_is_null) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// TR-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// TR-NEXT: [[ENTRY:.*:]]
// TR-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]]
// TR-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]]
@@ -116,7 +116,7 @@ int div(int x, int y) {
// TR-NEXT: ret i32 [[TMP2]]
//
// REC-LABEL: define dso_local i32 @null(
-// REC-SAME: ptr noundef readonly captures(address_is_null) [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// REC-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// REC-NEXT: [[ENTRY:.*:]]
// REC-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]]
// REC-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]]
diff --git a/clang/test/CodeGenCXX/RelativeVTablesABI/dynamic-cast.cpp b/clang/test/CodeGenCXX/RelativeVTablesABI/dynamic-cast.cpp
index 3662a270713b6..83daf57be22ff 100644
--- a/clang/test/CodeGenCXX/RelativeVTablesABI/dynamic-cast.cpp
+++ b/clang/test/CodeGenCXX/RelativeVTablesABI/dynamic-cast.cpp
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 %s -triple=aarch64-unknown-fuchsia -O3 -o - -emit-llvm | FileCheck %s
-// CHECK: define{{.*}} ptr @_Z6upcastP1B(ptr noundef readnone returned captures(ret: address, provenance) %b) local_unnamed_addr
+// CHECK: define{{.*}} ptr @_Z6upcastP1B(ptr noundef readnone returned %b) local_unnamed_addr
// CHECK-NEXT: entry:
// CHECK-NEXT: ret ptr %b
// CHECK-NEXT: }
@@ -22,12 +22,12 @@
// CHECK: declare ptr @__dynamic_cast(ptr, ptr, ptr, i64) local_unnamed_addr
-// CHECK: define{{.*}} ptr @_Z8selfcastP1B(ptr noundef readnone returned captures(ret: address, provenance) %b) local_unnamed_addr
+// CHECK: define{{.*}} ptr @_Z8selfcastP1B(ptr noundef readnone returned %b) local_unnamed_addr
// CHECK-NEXT: entry
// CHECK-NEXT: ret ptr %b
// CHECK-NEXT: }
-// CHECK: define{{.*}} ptr @_Z9void_castP1B(ptr noundef readonly captures(address_is_null, ret: address, provenance) %b) local_unnamed_addr
+// CHECK: define{{.*}} ptr @_Z9void_castP1B(ptr noundef readonly %b) local_unnamed_addr
// CHECK-NEXT: entry:
// CHECK-NEXT: [[isnull:%[0-9]+]] = icmp eq ptr %b, null
// CHECK-NEXT: br i1 [[isnull]], label %[[dynamic_cast_end:[a-z0-9._]+]], label %[[dynamic_cast_notnull:[a-z0-9._]+]]
diff --git a/clang/test/CodeGenCXX/RelativeVTablesABI/type-info.cpp b/clang/test/CodeGenCXX/RelativeVTablesABI/type-info.cpp
index 2a838708ca231..c471e5dbd7b33 100644
--- a/clang/test/CodeGenCXX/RelativeVTablesABI/type-info.cpp
+++ b/clang/test/CodeGenCXX/RelativeVTablesABI/type-info.cpp
@@ -24,7 +24,7 @@
// CHECK-NEXT: ret ptr @_ZTS1A
// CHECK-NEXT: }
-// CHECK: define{{.*}} i1 @_Z5equalP1A(ptr noundef readonly captures(address_is_null) %a) local_unnamed_addr
+// CHECK: define{{.*}} i1 @_Z5equalP1A(ptr noundef readonly %a) local_unnamed_addr
// CHECK-NEXT: entry:
// CHECK-NEXT: [[isnull:%[0-9]+]] = icmp eq ptr %a, null
// CHECK-NEXT: br i1 [[isnull]], label %[[bad_typeid:[a-z0-9._]+]], label %[[end:[a-z0-9.+]+]]
diff --git a/clang/test/CodeGenOpenCL/amdgcn-buffer-rsrc-type.cl b/clang/test/CodeGenOpenCL/amdgcn-buffer-rsrc-type.cl
index 62fd20c4d1414..0aadaad2dca5c 100644
--- a/clang/test/CodeGenOpenCL/amdgcn-buffer-rsrc-type.cl
+++ b/clang/test/CodeGenOpenCL/amdgcn-buffer-rsrc-type.cl
@@ -22,7 +22,7 @@ __amdgpu_buffer_rsrc_t getBuffer(void *p) {
}
// CHECK-LABEL: define {{[^@]+}}@consumeBufferPtr
-// CHECK-SAME: (ptr addrspace(5) noundef readonly captures(address) [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-SAME: (ptr addrspace(5) noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr addrspace(5) [[P]], addrspacecast (ptr null to ptr addrspace(5))
// CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
@@ -39,7 +39,7 @@ void consumeBufferPtr(__amdgpu_buffer_rsrc_t *p) {
}
// CHECK-LABEL: define {{[^@]+}}@test
-// CHECK-SAME: (ptr addrspace(5) noundef readonly captures(address) [[A:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-SAME: (ptr addrspace(5) noundef readonly [[A:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[A]], align 16, !tbaa [[TBAA8:![0-9]+]]
// CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[TMP0]], 0
diff --git a/clang/test/CodeGenOpenCL/as_type.cl b/clang/test/CodeGenOpenCL/as_type.cl
index 2c6cdc3810b4d..1fe26fbeafdb4 100644
--- a/clang/test/CodeGenOpenCL/as_type.cl
+++ b/clang/test/CodeGenOpenCL/as_type.cl
@@ -67,7 +67,7 @@ int3 f8(char16 x) {
return __builtin_astype(x, int3);
}
-//CHECK: define{{.*}} spir_func noundef ptr addrspace(1) @addr_cast(ptr noundef readnone captures(ret: address, provenance) %[[x:.*]])
+//CHECK: define{{.*}} spir_func noundef ptr addrspace(1) @addr_cast(ptr noundef readnone %[[x:.*]])
//CHECK: %[[cast:.*]] ={{.*}} addrspacecast ptr %[[x]] to ptr addrspace(1)
//CHECK: ret ptr addrspace(1) %[[cast]]
global int* addr_cast(int *x) {
diff --git a/llvm/include/llvm/Analysis/CaptureTracking.h b/llvm/include/llvm/Analysis/CaptureTracking.h
index 573df8833bd46..06a00d9ae7899 100644
--- a/llvm/include/llvm/Analysis/CaptureTracking.h
+++ b/llvm/include/llvm/Analysis/CaptureTracking.h
@@ -14,13 +14,11 @@
#define LLVM_ANALYSIS_CAPTURETRACKING_H
#include "llvm/ADT/DenseMap.h"
-#include "llvm/Support/ModRef.h"
namespace llvm {
class Value;
class Use;
- class CaptureInfo;
class DataLayout;
class Instruction;
class DominatorTree;
@@ -79,47 +77,10 @@ namespace llvm {
const DominatorTree &DT,
unsigned MaxUsesToExplore = 0);
- /// Capture information for a specific Use.
- struct UseCaptureInfo {
- /// Components captured by this use.
- CaptureComponents UseCC;
- /// Components captured by the return value of the user of this Use.
- CaptureComponents ResultCC;
-
- UseCaptureInfo(CaptureComponents UseCC,
- CaptureComponents ResultCC = CaptureComponents::None)
- : UseCC(UseCC), ResultCC(ResultCC) {}
-
- static UseCaptureInfo passthrough() {
- return UseCaptureInfo(CaptureComponents::None, CaptureComponents::All);
- }
-
- bool isPassthrough() const {
- return capturesNothing(UseCC) && capturesAnything(ResultCC);
- }
-
- operator CaptureComponents() const { return UseCC | ResultCC; }
- };
-
/// This callback is used in conjunction with PointerMayBeCaptured. In
/// addition to the interface here, you'll need to provide your own getters
/// to see whether anything was captured.
struct CaptureTracker {
- /// Action returned from captures().
- enum Action {
- /// Stop the traversal.
- Stop,
- /// Continue traversal, and also follow the return value of the user if
- /// it has additional capture components (that is, if it has capture
- /// components in Ret that are not part of Other).
- Continue,
- /// Continue traversal, but do not follow the return value of the user,
- /// even if it has additional capture components. Should only be used if
- /// captures() has already taken the potential return captures into
- /// account.
- ContinueIgnoringReturn,
- };
-
virtual ~CaptureTracker();
/// tooManyUses - The depth of traversal has breached a limit. There may be
@@ -133,12 +94,10 @@ namespace llvm {
/// U->getUser() is always an Instruction.
virtual bool shouldExplore(const Use *U);
- /// Use U directly captures CI.UseCC and additionally CI.ResultCC
- /// through the return value of the user of U.
- ///
- /// Return one of Stop, Continue or ContinueIgnoringReturn to control
- /// further traversal.
- virtual Action captured(const Use *U, UseCaptureInfo CI) = 0;
+ /// captured - Information about the pointer was captured by the user of
+ /// use U. Return true to stop the traversal or false to continue looking
+ /// for more capturing instructions.
+ virtual bool captured(const Use *U) = 0;
/// isDereferenceableOrNull - Overload to allow clients with additional
/// knowledge about pointer dereferenceability to provide it and thereby
@@ -146,18 +105,21 @@ namespace llvm {
virtual bool isDereferenceableOrNull(Value *O, const DataLayout &DL);
};
+ /// Types of use capture kinds, see \p DetermineUseCaptureKind.
+ enum class UseCaptureKind {
+ NO_CAPTURE,
+ MAY_CAPTURE,
+ PASSTHROUGH,
+ };
+
/// Determine what kind of capture behaviour \p U may exhibit.
///
- /// The returned UseCaptureInfo contains the components captured directly
- /// by the use (UseCC) and the components captured through the return value
- /// of the user (ResultCC).
- ///
- /// \p Base is the starting value of the capture analysis, which is
- /// relevant for address_is_null captures.
+ /// A use can be no-capture, a use can potentially capture, or a use can be
+ /// passthrough such that the uses of the user or \p U should be inspected.
/// The \p IsDereferenceableOrNull callback is used to rule out capturing for
/// certain comparisons.
- UseCaptureInfo
- DetermineUseCaptureKind(const Use &U, const Value *Base,
+ UseCaptureKind
+ DetermineUseCaptureKind(const Use &U,
llvm::function_ref<bool(Value *, const DataLayout &)>
IsDereferenceableOrNull);
diff --git a/llvm/include/llvm/Support/ModRef.h b/llvm/include/llvm/Support/ModRef.h
index 7f58f5236aedd..eb660844b0b3a 100644
--- a/llvm/include/llvm/Support/ModRef.h
+++ b/llvm/include/llvm/Support/ModRef.h
@@ -326,10 +326,6 @@ inline bool capturesFullProvenance(CaptureComponents CC) {
return (CC & CaptureComponents::Provenance) == CaptureComponents::Provenance;
}
-inline bool capturesAll(CaptureComponents CC) {
- return CC == CaptureComponents::All;
-}
-
raw_ostream &operator<<(raw_ostream &OS, CaptureComponents CC);
/// Represents which components of the pointer may be captured in which
@@ -354,15 +350,6 @@ class CaptureInfo {
/// Create CaptureInfo that may capture all components of the pointer.
static CaptureInfo all() { return CaptureInfo(CaptureComponents::All); }
- /// Create CaptureInfo that may only capture via the return value.
- static CaptureInfo
- retOnly(CaptureComponents RetComponents = CaptureComponents::All) {
- return CaptureInfo(CaptureComponents::None, RetComponents);
- }
-
- /// Whether the pointer is only captured via the return value.
- bool isRetOnly() const { return capturesNothing(OtherComponents); }
-
/// Get components potentially captured by the return value.
CaptureComponents getRetComponents() const { return RetComponents; }
diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp
index 5120b910e7896..49baf2eb84bb3 100644
--- a/llvm/lib/Analysis/CaptureTracking.cpp
+++ b/llvm/lib/Analysis/CaptureTracking.cpp
@@ -81,15 +81,14 @@ struct SimpleCaptureTracker : public CaptureTracker {
Captured = true;
}
- Action captured(const Use *U, UseCaptureInfo CI) override {
- // TODO(captures): Use UseCaptureInfo.
+ bool captured(const Use *U) override {
if (isa<ReturnInst>(U->getUser()) && !ReturnCaptures)
- return ContinueIgnoringReturn;
+ return false;
LLVM_DEBUG(dbgs() << "Captured by: " << *U->getUser() << "\n");
Captured = true;
- return Stop;
+ return true;
}
bool ReturnCaptures;
@@ -123,21 +122,19 @@ struct CapturesBefore : public CaptureTracker {
return !isPotentiallyReachable(I, BeforeHere, nullptr, DT, LI);
}
- Action captured(const Use *U, UseCaptureInfo CI) override {
- // TODO(captures): Use UseCaptureInfo.
+ bool captured(const Use *U) override {
Instruction *I = cast<Instruction>(U->getUser());
if (isa<ReturnInst>(I) && !ReturnCaptures)
- return ContinueIgnoringReturn;
+ return false;
// Check isSafeToPrune() here rather than in shouldExplore() to avoid
// an expensive reachability query for every instruction we look at.
// Instead we only do one for actual capturing candidates.
if (isSafeToPrune(I))
- // If the use is not reachable, the instruction result isn't either.
- return ContinueIgnoringReturn;
+ return false;
Captured = true;
- return Stop;
+ return true;
}
const Instruction *BeforeHere;
@@ -169,11 +166,10 @@ struct EarliestCaptures : public CaptureTracker {
EarliestCapture = &*F.getEntryBlock().begin();
}
- Action captured(const Use *U, UseCaptureInfo CI) override {
- // TODO(captures): Use UseCaptureInfo.
+ bool captured(const Use *U) override {
Instruction *I = cast<Instruction>(U->getUser());
if (isa<ReturnInst>(I) && !ReturnCaptures)
- return ContinueIgnoringReturn;
+ return false;
if (!EarliestCapture)
EarliestCapture = I;
@@ -181,10 +177,9 @@ struct EarliestCaptures : public CaptureTracker {
EarliestCapture = DT.findNearestCommonDominator(EarliestCapture, I);
Captured = true;
- // Continue analysis, as we need to see all potential captures. However,
- // we do not need to follow the instruction result, as this use will
- // dominate any captures made through the instruction result..
- return ContinueIgnoringReturn;
+ // Return false to continue analysis; we need to see all potential
+ // captures.
+ return false;
}
Instruction *EarliestCapture = nullptr;
@@ -279,26 +274,25 @@ Instruction *llvm::FindEarliestCapture(const Value *V, Function &F,
return CB.EarliestCapture;
}
-UseCaptureInfo llvm::DetermineUseCaptureKind(
- const Use &U, const Value *Base,
+UseCaptureKind llvm::DetermineUseCaptureKind(
+ const Use &U,
function_ref<bool(Value *, const DataLayout &)> IsDereferenceableOrNull) {
Instruction *I = dyn_cast<Instruction>(U.getUser());
// TODO: Investigate non-instruction uses.
if (!I)
- return CaptureComponents::All;
+ return UseCaptureKind::MAY_CAPTURE;
switch (I->getOpcode()) {
case Instruction::Call:
case Instruction::Invoke: {
- // TODO(captures): Make this more precise.
auto *Call = cast<CallBase>(I);
// Not captured if the callee is readonly, doesn't return a copy through
// its return value and doesn't unwind (a readonly function can leak bits
// by throwing an exception or not depending on the input value).
if (Call->onlyReadsMemory() && Call->doesNotThrow() &&
Call->getType()->isVoidTy())
- return CaptureComponents::None;
+ return UseCaptureKind::NO_CAPTURE;
// The pointer is not captured if returned pointer is not captured.
// NOTE: CaptureTracking users should not assume that only functions
@@ -306,13 +300,13 @@ UseCaptureInfo llvm::DetermineUseCaptureKind(
// getUnderlyingObject in ValueTracking or DecomposeGEPExpression
// in BasicAA also need to know about this property.
if (isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(Call, true))
- return UseCaptureInfo::passthrough();
+ return UseCaptureKind::PASSTHROUGH;
// Volatile operations effectively capture the memory location that they
// load and store to.
if (auto *MI = dyn_cast<MemIntrinsic>(Call))
if (MI->isVolatile())
- return CaptureComponents::All;
+ return UseCaptureKind::MAY_CAPTURE;
// Calling a function pointer does not in itself cause the pointer to
// be captured. This is a subtle point considering that (for example)
@@ -321,27 +315,30 @@ UseCaptureInfo llvm::DetermineUseCaptureKind(
// captured, even though the loaded value might be the pointer itself
// (think of self-referential objects).
if (Call->isCallee(&U))
- return CaptureComponents::None;
+ return UseCaptureKind::NO_CAPTURE;
// Not captured if only passed via 'nocapture' arguments.
assert(Call->isDataOperand(&U) && "Non-callee must be data operand");
- CaptureInfo CI = Call->getCaptureInfo(Call->getDataOperandNo(&U));
- return UseCaptureInfo(CI.getOtherComponents(), CI.getRetComponents());
+ if (!Call->doesNotCapture(Call->getDataOperandNo(&U))) {
+ // The parameter is not marked 'nocapture' - captured.
+ return UseCaptureKind::MAY_CAPTURE;
+ }
+ return UseCaptureKind::NO_CAPTURE;
}
case Instruction::Load:
// Volatile loads make the address observable.
if (cast<LoadInst>(I)->isVolatile())
- return CaptureComponents::All;
- return CaptureComponents::None;
+ return UseCaptureKind::MAY_CAPTURE;
+ return UseCaptureKind::NO_CAPTURE;
case Instruction::VAArg:
// "va-arg" from a pointer does not cause it to be captured.
- return CaptureComponents::None;
+ return UseCaptureKind::NO_CAPTURE;
case Instruction::Store:
// Stored the pointer - conservatively assume it may be captured.
// Volatile stores make the address observable.
if (U.getOperandNo() == 0 || cast<StoreInst>(I)->isVolatile())
- return CaptureComponents::All;
- return CaptureComponents::None;
+ return UseCaptureKind::MAY_CAPTURE;
+ return UseCaptureKind::NO_CAPTURE;
case Instruction::AtomicRMW: {
// atomicrmw conceptually includes both a load and store from
// the same location.
@@ -350,8 +347,8 @@ UseCaptureInfo llvm::DetermineUseCaptureKind(
// Volatile stores make the address observable.
auto *ARMWI = cast<AtomicRMWInst>(I);
if (U.getOperandNo() == 1 || ARMWI->isVolatile())
- return CaptureComponents::All;
- return CaptureComponents::None;
+ return UseCaptureKind::MAY_CAPTURE;
+ return UseCaptureKind::NO_CAPTURE;
}
case Instruction::AtomicCmpXchg: {
// cmpxchg conceptually includes both a load and store from
@@ -361,35 +358,31 @@ UseCaptureInfo llvm::DetermineUseCaptureKind(
// Volatile stores make the address observable.
auto *ACXI = cast<AtomicCmpXchgInst>(I);
if (U.getOperandNo() == 1 || U.getOperandNo() == 2 || ACXI->isVolatile())
- return CaptureComponents::All;
- return CaptureComponents::None;
+ return UseCaptureKind::MAY_CAPTURE;
+ return UseCaptureKind::NO_CAPTURE;
}
case Instruction::GetElementPtr:
// AA does not support pointers of vectors, so GEP vector splats need to
// be considered as captures.
if (I->getType()->isVectorTy())
- return CaptureComponents::All;
- return UseCaptureInfo::passthrough();
+ return UseCaptureKind::MAY_CAPTURE;
+ return UseCaptureKind::PASSTHROUGH;
case Instruction::BitCast:
case Instruction::PHI:
case Instruction::Select:
case Instruction::AddrSpaceCast:
// The original value is not captured via this if the new value isn't.
- return UseCaptureInfo::passthrough();
+ return UseCaptureKind::PASSTHROUGH;
case Instruction::ICmp: {
unsigned Idx = U.getOperandNo();
unsigned OtherIdx = 1 - Idx;
- if (isa<ConstantPointerNull>(I->getOperand(OtherIdx)) &&
- cast<ICmpInst>(I)->isEquality()) {
- // TODO(captures): Remove these special cases once we make use of
- // captures(address_is_null).
-
+ if (auto *CPN = dyn_cast<ConstantPointerNull>(I->getOperand(OtherIdx))) {
// Don't count comparisons of a no-alias return value against null as
// captures. This allows us to ignore comparisons of malloc results
// with null, for example.
- if (U->getType()->getPointerAddressSpace() == 0)
+ if (CPN->getType()->getAddressSpace() == 0)
if (isNoAliasCall(U.get()->stripPointerCasts()))
- return CaptureComponents::None;
+ return UseCaptureKind::NO_CAPTURE;
if (!I->getFunction()->nullPointerIsDefined()) {
auto *O = I->getOperand(Idx)->stripPointerCastsSameRepresentation();
// Comparing a dereferenceable_or_null pointer against null cannot
@@ -397,23 +390,17 @@ UseCaptureInfo llvm::DetermineUseCaptureKind(
// valid (in-bounds) pointer.
const DataLayout &DL = I->getDataLayout();
if (IsDereferenceableOrNull && IsDereferenceableOrNull(O, DL))
- return CaptureComponents::None;
+ return UseCaptureKind::NO_CAPTURE;
}
-
- // Check whether this is a comparison of the base pointer against
- // null.
- if (U.get() == Base)
- return CaptureComponents::AddressIsNull;
}
// Otherwise, be conservative. There are crazy ways to capture pointers
- // using comparisons. However, only the address is captured, not the
- // provenance.
- return CaptureComponents::Address;
+ // using comparisons.
+ return UseCaptureKind::MAY_CAPTURE;
}
default:
// Something else - be conservative and say it is captured.
- return CaptureComponents::All;
+ return UseCaptureKind::MAY_CAPTURE;
}
}
@@ -451,26 +438,18 @@ void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker,
};
while (!Worklist.empty()) {
const Use *U = Worklist.pop_back_val();
- UseCaptureInfo CI = DetermineUseCaptureKind(*U, V, IsDereferenceableOrNull);
- if (capturesAnything(CI.UseCC)) {
- switch (Tracker->captured(U, CI)) {
- case CaptureTracker::Stop:
+ switch (DetermineUseCaptureKind(*U, IsDereferenceableOrNull)) {
+ case UseCaptureKind::NO_CAPTURE:
+ continue;
+ case UseCaptureKind::MAY_CAPTURE:
+ if (Tracker->captured(U))
return;
- case CaptureTracker::ContinueIgnoringReturn:
- continue;
- case CaptureTracker::Continue:
- // Fall through to passthrough handling, but only if ResultCC contains
- // additional components that UseCC does not. We assume that a
- // capture at this point will be strictly more constraining than a
- // later capture from following the return value.
- if (capturesNothing(CI.ResultCC & ~CI.UseCC))
- continue;
- break;
- }
+ continue;
+ case UseCaptureKind::PASSTHROUGH:
+ if (!AddUses(U->getUser()))
+ return;
+ continue;
}
- // TODO(captures): We could keep track of ResultCC for the users.
- if (capturesAnything(CI.ResultCC) && !AddUses(U->getUser()))
- return;
}
// All uses examined.
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index d25c1eecaf1ca..59002cd934ab1 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2788,8 +2788,7 @@ static Constant *computePointerICmp(CmpPredicate Pred, Value *LHS, Value *RHS,
struct CustomCaptureTracker : public CaptureTracker {
bool Captured = false;
void tooManyUses() override { Captured = true; }
- Action captured(const Use *U, UseCaptureInfo CI) override {
- // TODO(captures): Use UseCaptureInfo.
+ bool captured(const Use *U) override {
if (auto *ICmp = dyn_cast<ICmpInst>(U->getUser())) {
// Comparison against value stored in global variable. Given the
// pointer does not escape, its value cannot be guessed and stored
@@ -2797,11 +2796,11 @@ static Constant *computePointerICmp(CmpPredicate Pred, Value *LHS, Value *RHS,
unsigned OtherIdx = 1 - U->getOperandNo();
auto *LI = dyn_cast<LoadInst>(ICmp->getOperand(OtherIdx));
if (LI && isa<GlobalVariable>(LI->getPointerOperand()))
- return Continue;
+ return false;
}
Captured = true;
- return Stop;
+ return true;
}
};
CustomCaptureTracker Tracker;
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index c1dd8bc393f33..17e7fada10827 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -3970,17 +3970,18 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl {
// TODO: We should track the capturing uses in AANoCapture but the problem
// is CGSCC runs. For those we would need to "allow" AANoCapture for
// a value in the module slice.
- // TODO(captures): Make this more precise.
- UseCaptureInfo CI =
- DetermineUseCaptureKind(U, /*Base=*/nullptr, IsDereferenceableOrNull);
- if (capturesNothing(CI))
+ switch (DetermineUseCaptureKind(U, IsDereferenceableOrNull)) {
+ case UseCaptureKind::NO_CAPTURE:
return true;
- if (CI.isPassthrough()) {
+ case UseCaptureKind::MAY_CAPTURE:
+ LLVM_DEBUG(dbgs() << "[AANoAliasCSArg] Unknown user: " << *UserI
+ << "\n");
+ return false;
+ case UseCaptureKind::PASSTHROUGH:
Follow = true;
return true;
}
- LLVM_DEBUG(dbgs() << "[AANoAliasCSArg] Unknown user: " << *UserI << "\n");
- return false;
+ llvm_unreachable("unknown UseCaptureKind");
};
bool IsKnownNoCapture;
@@ -6018,16 +6019,16 @@ ChangeStatus AANoCaptureImpl::updateImpl(Attributor &A) {
};
auto UseCheck = [&](const Use &U, bool &Follow) -> bool {
- // TODO(captures): Make this more precise.
- UseCaptureInfo CI =
- DetermineUseCaptureKind(U, /*Base=*/nullptr, IsDereferenceableOrNull);
- if (capturesNothing(CI))
+ switch (DetermineUseCaptureKind(U, IsDereferenceableOrNull)) {
+ case UseCaptureKind::NO_CAPTURE:
return true;
- if (CI.isPassthrough()) {
+ case UseCaptureKind::MAY_CAPTURE:
+ return checkUse(A, T, U, Follow);
+ case UseCaptureKind::PASSTHROUGH:
Follow = true;
return true;
}
- return checkUse(A, T, U, Follow);
+ llvm_unreachable("Unexpected use capture kind!");
};
if (!A.checkForAllUses(UseCheck, *this, *V))
@@ -12150,13 +12151,16 @@ struct AAGlobalValueInfoFloating : public AAGlobalValueInfo {
auto UsePred = [&](const Use &U, bool &Follow) -> bool {
Uses.insert(&U);
- // TODO(captures): Make this more precise.
- UseCaptureInfo CI = DetermineUseCaptureKind(U, /*Base=*/nullptr, nullptr);
- if (CI.isPassthrough()) {
+ switch (DetermineUseCaptureKind(U, nullptr)) {
+ case UseCaptureKind::NO_CAPTURE:
+ return checkUse(A, U, Follow, Worklist);
+ case UseCaptureKind::MAY_CAPTURE:
+ return checkUse(A, U, Follow, Worklist);
+ case UseCaptureKind::PASSTHROUGH:
Follow = true;
return true;
}
- return checkUse(A, U, Follow, Worklist);
+ return true;
};
auto EquivalentUseCB = [&](const Use &OldU, const Use &NewU) {
Uses.insert(&OldU);
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index a66d7ce9c3f50..415df169b88fc 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -71,9 +71,7 @@ using namespace llvm;
#define DEBUG_TYPE "function-attrs"
STATISTIC(NumMemoryAttr, "Number of functions with improved memory attribute");
-STATISTIC(NumCapturesNone, "Number of arguments marked captures(none)");
-STATISTIC(NumCapturesPartial, "Number of arguments marked with captures "
- "attribute other than captures(none)");
+STATISTIC(NumNoCapture, "Number of arguments marked nocapture");
STATISTIC(NumReturned, "Number of arguments marked returned");
STATISTIC(NumReadNoneArg, "Number of arguments marked readnone");
STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly");
@@ -110,13 +108,6 @@ static cl::opt<bool> DisableThinLTOPropagation(
"disable-thinlto-funcattrs", cl::init(true), cl::Hidden,
cl::desc("Don't propagate function-attrs in thinLTO"));
-static void addCapturesStat(CaptureInfo CI) {
- if (capturesNothing(CI))
- ++NumCapturesNone;
- else
- ++NumCapturesPartial;
-}
-
namespace {
using SCCNodeSet = SmallSetVector<Function *, 8>;
@@ -507,9 +498,6 @@ namespace {
/// SCC of the arguments.
struct ArgumentGraphNode {
Argument *Definition;
- /// CaptureComponents for this argument, excluding captures via Uses.
- /// We don't distinguish between other/return captures here.
- CaptureComponents CC = CaptureComponents::None;
SmallVector<ArgumentGraphNode *, 4> Uses;
};
@@ -551,36 +539,18 @@ class ArgumentGraph {
struct ArgumentUsesTracker : public CaptureTracker {
ArgumentUsesTracker(const SCCNodeSet &SCCNodes) : SCCNodes(SCCNodes) {}
- void tooManyUses() override { CI = CaptureInfo::all(); }
-
- Action captured(const Use *U, UseCaptureInfo UseCI) override {
- if (updateCaptureInfo(U, UseCI.UseCC)) {
- // Don't bother continuing if we already capture everything.
- if (capturesAll(CI.getOtherComponents()))
- return Stop;
- return Continue;
- }
-
- // For SCC argument tracking, we're not going to analyze other/ret
- // components separately, so don't follow the return value.
- return ContinueIgnoringReturn;
- }
+ void tooManyUses() override { Captured = true; }
- bool updateCaptureInfo(const Use *U, CaptureComponents CC) {
+ bool captured(const Use *U) override {
CallBase *CB = dyn_cast<CallBase>(U->getUser());
if (!CB) {
- if (isa<ReturnInst>(U->getUser()))
- CI |= CaptureInfo::retOnly(CC);
- else
- // Conservatively assume that the captured value might make its way
- // into the return value as well. This could be made more precise.
- CI |= CaptureInfo(CC);
+ Captured = true;
return true;
}
Function *F = CB->getCalledFunction();
if (!F || !F->hasExactDefinition() || !SCCNodes.count(F)) {
- CI |= CaptureInfo(CC);
+ Captured = true;
return true;
}
@@ -594,24 +564,22 @@ struct ArgumentUsesTracker : public CaptureTracker {
// use. In this case it does not matter if the callee is within our SCC
// or not -- we've been captured in some unknown way, and we have to be
// conservative.
- CI |= CaptureInfo(CC);
+ Captured = true;
return true;
}
if (UseIndex >= F->arg_size()) {
assert(F->isVarArg() && "More params than args in non-varargs call");
- CI |= CaptureInfo(CC);
+ Captured = true;
return true;
}
- // TODO(captures): Could improve precision by remembering maximum
- // capture components for the argument.
Uses.push_back(&*std::next(F->arg_begin(), UseIndex));
return false;
}
- // Does not include potential captures via Uses in the SCC.
- CaptureInfo CI = CaptureInfo::none();
+ // True only if certainly captured (used outside our SCC).
+ bool Captured = false;
// Uses within our SCC.
SmallVector<Argument *, 4> Uses;
@@ -1226,15 +1194,6 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
bool SkipInitializes) {
ArgumentGraph AG;
- auto DetermineAccessAttrsForSingleton = [](Argument *A) {
- SmallPtrSet<Argument *, 8> Self;
- Self.insert(A);
- Attribute::AttrKind R = determinePointerAccessAttrs(A, Self);
- if (R != Attribute::None)
- return addAccessAttr(A, R);
- return false;
- };
-
// Check each function in turn, determining which pointer arguments are not
// captured.
for (Function *F : SCCNodes) {
@@ -1255,7 +1214,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (A.getType()->isPointerTy() && !A.hasNoCaptureAttr()) {
A.addAttr(Attribute::getWithCaptureInfo(A.getContext(),
CaptureInfo::none()));
- ++NumCapturesNone;
+ ++NumNoCapture;
Changed.insert(F);
}
}
@@ -1266,23 +1225,21 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (!A.getType()->isPointerTy())
continue;
bool HasNonLocalUses = false;
- CaptureInfo OrigCI = A.getAttributes().getCaptureInfo();
- if (!capturesNothing(OrigCI)) {
+ if (!A.hasNoCaptureAttr()) {
ArgumentUsesTracker Tracker(SCCNodes);
PointerMayBeCaptured(&A, &Tracker);
- CaptureInfo NewCI = Tracker.CI & OrigCI;
- if (NewCI != OrigCI) {
+ if (!Tracker.Captured) {
if (Tracker.Uses.empty()) {
- // If the information is complete, add the attribute now.
- A.addAttr(Attribute::getWithCaptureInfo(A.getContext(), NewCI));
- addCapturesStat(NewCI);
+ // If it's trivially not captured, mark it nocapture now.
+ A.addAttr(Attribute::getWithCaptureInfo(A.getContext(),
+ CaptureInfo::none()));
+ ++NumNoCapture;
Changed.insert(F);
} else {
// If it's not trivially captured and not trivially not captured,
// then it must be calling into another function in our SCC. Save
// its particulars for Argument-SCC analysis later.
ArgumentGraphNode *Node = AG[&A];
- Node->CC = CaptureComponents(NewCI);
for (Argument *Use : Tracker.Uses) {
Node->Uses.push_back(AG[Use]);
if (Use != &A)
@@ -1297,8 +1254,12 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
// an SCC? Note that we don't allow any calls at all here, or else our
// result will be dependent on the iteration order through the
// functions in the SCC.
- if (DetermineAccessAttrsForSingleton(&A))
- Changed.insert(F);
+ SmallPtrSet<Argument *, 8> Self;
+ Self.insert(&A);
+ Attribute::AttrKind R = determinePointerAccessAttrs(&A, Self);
+ if (R != Attribute::None)
+ if (addAccessAttr(&A, R))
+ Changed.insert(F);
}
if (!SkipInitializes && !A.onlyReadsMemory()) {
if (inferInitializes(A, *F))
@@ -1324,17 +1285,17 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (ArgumentSCC[0]->Uses.size() == 1 &&
ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
Argument *A = ArgumentSCC[0]->Definition;
- CaptureInfo OrigCI = A->getAttributes().getCaptureInfo();
- CaptureInfo NewCI = CaptureInfo(ArgumentSCC[0]->CC) & OrigCI;
- if (NewCI != OrigCI) {
- A->addAttr(Attribute::getWithCaptureInfo(A->getContext(), NewCI));
- addCapturesStat(NewCI);
- Changed.insert(A->getParent());
- }
-
- // Infer the access attributes given the new captures one
- if (DetermineAccessAttrsForSingleton(A))
- Changed.insert(A->getParent());
+ A->addAttr(Attribute::getWithCaptureInfo(A->getContext(),
+ CaptureInfo::none()));
+ ++NumNoCapture;
+ Changed.insert(A->getParent());
+
+ // Infer the access attributes given the new nocapture one
+ SmallPtrSet<Argument *, 8> Self;
+ Self.insert(&*A);
+ Attribute::AttrKind R = determinePointerAccessAttrs(&*A, Self);
+ if (R != Attribute::None)
+ addAccessAttr(A, R);
}
continue;
}
@@ -1346,45 +1307,27 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
ArgumentSCCNodes.insert(I->Definition);
}
- // At the SCC level, only track merged CaptureComponents. We're not
- // currently prepared to handle propagation of return-only captures across
- // the SCC.
- CaptureComponents CC = CaptureComponents::None;
+ bool SCCCaptured = false;
for (ArgumentGraphNode *N : ArgumentSCC) {
for (ArgumentGraphNode *Use : N->Uses) {
Argument *A = Use->Definition;
- if (ArgumentSCCNodes.count(A))
- CC |= Use->CC;
- else
- CC |= CaptureComponents(A->getAttributes().getCaptureInfo());
+ if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A))
+ continue;
+ SCCCaptured = true;
break;
}
- if (capturesAll(CC))
+ if (SCCCaptured)
break;
}
-
- if (!capturesAll(CC)) {
- for (ArgumentGraphNode *N : ArgumentSCC) {
- Argument *A = N->Definition;
- CaptureInfo OrigCI = A->getAttributes().getCaptureInfo();
- CaptureInfo NewCI = CaptureInfo(N->CC | CC) & OrigCI;
- if (NewCI != OrigCI) {
- A->addAttr(Attribute::getWithCaptureInfo(A->getContext(), NewCI));
- addCapturesStat(NewCI);
- Changed.insert(A->getParent());
- }
- }
- }
-
- // TODO(captures): Ignore address-only captures.
- if (capturesAnything(CC)) {
- // As the pointer may be captured, determine the pointer attributes
- // looking at each argument invidivually.
- for (ArgumentGraphNode *N : ArgumentSCC) {
- if (DetermineAccessAttrsForSingleton(N->Definition))
- Changed.insert(N->Definition->getParent());
- }
+ if (SCCCaptured)
continue;
+
+ for (ArgumentGraphNode *N : ArgumentSCC) {
+ Argument *A = N->Definition;
+ A->addAttr(
+ Attribute::getWithCaptureInfo(A->getContext(), CaptureInfo::none()));
+ ++NumNoCapture;
+ Changed.insert(A->getParent());
}
// We also want to compute readonly/readnone/writeonly. With a small number
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 96d6db2ba5bfe..0feb6160b68fb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -882,8 +882,7 @@ bool InstCombinerImpl::foldAllocaCmp(AllocaInst *Alloca) {
void tooManyUses() override { Captured = true; }
- Action captured(const Use *U, UseCaptureInfo CI) override {
- // TODO(captures): Use UseCaptureInfo.
+ bool captured(const Use *U) override {
auto *ICmp = dyn_cast<ICmpInst>(U->getUser());
// We need to check that U is based *only* on the alloca, and doesn't
// have other contributions from a select/phi operand.
@@ -893,11 +892,11 @@ bool InstCombinerImpl::foldAllocaCmp(AllocaInst *Alloca) {
// Collect equality icmps of the alloca, and don't treat them as
// captures.
ICmps[ICmp] |= 1u << U->getOperandNo();
- return Continue;
+ return false;
}
Captured = true;
- return Stop;
+ return true;
}
};
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index 9a729b7afb8b9..87b27beb01a0a 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -1550,33 +1550,32 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
}
if (!Visited.insert(&U).second)
continue;
- UseCaptureInfo CI =
- DetermineUseCaptureKind(U, AI, IsDereferenceableOrNull);
- // TODO(captures): Make this more precise.
- if (CI.isPassthrough()) {
+ switch (DetermineUseCaptureKind(U, IsDereferenceableOrNull)) {
+ case UseCaptureKind::MAY_CAPTURE:
+ return false;
+ case UseCaptureKind::PASSTHROUGH:
+ // Instructions cannot have non-instruction users.
Worklist.push_back(UI);
continue;
- }
-
- if (capturesAnything(CI))
- return false;
-
- if (UI->isLifetimeStartOrEnd()) {
- // We note the locations of these intrinsic calls so that we can
- // delete them later if the optimization succeeds, this is safe
- // since both llvm.lifetime.start and llvm.lifetime.end intrinsics
- // practically fill all the bytes of the alloca with an undefined
- // value, although conceptually marked as alive/dead.
- int64_t Size = cast<ConstantInt>(UI->getOperand(0))->getSExtValue();
- if (Size < 0 || Size == DestSize) {
- LifetimeMarkers.push_back(UI);
- continue;
+ case UseCaptureKind::NO_CAPTURE: {
+ if (UI->isLifetimeStartOrEnd()) {
+ // We note the locations of these intrinsic calls so that we can
+ // delete them later if the optimization succeeds, this is safe
+ // since both llvm.lifetime.start and llvm.lifetime.end intrinsics
+ // practically fill all the bytes of the alloca with an undefined
+ // value, although conceptually marked as alive/dead.
+ int64_t Size = cast<ConstantInt>(UI->getOperand(0))->getSExtValue();
+ if (Size < 0 || Size == DestSize) {
+ LifetimeMarkers.push_back(UI);
+ continue;
+ }
}
+ if (UI->hasMetadata(LLVMContext::MD_noalias))
+ NoAliasInstrs.insert(UI);
+ if (!ModRefCallback(UI))
+ return false;
+ }
}
- if (UI->hasMetadata(LLVMContext::MD_noalias))
- NoAliasInstrs.insert(UI);
- if (!ModRefCallback(UI))
- return false;
}
}
return true;
diff --git a/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll b/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
index a3b065667702f..f706184f9727e 100644
--- a/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
+++ b/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
@@ -14,7 +14,7 @@ define ptr @b(ptr %q) {
ret ptr %tmp
}
-; CHECK: define ptr @c(ptr readnone returned captures(address_is_null, ret: address, provenance) %r)
+; CHECK: define ptr @c(ptr readnone returned %r)
@g = global i32 0
define ptr @c(ptr %r) {
%a = icmp eq ptr %r, null
diff --git a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
index 99406696d33d1..13954694eefe0 100644
--- a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
+++ b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
@@ -145,8 +145,8 @@ return: ; preds = %cond.end, %if.then3
; TEST SCC test returning a pointer value argument
;
-; FNATTR: define ptr @ptr_sink_r0(ptr readnone returned captures(ret: address, provenance) %r)
-; FNATTR: define ptr @ptr_scc_r1(ptr readnone %a, ptr readnone %r, ptr readnone captures(none) %b)
+; FNATTR: define ptr @ptr_sink_r0(ptr readnone returned %r)
+; FNATTR: define ptr @ptr_scc_r1(ptr %a, ptr readnone %r, ptr readnone captures(none) %b)
; FNATTR: define ptr @ptr_scc_r2(ptr readnone %a, ptr readnone %b, ptr readnone %r)
;
;
@@ -260,8 +260,8 @@ entry:
; TEST another SCC test
;
-; FNATTR: define ptr @rt2_helper(ptr readnone captures(address_is_null) %a)
-; FNATTR: define ptr @rt2(ptr readnone captures(address_is_null) %a, ptr readnone captures(ret: address, provenance) %b)
+; FNATTR: define ptr @rt2_helper(ptr %a)
+; FNATTR: define ptr @rt2(ptr readnone %a, ptr readnone %b)
define ptr @rt2_helper(ptr %a) #0 {
entry:
%call = call ptr @rt2(ptr %a, ptr %a)
@@ -284,8 +284,8 @@ if.end:
; TEST another SCC test
;
-; FNATTR: define ptr @rt3_helper(ptr readnone captures(address_is_null) %a, ptr readnone %b)
-; FNATTR: define ptr @rt3(ptr readnone captures(address_is_null) %a, ptr readnone %b)
+; FNATTR: define ptr @rt3_helper(ptr %a, ptr %b)
+; FNATTR: define ptr @rt3(ptr readnone %a, ptr readnone %b)
define ptr @rt3_helper(ptr %a, ptr %b) #0 {
entry:
%call = call ptr @rt3(ptr %a, ptr %b)
@@ -316,7 +316,7 @@ if.end:
; }
;
;
-; FNATTR: define ptr @calls_unknown_fn(ptr readnone returned captures(ret: address, provenance) %r)
+; FNATTR: define ptr @calls_unknown_fn(ptr readnone returned %r)
declare void @unknown_fn(ptr) #0
define ptr @calls_unknown_fn(ptr %r) #0 {
@@ -415,7 +415,7 @@ if.end: ; preds = %if.then, %entry
; }
;
;
-; FNATTR: define ptr @bitcast(ptr readnone returned captures(ret: address, provenance) %b)
+; FNATTR: define ptr @bitcast(ptr readnone returned %b)
;
define ptr @bitcast(ptr %b) #0 {
entry:
@@ -433,7 +433,7 @@ entry:
; }
;
;
-; FNATTR: define ptr @bitcasts_select_and_phi(ptr readnone captures(address_is_null, ret: address, provenance) %b)
+; FNATTR: define ptr @bitcasts_select_and_phi(ptr readnone %b)
;
define ptr @bitcasts_select_and_phi(ptr %b) #0 {
entry:
@@ -462,7 +462,7 @@ if.end: ; preds = %if.then, %entry
; }
;
;
-; FNATTR: define ptr @ret_arg_arg_undef(ptr readnone captures(address_is_null, ret: address, provenance) %b)
+; FNATTR: define ptr @ret_arg_arg_undef(ptr readnone %b)
;
define ptr @ret_arg_arg_undef(ptr %b) #0 {
entry:
@@ -494,7 +494,7 @@ ret_undef:
; }
;
;
-; FNATTR: define ptr @ret_undef_arg_arg(ptr readnone captures(address_is_null, ret: address, provenance) %b)
+; FNATTR: define ptr @ret_undef_arg_arg(ptr readnone %b)
;
define ptr @ret_undef_arg_arg(ptr %b) #0 {
entry:
@@ -526,7 +526,7 @@ ret_arg1:
; }
;
;
-; FNATTR: define ptr @ret_undef_arg_undef(ptr readnone captures(address_is_null, ret: address, provenance) %b)
+; FNATTR: define ptr @ret_undef_arg_undef(ptr readnone %b)
define ptr @ret_undef_arg_undef(ptr %b) #0 {
entry:
%cmp = icmp eq ptr %b, null
diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
index 6debe5de3966e..6164f2adbf5b9 100644
--- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
@@ -7,7 +7,7 @@
define ptr @c1(ptr %q) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define ptr @c1
-; FNATTRS-SAME: (ptr readnone returned captures(ret: address, provenance) [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
+; FNATTRS-SAME: (ptr readnone returned [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
; FNATTRS-NEXT: ret ptr [[Q]]
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
@@ -512,7 +512,7 @@ define void @test4_1(ptr %x4_1, i1 %c) {
define ptr @test4_2(ptr %x4_2, ptr %y4_2, ptr %z4_2, i1 %c) {
; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none)
; FNATTRS-LABEL: define ptr @test4_2
-; FNATTRS-SAME: (ptr readnone captures(none) [[X4_2:%.*]], ptr readnone returned captures(ret: address, provenance) [[Y4_2:%.*]], ptr readnone captures(none) [[Z4_2:%.*]], i1 [[C:%.*]]) #[[ATTR10]] {
+; FNATTRS-SAME: (ptr readnone captures(none) [[X4_2:%.*]], ptr readnone returned [[Y4_2:%.*]], ptr readnone captures(none) [[Z4_2:%.*]], i1 [[C:%.*]]) #[[ATTR10]] {
; FNATTRS-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; FNATTRS: t:
; FNATTRS-NEXT: call void @test4_1(ptr null, i1 [[C]])
@@ -740,7 +740,7 @@ define void @captureStrip(ptr %p) {
define i1 @captureICmp(ptr %x) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define i1 @captureICmp
-; FNATTRS-SAME: (ptr readnone captures(address_is_null) [[X:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null
; FNATTRS-NEXT: ret i1 [[TMP1]]
;
@@ -757,7 +757,7 @@ define i1 @captureICmp(ptr %x) {
define i1 @captureICmpRev(ptr %x) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define i1 @captureICmpRev
-; FNATTRS-SAME: (ptr readnone captures(address_is_null) [[X:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr null, [[X]]
; FNATTRS-NEXT: ret i1 [[TMP1]]
;
@@ -771,29 +771,10 @@ define i1 @captureICmpRev(ptr %x) {
ret i1 %1
}
-define i1 @captureICmpWrongPred(ptr %x) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; FNATTRS-LABEL: define i1 @captureICmpWrongPred
-; FNATTRS-SAME: (ptr readnone captures(address) [[X:%.*]]) #[[ATTR0]] {
-; FNATTRS-NEXT: [[TMP1:%.*]] = icmp slt ptr [[X]], null
-; FNATTRS-NEXT: ret i1 [[TMP1]]
-;
-; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; ATTRIBUTOR-LABEL: define i1 @captureICmpWrongPred
-; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] {
-; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp slt ptr [[X]], null
-; ATTRIBUTOR-NEXT: ret i1 [[TMP1]]
-;
- %1 = icmp slt ptr %x, null
- ret i1 %1
-}
-
-; We could infer captures(address_is_null) here, but don't bother, because
-; InstCombine will optimize the GEP away.
define i1 @nocaptureInboundsGEPICmp(ptr %x) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define i1 @nocaptureInboundsGEPICmp
-; FNATTRS-SAME: (ptr readnone captures(address) [[X:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5
; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
; FNATTRS-NEXT: ret i1 [[TMP2]]
@@ -813,7 +794,7 @@ define i1 @nocaptureInboundsGEPICmp(ptr %x) {
define i1 @nocaptureInboundsGEPICmpRev(ptr %x) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define i1 @nocaptureInboundsGEPICmpRev
-; FNATTRS-SAME: (ptr readnone captures(address) [[X:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5
; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr null, [[TMP1]]
; FNATTRS-NEXT: ret i1 [[TMP2]]
@@ -830,46 +811,6 @@ define i1 @nocaptureInboundsGEPICmpRev(ptr %x) {
ret i1 %2
}
-define i1 @notInboundsGEPICmp(ptr %x) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; FNATTRS-LABEL: define i1 @notInboundsGEPICmp
-; FNATTRS-SAME: (ptr readnone captures(address) [[X:%.*]]) #[[ATTR0]] {
-; FNATTRS-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[X]], i32 5
-; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
-; FNATTRS-NEXT: ret i1 [[TMP2]]
-;
-; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; ATTRIBUTOR-LABEL: define i1 @notInboundsGEPICmp
-; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] {
-; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[X]], i32 5
-; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
-; ATTRIBUTOR-NEXT: ret i1 [[TMP2]]
-;
- %1 = getelementptr i32, ptr %x, i32 5
- %2 = icmp eq ptr %1, null
- ret i1 %2
-}
-
-define i1 @inboundsGEPICmpNullPointerDefined(ptr %x) null_pointer_is_valid {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
-; FNATTRS-LABEL: define i1 @inboundsGEPICmpNullPointerDefined
-; FNATTRS-SAME: (ptr readnone captures(address) [[X:%.*]]) #[[ATTR16:[0-9]+]] {
-; FNATTRS-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[X]], i32 5
-; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
-; FNATTRS-NEXT: ret i1 [[TMP2]]
-;
-; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
-; ATTRIBUTOR-LABEL: define i1 @inboundsGEPICmpNullPointerDefined
-; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR12:[0-9]+]] {
-; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[X]], i32 5
-; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
-; ATTRIBUTOR-NEXT: ret i1 [[TMP2]]
-;
- %1 = getelementptr i32, ptr %x, i32 5
- %2 = icmp eq ptr %1, null
- ret i1 %2
-}
-
define i1 @nocaptureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define noundef i1 @nocaptureDereferenceableOrNullICmp
@@ -890,13 +831,13 @@ define i1 @nocaptureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x)
define i1 @captureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) null_pointer_is_valid {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
; FNATTRS-LABEL: define noundef i1 @captureDereferenceableOrNullICmp
-; FNATTRS-SAME: (ptr readnone captures(address_is_null) dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR16]] {
+; FNATTRS-SAME: (ptr readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR16:[0-9]+]] {
; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null
; FNATTRS-NEXT: ret i1 [[TMP1]]
;
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
; ATTRIBUTOR-LABEL: define i1 @captureDereferenceableOrNullICmp
-; ATTRIBUTOR-SAME: (ptr nofree readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR12]] {
+; ATTRIBUTOR-SAME: (ptr nofree readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR12:[0-9]+]] {
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null
; ATTRIBUTOR-NEXT: ret i1 [[TMP1]]
;
@@ -962,7 +903,7 @@ define void @readnone_indirec(ptr %f, ptr %p) {
define ptr @captures_ret_only(ptr %p) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define ptr @captures_ret_only
-; FNATTRS-SAME: (ptr readnone captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: (ptr readnone [[P:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
; FNATTRS-NEXT: ret ptr [[GEP]]
;
@@ -976,8 +917,6 @@ define ptr @captures_ret_only(ptr %p) {
ret ptr %gep
}
-; Even though the ptrtoint is only used in the return value, this should *not*
-; be considered a read-only capture.
define i64 @captures_not_ret_only(ptr %p) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define i64 @captures_not_ret_only
@@ -996,52 +935,35 @@ define i64 @captures_not_ret_only(ptr %p) {
}
define void @captures_read_provenance(ptr %p) {
-; FNATTRS-LABEL: define void @captures_read_provenance
-; FNATTRS-SAME: (ptr captures(address, read_provenance) [[P:%.*]]) {
-; FNATTRS-NEXT: call void @capture(ptr captures(address, read_provenance) [[P]])
-; FNATTRS-NEXT: ret void
-;
-; ATTRIBUTOR-LABEL: define void @captures_read_provenance
-; ATTRIBUTOR-SAME: (ptr [[P:%.*]]) {
-; ATTRIBUTOR-NEXT: call void @capture(ptr captures(address, read_provenance) [[P]])
-; ATTRIBUTOR-NEXT: ret void
+; COMMON-LABEL: define void @captures_read_provenance
+; COMMON-SAME: (ptr [[P:%.*]]) {
+; COMMON-NEXT: call void @capture(ptr captures(address, read_provenance) [[P]])
+; COMMON-NEXT: ret void
;
call void @capture(ptr captures(address, read_provenance) %p)
ret void
}
define void @captures_unused_ret(ptr %p) {
-; FNATTRS-LABEL: define void @captures_unused_ret
-; FNATTRS-SAME: (ptr captures(address_is_null) [[P:%.*]]) {
-; FNATTRS-NEXT: [[TMP1:%.*]] = call ptr @capture(ptr captures(address_is_null, ret: address, read_provenance) [[P]])
-; FNATTRS-NEXT: ret void
-;
-; ATTRIBUTOR-LABEL: define void @captures_unused_ret
-; ATTRIBUTOR-SAME: (ptr [[P:%.*]]) {
-; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = call ptr @capture(ptr captures(address_is_null, ret: address, read_provenance) [[P]])
-; ATTRIBUTOR-NEXT: ret void
+; COMMON-LABEL: define void @captures_unused_ret
+; COMMON-SAME: (ptr [[P:%.*]]) {
+; COMMON-NEXT: [[TMP1:%.*]] = call ptr @capture(ptr captures(address_is_null, ret: address, read_provenance) [[P]])
+; COMMON-NEXT: ret void
;
call ptr @capture(ptr captures(address_is_null, ret: address, read_provenance) %p)
ret void
}
define ptr @captures_used_ret(ptr %p) {
-; FNATTRS-LABEL: define ptr @captures_used_ret
-; FNATTRS-SAME: (ptr captures(address_is_null, ret: address, provenance) [[P:%.*]]) {
-; FNATTRS-NEXT: [[RET:%.*]] = call ptr @capture(ptr captures(address_is_null, ret: address, read_provenance) [[P]])
-; FNATTRS-NEXT: ret ptr [[RET]]
-;
-; ATTRIBUTOR-LABEL: define ptr @captures_used_ret
-; ATTRIBUTOR-SAME: (ptr [[P:%.*]]) {
-; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @capture(ptr captures(address_is_null, ret: address, read_provenance) [[P]])
-; ATTRIBUTOR-NEXT: ret ptr [[RET]]
+; COMMON-LABEL: define ptr @captures_used_ret
+; COMMON-SAME: (ptr [[P:%.*]]) {
+; COMMON-NEXT: [[RET:%.*]] = call ptr @capture(ptr captures(address_is_null, ret: address, read_provenance) [[P]])
+; COMMON-NEXT: ret ptr [[RET]]
;
%ret = call ptr @capture(ptr captures(address_is_null, ret: address, read_provenance) %p)
ret ptr %ret
}
-; Make sure this is does not produce captures(ret: ...). We need to take the
-; return capture components into account when handling argument SCCs.
define ptr @scc_capture_via_ret(i1 %c, ptr %p) {
; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none)
; FNATTRS-LABEL: define ptr @scc_capture_via_ret
@@ -1077,72 +999,5 @@ else:
ret ptr %p
}
-define i1 @improve_existing_captures(ptr captures(address) %p) {
-; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; FNATTRS-LABEL: define i1 @improve_existing_captures
-; FNATTRS-SAME: (ptr readnone captures(address_is_null) [[P:%.*]]) #[[ATTR0]] {
-; FNATTRS-NEXT: [[CMP:%.*]] = icmp eq ptr [[P]], null
-; FNATTRS-NEXT: ret i1 [[CMP]]
-;
-; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; ATTRIBUTOR-LABEL: define i1 @improve_existing_captures
-; ATTRIBUTOR-SAME: (ptr nofree readnone captures(address) [[P:%.*]]) #[[ATTR0]] {
-; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp eq ptr [[P]], null
-; ATTRIBUTOR-NEXT: ret i1 [[CMP]]
-;
- %cmp = icmp eq ptr %p, null
- ret i1 %cmp
-}
-
-define void @dont_increase_existing_captures(ptr captures(address) %p) {
-; COMMON-LABEL: define void @dont_increase_existing_captures
-; COMMON-SAME: (ptr captures(address) [[P:%.*]]) {
-; COMMON-NEXT: call void @capture(ptr [[P]])
-; COMMON-NEXT: ret void
-;
- call void @capture(ptr %p)
- ret void
-}
-
-define void @dont_increase_existing_captures_trivial_scc(ptr captures(address) %p) {
-; COMMON-LABEL: define void @dont_increase_existing_captures_trivial_scc
-; COMMON-SAME: (ptr captures(address) [[P:%.*]]) {
-; COMMON-NEXT: call void @capture(ptr captures(address, read_provenance) [[P]])
-; COMMON-NEXT: call void @dont_increase_existing_captures_trivial_scc(ptr [[P]])
-; COMMON-NEXT: ret void
-;
- call void @capture(ptr captures(address, read_provenance) %p)
- call void @dont_increase_existing_captures_trivial_scc(ptr %p)
- ret void
-}
-
-define void @dont_increase_existing_captures_scc1(ptr captures(address) %p) {
-; COMMON-LABEL: define void @dont_increase_existing_captures_scc1
-; COMMON-SAME: (ptr captures(address) [[P:%.*]]) {
-; COMMON-NEXT: call void @dont_increase_existing_captures_scc2(ptr [[P]])
-; COMMON-NEXT: ret void
-;
- call void @dont_increase_existing_captures_scc2(ptr %p)
- ret void
-}
-
-define void @dont_increase_existing_captures_scc2(ptr %p) {
-; FNATTRS-LABEL: define void @dont_increase_existing_captures_scc2
-; FNATTRS-SAME: (ptr captures(address, read_provenance) [[P:%.*]]) {
-; FNATTRS-NEXT: call void @capture(ptr captures(address, read_provenance) [[P]])
-; FNATTRS-NEXT: call void @dont_increase_existing_captures_scc1(ptr [[P]])
-; FNATTRS-NEXT: ret void
-;
-; ATTRIBUTOR-LABEL: define void @dont_increase_existing_captures_scc2
-; ATTRIBUTOR-SAME: (ptr [[P:%.*]]) {
-; ATTRIBUTOR-NEXT: call void @capture(ptr captures(address, read_provenance) [[P]])
-; ATTRIBUTOR-NEXT: call void @dont_increase_existing_captures_scc1(ptr [[P]])
-; ATTRIBUTOR-NEXT: ret void
-;
- call void @capture(ptr captures(address, read_provenance) %p)
- call void @dont_increase_existing_captures_scc1(ptr %p)
- ret void
-}
-
declare ptr @llvm.launder.invariant.group.p0(ptr)
declare ptr @llvm.strip.invariant.group.p0(ptr)
diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
index 94093568419af..0f6762f0d4342 100644
--- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
@@ -19,7 +19,7 @@ define ptr @test1() {
; Return a pointer trivially nonnull (argument attribute)
define ptr @test2(ptr nonnull %p) {
; FNATTRS-LABEL: define nonnull ptr @test2(
-; FNATTRS-SAME: ptr nonnull readnone returned captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+; FNATTRS-SAME: ptr nonnull readnone returned [[P:%.*]]) #[[ATTR0:[0-9]+]] {
; FNATTRS-NEXT: ret ptr [[P]]
;
; ATTRIBUTOR-LABEL: define nonnull ptr @test2(
@@ -194,7 +194,7 @@ exit:
define ptr @test7(ptr %a) {
; FNATTRS-LABEL: define ptr @test7(
-; FNATTRS-SAME: ptr readnone returned captures(ret: address, provenance) [[A:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: ptr readnone returned [[A:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: ret ptr [[A]]
;
; ATTRIBUTOR-LABEL: define ptr @test7(
@@ -206,7 +206,7 @@ define ptr @test7(ptr %a) {
define ptr @test8(ptr %a) {
; FNATTRS-LABEL: define nonnull ptr @test8(
-; FNATTRS-SAME: ptr readnone captures(ret: address, provenance) [[A:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: ptr readnone [[A:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 1
; FNATTRS-NEXT: ret ptr [[B]]
;
@@ -221,7 +221,7 @@ define ptr @test8(ptr %a) {
define ptr @test9(ptr %a, i64 %n) {
; FNATTRS-LABEL: define ptr @test9(
-; FNATTRS-SAME: ptr readnone captures(ret: address, provenance) [[A:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: ptr readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
; FNATTRS-NEXT: ret ptr [[B]]
;
@@ -238,7 +238,7 @@ declare void @llvm.assume(i1)
; FIXME: missing nonnull
define ptr @test10(ptr %a, i64 %n) {
; FNATTRS-LABEL: define ptr @test10(
-; FNATTRS-SAME: ptr readnone captures(ret: address, provenance) [[A:%.*]], i64 [[N:%.*]]) #[[ATTR3:[0-9]+]] {
+; FNATTRS-SAME: ptr readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR3:[0-9]+]] {
; FNATTRS-NEXT: [[CMP:%.*]] = icmp ne i64 [[N]], 0
; FNATTRS-NEXT: call void @llvm.assume(i1 [[CMP]])
; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
@@ -263,7 +263,7 @@ define ptr @test10(ptr %a, i64 %n) {
; }
define ptr @test11(ptr) local_unnamed_addr {
; FNATTRS-LABEL: define nonnull ptr @test11(
-; FNATTRS-SAME: ptr readnone captures(address_is_null, ret: address, provenance) [[TMP0:%.*]]) local_unnamed_addr {
+; FNATTRS-SAME: ptr readnone [[TMP0:%.*]]) local_unnamed_addr {
; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null
; FNATTRS-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; FNATTRS: 3:
@@ -362,7 +362,7 @@ declare nonnull ptr @nonnull()
define internal ptr @f1(ptr %arg) {
; FIXME: missing nonnull It should be nonnull @f1(ptr nonnull readonly %arg)
; FNATTRS-LABEL: define internal nonnull ptr @f1(
-; FNATTRS-SAME: ptr readonly captures(address_is_null) [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
+; FNATTRS-SAME: ptr readonly [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
; FNATTRS-NEXT: bb:
; FNATTRS-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null
; FNATTRS-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]]
@@ -431,7 +431,7 @@ bb9: ; preds = %bb4, %bb
define internal ptr @f2(ptr %arg) {
; FIXME: missing nonnull. It should be nonnull @f2(ptr nonnull %arg)
; FNATTRS-LABEL: define internal nonnull ptr @f2(
-; FNATTRS-SAME: ptr readonly captures(address_is_null) [[ARG:%.*]]) #[[ATTR4]] {
+; FNATTRS-SAME: ptr [[ARG:%.*]]) #[[ATTR4]] {
; FNATTRS-NEXT: bb:
; FNATTRS-NEXT: [[TMP:%.*]] = tail call ptr @f1(ptr [[ARG]])
; FNATTRS-NEXT: ret ptr [[TMP]]
@@ -452,7 +452,7 @@ bb:
define dso_local noalias ptr @f3(ptr %arg) {
; FIXME: missing nonnull. It should be nonnull @f3(ptr nonnull readonly %arg)
; FNATTRS-LABEL: define dso_local noalias nonnull ptr @f3(
-; FNATTRS-SAME: ptr readonly captures(address_is_null) [[ARG:%.*]]) #[[ATTR4]] {
+; FNATTRS-SAME: ptr [[ARG:%.*]]) #[[ATTR4]] {
; FNATTRS-NEXT: bb:
; FNATTRS-NEXT: [[TMP:%.*]] = call ptr @f1(ptr [[ARG]])
; FNATTRS-NEXT: ret ptr [[TMP]]
@@ -945,7 +945,7 @@ exc:
define ptr @gep1(ptr %p) {
; FNATTRS-LABEL: define nonnull ptr @gep1(
-; FNATTRS-SAME: ptr readnone captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: ptr readnone [[P:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1
; FNATTRS-NEXT: ret ptr [[Q]]
;
@@ -961,7 +961,7 @@ define ptr @gep1(ptr %p) {
define ptr @gep1_no_null_opt(ptr %p) #0 {
; Should't be able to derive nonnull based on gep.
; FNATTRS-LABEL: define ptr @gep1_no_null_opt(
-; FNATTRS-SAME: ptr readnone captures(ret: address, provenance) [[P:%.*]]) #[[ATTR8:[0-9]+]] {
+; FNATTRS-SAME: ptr readnone [[P:%.*]]) #[[ATTR8:[0-9]+]] {
; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1
; FNATTRS-NEXT: ret ptr [[Q]]
;
@@ -976,7 +976,7 @@ define ptr @gep1_no_null_opt(ptr %p) #0 {
define ptr addrspace(3) @gep2(ptr addrspace(3) %p) {
; FNATTRS-LABEL: define ptr addrspace(3) @gep2(
-; FNATTRS-SAME: ptr addrspace(3) readnone captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: ptr addrspace(3) readnone [[P:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr addrspace(3) [[P]], i32 1
; FNATTRS-NEXT: ret ptr addrspace(3) [[Q]]
;
@@ -992,7 +992,7 @@ define ptr addrspace(3) @gep2(ptr addrspace(3) %p) {
; FIXME: We should propagate dereferenceable here but *not* nonnull
define ptr addrspace(3) @as(ptr addrspace(3) dereferenceable(4) %p) {
; FNATTRS-LABEL: define noundef ptr addrspace(3) @as(
-; FNATTRS-SAME: ptr addrspace(3) readnone returned captures(ret: address, provenance) dereferenceable(4) [[P:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: ptr addrspace(3) readnone returned dereferenceable(4) [[P:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: ret ptr addrspace(3) [[P]]
;
; ATTRIBUTOR-LABEL: define ptr addrspace(3) @as(
@@ -1383,7 +1383,7 @@ define void @PR43833_simple(ptr %0, i32 %1) {
define ptr @pr91177_non_inbounds_gep(ptr nonnull %arg) {
; FNATTRS-LABEL: define ptr @pr91177_non_inbounds_gep(
-; FNATTRS-SAME: ptr nonnull readnone captures(ret: address, provenance) [[ARG:%.*]]) #[[ATTR0]] {
+; FNATTRS-SAME: ptr nonnull readnone [[ARG:%.*]]) #[[ATTR0]] {
; FNATTRS-NEXT: [[RES:%.*]] = getelementptr i8, ptr [[ARG]], i64 -8
; FNATTRS-NEXT: ret ptr [[RES]]
;
diff --git a/llvm/test/Transforms/FunctionAttrs/noundef.ll b/llvm/test/Transforms/FunctionAttrs/noundef.ll
index 4f53c08804621..b7c583880501a 100644
--- a/llvm/test/Transforms/FunctionAttrs/noundef.ll
+++ b/llvm/test/Transforms/FunctionAttrs/noundef.ll
@@ -169,7 +169,7 @@ define i64 @test_trunc_with_constexpr() {
define align 4 ptr @maybe_not_aligned(ptr noundef %p) {
; CHECK-LABEL: define align 4 ptr @maybe_not_aligned(
-; CHECK-SAME: ptr noundef readnone returned captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: ptr noundef readnone returned [[P:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: ret ptr [[P]]
;
ret ptr %p
@@ -177,7 +177,7 @@ define align 4 ptr @maybe_not_aligned(ptr noundef %p) {
define align 4 ptr @definitely_aligned(ptr noundef align 4 %p) {
; CHECK-LABEL: define noundef align 4 ptr @definitely_aligned(
-; CHECK-SAME: ptr noundef readnone returned align 4 captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: ptr noundef readnone returned align 4 [[P:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: ret ptr [[P]]
;
ret ptr %p
@@ -185,7 +185,7 @@ define align 4 ptr @definitely_aligned(ptr noundef align 4 %p) {
define nonnull ptr @maybe_not_nonnull(ptr noundef %p) {
; CHECK-LABEL: define nonnull ptr @maybe_not_nonnull(
-; CHECK-SAME: ptr noundef readnone returned captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: ptr noundef readnone returned [[P:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: ret ptr [[P]]
;
ret ptr %p
@@ -193,7 +193,7 @@ define nonnull ptr @maybe_not_nonnull(ptr noundef %p) {
define nonnull ptr @definitely_nonnull(ptr noundef nonnull %p) {
; CHECK-LABEL: define noundef nonnull ptr @definitely_nonnull(
-; CHECK-SAME: ptr noundef nonnull readnone returned captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: ptr noundef nonnull readnone returned [[P:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: ret ptr [[P]]
;
ret ptr %p
diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
index 5fc88d623c0ec..b24c097ad54d0 100644
--- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll
+++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
@@ -35,7 +35,7 @@ define void @test1_2(ptr %x1_2, ptr %y1_2, ptr %z1_2) {
define ptr @test2(ptr %p) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
; FNATTRS-LABEL: define {{[^@]+}}@test2
-; FNATTRS-SAME: (ptr readnone returned captures(ret: address, provenance) [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+; FNATTRS-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR0:[0-9]+]] {
; FNATTRS-NEXT: store i32 0, ptr @x, align 4
; FNATTRS-NEXT: ret ptr [[P]]
;
@@ -58,7 +58,7 @@ define ptr @test2(ptr %p) {
define i1 @test3(ptr %p, ptr %q) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define {{[^@]+}}@test3
-; FNATTRS-SAME: (ptr readnone captures(address) [[P:%.*]], ptr readnone captures(address) [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
+; FNATTRS-SAME: (ptr readnone [[P:%.*]], ptr readnone [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
; FNATTRS-NEXT: [[A:%.*]] = icmp ult ptr [[P]], [[Q]]
; FNATTRS-NEXT: ret i1 [[A]]
;
@@ -197,7 +197,7 @@ define void @test7_2(ptr preallocated(i32) %a) {
define ptr @test8_1(ptr %p) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; FNATTRS-LABEL: define {{[^@]+}}@test8_1
-; FNATTRS-SAME: (ptr readnone returned captures(ret: address, provenance) [[P:%.*]]) #[[ATTR1]] {
+; FNATTRS-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR1]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: ret ptr [[P]]
;
@@ -220,7 +220,7 @@ entry:
define void @test8_2(ptr %p) {
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
; FNATTRS-LABEL: define {{[^@]+}}@test8_2
-; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR4]] {
+; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR4]] {
; FNATTRS-NEXT: entry:
; FNATTRS-NEXT: [[CALL:%.*]] = call ptr @test8_1(ptr [[P]])
; FNATTRS-NEXT: store i32 10, ptr [[CALL]], align 4
diff --git a/llvm/test/Transforms/FunctionAttrs/stats.ll b/llvm/test/Transforms/FunctionAttrs/stats.ll
index dc0387e57174a..5f007b4078ff3 100644
--- a/llvm/test/Transforms/FunctionAttrs/stats.ll
+++ b/llvm/test/Transforms/FunctionAttrs/stats.ll
@@ -16,8 +16,8 @@ entry:
ret void
}
-; CHECK: 1 function-attrs - Number of arguments marked captures(none)
-; CHECK-NEXT: 2 function-attrs - Number of functions with improved memory attribute
+; CHECK: 2 function-attrs - Number of functions with improved memory attribute
+; CHECK-NEXT: 1 function-attrs - Number of arguments marked nocapture
; CHECK-NEXT: 1 function-attrs - Number of functions marked as nofree
; CHECK-NEXT: 2 function-attrs - Number of functions marked as norecurse
; CHECK-NEXT: 2 function-attrs - Number of functions marked as nosync
diff --git a/llvm/test/Transforms/PhaseOrdering/AArch64/block_scaling_decompr_8bit.ll b/llvm/test/Transforms/PhaseOrdering/AArch64/block_scaling_decompr_8bit.ll
index 7175816963ed1..e01dba328a3a1 100644
--- a/llvm/test/Transforms/PhaseOrdering/AArch64/block_scaling_decompr_8bit.ll
+++ b/llvm/test/Transforms/PhaseOrdering/AArch64/block_scaling_decompr_8bit.ll
@@ -9,7 +9,7 @@ target triple = "aarch64"
define dso_local noundef i32 @_Z33block_scaling_decompr_8bitjPK27compressed_data_8bitP20cmplx_int16_tPKS2_(i32 noundef %n_prb, ptr noundef %src, ptr noundef %dst, ptr noundef %scale) #0 {
; CHECK-LABEL: define dso_local noundef i32 @_Z33block_scaling_decompr_8bitjPK27compressed_data_8bitP20cmplx_int16_tPKS2_(
-; CHECK-SAME: i32 noundef [[N_PRB:%.*]], ptr noundef readonly captures(none) [[SRC:%.*]], ptr noundef writeonly captures(none) [[DST:%.*]], ptr noundef readonly captures(address_is_null) [[SCALE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+; CHECK-SAME: i32 noundef [[N_PRB:%.*]], ptr noundef readonly captures(none) [[SRC:%.*]], ptr noundef writeonly captures(none) [[DST:%.*]], ptr noundef readonly [[SCALE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[CMP47_NOT:%.*]] = icmp eq i32 [[N_PRB]], 0
; CHECK-NEXT: br i1 [[CMP47_NOT]], label %[[FOR_END:.*]], label %[[FOR_BODY_LR_PH:.*]]
diff --git a/llvm/test/Transforms/PhaseOrdering/bitcast-store-branch.ll b/llvm/test/Transforms/PhaseOrdering/bitcast-store-branch.ll
index d5edf83ee52e2..bbd4849c32296 100644
--- a/llvm/test/Transforms/PhaseOrdering/bitcast-store-branch.ll
+++ b/llvm/test/Transforms/PhaseOrdering/bitcast-store-branch.ll
@@ -12,7 +12,7 @@ entry:
define ptr @parent(ptr align 8 dereferenceable(72) %f, half %val1, i16 %val2, i32 %val3) align 2 {
; CHECK-LABEL: define noundef nonnull ptr @parent
-; CHECK-SAME: (ptr readonly returned align 8 captures(ret: address, provenance) dereferenceable(72) [[F:%.*]], half [[VAL1:%.*]], i16 [[VAL2:%.*]], i32 [[VAL3:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
+; CHECK-SAME: (ptr readonly returned align 8 dereferenceable(72) [[F:%.*]], half [[VAL1:%.*]], i16 [[VAL2:%.*]], i32 [[VAL3:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[F]], i64 64
; CHECK-NEXT: [[F_VAL:%.*]] = load ptr, ptr [[TMP0]], align 8
diff --git a/llvm/test/Transforms/PhaseOrdering/dce-after-argument-promotion-loads.ll b/llvm/test/Transforms/PhaseOrdering/dce-after-argument-promotion-loads.ll
index 4b422f205138a..ee7698b116aa2 100644
--- a/llvm/test/Transforms/PhaseOrdering/dce-after-argument-promotion-loads.ll
+++ b/llvm/test/Transforms/PhaseOrdering/dce-after-argument-promotion-loads.ll
@@ -14,7 +14,7 @@ entry:
define ptr @parent(ptr align 8 dereferenceable(72) %f, i16 %val1, i16 %val2, i32 %val3) align 2 {
; CHECK-LABEL: define noundef nonnull ptr @parent
-; CHECK-SAME: (ptr readonly returned align 8 captures(ret: address, provenance) dereferenceable(72) [[F:%.*]], i16 [[VAL1:%.*]], i16 [[VAL2:%.*]], i32 [[VAL3:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
+; CHECK-SAME: (ptr readonly returned align 8 dereferenceable(72) [[F:%.*]], i16 [[VAL1:%.*]], i16 [[VAL2:%.*]], i32 [[VAL3:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[F]], i64 64
; CHECK-NEXT: [[F_VAL:%.*]] = load ptr, ptr [[TMP0]], align 8
diff --git a/llvm/test/Transforms/PhaseOrdering/enable-loop-header-duplication-oz.ll b/llvm/test/Transforms/PhaseOrdering/enable-loop-header-duplication-oz.ll
index cd2ed37b22db5..5f75bd788e4bb 100644
--- a/llvm/test/Transforms/PhaseOrdering/enable-loop-header-duplication-oz.ll
+++ b/llvm/test/Transforms/PhaseOrdering/enable-loop-header-duplication-oz.ll
@@ -11,7 +11,7 @@
define void @test(i8* noalias nonnull align 1 %start, i8* %end) unnamed_addr {
; NOROTATION-LABEL: define void @test(
-; NOROTATION-SAME: ptr noalias nonnull writeonly align 1 captures(address) [[START:%.*]], ptr readnone captures(address) [[END:%.*]]) unnamed_addr #[[ATTR0:[0-9]+]] {
+; NOROTATION-SAME: ptr noalias nonnull writeonly align 1 [[START:%.*]], ptr readnone [[END:%.*]]) unnamed_addr #[[ATTR0:[0-9]+]] {
; NOROTATION-NEXT: entry:
; NOROTATION-NEXT: br label [[LOOP_HEADER:%.*]]
; NOROTATION: loop.header:
@@ -26,7 +26,7 @@ define void @test(i8* noalias nonnull align 1 %start, i8* %end) unnamed_addr {
; NOROTATION-NEXT: ret void
;
; ROTATION-LABEL: define void @test(
-; ROTATION-SAME: ptr noalias nonnull writeonly align 1 captures(address) [[START:%.*]], ptr readnone captures(address) [[END:%.*]]) unnamed_addr #[[ATTR0:[0-9]+]] {
+; ROTATION-SAME: ptr noalias nonnull writeonly align 1 [[START:%.*]], ptr readnone [[END:%.*]]) unnamed_addr #[[ATTR0:[0-9]+]] {
; ROTATION-NEXT: entry:
; ROTATION-NEXT: [[_12_I1:%.*]] = icmp eq ptr [[START]], [[END]]
; ROTATION-NEXT: br i1 [[_12_I1]], label [[EXIT:%.*]], label [[LOOP_LATCH_PREHEADER:%.*]]
diff --git a/llvm/unittests/Analysis/CaptureTrackingTest.cpp b/llvm/unittests/Analysis/CaptureTrackingTest.cpp
index 3f5c10d935167..73dd82fb921f7 100644
--- a/llvm/unittests/Analysis/CaptureTrackingTest.cpp
+++ b/llvm/unittests/Analysis/CaptureTrackingTest.cpp
@@ -77,9 +77,9 @@ TEST(CaptureTracking, MaxUsesToExplore) {
struct CollectingCaptureTracker : public CaptureTracker {
SmallVector<const Use *, 4> Captures;
void tooManyUses() override { }
- Action captured(const Use *U, UseCaptureInfo CI) override {
+ bool captured(const Use *U) override {
Captures.push_back(U);
- return Continue;
+ return false;
}
};
More information about the cfe-commits
mailing list