diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp --- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -1366,8 +1366,16 @@ LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n"); continue; } - if (auto *I = dyn_cast(V)) - I->andIRFlags(&Inst); + if (auto *I = dyn_cast(V)) { + // If I being poison triggers UB, there is no need to drop those + // flags. Otherwise, only retain flags present on both I and Inst. + // TODO: Currently some fast-math flags are not treated as + // poison-generating even though they should. Until this is fixed, + // always retain flags present on both I and Inst for floating point + // instructions. + if (isa(I) || (I->hasPoisonGeneratingFlags() && !programUndefinedIfPoison(I))) + I->andIRFlags(&Inst); + } Inst.replaceAllUsesWith(V); salvageKnowledge(&Inst, &AC); removeMSSA(Inst); diff --git a/llvm/test/Transforms/EarlyCSE/flags.ll b/llvm/test/Transforms/EarlyCSE/flags.ll --- a/llvm/test/Transforms/EarlyCSE/flags.ll +++ b/llvm/test/Transforms/EarlyCSE/flags.ll @@ -22,7 +22,7 @@ define void @test_inbounds_program_ub_if_first_gep_poison(i8* %ptr, i64 %n) { ; CHECK-LABEL: @test_inbounds_program_ub_if_first_gep_poison( -; CHECK-NEXT: [[ADD_PTR_1:%.*]] = getelementptr i8, i8* [[PTR:%.*]], i64 [[N:%.*]] +; CHECK-NEXT: [[ADD_PTR_1:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[N:%.*]] ; CHECK-NEXT: call void @use.i8(i8* noundef [[ADD_PTR_1]]) ; CHECK-NEXT: call void @use.i8(i8* [[ADD_PTR_1]]) ; CHECK-NEXT: ret void