This is an archive of the discontinued LLVM Phabricator instance.

[mlir][arith] Fold `select` with poison
ClosedPublic

Authored by zero9178 on Aug 28 2023, 7:09 AM.

Details

Summary

If either of the operands of select is fully poisoned we can simply return the other.
This PR implements this optimization inside the fold method.

Note that this patch is the first to add a dependency on the UB dialect within Arith. Given this was inevitable (and part of the motivation) it should be fine I believe.

Diff Detail

Event Timeline

zero9178 created this revision.Aug 28 2023, 7:09 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 28 2023, 7:09 AM
zero9178 requested review of this revision.Aug 28 2023, 7:09 AM
Hardcode84 added a comment.EditedAug 28 2023, 7:42 AM

Which folding should applied first?

%val = select %true %poison %non_poison

or more complicated example

%1 = foldable_op %true
%2 = foldable_op %poison
%val = select %1 %2 %non_poison

Here we can end up with different code depending on order of folders.

kuhar added a comment.Aug 28 2023, 8:05 AM

Which folding should applied first?

%val = select %true %poison %non_poison

or more complicated example

%1 = foldable_op %true
%2 = foldable_op %poison
%val = select %1 %2 %non_poison

Here we can end up with different code depending on order of folders.

Good question, we should have a test case for this.
I think either one is fine but select true, %poison, %nonpoison => %poison should probably allow for more speculation later. What does llvm do in this case?

mlir/test/Dialect/Arith/canonicalize.mlir
2579

nit: missing newline

kuhar added a comment.Aug 28 2023, 8:08 AM

@zero9178

Note that this patch is the first to add a dependency on the UB dialect within Arith. Given this was inevitable (and part of the motivation) it should be fine I believe.

This is super exciting! Do you have some immediate plan for growing this set of folds?

zero9178 updated this revision to Diff 553946.Aug 28 2023, 8:11 AM

Change order of fold application, doing constant folding prior to handling poison

Which folding should applied first?

%val = select %true %poison %non_poison

or more complicated example

%1 = foldable_op %true
%2 = foldable_op %poison
%val = select %1 %2 %non_poison

Here we can end up with different code depending on order of folders.

Good point! I ran both patterns through alive2 (yes we can define different semantics for arith than LLVM, but for a lack of tooling lets go with that) and both transforms are luckily valid.
I think it makes a lot more sense to return the poison in this case as that will enable more transformations. This also matches what LLVM does.

@zero9178

Note that this patch is the first to add a dependency on the UB dialect within Arith. Given this was inevitable (and part of the motivation) it should be fine I believe.

This is super exciting! Do you have some immediate plan for growing this set of folds?

I sadly do not have any concrete plans. The motivation for this fold in particular was that the lift-cfg-to-scf pattern creates ub.poison which after canonicalization end up in arith.select. So unless I see a need to implement more of these folds/patterns in arith I cannot guarantee that I'll be working on these anytime soon

zero9178 marked an inline comment as done.Aug 28 2023, 8:14 AM
kuhar added inline comments.Aug 28 2023, 8:20 AM
mlir/test/Dialect/Arith/canonicalize.mlir
2582

Can you also add a case when poison is the second alternative or with false, so that we can disambiguate returning poison value from returning the true/false value?

zero9178 updated this revision to Diff 553953.Aug 28 2023, 8:29 AM

Address review comments

zero9178 marked an inline comment as done.Aug 28 2023, 8:29 AM
kuhar added inline comments.Aug 28 2023, 8:32 AM
mlir/test/Dialect/Arith/canonicalize.mlir
2584

I thought you wanted this to be poison like in the original code?

I think it makes a lot more sense to return the poison in this case as that will enable more transformations. This also matches what LLVM does.

zero9178 added inline comments.Aug 28 2023, 8:35 AM
mlir/test/Dialect/Arith/canonicalize.mlir
2584

That would be illegal if we are to follow LLVMs example: https://alive2.llvm.org/ce/z/3-KebL (this is also very desireable as this matches the semantics of condition control flow and would otherwise make a lot of the scf.if and cf.cond_br folds to arith.select illegal otherwise.
It was specifically select true, %poison, %other where I wanted it to return %poison rather than %other.

kuhar added a comment.Aug 28 2023, 8:39 AM

LGTM

mlir/test/Dialect/Arith/canonicalize.mlir
2584

Sorry, I misread your testcase, I thought it was select false, arg, poison which can be folded: https://alive2.llvm.org/ce/z/unind0

kuhar accepted this revision.Aug 28 2023, 8:40 AM
This revision is now accepted and ready to land.Aug 28 2023, 8:40 AM

@zero9178

Note that this patch is the first to add a dependency on the UB dialect within Arith. Given this was inevitable (and part of the motivation) it should be fine I believe.

This is super exciting! Do you have some immediate plan for growing this set of folds?

Regarding more foldings, adding poison arg support to constFoldBinaryOpConditional and friends in CommonFolders.h seems straightforward and it should cover most of arith/math ops. I can create a patch.

This revision was automatically updated to reflect the committed changes.