diff --git a/llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h b/llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h --- a/llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h +++ b/llvm/include/llvm/Transforms/IPO/DeadArgumentElimination.h @@ -128,6 +128,7 @@ Liveness SurveyUses(const Value *V, UseVector &MaybeLiveUses); void SurveyFunction(const Function &F); + bool IsLive(const RetOrArg &RA); void MarkValue(const RetOrArg &RA, Liveness L, const UseVector &MaybeLiveUses); void MarkLive(const RetOrArg &RA); diff --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp --- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -357,7 +357,7 @@ DeadArgumentEliminationPass::MarkIfNotLive(RetOrArg Use, UseVector &MaybeLiveUses) { // We're live if our use or its Function is already marked as live. - if (LiveFunctions.count(Use.F) || LiveValues.count(Use)) + if (IsLive(Use)) return Live; // We're maybe live otherwise, but remember that we must become live if @@ -657,10 +657,18 @@ MarkLive(RA); break; case MaybeLive: - // Note any uses of this value, so this return value can be - // marked live whenever one of the uses becomes live. - for (const auto &MaybeLiveUse : MaybeLiveUses) - Uses.insert(std::make_pair(MaybeLiveUse, RA)); + assert(!IsLive(RA) && "Use is already live!"); + for (const auto &MaybeLiveUse : MaybeLiveUses) { + if (IsLive(MaybeLiveUse)) { + // A use is live, so this value is live. + MarkLive(RA); + break; + } else { + // Note any uses of this value, so this value can be + // marked live whenever one of the uses becomes live. + Uses.insert(std::make_pair(MaybeLiveUse, RA)); + } + } break; } } @@ -686,17 +694,20 @@ /// mark any values that are used by this value (according to Uses) live as /// well. void DeadArgumentEliminationPass::MarkLive(const RetOrArg &RA) { - if (LiveFunctions.count(RA.F)) - return; // Function was already marked Live. + if (IsLive(RA)) + return; // Already marked Live. - if (!LiveValues.insert(RA).second) - return; // We were already marked Live. + LiveValues.insert(RA); LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - Marking " << RA.getDescription() << " live\n"); PropagateLiveness(RA); } +bool DeadArgumentEliminationPass::IsLive(const RetOrArg &RA) { + return LiveFunctions.count(RA.F) || LiveValues.count(RA); +} + /// PropagateLiveness - Given that RA is a live value, propagate it's liveness /// to any other values it uses (according to Uses). void DeadArgumentEliminationPass::PropagateLiveness(const RetOrArg &RA) { diff --git a/llvm/test/Transforms/DeadArgElim/preserve-used-ret.ll b/llvm/test/Transforms/DeadArgElim/preserve-used-ret.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/DeadArgElim/preserve-used-ret.ll @@ -0,0 +1,32 @@ +; RUN: opt -S -deadargelim %s | FileCheck %s + +define internal { i64, i64 } @f(i64 %a, i64 %b) { +start: + %0 = insertvalue { i64, i64 } undef, i64 %a, 0 + %1 = insertvalue { i64, i64 } %0, i64 %b, 1 + ret { i64, i64 } %1 +} + +; Check that we don't delete either of g's return values + +; CHECK-LABEL: define internal { i64, i64 } @g(i64 %a, i64 %b) +define internal { i64, i64 } @g(i64 %a, i64 %b) { +start: + %0 = call { i64, i64 } @f(i64 %a, i64 %b) + ret { i64, i64 } %0 +} + +declare dso_local i32 @test(i64, i64) + +define i32 @main(i32 %argc, i8** %argv) { +start: + %x = call { i64, i64 } @g(i64 13, i64 42) + %x.0 = extractvalue { i64, i64 } %x, 0 + %x.1 = extractvalue { i64, i64 } %x, 1 + %z = bitcast i64 %x.0 to i64 + %y = call { i64, i64 } @f(i64 %x.0, i64 %x.1) + %y.1 = extractvalue { i64, i64 } %y, 1 + %0 = call i32 @test(i64 %x.0, i64 %y.1) + ret i32 %0 +} +