Skip to content

Commit f753f5b

Browse files
committed
[ValueTracking] Let getGuaranteedNonPoisonOp find multiple non-poison operands
This patch helps getGuaranteedNonPoisonOp find multiple non-poison operands. Instead of special-casing llvm.assume, I think it is also a viable option to add noundef to Intrinsics.td. If it makes sense, I'll make a patch for that. Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D86477
1 parent 8e51bb2 commit f753f5b

File tree

4 files changed

+44
-20
lines changed

4 files changed

+44
-20
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -584,10 +584,10 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6;
584584
/// getGuaranteedNonPoisonOp.
585585
bool propagatesPoison(const Instruction *I);
586586

587-
/// Return either nullptr or an operand of I such that I will trigger
588-
/// undefined behavior if I is executed and that operand has a poison
589-
/// value.
590-
const Value *getGuaranteedNonPoisonOp(const Instruction *I);
587+
/// Insert operands of I into Ops such that I will trigger undefined behavior
588+
/// if I is executed and that operand has a poison value.
589+
void getGuaranteedNonPoisonOps(const Instruction *I,
590+
SmallPtrSetImpl<const Value *> &Ops);
591591

592592
/// Return true if the given instruction must trigger undefined behavior.
593593
/// when I is executed with any operands which appear in KnownPoison holding

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5065,46 +5065,69 @@ bool llvm::propagatesPoison(const Instruction *I) {
50655065
}
50665066
}
50675067

5068-
const Value *llvm::getGuaranteedNonPoisonOp(const Instruction *I) {
5068+
void llvm::getGuaranteedNonPoisonOps(const Instruction *I,
5069+
SmallPtrSetImpl<const Value *> &Operands) {
50695070
switch (I->getOpcode()) {
50705071
case Instruction::Store:
5071-
return cast<StoreInst>(I)->getPointerOperand();
5072+
Operands.insert(cast<StoreInst>(I)->getPointerOperand());
5073+
break;
50725074

50735075
case Instruction::Load:
5074-
return cast<LoadInst>(I)->getPointerOperand();
5076+
Operands.insert(cast<LoadInst>(I)->getPointerOperand());
5077+
break;
50755078

50765079
case Instruction::AtomicCmpXchg:
5077-
return cast<AtomicCmpXchgInst>(I)->getPointerOperand();
5080+
Operands.insert(cast<AtomicCmpXchgInst>(I)->getPointerOperand());
5081+
break;
50785082

50795083
case Instruction::AtomicRMW:
5080-
return cast<AtomicRMWInst>(I)->getPointerOperand();
5084+
Operands.insert(cast<AtomicRMWInst>(I)->getPointerOperand());
5085+
break;
50815086

50825087
case Instruction::UDiv:
50835088
case Instruction::SDiv:
50845089
case Instruction::URem:
50855090
case Instruction::SRem:
5086-
return I->getOperand(1);
5091+
Operands.insert(I->getOperand(1));
5092+
break;
50875093

50885094
case Instruction::Call:
5095+
case Instruction::Invoke: {
50895096
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
50905097
switch (II->getIntrinsicID()) {
50915098
case Intrinsic::assume:
5092-
return II->getArgOperand(0);
5099+
Operands.insert(II->getArgOperand(0));
5100+
break;
50935101
default:
5094-
return nullptr;
5102+
break;
50955103
}
50965104
}
5097-
return nullptr;
5105+
5106+
const CallBase *CB = cast<CallBase>(I);
5107+
if (CB->isIndirectCall())
5108+
Operands.insert(CB->getCalledOperand());
5109+
for (unsigned i = 0; i < CB->arg_size(); ++i) {
5110+
if (CB->paramHasAttr(i, Attribute::NoUndef))
5111+
Operands.insert(CB->getArgOperand(i));
5112+
}
5113+
break;
5114+
}
50985115

50995116
default:
5100-
return nullptr;
5117+
break;
51015118
}
51025119
}
51035120

51045121
bool llvm::mustTriggerUB(const Instruction *I,
51055122
const SmallSet<const Value *, 16>& KnownPoison) {
5106-
auto *NotPoison = getGuaranteedNonPoisonOp(I);
5107-
return (NotPoison && KnownPoison.count(NotPoison));
5123+
SmallPtrSet<const Value *, 4> NonPoisonOps;
5124+
getGuaranteedNonPoisonOps(I, NonPoisonOps);
5125+
5126+
for (const auto *V : NonPoisonOps)
5127+
if (KnownPoison.count(V))
5128+
return true;
5129+
5130+
return false;
51085131
}
51095132

51105133

llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,10 @@ static bool rewrite(Function &F) {
282282

283283
// Note: There are many more sources of documented UB, but this pass only
284284
// attempts to find UB triggered by propagation of poison.
285-
if (Value *Op = const_cast<Value*>(getGuaranteedNonPoisonOp(&I)))
286-
CreateAssertNot(B, getPoisonFor(ValToPoison, Op));
285+
SmallPtrSet<const Value *, 4> NonPoisonOps;
286+
getGuaranteedNonPoisonOps(&I, NonPoisonOps);
287+
for (const Value *Op : NonPoisonOps)
288+
CreateAssertNot(B, getPoisonFor(ValToPoison, const_cast<Value *>(Op)));
287289

288290
if (LocalCheck)
289291
if (auto *RI = dyn_cast<ReturnInst>(&I))

llvm/test/Transforms/InstSimplify/freeze-noundef.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@ define i1 @used_by_fncall(i1 %x) {
9797
; CHECK-LABEL: @used_by_fncall(
9898
; CHECK-NEXT: [[Y:%.*]] = add nsw i1 [[X:%.*]], true
9999
; CHECK-NEXT: call void @use_i1(i1 [[Y]])
100-
; CHECK-NEXT: [[F:%.*]] = freeze i1 [[Y]]
101-
; CHECK-NEXT: ret i1 [[F]]
100+
; CHECK-NEXT: ret i1 [[Y]]
102101
;
103102
%y = add nsw i1 %x, 1
104103
call void @use_i1(i1 %y)

0 commit comments

Comments
 (0)