Index: llvm/lib/Transforms/IPO/AttributorAttributes.cpp =================================================================== --- llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -7786,8 +7786,18 @@ struct AANoUndefReturned final : AAReturnedFromReturnedValues { - AANoUndefReturned(const IRPosition &IRP, Attributor &A) - : AAReturnedFromReturnedValues(IRP, A) {} + using Base = AAReturnedFromReturnedValues; + AANoUndefReturned(const IRPosition &IRP, Attributor &A) : Base(IRP, A) {} + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + auto &LivenessAA = A.getAAFor(*this, getIRPosition()); + // When the returned position is dead, returned values will be replaced with + // undef values by AAIsDead. So we don't deduce noundef for this position. + if (LivenessAA.isKnown()) + return indicatePessimisticFixpoint(); + return Base::updateImpl(A); + } /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(noundef) } Index: llvm/test/Transforms/Attributor/noundef.ll =================================================================== --- llvm/test/Transforms/Attributor/noundef.ll +++ llvm/test/Transforms/Attributor/noundef.ll @@ -20,3 +20,21 @@ call void @bar(i32* %x) ret void } + +define internal i8* @returned_dead() { +; CHECK-LABEL: define internal noalias align 536870912 i8* @returned_dead( +; CHECK-NEXT: call void @unknown() +; CHECK-NEXT: ret i8* undef +; + call void @unknown() + ret i8* null +} + +define void @caller() { +; CHECK-LABEL: @caller( +; CHECK-NEXT: [[TMP1:%.*]] = call i8* @returned_dead() +; CHECK-NEXT: ret void +; + call i8* @returned_dead() + ret void +}