This is an archive of the discontinued LLVM Phabricator instance.

[ValueTracking] Let propgatesPoison consider single poison operand.
ClosedPublic

Authored by fhahn on Oct 12 2021, 6:54 AM.

Details

Summary

This patch extends propgatesPoison to take an optional PoisonOp
argument. If not nullptr, the passed value must be an operand of I. In
that case, propagatesPoison returns true, if I yields poison or raises
UB if PoisonOp is poison.

This allows propagating poison if the condition of a select is poison.
Among other things, this helps improve results for
programUndefinedIfUndefOrPoison and allows removing special select
handling from directlyImpliesPoison.

Diff Detail

Event Timeline

fhahn created this revision.Oct 12 2021, 6:54 AM
fhahn requested review of this revision.Oct 12 2021, 6:54 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 12 2021, 6:54 AM

The change looks great to me.

Alive2 proofs for the changed instcombine tests:

Were the InstCombine test changes supposed to be included in this patch?

nikic added inline comments.Oct 12 2021, 7:19 AM
llvm/include/llvm/Analysis/ValueTracking.h
545

Can we make this function accept (only) a Use?

reames added a comment.EditedOct 12 2021, 9:03 AM

This looks pretty reasonable to me overall. A couple high level suggestions:

  • I second the suggestion of taking the new operand as a Use.
  • Framing wise, I suggest making it clear that we're restricting the set of operands known to be poison. And that the nullptr value has no restriction. I found your comment and patch framing difficult to decipher. I had to work back to what you meant from the code.

(Edit - dropped my original last point as further consideration indicated it involved too much complexity in reasoning, and could be handled later if desired.)

fhahn added a comment.Oct 13 2021, 1:56 PM

This looks pretty reasonable to me overall. A couple high level suggestions:

  • I second the suggestion of taking the new operand as a Use.

That should be doable with adjusting the callers a bit. I'll update the patch.

  • Framing wise, I suggest making it clear that we're restricting the set of operands known to be poison. And that the nullptr value has no restriction. I found your comment and patch framing difficult to decipher. I had to work back to what you meant from the code.

I'll try to make it a bit clearer. I might be mis-interpreting the exact meaning of restricting, but I am not sure if that's entirely accurate. With the nullptr value, we known that at least one of the operands is poison, but we do not know which; if a value is passed, we know that exactly this value is poison.

Extending it to an ArrayRef would mean the following I think: if it is empty, at least one operand is poison, but we do not know which. Otherwise we know that all values in the ArrayRef are poison. I think the ArrayRef could also be used to communicate the fact that both options of a select are poison, hence the select itself is poison.

The change looks great to me.

Alive2 proofs for the changed instcombine tests:

Were the InstCombine test changes supposed to be included in this patch?

Argh, originally they were, but it turns out there was a problem with early iterations that made us transform the test cases. While it was correct for the test cases, it was not correct in general unfortunately. I added a SCEV IR test in 4cd6cc64edb3833327601fb9eb2b5a9b6fb2bb7f

llvm/include/llvm/Analysis/ValueTracking.h
545

I think that should be possible, it just requires updating a few of the users.

fhahn updated this revision to Diff 379655.Oct 14 2021, 4:02 AM

Change argument from const Value * to const Use *.

fhahn edited the summary of this revision. (Show Details)Oct 14 2021, 4:03 AM
nikic added inline comments.Oct 14 2021, 4:06 AM
llvm/include/llvm/Analysis/ValueTracking.h
545

This isn't really what I had in mind. Why do we need both an Operator and a Use? Can't we make this API accept only a (required) Use and dispatch based on U.getUser()? Are there any usages that don't work on a specific Use?

fhahn updated this revision to Diff 379688.Oct 14 2021, 6:05 AM
fhahn edited the summary of this revision. (Show Details)

Updated to only provide propagatesPoison(const Use &PoisonOp). Note that this requires updating some of the existing users to first determine *which* operand is poison.

fhahn added inline comments.Oct 14 2021, 6:07 AM
llvm/include/llvm/Analysis/ValueTracking.h
545

That's an option. If we do not want to provide 2 versions of the function this requires updating all users to actually check which operands are poison before calling propagatesPoison. I did that in the latest iteration of the patch. It doesn't look too bad, I am not sure if the convenience of having a version that does not require specifying *which* operand may be poison would still be desirable.

nikic added inline comments.Oct 14 2021, 9:36 AM
llvm/include/llvm/Analysis/ValueTracking.h
551

nit: Too many new lines

llvm/lib/Analysis/ValueTracking.cpp
5333–5337

The isa<> check is unnecessary -- all Instructions are Operators.

5496–5497

Opr capture is unnecessary.

5627

I guess this is technically not wrong, but muddies the contract of the function a bit. I'd prefer using PoisonOp.getOperandNo() == 0 here.

llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
292–295

This doesn't look quite right to me, shouldn't this only push a check specifically for poison-propagating operands, rather than for all operands if at least one propagates?

llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
798

It would probably be more elegant to implement this the same as programUndefinedIfUndefOrPoison(), but I'm okay with this for now.

fhahn updated this revision to Diff 379763.Oct 14 2021, 10:35 AM

Address latest comments, thanks!

fhahn marked 5 inline comments as done.Oct 14 2021, 10:36 AM
fhahn added inline comments.
llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
292–295

Agreed, this is more obvious now, but it should retain the original behavior, right? I'd prefer to not pull in a separate functional improvement in this patch if possible.

nikic added inline comments.Oct 14 2021, 11:30 AM
llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
292–295

If I understand correctly, ValToPoison computes "this value is definitely poison". Previously, the propagatesPoison() check told you that any poison operand would make the result also poison, so simply or'ing together ValToPoison of all operands was correct. Now that only some operands may propagate, it's no longer correct. For the select case, we should only be using the condition operand, while as written it would or all three operands.

I think your code would be correct if you replaced any_of with all_of, but only picking the right operands seems like it would be cleaner and simpler.

fhahn updated this revision to Diff 483827.Dec 18 2022, 10:58 AM
fhahn marked an inline comment as done.

Finally addressed outstanding comments and added tests for PoisonChecking in 869f60ffa13b.

Herald added a project: Restricted Project. · View Herald TranscriptDec 18 2022, 10:58 AM
Herald added subscribers: Enna1, zzheng. · View Herald Transcript
fhahn marked 3 inline comments as done.Dec 18 2022, 11:00 AM
fhahn added inline comments.
llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
292–295

Updated to check for each operand individually. Added some extra tests in 869f60ffa13bdcb02

nikic requested changes to this revision.Dec 18 2022, 11:25 AM
nikic added inline comments.
llvm/include/llvm/Analysis/ValueTracking.h
631

Shouldn't this be modifying the declaration above?

llvm/lib/Analysis/ValueTracking.cpp
5808

This is incorrect, needs to be synchronized with the YieldsPoison check below.

llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
293

count/contains. Also the indentation looks broken here.

This revision now requires changes to proceed.Dec 18 2022, 11:25 AM
fhahn updated this revision to Diff 483836.Dec 18 2022, 12:32 PM
fhahn marked an inline comment as done.

Address rebase issues, thanks!

fhahn marked 3 inline comments as done.Dec 18 2022, 12:34 PM
fhahn added inline comments.
llvm/include/llvm/Analysis/ValueTracking.h
631

Yeah looks like the rebase went wrong. Should be fixed now, thanks!

llvm/lib/Analysis/ValueTracking.cpp
5808

Yeah looks like the rebase went wrong here. Should be fixed now, thanks!

llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp
293

updated to use count and fixed indent, thanks!

nikic accepted this revision.Dec 18 2022, 12:45 PM

LGTM with updated patch description.

This revision is now accepted and ready to land.Dec 18 2022, 12:45 PM
This revision was automatically updated to reflect the committed changes.
fhahn marked 3 inline comments as done.