Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,9 @@ LLVM_ABI bool isGuaranteedToExecuteForEveryIteration(const Instruction *I,
/// getGuaranteedNonPoisonOp.
LLVM_ABI bool propagatesPoison(const Use &PoisonOp);

/// Return whether this intrinsic propagates poison for all operands.
LLVM_ABI bool intrinsicPropagatesPoison(Intrinsic::ID IID);

/// Return true if the given instruction must trigger undefined behavior
/// when I is executed with any operands which appear in KnownPoison holding
/// a poison value at the point of execution.
Expand Down
39 changes: 5 additions & 34 deletions llvm/lib/Analysis/ConstantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2229,17 +2229,6 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return nullptr;
}

if (isa<PoisonValue>(Operands[0])) {
// TODO: All of these operations should probably propagate poison.
switch (IntrinsicID) {
case Intrinsic::canonicalize:
case Intrinsic::sqrt:
return PoisonValue::get(Ty);
default:
break;
}
}

if (isa<UndefValue>(Operands[0])) {
// cosine(arg) is between -1 and 1. cosine(invalid arg) is NaN.
// ctpop() is between 0 and bitwidth, pick 0 for undef.
Expand Down Expand Up @@ -3228,11 +3217,6 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
case Intrinsic::smin:
case Intrinsic::umax:
case Intrinsic::umin:
// This is the same as for binary ops - poison propagates.
// TODO: Poison handling should be consolidated.
if (isa<PoisonValue>(Operands[0]) || isa<PoisonValue>(Operands[1]))
return PoisonValue::get(Ty);

if (!C0 && !C1)
return UndefValue::get(Ty);
if (!C0 || !C1)
Expand All @@ -3245,9 +3229,6 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,

case Intrinsic::scmp:
case Intrinsic::ucmp:
if (isa<PoisonValue>(Operands[0]) || isa<PoisonValue>(Operands[1]))
return PoisonValue::get(Ty);

if (!C0 || !C1)
return ConstantInt::get(Ty, 0);

Expand Down Expand Up @@ -3314,11 +3295,6 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
}
case Intrinsic::uadd_sat:
case Intrinsic::sadd_sat:
// This is the same as for binary ops - poison propagates.
// TODO: Poison handling should be consolidated.
if (isa<PoisonValue>(Operands[0]) || isa<PoisonValue>(Operands[1]))
return PoisonValue::get(Ty);

if (!C0 && !C1)
return UndefValue::get(Ty);
if (!C0 || !C1)
Expand All @@ -3329,11 +3305,6 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
return ConstantInt::get(Ty, C0->sadd_sat(*C1));
case Intrinsic::usub_sat:
case Intrinsic::ssub_sat:
// This is the same as for binary ops - poison propagates.
// TODO: Poison handling should be consolidated.
if (isa<PoisonValue>(Operands[0]) || isa<PoisonValue>(Operands[1]))
return PoisonValue::get(Ty);

if (!C0 && !C1)
return UndefValue::get(Ty);
if (!C0 || !C1)
Expand Down Expand Up @@ -3592,11 +3563,6 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,

if (IntrinsicID == Intrinsic::smul_fix ||
IntrinsicID == Intrinsic::smul_fix_sat) {
// poison * C -> poison
// C * poison -> poison
if (isa<PoisonValue>(Operands[0]) || isa<PoisonValue>(Operands[1]))
return PoisonValue::get(Ty);

const APInt *C0, *C1;
if (!getConstIntOrUndef(Operands[0], C0) ||
!getConstIntOrUndef(Operands[1], C1))
Expand Down Expand Up @@ -3670,6 +3636,11 @@ static Constant *ConstantFoldScalarCall(StringRef Name,
ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI,
const CallBase *Call) {
if (IntrinsicID != Intrinsic::not_intrinsic &&
any_of(Operands, [](Constant *Op) { return isa<PoisonValue>(Op); }) &&
intrinsicPropagatesPoison(IntrinsicID))
return PoisonValue::get(Ty);

if (Operands.size() == 1)
return ConstantFoldScalarCall1(Name, IntrinsicID, Ty, Operands, TLI, Call);

Expand Down
75 changes: 43 additions & 32 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7879,6 +7879,47 @@ bool llvm::isGuaranteedToExecuteForEveryIteration(const Instruction *I,
llvm_unreachable("Instruction not contained in its own parent basic block.");
}

bool llvm::intrinsicPropagatesPoison(Intrinsic::ID IID) {
switch (IID) {
// TODO: Add more intrinsics.
case Intrinsic::sadd_with_overflow:
case Intrinsic::ssub_with_overflow:
case Intrinsic::smul_with_overflow:
case Intrinsic::uadd_with_overflow:
case Intrinsic::usub_with_overflow:
case Intrinsic::umul_with_overflow:
// If an input is a vector containing a poison element, the
// two output vectors (calculated results, overflow bits)'
// corresponding lanes are poison.
return true;
case Intrinsic::ctpop:
case Intrinsic::ctlz:
case Intrinsic::cttz:
case Intrinsic::abs:
case Intrinsic::smax:
case Intrinsic::smin:
case Intrinsic::umax:
case Intrinsic::umin:
case Intrinsic::scmp:
case Intrinsic::ucmp:
case Intrinsic::bitreverse:
case Intrinsic::bswap:
case Intrinsic::sadd_sat:
case Intrinsic::ssub_sat:
case Intrinsic::sshl_sat:
case Intrinsic::uadd_sat:
case Intrinsic::usub_sat:
case Intrinsic::ushl_sat:
case Intrinsic::smul_fix:
case Intrinsic::smul_fix_sat:
case Intrinsic::canonicalize:
case Intrinsic::sqrt:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
case Intrinsic::sqrt:
case Intrinsic::sqrt:
case Intrinsic::frexp:

See

if (isa<PoisonValue>(Op))
return {Op, PoisonValue::get(IntTy)};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consolidating the frexp case is more complicated due to the struct return. I think it needs some refactorings to ConstantFoldStructCall first.

return true;
default:
return false;
}
}

bool llvm::propagatesPoison(const Use &PoisonOp) {
const Operator *I = cast<Operator>(PoisonOp.getUser());
switch (I->getOpcode()) {
Expand All @@ -7889,38 +7930,8 @@ bool llvm::propagatesPoison(const Use &PoisonOp) {
case Instruction::Select:
return PoisonOp.getOperandNo() == 0;
case Instruction::Call:
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
switch (II->getIntrinsicID()) {
// TODO: Add more intrinsics.
case Intrinsic::sadd_with_overflow:
case Intrinsic::ssub_with_overflow:
case Intrinsic::smul_with_overflow:
case Intrinsic::uadd_with_overflow:
case Intrinsic::usub_with_overflow:
case Intrinsic::umul_with_overflow:
// If an input is a vector containing a poison element, the
// two output vectors (calculated results, overflow bits)'
// corresponding lanes are poison.
return true;
case Intrinsic::ctpop:
case Intrinsic::ctlz:
case Intrinsic::cttz:
case Intrinsic::abs:
case Intrinsic::smax:
case Intrinsic::smin:
case Intrinsic::umax:
case Intrinsic::umin:
case Intrinsic::bitreverse:
case Intrinsic::bswap:
case Intrinsic::sadd_sat:
case Intrinsic::ssub_sat:
case Intrinsic::sshl_sat:
case Intrinsic::uadd_sat:
case Intrinsic::usub_sat:
case Intrinsic::ushl_sat:
return true;
}
}
if (auto *II = dyn_cast<IntrinsicInst>(I))
return intrinsicPropagatesPoison(II->getIntrinsicID());
return false;
case Instruction::ICmp:
case Instruction::FCmp:
Expand Down
8 changes: 8 additions & 0 deletions llvm/test/Transforms/InstSimplify/fold-intrinsics.ll
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,11 @@ define void @powi_i16(float %V, ptr%P) {

ret void
}

define i32 @test_ctpop_poison(i32 %a) {
; CHECK-LABEL: @test_ctpop_poison(
; CHECK-NEXT: ret i32 poison
;
%res = tail call i32 @llvm.ctpop.i32(i32 poison)
ret i32 %res
}
2 changes: 1 addition & 1 deletion llvm/unittests/Analysis/ValueTrackingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ TEST(ValueTracking, propagatesPoison) {
{false, "call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %shamt)", 0},
{false, "call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %shamt)", 1},
{false, "call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %shamt)", 2},
{false, "call float @llvm.sqrt.f32(float %fx)", 0},
{true, "call float @llvm.sqrt.f32(float %fx)", 0},
{false, "call float @llvm.powi.f32.i32(float %fx, i32 %x)", 0},
{false, "call float @llvm.sin.f32(float %fx)", 0},
{false, "call float @llvm.cos.f32(float %fx)", 0},
Expand Down
Loading