diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -608,7 +608,7 @@ } // No matching attribute found, create one. - auto &AA = AAType::createForPosition(IRP, *this) + auto &AA = AAType::createForPosition(IRP, *this); registerAA(AA); if (AA.getState().isValidState()) QueryMap[&AA].insert(const_cast(&QueryingAA)); diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -1269,15 +1269,17 @@ auto VisitValueCB = [&](Value &V, AAAlign::StateType &T, bool Stripped) -> bool { - if (isKnownNonZero(&V, DL, 0, /* TODO: AC */ nullptr, + const auto &AA = A.getAAFor(*this, IRPosition::value(V)); + if (!Stripped && this == &AA) { + if (!isKnownNonZero(&V, DL, 0, /* TODO: AC */ nullptr, /* TODO: CtxI */ nullptr, - /* TODO: DT */ nullptr)) { - // Known non-zero, all good. + /* TODO: DT */ nullptr)) + T.indicatePessimisticFixpoint(); } else { - const auto &AA = A.getAAFor(*this, IRPosition::value(V)); - // Try to use abstract attribute information. - if (!AA.isAssumedNonNull()) - T.indicateOptimisticFixpoint(); + // Use abstract attribute information. + const AANonNull::StateType &NS = + static_cast(AA.getState()); + T ^= NS; } return T.isValidState(); }; @@ -1360,6 +1362,8 @@ void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(norecurse) } }; +using AANoRecurseCallSite = AANoRecurseFunction; + /// ------------------------ Will-Return Attributes ---------------------------- // Helper function that checks whether a function has any cycle. @@ -1993,18 +1997,17 @@ const Value *Base = V.stripAndAccumulateInBoundsConstantOffsets(DL, Offset); - const auto *AA = - A.getAAFor(*this, IRPosition::value(*Base)); + const auto &AA = + A.getAAFor(*this, IRPosition::value(*Base)); int64_t DerefBytes = 0; - if (!AA || (!Stripped && - getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT)) { + if (!Stripped && this == &AA) { // Use IR information if we did not strip anything. // TODO: track globally. bool CanBeNull; DerefBytes = Base->getPointerDereferenceableBytes(DL, CanBeNull); T.GlobalState.indicatePessimisticFixpoint(); } else { - const DerefState &DS = static_cast(AA->getState()); + const DerefState &DS = static_cast(AA.getState()); DerefBytes = DS.DerefBytesState.getAssumed(); T.GlobalState &= DS.GlobalState; } @@ -2012,8 +2015,7 @@ T.takeAssumedDerefBytesMinimum( std::max(int64_t(0), DerefBytes - Offset.getSExtValue())); - if (!Stripped && - getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT) { + if (!Stripped && this == &AA) { T.takeKnownDerefBytesMaximum( std::max(int64_t(0), DerefBytes - Offset.getSExtValue())); T.indicatePessimisticFixpoint(); @@ -2038,9 +2040,11 @@ /// Dereferenceable attribute for a return value. struct AADereferenceableReturned final - : AAReturnedFromReturnedValues { + : AAReturnedFromReturnedValues { AADereferenceableReturned(const IRPosition &IRP) - : AAReturnedFromReturnedValues(IRP) {} + : AAReturnedFromReturnedValues(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { @@ -2050,9 +2054,12 @@ /// Dereferenceable attribute for an argument struct AADereferenceableArgument final - : AAArgumentFromCallSiteArguments { + : AAArgumentFromCallSiteArguments { AADereferenceableArgument(const IRPosition &IRP) - : AAArgumentFromCallSiteArguments(IRP) {} + : AAArgumentFromCallSiteArguments( + IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override{ @@ -2117,17 +2124,16 @@ auto VisitValueCB = [&](Value &V, AAAlign::StateType &T, bool Stripped) -> bool { - if (!Stripped && - getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT) { + const auto &AA = A.getAAFor(*this, IRPosition::value(V)); + if (!Stripped && this == &AA) { // Use only IR information if we did not strip anything. T.takeKnownMaximum(V.getPointerAlignment(DL)); T.indicatePessimisticFixpoint(); } else { - const auto &AA = A.getAAFor(*this, IRPosition::value(V)); - // Try to use abstract attribute information. + // Use abstract attribute information. const AAAlign::StateType &DS = static_cast(AA.getState()); - T.takeAssumedMinimum(DS.getAssumed()); + T ^= DS; } return T.isValidState(); }; diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/FunctionAttrs/align.ll --- a/llvm/test/Transforms/FunctionAttrs/align.ll +++ b/llvm/test/Transforms/FunctionAttrs/align.ll @@ -39,8 +39,7 @@ ; FIXME: Until we have "on-demand" attribute generation we do not determine the ; alignment for the return value here. -; define align 8 i32* @test5_1() -; ATTRIBUTOR: define i32* @test5_1() +; ATTRIBUTOR: define align 8 i32* @test5_1() define i32* @test5_1() { %ret = tail call align 8 i32* @unknown() ret i32* %ret @@ -48,8 +47,7 @@ ; FIXME: Until we have "on-demand" attribute generation we do not determine the ; alignment for the return value here. -; define align 8 i32* @test5_2() -; ATTRIBUTOR: define i32* @test5_2() +; ATTRIBUTOR: define align 8 i32* @test5_2() define i32* @test5_2() { %ret = tail call i32* @align8() ret i32* %ret @@ -89,10 +87,7 @@ ; Function Attrs: nounwind readnone ssp uwtable define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 { -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; alignment for the return value here. -; define internal nonnull align 8 i8* @f1(i8* nonnull readnone align 8 %0) -; ATTRIBUTOR: define internal i8* @f1(i8* nonnull readnone align 8 dereferenceable(1) %0) +; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f1(i8* nonnull readnone align 8 dereferenceable(1) %0) %2 = icmp eq i8* %0, null br i1 %2, label %3, label %5 @@ -108,10 +103,7 @@ ; Function Attrs: nounwind readnone ssp uwtable define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 { -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; alignment for the return value here. -; define internal nonnull align 8 i8* @f2(i8* nonnull readnone align 8 %0) -; ATTRIBUTOR: define internal i8* @f2(i8* nonnull readnone align 8 dereferenceable(1) %0) +; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f2(i8* nonnull readnone align 8 dereferenceable(1) %0) %2 = icmp eq i8* %0, null br i1 %2, label %5, label %3 @@ -133,10 +125,7 @@ ; Function Attrs: nounwind readnone ssp uwtable define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 { -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; alignment for the return value here. -; define internal nonnull align 8 i8* @f3(i8* nonnull readnone align 16 %0) -; ATTRIBUTOR: define internal i8* @f3(i8* nonnull readnone align 16 dereferenceable(1) %0) +; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f3(i8* nonnull readnone align 16 dereferenceable(1) %0) %2 = icmp eq i8* %0, null br i1 %2, label %3, label %5 diff --git a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll --- a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll +++ b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll @@ -806,5 +806,8 @@ ; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind uwtable } ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readnone uwtable willreturn } ; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind uwtable willreturn } +; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync willreturn } +; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync } +; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noreturn nosync } ; BOTH-DAG: attributes #{{[0-9]*}} = { noreturn } ; BOTH-NOT: attributes # diff --git a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll --- a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll +++ b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll @@ -22,23 +22,20 @@ ; TEST 3 ; GEP inbounds define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr { -; define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull dereferenceable(8) %0) -; ATTRIBUTOR: define i32* @test3_1(i32* nonnull dereferenceable(8) %0) +; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull dereferenceable(8) %0) %ret = getelementptr inbounds i32, i32* %0, i64 1 ret i32* %ret } define i32* @test3_2(i32* dereferenceable_or_null(32) %0) local_unnamed_addr { ; FIXME: Argument should be mark dereferenceable because of GEP `inbounds`. -; define nonnull dereferenceable(16) i32* @test3_2(i32* dereferenceable_or_null(32) %0) -; ATTRIBUTOR: define i32* @test3_2(i32* dereferenceable_or_null(32) %0) +; ATTRIBUTOR: define nonnull dereferenceable(16) i32* @test3_2(i32* dereferenceable_or_null(32) %0) %ret = getelementptr inbounds i32, i32* %0, i64 4 ret i32* %ret } define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1 %2) local_unnamed_addr { -; define nonnull dereferenceable(4) i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr -; ATTRIBUTOR: define i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr +; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr %ret1 = getelementptr inbounds i32, i32* %0, i64 1 %ret2 = getelementptr inbounds i32, i32* %1, i64 2 %ret = select i1 %2, i32* %ret1, i32* %ret2 diff --git a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll --- a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll +++ b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll @@ -79,19 +79,13 @@ ; TEST 5 ; Returning global pointer. Should not be noalias. -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; alignment for the return value here. -; define nonnull align 8 dereferenceable(8) i8** @getter() -; CHECK: define i8** @getter() +; CHECK: define nonnull align 8 dereferenceable(8) i8** @getter() define i8** @getter() { ret i8** @G } -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; alignment for the return value here. ; Returning global pointer. Should not be noalias. -; define nonnull align 8 dereferenceable(8) i8** @calle1() -; CHECK: define i8** @calle1() +; CHECK: define nonnull align 8 dereferenceable(8) i8** @calle1() define i8** @calle1(){ %1 = call i8** @getter() ret i8** %1 diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll --- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll +++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll @@ -8,18 +8,13 @@ ; Return a pointer trivially nonnull (call return attribute) define i8* @test1() { -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; return value properties. -; FNATTR: define nonnull i8* @test1 -; ATTRIBUTOR: define i8* @test1 +; BOTH: define nonnull i8* @test1 %ret = call i8* @ret_nonnull() ret i8* %ret } ; Return a pointer trivially nonnull (argument attribute) define i8* @test2(i8* nonnull %p) { -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; return value properties. ; BOTH: define nonnull i8* @test2 ret i8* %p } @@ -38,10 +33,7 @@ } define i8* @test3(i1 %c) { -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; return value properties. -; FNATTR: define nonnull i8* @test3 -; ATTRIBUTOR: define i8* @test3 +; BOTH: define nonnull i8* @test3 call i8* @scc_binder(i1 %c) %ret = call i8* @ret_nonnull() ret i8* %ret @@ -87,10 +79,7 @@ ; Local analysis, but going through a self recursive phi define i8* @test6() { entry: -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; return value properties. -; FNATTR: define nonnull i8* @test6 -; ATTRIBUTOR: define i8* @test6 +; BOTH: define nonnull i8* @test6 %ret = call i8* @ret_nonnull() br label %loop loop: @@ -106,10 +95,7 @@ ret i8* %b } -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; return value properties. -; FNATTR: define nonnull i8* @test8 -; ATTRIBUTOR: define i8* @test8 +; BOTH: define nonnull i8* @test8 define i8* @test8(i8* %a) { %b = getelementptr inbounds i8, i8* %a, i64 1 ret i8* %b @@ -193,7 +179,7 @@ define internal i32* @f1(i32* %arg) { ; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull %arg) -; ATTRIBUTOR: define internal i32* @f1(i32* %arg) +; ATTRIBUTOR: define internal nonnull i32* @f1(i32* %arg) bb: %tmp = icmp eq i32* %arg, null @@ -212,7 +198,7 @@ bb6: ; preds = %bb1 ; FIXME: missing nonnull. It should be @f2(i32* nonnull %arg) -; ATTRIBUTOR: %tmp7 = tail call i32* @f2(i32* %arg) +; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* %arg) %tmp7 = tail call i32* @f2(i32* %arg) ret i32* %tmp7 @@ -223,11 +209,11 @@ define internal i32* @f2(i32* %arg) { ; FIXME: missing nonnull. It should be nonnull @f2(i32* nonnull %arg) -; ATTRIBUTOR: define internal i32* @f2(i32* %arg) +; ATTRIBUTOR: define internal nonnull i32* @f2(i32* %arg) bb: ; FIXME: missing nonnull. It should be @f1(i32* nonnull %arg) -; ATTRIBUTOR: %tmp = tail call i32* @f1(i32* %arg) +; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* %arg) %tmp = tail call i32* @f1(i32* %arg) ret i32* %tmp } @@ -443,10 +429,7 @@ unreachable } -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; return value properties. -; FNATTR: define nonnull i32* @gep1( -; ATTRIBUTOR: define i32* @gep1( +; BOTH: define nonnull i32* @gep1( define i32* @gep1(i32* %p) { %q = getelementptr inbounds i32, i32* %p, i32 1 ret i32* %q @@ -465,10 +448,7 @@ ret i32 addrspace(3)* %q } -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; return value properties. -; FNATTR: define internal nonnull i32* @g2() -; ATTRIBUTOR: define internal i32* @g2() +; BOTH: define internal nonnull i32* @g2() define internal i32* @g2() { ret i32* inttoptr (i64 4 to i32*) } diff --git a/llvm/test/Transforms/FunctionAttrs/nosync.ll b/llvm/test/Transforms/FunctionAttrs/nosync.ll --- a/llvm/test/Transforms/FunctionAttrs/nosync.ll +++ b/llvm/test/Transforms/FunctionAttrs/nosync.ll @@ -27,11 +27,8 @@ ; FNATTR: Function Attrs: norecurse nounwind optsize readnone ssp uwtable ; FNATTR-NEXT: define nonnull i32* @foo(%struct.ST* readnone %s) -; FIXME: Until we have "on-demand" attribute generation we do not determine the -; return value properties. ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable -; define nonnull i32* @foo(%struct.ST* %s) -; ATTRIBUTOR-NEXT: define i32* @foo(%struct.ST* %s) +; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* %s) define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp { entry: %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 diff --git a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll --- a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll +++ b/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll @@ -162,4 +162,5 @@ ; CHECK-NOT: attributes # ; CHECK: attributes #{{.*}} = { nofree nosync nounwind } ; CHECK: attributes #{{.*}} = { nofree norecurse nosync nounwind } +; CHECK: attributes #{{.*}} = { nosync } ; CHECK-NOT: attributes #