forked from OSchip/llvm-project
[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:
parent
24ae77eebf
commit
53992c7bf7
|
@ -2504,8 +2504,57 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl {
|
||||||
indicateOptimisticFixpoint();
|
indicateOptimisticFixpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See AbstractAttribute::updateImpl(...).
|
/// Determine if the underlying value may alias with the call site argument
|
||||||
ChangeStatus updateImpl(Attributor &A) override {
|
/// \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.
|
// We can deduce "noalias" if the following conditions hold.
|
||||||
// (i) Associated value is assumed to be noalias in the definition.
|
// (i) Associated value is assumed to be noalias in the definition.
|
||||||
// (ii) Associated value is assumed to be no-capture in all the uses
|
// (ii) Associated value is assumed to be no-capture in all the uses
|
||||||
|
@ -2513,64 +2562,66 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl {
|
||||||
// (iii) There is no other pointer argument which could alias with the
|
// (iii) There is no other pointer argument which could alias with the
|
||||||
// value.
|
// value.
|
||||||
|
|
||||||
const Value &V = getAssociatedValue();
|
bool AssociatedValueIsNoAliasAtDef = NoAliasAA.isAssumedNoAlias();
|
||||||
const IRPosition IRP = IRPosition::value(V);
|
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.
|
const IRPosition &VIRP = IRPosition::value(getAssociatedValue());
|
||||||
|
auto &NoCaptureAA =
|
||||||
auto &NoAliasAA = A.getAAFor<AANoAlias>(*this, IRP);
|
A.getAAFor<AANoCapture>(*this, VIRP, /* TrackDependence */ false);
|
||||||
LLVM_DEBUG(dbgs() << "[AANoAliasCSArg] check definition: " << V
|
// Check whether the value is captured in the scope using AANoCapture.
|
||||||
<< " :: " << 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
|
// FIXME: This is conservative though, it is better to look at CFG and
|
||||||
// check only uses possibly executed before this callsite.
|
// check only uses possibly executed before this callsite.
|
||||||
|
|
||||||
auto &NoCaptureAA = A.getAAFor<AANoCapture>(*this, IRP);
|
|
||||||
if (!NoCaptureAA.isAssumedNoCaptureMaybeReturned()) {
|
if (!NoCaptureAA.isAssumedNoCaptureMaybeReturned()) {
|
||||||
LLVM_DEBUG(
|
LLVM_DEBUG(
|
||||||
dbgs() << "[AANoAliasCSArg] " << V
|
dbgs() << "[AANoAliasCSArg] " << getAssociatedValue()
|
||||||
<< " cannot be noalias as it is potentially captured\n");
|
<< " 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
|
// Check there is no other pointer argument which could alias with the
|
||||||
// value.
|
// value passed at this call site.
|
||||||
// TODO: AbstractCallSite
|
// TODO: AbstractCallSite
|
||||||
ImmutableCallSite ICS(&getAnchorValue());
|
ImmutableCallSite ICS(&getAnchorValue());
|
||||||
for (unsigned i = 0; i < ICS.getNumArgOperands(); i++) {
|
for (unsigned OtherArgNo = 0; OtherArgNo < ICS.getNumArgOperands();
|
||||||
if (getArgNo() == (int)i)
|
OtherArgNo++)
|
||||||
continue;
|
if (mayAliasWithArgument(A, AAR, MemBehaviorAA, ICS, OtherArgNo))
|
||||||
const Value *ArgOp = ICS.getArgOperand(i);
|
return false;
|
||||||
if (!ArgOp->getType()->isPointerTy())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (const Function *F = getAnchorScope()) {
|
return true;
|
||||||
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");
|
|
||||||
|
|
||||||
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()
|
/// See AbstractAttribute::trackStatistics()
|
||||||
void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(noalias) }
|
void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(noalias) }
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,7 @@ entry:
|
||||||
; Function Attrs: nounwind uwtable
|
; 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, ...) {
|
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-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: entry:
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
|
|
|
@ -34,9 +34,9 @@ define dso_local i32 @main() {
|
||||||
; CHECK-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
|
; CHECK-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
|
||||||
; CHECK-NEXT: [[THREAD:%.*]] = alloca i64, 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: [[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: [[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
|
; CHECK-NEXT: ret i32 0
|
||||||
;
|
;
|
||||||
entry:
|
entry:
|
||||||
|
@ -64,7 +64,7 @@ entry:
|
||||||
|
|
||||||
define internal i8* @bar(i8* %arg) {
|
define internal i8* @bar(i8* %arg) {
|
||||||
; CHECK-LABEL: define {{[^@]+}}@bar
|
; 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: entry:
|
||||||
; CHECK-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
|
; CHECK-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
|
||||||
;
|
;
|
||||||
|
@ -84,7 +84,7 @@ entry:
|
||||||
|
|
||||||
define internal i8* @buz(i8* %arg) {
|
define internal i8* @buz(i8* %arg) {
|
||||||
; CHECK-LABEL: define {{[^@]+}}@buz
|
; 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: entry:
|
||||||
; CHECK-NEXT: ret i8* [[ARG]]
|
; CHECK-NEXT: ret i8* [[ARG]]
|
||||||
;
|
;
|
||||||
|
|
|
@ -147,11 +147,11 @@ define align 4 i32* @test7(i32* align 32 %p) #0 {
|
||||||
; Function Attrs: nounwind readnone ssp uwtable
|
; Function Attrs: nounwind readnone ssp uwtable
|
||||||
define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
|
define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
|
||||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f1b
|
; 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: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
|
||||||
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
|
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
|
||||||
; ATTRIBUTOR: 3:
|
; 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: [[L:%.*]] = load i8, i8* [[TMP4]], align 8
|
||||||
; ATTRIBUTOR-NEXT: store i8 [[L]], i8* @a1, align 8
|
; ATTRIBUTOR-NEXT: store i8 [[L]], i8* @a1, align 8
|
||||||
; ATTRIBUTOR-NEXT: br label [[TMP5]]
|
; 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 {
|
define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 {
|
||||||
;
|
;
|
||||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f2b
|
; 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: [[TMP2:%.*]] = icmp eq i8* @a1, null
|
||||||
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
|
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
|
||||||
; ATTRIBUTOR: 3:
|
; 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-NEXT: br label [[TMP7:%.*]]
|
||||||
; ATTRIBUTOR: 5:
|
; 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-NEXT: br label [[TMP7]]
|
||||||
; ATTRIBUTOR: 7:
|
; ATTRIBUTOR: 7:
|
||||||
; ATTRIBUTOR-NEXT: [[TMP8:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ]
|
; 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 {
|
define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 {
|
||||||
;
|
;
|
||||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f3b
|
; 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: [[TMP2:%.*]] = icmp eq i8* @a2, null
|
||||||
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
|
; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
|
||||||
; ATTRIBUTOR: 3:
|
; 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-NEXT: br label [[TMP5]]
|
||||||
; ATTRIBUTOR: 5:
|
; ATTRIBUTOR: 5:
|
||||||
; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ @a1, [[TMP1:%.*]] ]
|
; 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 {
|
define align 4 i32* @test7b(i32* align 32 %p) #0 {
|
||||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7b
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7b
|
||||||
; ATTRIBUTOR-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]])
|
; 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]]
|
; ATTRIBUTOR-NEXT: ret i32* [[P]]
|
||||||
;
|
;
|
||||||
tail call i8* @f1b(i8* align 8 dereferenceable(1) @a1)
|
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()
|
%ptr2 = tail call align 8 i32* @unknown()
|
||||||
|
|
||||||
tail call void @test8(i32* %ptr1, i32* %ptr1, i32* %ptr0)
|
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)
|
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)
|
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
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @user_i32_ptr(i32*) readnone nounwind
|
declare void @user_i32_ptr(i32*) readnone nounwind
|
||||||
define internal void @test8(i32* %a, i32* %b, i32* %c) {
|
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* %a)
|
||||||
call void @user_i32_ptr(i32* %b)
|
call void @user_i32_ptr(i32* %b)
|
||||||
call void @user_i32_ptr(i32* %c)
|
call void @user_i32_ptr(i32* %c)
|
||||||
|
|
|
@ -21,11 +21,7 @@ entry:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
; FIXME: Should be something like this.
|
; 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* 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)
|
|
||||||
|
|
||||||
;
|
|
||||||
define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 {
|
define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 {
|
||||||
entry:
|
entry:
|
||||||
%0 = load i32, i32* %A, align 4
|
%0 = load i32, i32* %A, align 4
|
||||||
|
@ -44,5 +40,34 @@ entry:
|
||||||
ret i32 %add
|
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 #0 = { noinline nounwind uwtable willreturn }
|
||||||
attributes #1 = { argmemonly noinline nounwind uwtable willreturn}
|
attributes #1 = { argmemonly noinline nounwind uwtable willreturn}
|
||||||
|
|
|
@ -10,7 +10,7 @@ define internal void @internal(void (i8*)* %fp) {
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||||
; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
|
; 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 [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
|
||||||
; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo)
|
; 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*)* 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: entry:
|
||||||
; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4
|
; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||||
; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
|
; 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 [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
|
||||||
; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo)
|
; 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*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
|
||||||
|
@ -52,7 +52,7 @@ define void @external(void (i8*)* %fp) {
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||||
; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
|
; 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 @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*)* bitcast (void (i32*)* @foo to void (i8*)*))
|
||||||
; CHECK-NEXT: call void @callback2(void (i8*)* [[FP]])
|
; 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: entry:
|
||||||
; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4
|
; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4
|
||||||
; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
|
; 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 @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*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
|
||||||
; DECL_CS-NEXT: call void @callback2(void (i8*)* [[FP]])
|
; DECL_CS-NEXT: call void @callback2(void (i8*)* [[FP]])
|
||||||
|
|
|
@ -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.
|
; TEST 1 - negative.
|
||||||
|
|
||||||
|
@ -152,27 +152,39 @@ define i8* @test8(i32* %0) nounwind uwtable {
|
||||||
|
|
||||||
; TEST 9
|
; TEST 9
|
||||||
; Simple Argument Test
|
; Simple Argument Test
|
||||||
declare void @use_i8(i8* nocapture) readnone
|
declare void @use_i8(i8* nocapture)
|
||||||
define internal void @test9a(i8* %a, i8* %b) {
|
define internal void @test9a(i8* %a, i8* %b) {
|
||||||
; CHECK: define internal void @test9a()
|
; CHECK: define internal void @test9a()
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
define internal void @test9b(i8* %a, i8* %b) {
|
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* %a)
|
||||||
call void @use_i8(i8* %b)
|
call void @use_i8(i8* %b)
|
||||||
ret void
|
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) {
|
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 @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 %a, i8* nocapture %b)
|
||||||
; CHECK: tail call void @test9b(i8* noalias nocapture readnone %b, i8* noalias nocapture readnone %a)
|
; 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 %a, i8* %b)
|
||||||
tail call void @test9a(i8* noalias %b, i8* noalias %a)
|
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 %a, i8* %b)
|
||||||
tail call void @test9b(i8* noalias %b, i8* noalias %a)
|
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
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ define void @test13_helper() {
|
||||||
}
|
}
|
||||||
declare void @use_i8_ptr(i8* nofree) readnone nounwind
|
declare void @use_i8_ptr(i8* nofree) readnone nounwind
|
||||||
define internal void @test13(i8* %a, i8* %b, i8* %c) {
|
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* %a)
|
||||||
call void @use_i8_ptr(i8* %b)
|
call void @use_i8_ptr(i8* %b)
|
||||||
call void @use_i8_ptr(i8* %c)
|
call void @use_i8_ptr(i8* %c)
|
||||||
|
@ -536,7 +536,7 @@ define i32* @g1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @use_i32_ptr(i32*) readnone nounwind
|
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) {
|
define internal void @called_by_weak(i32* %a) {
|
||||||
call void @use_i32_ptr(i32* %a)
|
call void @use_i32_ptr(i32* %a)
|
||||||
ret void
|
ret void
|
||||||
|
@ -550,7 +550,7 @@ define weak_odr void @weak_caller(i32* nonnull %a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
; Expect nonnull
|
; 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) {
|
define internal void @control(i32* dereferenceable(4) %a) {
|
||||||
call void @use_i32_ptr(i32* %a)
|
call void @use_i32_ptr(i32* %a)
|
||||||
ret void
|
ret void
|
||||||
|
|
Loading…
Reference in New Issue