Index: llvm/trunk/include/llvm/IR/Instruction.h =================================================================== --- llvm/trunk/include/llvm/IR/Instruction.h +++ llvm/trunk/include/llvm/IR/Instruction.h @@ -276,6 +276,10 @@ /// Determine whether the no signed wrap flag is set. bool hasNoSignedWrap() const; + /// Drops flags that may cause this instruction to evaluate to poison despite + /// having non-poison inputs. + void dropPoisonGeneratingFlags(); + /// Determine whether the exact flag is set. bool isExact() const; Index: llvm/trunk/lib/IR/Instruction.cpp =================================================================== --- llvm/trunk/lib/IR/Instruction.cpp +++ llvm/trunk/lib/IR/Instruction.cpp @@ -122,6 +122,29 @@ return cast(this)->hasNoSignedWrap(); } +void Instruction::dropPoisonGeneratingFlags() { + switch (getOpcode()) { + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::Shl: + cast(this)->setHasNoUnsignedWrap(false); + cast(this)->setHasNoSignedWrap(false); + break; + + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::AShr: + case Instruction::LShr: + cast(this)->setIsExact(false); + break; + + case Instruction::GetElementPtr: + cast(this)->setIsInBounds(false); + break; + } +} + bool Instruction::isExact() const { return cast(this)->isExact(); } Index: llvm/trunk/unittests/IR/InstructionsTest.cpp =================================================================== --- llvm/trunk/unittests/IR/InstructionsTest.cpp +++ llvm/trunk/unittests/IR/InstructionsTest.cpp @@ -19,6 +19,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" +#include "llvm/IR/NoFolder.h" #include "llvm/IR/Operator.h" #include "gtest/gtest.h" #include @@ -579,5 +580,65 @@ EXPECT_TRUE(Clone->getOperandBundle("after").hasValue()); } +TEST_F(ModuleWithFunctionTest, DropPoisonGeneratingFlags) { + auto *OnlyBB = BasicBlock::Create(Ctx, "bb", F); + auto *Arg0 = &*F->arg_begin(); + + IRBuilder B(Ctx); + B.SetInsertPoint(OnlyBB); + + { + auto *UI = + cast(B.CreateUDiv(Arg0, Arg0, "", /*isExact*/ true)); + ASSERT_TRUE(UI->isExact()); + UI->dropPoisonGeneratingFlags(); + ASSERT_FALSE(UI->isExact()); + } + + { + auto *ShrI = + cast(B.CreateLShr(Arg0, Arg0, "", /*isExact*/ true)); + ASSERT_TRUE(ShrI->isExact()); + ShrI->dropPoisonGeneratingFlags(); + ASSERT_FALSE(ShrI->isExact()); + } + + { + auto *AI = cast( + B.CreateAdd(Arg0, Arg0, "", /*HasNUW*/ true, /*HasNSW*/ false)); + ASSERT_TRUE(AI->hasNoUnsignedWrap()); + AI->dropPoisonGeneratingFlags(); + ASSERT_FALSE(AI->hasNoUnsignedWrap()); + ASSERT_FALSE(AI->hasNoSignedWrap()); + } + + { + auto *SI = cast( + B.CreateAdd(Arg0, Arg0, "", /*HasNUW*/ false, /*HasNSW*/ true)); + ASSERT_TRUE(SI->hasNoSignedWrap()); + SI->dropPoisonGeneratingFlags(); + ASSERT_FALSE(SI->hasNoUnsignedWrap()); + ASSERT_FALSE(SI->hasNoSignedWrap()); + } + + { + auto *ShlI = cast( + B.CreateShl(Arg0, Arg0, "", /*HasNUW*/ true, /*HasNSW*/ true)); + ASSERT_TRUE(ShlI->hasNoSignedWrap()); + ASSERT_TRUE(ShlI->hasNoUnsignedWrap()); + ShlI->dropPoisonGeneratingFlags(); + ASSERT_FALSE(ShlI->hasNoUnsignedWrap()); + ASSERT_FALSE(ShlI->hasNoSignedWrap()); + } + + { + Value *GEPBase = Constant::getNullValue(B.getInt8PtrTy()); + auto *GI = cast(B.CreateInBoundsGEP(GEPBase, {Arg0})); + ASSERT_TRUE(GI->isInBounds()); + GI->dropPoisonGeneratingFlags(); + ASSERT_FALSE(GI->isInBounds()); + } +} + } // end anonymous namespace } // end namespace llvm