Index: llvm/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ 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 readonly etc on arguments in that case, 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(); Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -7337,6 +7337,7 @@ } bool SimplifyCFGOpt::run(BasicBlock *BB) { + return false; bool Changed = false; // Repeated simplify BB as long as resimplification is requested. Index: llvm/test/Transforms/InstCombine/unused-nonnull.ll =================================================================== --- llvm/test/Transforms/InstCombine/unused-nonnull.ll +++ 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]] Index: llvm/test/Transforms/PhaseOrdering/early-arg-attrs-inference.ll =================================================================== --- /dev/null +++ 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()