[PATCH] D78615: [ValueTracking] Let propagatesPoison support binops/unaryops/cast/etc.

Juneyoung Lee via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 24 11:53:16 PDT 2020


aqjune marked an inline comment as done.
aqjune added a comment.

Hello all,
I ran experiment with an alternative semantics which defines `and poison, 0` and `or poison, -1` to block propagation of poison. In this semantics, `and poison, 0` is 0, and `or poison, -1` is -1.

Here are a few optimizations that I discovered from llvm/test/Transforms becoming incorrect in the alternative semantics:

1. <Transforms/InstCombine/and-or-icmps.ll>

  define i1 @PR2330(i32 %a, i32 %b) {
  %0:
    %cmp1 = icmp ult i32 %a, 8
    %cmp2 = icmp ult i32 %b, 8
    %and = and i1 %cmp2, %cmp1
    ret i1 %and
  }
  =>
  define i1 @PR2330(i32 %a, i32 %b) {
  %0:
    %1 = or i32 %b, %a
    %2 = icmp ult i32 %1, 8
    ret i1 %2
  }

If %a = poison && %b = 9, the source returns poison && 0 = 0, whereas target returns poison.

2. <Transforms/InstCombine/apint-shift-simplify.ll>

  define i41 @test0(i41 %A, i41 %B, i41 %C) {
  %0:
    %X = shl i41 %A, %C
    %Y = shl i41 %B, %C
    %Z = and i41 %X, %Y
    ret i41 %Z
  }
  =>
  define i41 @test0(i41 %A, i41 %B, i41 %C) {
  %0:
    %X1 = and i41 %A, %B
    %Z = shl i41 %X1, %C
    ret i41 %Z
  }

If %A = 100...00 && %B = poison && %C = 1, the source returns 0 whereas target returns poison.

3. <Transforms/InstCombine/and-fcmp.ll>

  define i1 @PR1738(double %x, double %y) {
  %0:
    %cmp1 = fcmp ord %x, 0.000000
    %cmp2 = fcmp ord %y, 0.000000
    %and = and i1 %cmp1, %cmp2
    ret i1 %and 
  }
  =>
  define i1 @PR1738(double %x, double %y) {
  %0:
    %1 = fcmp ord %x, %y
    ret i1 %1
  }

If %x = poison && %y = NaN, the source returns 0 whereas target returns poison.

When I run Alive2, I see that 50 more lit tests from test/Transforms/ are failing, compared with the base semantics (and/ors unconditionally propagating poison)
To fix this - we need to redefine the semantics of many existing operations. For example, `fcmp ord` should be redefined to determine when it returns poison / when it does not, which might be a pain. Same for shl/icmp etc. So I vote for the simpler semantics (and/or unconditionally propagating poison).

Also, LangRef states that values other than select/phi depends on their operands, and an instruction that depends on a poison value, produces a poison value, so it implies that and/or propagates poison.
`propagatesPoison` in this patch returns true on and/or operations for this reason.



================
Comment at: llvm/test/Analysis/ScalarEvolution/nsw.ll:242
   ret void
 }
 
----------------
I investigated a bit, and the history was like this:

https://github.com/llvm/llvm-project/commit/7e4a64167d4d2e7b0b680fae1706182223047af1 fixed a bug in SCEV which was incorrectly adding no-wrap flag to a post-inc add recurrence. The patch added `isAddRecNeverPoison`, which checks whether it is UB if the given add recurrence is poison, by consecutively calling `propagatesFullPoison` on its use chain.

However, the patch wasn't calling `propagatesFullPoison` on the direct uses of the add recurrence, so https://github.com/llvm/llvm-project/commit/a19edc4d15b0dae0210b90615775edd76f021008 added the call & added these two tests (bad_postinc_nsw_a/b).

In bad_postinc_nsw_b, `and %iv.inc, 0` was inserted to test whether the first `propagateFullPoison` check successfully blocks propagation of poison. Now `propagatesPoison` returns true, so the test has changed.
To summarize, the validity of this change depends on whether `and x, 0` should propagate poison or not. I think it should propagate (as I wrote on another comment). As suggested, I'll change the function name & leave a comment.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D78615/new/

https://reviews.llvm.org/D78615





More information about the llvm-commits mailing list