[llvm-dev] IR canonicalization: select or bool math?
Sanjay Patel via llvm-dev
llvm-dev at lists.llvm.org
Thu Sep 29 09:20:16 PDT 2016
I hadn't thought about the no-wrap consequences. That does seem like a good
argument to always favor select since propagating nsw/nuw correctly is a
weak point as I understand it. It would also make the instcombine behavior
more consistent despite the fact that, as Chris points out, zext/sext are
acknowledged as simpler ops.
Sadly (for me anyway since I want to clean this up!) this means, as Hal
noted: in general we want to canonicalize toward select in IR, and
canonicalize toward bool math in the DAG. I don't know of any target that
does better lowering the select variants. In some cases today, we even
create control flow where there was none in the original code when we
transform bool math into select in IR. Prejudiced by that knowledge, I've
been enhancing IR transforms that effectively assume that 2 cheap IR ops
(ext+add/sub) are more canonical than 1 select.
So a proposal to move this forward:
1. Add DAG combines (possibly with TLI hooks) to turn selects into bool
math. This will be a translation of existing IR select instcombines + new
transforms. We can't knowingly create IR patterns that the backend is not
prepped to handle.
2. Remove existing IR instcombines that remove selects in favor of bool
math.
3. Add IR instcombines to transform bool math into selects.
Here are the quiz answers based on current trunk - if you did actually try
to compile the code, sorry about all of the typos that made that
impossible! :
#1 - 4 are canonicalized to bool math. Ie, we don't care about the relative
cost of sext vs. zext or if the transform needs an extra instruction (the
'not') for these cases.
#5 is canonicalized to select.
#6 is not canonicalized either way; 5/6 were introduced together as you
might expect, but 6 was backed out due to lousy codegen!
#7 is not canonicalized either way; too rare to care about?
#8 is not canonicalized either way; this one is fun because it exists in
the instcombine source code itself - and we do a lousy job with it.
On Wed, Sep 28, 2016 at 11:12 PM, Sanjoy Das <sanjoy at playingwithpointers.com
> wrote:
> My gut tells me that Hal is right, and we should prefer zexts as long
> as the select boils down to one instruction, but let me go against my
> intuition and try to list two reasons why we should prefer selects:
>
> * Folding operations into selects: it is trivial to transform
> f(select X, Const0, Const1) to select X, f(Const0), f(Const1),
> while doing that can be difficult for zexts.
>
> define i32 @sel_1_or_0(i1 %a) {
> %b = select i1 %a, i32 1, i32 0
> %k = add i32 %b, 50
> ret i32 %k
> }
>
> ==>
>
> define i32 @sel_1_or_0(i1 %a) {
> %b = select i1 %a, i32 51, i32 50
> ret i32 %b
> }
>
> but
>
> define i32 @sel_1_or_0(i1 %a) {
> %b = zext i1 %a to i32
> %k = add i32 %b, 50
> ret i32 %k
> }
>
> is not as natural to transform.
>
> * zexts (resp. sexts) lose information when combined with nuw
> (resp. nsw) operations.
>
> That is, if we inline
>
> define i32 @sel_1_or_0(i1 %a) {
> %b = zext i1 %a to i32
> ret i32 %b
> }
>
> into f and get
>
> define i32 @f(i32 %x, i32 %y) {
> %x.zext = ...
> %y.zext = ...
> ;; There are some existing use of %x.zext and %y.zext
> %a = add nuw i1 %x, %y
> %b = zext i1 %a to i32
> ret i32 %b
> }
>
> then we'll get (following your instructions, I've not verified that
> this actually happens :) )
>
> define i32 @f(i1 %x, i1 %y) {
> %x.zext = ...
> %y.zext = ...
> %a = add nuw i32 %x.zext, %y.zext
> ret i32 %a
> }
>
> but we've now lost information -- we no longer know that %a is 0 or
> 1 -- it can also be 2. This would not happen if we always
> canonicalized zext i1 C to iN to select C, iN 1, iN 0
>
> -- Sanjoy
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160929/1da5159c/attachment.html>
More information about the llvm-dev
mailing list