[Attributor] Modularize AANoAliasCallSiteArgument to simplify extensions

This patch modularizes the way we check for no-alias call site arguments
by putting the existing logic into helper functions. The reasoning was
not changed but special cases for readonly/readnone were added.
This commit is contained in:
Johannes Doerfert 2020-01-27 22:24:32 -06:00
parent 24ae77eebf
commit 53992c7bf7
8 changed files with 169 additions and 81 deletions

View File

@ -2504,8 +2504,57 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl {
indicateOptimisticFixpoint();
}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
/// Determine if the underlying value may alias with the call site argument
/// \p OtherArgNo of \p ICS (= the underlying call site).
bool mayAliasWithArgument(Attributor &A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA,
ImmutableCallSite ICS, unsigned OtherArgNo) {
// We do not need to worry about aliasing with the underlying IRP.
if (this->getArgNo() == (int)OtherArgNo)
return false;
// If it is not a pointer or pointer vector we do not alias.
const Value *ArgOp = ICS.getArgOperand(OtherArgNo);
if (!ArgOp->getType()->isPtrOrPtrVectorTy())
return false;
auto &ICSArgMemBehaviorAA = A.getAAFor<AAMemoryBehavior>(
*this, IRPosition::callsite_argument(ICS, OtherArgNo),
/* TrackDependence */ false);
// If the argument is readnone, there is no read-write aliasing.
if (ICSArgMemBehaviorAA.isAssumedReadNone()) {
A.recordDependence(ICSArgMemBehaviorAA, *this, DepClassTy::OPTIONAL);
return false;
}
// If the argument is readonly and the underlying value is readonly, there
// is no read-write aliasing.
bool IsReadOnly = MemBehaviorAA.isAssumedReadOnly();
if (ICSArgMemBehaviorAA.isAssumedReadOnly() && IsReadOnly) {
A.recordDependence(MemBehaviorAA, *this, DepClassTy::OPTIONAL);
A.recordDependence(ICSArgMemBehaviorAA, *this, DepClassTy::OPTIONAL);
return false;
}
// We have to utilize actual alias analysis queries so we need the object.
if (!AAR)
AAR = A.getInfoCache().getAAResultsForFunction(*getAnchorScope());
// Try to rule it out at the call site.
bool IsAliasing = !AAR || !AAR->isNoAlias(&getAssociatedValue(), ArgOp);
LLVM_DEBUG(dbgs() << "[NoAliasCSArg] Check alias between "
"callsite arguments: "
<< getAssociatedValue() << " " << *ArgOp << " => "
<< (IsAliasing ? "" : "no-") << "alias \n");
return IsAliasing;
}
bool
isKnownNoAliasDueToNoAliasPreservation(Attributor &A, AAResults *&AAR,
const AAMemoryBehavior &MemBehaviorAA,
const AANoAlias &NoAliasAA) {
// We can deduce "noalias" if the following conditions hold.
// (i) Associated value is assumed to be noalias in the definition.
// (ii) Associated value is assumed to be no-capture in all the uses
@ -2513,62 +2562,64 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl {
// (iii) There is no other pointer argument which could alias with the
// value.
const Value &V = getAssociatedValue();
const IRPosition IRP = IRPosition::value(V);
bool AssociatedValueIsNoAliasAtDef = NoAliasAA.isAssumedNoAlias();
if (!AssociatedValueIsNoAliasAtDef) {
LLVM_DEBUG(dbgs() << "[AANoAlias] " << getAssociatedValue()
<< " is not no-alias at the definition\n");
return false;
}
// (i) Check whether noalias holds in the definition.
auto &NoAliasAA = A.getAAFor<AANoAlias>(*this, IRP);
LLVM_DEBUG(dbgs() << "[AANoAliasCSArg] check definition: " << V
<< " :: " << NoAliasAA << "\n");
if (!NoAliasAA.isAssumedNoAlias())
return indicatePessimisticFixpoint();
LLVM_DEBUG(dbgs() << "[AANoAliasCSArg] " << V
<< " is assumed NoAlias in the definition\n");
// (ii) Check whether the value is captured in the scope using AANoCapture.
// FIXME: This is conservative though, it is better to look at CFG and
// check only uses possibly executed before this callsite.
auto &NoCaptureAA = A.getAAFor<AANoCapture>(*this, IRP);
const IRPosition &VIRP = IRPosition::value(getAssociatedValue());
auto &NoCaptureAA =
A.getAAFor<AANoCapture>(*this, VIRP, /* TrackDependence */ false);
// Check whether the value is captured in the scope using AANoCapture.
// FIXME: This is conservative though, it is better to look at CFG and
// check only uses possibly executed before this callsite.
if (!NoCaptureAA.isAssumedNoCaptureMaybeReturned()) {
LLVM_DEBUG(
dbgs() << "[AANoAliasCSArg] " << V
dbgs() << "[AANoAliasCSArg] " << getAssociatedValue()
<< " cannot be noalias as it is potentially captured\n");
return indicatePessimisticFixpoint();
return false;
}
A.recordDependence(NoCaptureAA, *this, DepClassTy::OPTIONAL);
// (iii) Check there is no other pointer argument which could alias with the
// value.
// Check there is no other pointer argument which could alias with the
// value passed at this call site.
// TODO: AbstractCallSite
ImmutableCallSite ICS(&getAnchorValue());
for (unsigned i = 0; i < ICS.getNumArgOperands(); i++) {
if (getArgNo() == (int)i)
continue;
const Value *ArgOp = ICS.getArgOperand(i);
if (!ArgOp->getType()->isPointerTy())
continue;
for (unsigned OtherArgNo = 0; OtherArgNo < ICS.getNumArgOperands();
OtherArgNo++)
if (mayAliasWithArgument(A, AAR, MemBehaviorAA, ICS, OtherArgNo))
return false;
if (const Function *F = getAnchorScope()) {
if (AAResults *AAR = A.getInfoCache().getAAResultsForFunction(*F)) {
bool IsAliasing = !AAR->isNoAlias(&getAssociatedValue(), ArgOp);
LLVM_DEBUG(dbgs()
<< "[NoAliasCSArg] Check alias between "
"callsite arguments "
<< AAR->isNoAlias(&getAssociatedValue(), ArgOp) << " "
<< getAssociatedValue() << " " << *ArgOp << " => "
<< (IsAliasing ? "" : "no-") << "alias \n");
return true;
}
if (!IsAliasing)
continue;
}
}
return indicatePessimisticFixpoint();
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
// If the argument is readnone we are done as there are no accesses via the
// argument.
auto &MemBehaviorAA =
A.getAAFor<AAMemoryBehavior>(*this, getIRPosition(),
/* TrackDependence */ false);
if (MemBehaviorAA.isAssumedReadNone()) {
A.recordDependence(MemBehaviorAA, *this, DepClassTy::OPTIONAL);
return ChangeStatus::UNCHANGED;
}
return ChangeStatus::UNCHANGED;
const IRPosition &VIRP = IRPosition::value(getAssociatedValue());
const auto &NoAliasAA = A.getAAFor<AANoAlias>(*this, VIRP,
/* TrackDependence */ false);
AAResults *AAR = nullptr;
if (isKnownNoAliasDueToNoAliasPreservation(A, AAR, MemBehaviorAA,
NoAliasAA)) {
LLVM_DEBUG(
dbgs() << "[AANoAlias] No-Alias deduced via no-alias preservation\n");
return ChangeStatus::UNCHANGED;
}
return indicatePessimisticFixpoint();
}
/// See AbstractAttribute::trackStatistics()

View File

@ -29,7 +29,7 @@ entry:
; Function Attrs: nounwind uwtable
define internal void @callee_t0f(i8* nocapture readnone %tp13, i8* nocapture readnone %tp14, i8* nocapture readnone %tp15, i8* nocapture readnone %tp16, i8* nocapture readnone %tp17, ...) {
; CHECK-LABEL: define {{[^@]+}}@callee_t0f
; CHECK-SAME: (i8* nocapture nofree nonnull readnone [[TP13:%.*]], i8* nocapture nofree nonnull readnone [[TP14:%.*]], i8* nocapture nofree nonnull readnone [[TP15:%.*]], i8* nocapture nofree nonnull readnone [[TP16:%.*]], i8* nocapture nofree nonnull readnone [[TP17:%.*]], ...)
; CHECK-SAME: (i8* noalias nocapture nofree nonnull readnone [[TP13:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP14:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP15:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP16:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP17:%.*]], ...)
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;

View File

@ -34,9 +34,9 @@ define dso_local i32 @main() {
; CHECK-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; CHECK-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; CHECK-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 null)
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; CHECK-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; CHECK-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; CHECK-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; CHECK-NEXT: ret i32 0
;
entry:
@ -64,7 +64,7 @@ entry:
define internal i8* @bar(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@bar
; CHECK-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(8) [[ARG:%.*]])
; CHECK-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(8) [[ARG:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
;
@ -84,7 +84,7 @@ entry:
define internal i8* @buz(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@buz
; CHECK-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(1) [[ARG:%.*]])
; CHECK-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(1) [[ARG:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i8* [[ARG]]
;

View File

@ -147,11 +147,11 @@ define align 4 i32* @test7(i32* align 32 %p) #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f1b
; ATTRIBUTOR-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; ATTRIBUTOR: 3:
; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b(i8* nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8
; ATTRIBUTOR-NEXT: store i8 [[L]], i8* @a1, align 8
; ATTRIBUTOR-NEXT: br label [[TMP5]]
@ -177,14 +177,14 @@ define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 {
;
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f2b
; ATTRIBUTOR-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* @a1, null
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
; ATTRIBUTOR: 3:
; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1)
; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1)
; ATTRIBUTOR-NEXT: br label [[TMP7:%.*]]
; ATTRIBUTOR: 5:
; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = tail call i8* @f3b(i8* nofree nonnull readnone align 16 dereferenceable(1) @a2)
; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = tail call i8* @f3b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2)
; ATTRIBUTOR-NEXT: br label [[TMP7]]
; ATTRIBUTOR: 7:
; ATTRIBUTOR-NEXT: [[TMP8:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ]
@ -211,11 +211,11 @@ define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 {
define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 {
;
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f3b
; ATTRIBUTOR-SAME: (i8* nocapture nofree nonnull readnone align 16 dereferenceable(1) [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR-SAME: (i8* noalias nocapture nofree nonnull readnone align 16 dereferenceable(1) [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* @a2, null
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; ATTRIBUTOR: 3:
; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* nofree nonnull readnone align 16 dereferenceable(1) @a2)
; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2)
; ATTRIBUTOR-NEXT: br label [[TMP5]]
; ATTRIBUTOR: 5:
; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ @a1, [[TMP1:%.*]] ]
@ -236,7 +236,7 @@ define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 {
define align 4 i32* @test7b(i32* align 32 %p) #0 {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7b
; ATTRIBUTOR-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]])
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = tail call i8* @f1b(i8* nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR-NEXT: ret i32* [[P]]
;
tail call i8* @f1b(i8* align 8 dereferenceable(1) @a1)
@ -252,17 +252,17 @@ define void @test8_helper() {
%ptr2 = tail call align 8 i32* @unknown()
tail call void @test8(i32* %ptr1, i32* %ptr1, i32* %ptr0)
; ATTRIBUTOR: tail call void @test8(i32* readnone align 4 %ptr1, i32* readnone align 4 %ptr1, i32* readnone %ptr0)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1, i32* noalias readnone %ptr0)
tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1)
; ATTRIBUTOR: tail call void @test8(i32* readnone align 8 %ptr2, i32* readnone align 4 %ptr1, i32* readnone align 4 %ptr1)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 8 %ptr2, i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1)
tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1)
; ATTRIBUTOR: tail call void @test8(i32* readnone align 8 %ptr2, i32* readnone align 4 %ptr1, i32* readnone align 4 %ptr1)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 8 %ptr2, i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1)
ret void
}
declare void @user_i32_ptr(i32*) readnone nounwind
define internal void @test8(i32* %a, i32* %b, i32* %c) {
; ATTRIBUTOR: define internal void @test8(i32* nocapture readnone align 4 %a, i32* nocapture readnone align 4 %b, i32* nocapture readnone %c)
; ATTRIBUTOR: define internal void @test8(i32* noalias nocapture readnone align 4 %a, i32* noalias nocapture readnone align 4 %b, i32* noalias nocapture readnone %c)
call void @user_i32_ptr(i32* %a)
call void @user_i32_ptr(i32* %b)
call void @user_i32_ptr(i32* %c)

View File

@ -21,11 +21,7 @@ entry:
}
; FIXME: Should be something like this.
; define internal i32 @noalias_args_argmem(i32* noalias nocapture readonly %A, i32* noalias nocapture readonly %B)
; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %B)
;
; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B)
define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 {
entry:
%0 = load i32, i32* %A, align 4
@ -44,5 +40,34 @@ entry:
ret i32 %add
}
; CHECK: define internal i32 @noalias_args_argmem_ro(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B)
define internal i32 @noalias_args_argmem_ro(i32* %A, i32* %B) #1 {
%t0 = load i32, i32* %A, align 4
%t1 = load i32, i32* %B, align 4
%add = add nsw i32 %t0, %t1
ret i32 %add
}
define i32 @visible_local_2() {
%B = alloca i32, align 4
store i32 5, i32* %B, align 4
%call = call i32 @noalias_args_argmem_ro(i32* %B, i32* %B)
ret i32 %call
}
; CHECK: define internal i32 @noalias_args_argmem_rn(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) %B)
define internal i32 @noalias_args_argmem_rn(i32* %A, i32* %B) #1 {
%t0 = load i32, i32* %B, align 4
store i32 0, i32* %B
ret i32 %t0
}
define i32 @visible_local_3() {
%B = alloca i32, align 4
store i32 5, i32* %B, align 4
%call = call i32 @noalias_args_argmem_rn(i32* %B, i32* %B)
ret i32 %call
}
attributes #0 = { noinline nounwind uwtable willreturn }
attributes #1 = { argmemonly noinline nounwind uwtable willreturn}

View File

@ -10,7 +10,7 @@ define internal void @internal(void (i8*)* %fp) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) undef)
; CHECK-NEXT: call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef)
; CHECK-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
@ -24,7 +24,7 @@ define internal void @internal(void (i8*)* %fp) {
; DECL_CS-NEXT: entry:
; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4
; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) undef)
; DECL_CS-NEXT: call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef)
; DECL_CS-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
@ -52,7 +52,7 @@ define void @external(void (i8*)* %fp) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) undef)
; CHECK-NEXT: call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef)
; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
; CHECK-NEXT: call void @callback2(void (i8*)* [[FP]])
@ -67,7 +67,7 @@ define void @external(void (i8*)* %fp) {
; DECL_CS-NEXT: entry:
; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4
; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) undef)
; DECL_CS-NEXT: call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef)
; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
; DECL_CS-NEXT: call void @callback2(void (i8*)* [[FP]])

View File

@ -1,4 +1,4 @@
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 < %s | FileCheck %s
; TEST 1 - negative.
@ -152,27 +152,39 @@ define i8* @test8(i32* %0) nounwind uwtable {
; TEST 9
; Simple Argument Test
declare void @use_i8(i8* nocapture) readnone
declare void @use_i8(i8* nocapture)
define internal void @test9a(i8* %a, i8* %b) {
; CHECK: define internal void @test9a()
ret void
}
define internal void @test9b(i8* %a, i8* %b) {
; CHECK: define internal void @test9b(i8* noalias nocapture readnone %a, i8* nocapture readnone %b)
; FIXME: %b should be noalias
; CHECK: define internal void @test9b(i8* noalias nocapture %a, i8* nocapture %b)
call void @use_i8(i8* %a)
call void @use_i8(i8* %b)
ret void
}
define internal void @test9c(i8* %a, i8* %b, i8* %c) {
; CHECK: define internal void @test9c(i8* noalias nocapture %a, i8* nocapture %b, i8* nocapture %c)
call void @use_i8(i8* %a)
call void @use_i8(i8* %b)
call void @use_i8(i8* %c)
ret void
}
define void @test9_helper(i8* %a, i8* %b) {
; CHECK: define void @test9_helper(i8* nocapture readnone %a, i8* nocapture readnone %b)
; CHECK: define void @test9_helper(i8* nocapture %a, i8* nocapture %b)
; CHECK: tail call void @test9a()
; CHECK: tail call void @test9a()
; CHECK: tail call void @test9b(i8* noalias nocapture readnone %a, i8* nocapture readnone %b)
; CHECK: tail call void @test9b(i8* noalias nocapture readnone %b, i8* noalias nocapture readnone %a)
; CHECK: tail call void @test9b(i8* noalias nocapture %a, i8* nocapture %b)
; CHECK: tail call void @test9b(i8* noalias nocapture %b, i8* noalias nocapture %a)
; CHECK: tail call void @test9c(i8* noalias nocapture %a, i8* nocapture %b, i8* nocapture %b)
; CHECK: tail call void @test9c(i8* noalias nocapture %b, i8* noalias nocapture %a, i8* noalias nocapture %a)
tail call void @test9a(i8* noalias %a, i8* %b)
tail call void @test9a(i8* noalias %b, i8* noalias %a)
tail call void @test9b(i8* noalias %a, i8* %b)
tail call void @test9b(i8* noalias %b, i8* noalias %a)
tail call void @test9c(i8* noalias %a, i8* %b, i8* %b)
tail call void @test9c(i8* noalias %b, i8* noalias %a, i8* noalias %a)
ret void
}

View File

@ -167,7 +167,7 @@ define void @test13_helper() {
}
declare void @use_i8_ptr(i8* nofree) readnone nounwind
define internal void @test13(i8* %a, i8* %b, i8* %c) {
; ATTRIBUTOR: define internal void @test13(i8* nocapture nofree nonnull readnone %a, i8* nocapture nofree readnone %b, i8* nocapture nofree readnone %c)
; ATTRIBUTOR: define internal void @test13(i8* noalias nocapture nofree nonnull readnone %a, i8* noalias nocapture nofree readnone %b, i8* noalias nocapture nofree readnone %c)
call void @use_i8_ptr(i8* %a)
call void @use_i8_ptr(i8* %b)
call void @use_i8_ptr(i8* %c)
@ -536,7 +536,7 @@ define i32* @g1() {
}
declare void @use_i32_ptr(i32*) readnone nounwind
; ATTRIBUTOR: define internal void @called_by_weak(i32* nocapture nonnull readnone %a)
; ATTRIBUTOR: define internal void @called_by_weak(i32* noalias nocapture nonnull readnone %a)
define internal void @called_by_weak(i32* %a) {
call void @use_i32_ptr(i32* %a)
ret void
@ -550,7 +550,7 @@ define weak_odr void @weak_caller(i32* nonnull %a) {
}
; Expect nonnull
; ATTRIBUTOR: define internal void @control(i32* nocapture nonnull readnone align 16 dereferenceable(8) %a)
; ATTRIBUTOR: define internal void @control(i32* noalias nocapture nonnull readnone align 16 dereferenceable(8) %a)
define internal void @control(i32* dereferenceable(4) %a) {
call void @use_i32_ptr(i32* %a)
ret void