Index: llvm/lib/Transforms/Scalar/SCCP.cpp =================================================================== --- llvm/lib/Transforms/Scalar/SCCP.cpp +++ llvm/lib/Transforms/Scalar/SCCP.cpp @@ -34,6 +34,7 @@ #include "llvm/Analysis/ValueLattice.h" #include "llvm/Analysis/ValueLatticeUtils.h" #include "llvm/IR/BasicBlock.h" +#include "llvm/IR/AbstractCallSite.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" @@ -2035,11 +2036,29 @@ } // Zap all returns which we've identified as zap to change. + SmallPtrSet FuncZappedReturn; for (unsigned i = 0, e = ReturnsToZap.size(); i != e; ++i) { Function *F = ReturnsToZap[i]->getParent()->getParent(); ReturnsToZap[i]->setOperand(0, UndefValue::get(F->getReturnType())); + // Record all functions that are zapped + if (FuncZappedReturn.find(F) == FuncZappedReturn.end()) + FuncZappedReturn.insert(F); + } + + // Remove the returned attribute for zapped functions and the + // corresponding call sites + for (Function *F : FuncZappedReturn) { + for (Argument &A : F->args()) + F->removeParamAttr(A.getArgNo(), Attribute::Returned); + for (Use &U : F->uses()) { + CallBase *CB = dyn_cast(U.getUser()); + if (!CB) + continue; + for (auto &arg : CB->args()) { + CB->removeParamAttr(CB->getArgOperandNo(&arg), Attribute::Returned); + } + } } - // If we inferred constant or undef values for globals variables, we can // delete the global and any stores that remain to it. for (auto &I : make_early_inc_range(Solver.getTrackedGlobals())) { Index: llvm/test/Transforms/SCCP/ipsccp-clear-returned.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/SCCP/ipsccp-clear-returned.ll @@ -0,0 +1,24 @@ +; if IPSCCP determines a function returns undef, +; then the "returned" attribute of input arguments +; should be cleared. + +; RUN: opt < %s -ipsccp -S | FileCheck %s +define i32 @main() { +; CHECK-LABEL: @main +entry: +; CHECK-NEXT: entry: + %call = call i32 @func_return_undef(i32 returned 1) +; CHECK: call i32 @func_return_undef(i32 1) +; CHECK-NOT: returned + ret i32 %call +; CHECK: ret i32 1 +} + +define internal i32 @func_return_undef(i32 returned %arg) { +; CHECK: {{define.*@func_return_undef}} +; CHECK-NOT: returned +entry: +; CHECK-NEXT: entry: +; CHECK-NEXT: {{ret.*undef}} +ret i32 %arg +}