diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -693,7 +693,7 @@ } Expected parsePostOrderFunctionAttrsPassOptions(StringRef Params) { - return parseSinglePassOption(Params, "skip-non-recursive", + return parseSinglePassOption(Params, "skip-non-recursive-function-attrs", "PostOrderFunctionAttrs"); } diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -235,7 +235,7 @@ return PostOrderFunctionAttrsPass(SkipNonRecursive); }, parsePostOrderFunctionAttrsPassOptions, - "skip-non-recursive") + "skip-non-recursive-function-attrs") #undef CGSCC_PASS_WITH_PARAMS #ifndef FUNCTION_ANALYSIS diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1720,7 +1720,8 @@ template static SmallSet -deriveAttrsInPostOrder(ArrayRef Functions, AARGetterT &&AARGetter) { +deriveAttrsInPostOrder(ArrayRef Functions, AARGetterT &&AARGetter, + bool ArgAttrsOnly) { SCCNodesResult Nodes = createSCCNodeSet(Functions); // Bail if the SCC only contains optnone functions. @@ -1728,6 +1729,10 @@ return {}; SmallSet Changed; + if (ArgAttrsOnly) { + addArgumentAttrs(Nodes.SCCNodes, Changed); + return Changed; + } addArgumentReturnedAttrs(Nodes.SCCNodes, Changed); addMemoryAttrs(Nodes.SCCNodes, AARGetter, Changed); @@ -1762,10 +1767,13 @@ LazyCallGraph &CG, CGSCCUpdateResult &) { // Skip non-recursive functions if requested. + // Only infer argument attributes for non-recursive functions, because + // it can affect optimization behavior in conjunction with noalias. + bool ArgAttrsOnly = false; if (C.size() == 1 && SkipNonRecursive) { LazyCallGraph::Node &N = *C.begin(); if (!N->lookup(N)) - return PreservedAnalyses::all(); + ArgAttrsOnly = true; } FunctionAnalysisManager &FAM = @@ -1782,7 +1790,8 @@ Functions.push_back(&N.getFunction()); } - auto ChangedFunctions = deriveAttrsInPostOrder(Functions, AARGetter); + auto ChangedFunctions = + deriveAttrsInPostOrder(Functions, AARGetter, ArgAttrsOnly); if (ChangedFunctions.empty()) return PreservedAnalyses::all(); @@ -1818,7 +1827,7 @@ static_cast *>(this)->printPipeline( OS, MapClassName2PassName); if (SkipNonRecursive) - OS << ""; + OS << ""; } template diff --git a/llvm/test/Other/new-pm-print-pipeline.ll b/llvm/test/Other/new-pm-print-pipeline.ll --- a/llvm/test/Other/new-pm-print-pipeline.ll +++ b/llvm/test/Other/new-pm-print-pipeline.ll @@ -99,8 +99,8 @@ ; CHECK-28: function(instcombine,instcombine) ;; Test function-attrs -; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='cgscc(function-attrs)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-29 -; CHECK-29: cgscc(function-attrs) +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='cgscc(function-attrs)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-29 +; CHECK-29: cgscc(function-attrs) ;; Test cgscc -> function adaptor ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='cgscc(function(no-op-function))' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-30 diff --git a/llvm/test/Transforms/InstCombine/unused-nonnull.ll b/llvm/test/Transforms/InstCombine/unused-nonnull.ll --- a/llvm/test/Transforms/InstCombine/unused-nonnull.ll +++ b/llvm/test/Transforms/InstCombine/unused-nonnull.ll @@ -9,7 +9,7 @@ define i32 @main(i32 %argc, ptr %argv) #0 { ; CHECK-LABEL: define {{[^@]+}}@main -; CHECK-SAME: (i32 [[ARGC:%.*]], ptr nocapture readnone [[ARGV:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +; CHECK-SAME: (i32 [[ARGC:%.*]], ptr nocapture readonly [[ARGV:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[ARGC]], 2 ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TMP0]], i32 0, i32 [[ARGC]] diff --git a/llvm/test/Transforms/PhaseOrdering/early-arg-attrs-inference.ll b/llvm/test/Transforms/PhaseOrdering/early-arg-attrs-inference.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/PhaseOrdering/early-arg-attrs-inference.ll @@ -0,0 +1,27 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: opt -S -O3 -memssa-check-limit=1 -memdep-block-scan-limit=1 < %s | FileCheck %s + +define i32 @f(ptr noalias %p, i32 %c) { +; CHECK-LABEL: define i32 @f +; CHECK-SAME: (ptr noalias nocapture readonly [[P:%.*]], i32 [[C:%.*]]) local_unnamed_addr { +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: ret i32 0 +; + %i = load i32, ptr %p + call void @g() + call void @g() + call void @g() + call void @g() + call void @g() + call void @g() + %i2 = load i32, ptr %p + %r = sub i32 %i, %i2 + ret i32 %r +} + +declare void @g()