[llvm-dev] RFC: Killing undef and spreading poison
Hal Finkel via llvm-dev
llvm-dev at lists.llvm.org
Tue Oct 18 11:01:20 PDT 2016
----- Original Message -----
> From: "Nuno Lopes" <nuno.lopes at ist.utl.pt>
> To: "Hal Finkel" <hfinkel at anl.gov>
> Cc: "Sanjoy Das" <sanjoy at playingwithpointers.com>, "David Majnemer" <david.majnemer at gmail.com>, "John Regehr"
> <regehr at cs.utah.edu>, "Chung-Kil Hur" <gil.hur at sf.snu.ac.kr>, "Juneyoung Lee" <juneyoung.lee at sf.snu.ac.kr>,
> "Yoonseung Kim" <yoonseung.kim at sf.snu.ac.kr>, "Youngju Song" <youngju.song at sf.snu.ac.kr>, "Dan Gohman"
> <dan433584 at gmail.com>, nlewycky at google.com, mbraun at apple.com, qcolombet at apple.com, "t p northover"
> <t.p.northover at gmail.com>, llvm-dev at lists.llvm.org
> Sent: Tuesday, October 18, 2016 10:10:41 AM
> Subject: RE: RFC: Killing undef and spreading poison
>
> >> A use of freeze is to enable speculative execution. For example,
> >> loop
> >> switching does the following transformation:
> >> while (C) {
> >> if (C2) {
> >> A
> >> } else {
> >> B
> >> }
> >> }
> >> =>
> >> if (C2) {
> >> while (C)
> >> A
> >> } else {
> >> while (C)
> >> B
> >> }
> >>
> >> Here we are evaluating C2 before C. If the original loop never
> >> executed then we had never evaluated C2, while now we do. So we
> >> need
> >> to make sure there's no UB for branching on C2. Freeze ensures
> >> that
> >> so we would actually have 'if (freeze(C2))' instead.
> >> Note that having branch on poison not trigger UB has its own
> >> problems.
> >
> > Can you please elaborate on these problems?
>
> Sure! For example, the following transformation would be wrong if
> branch on poison was a non-deterministic branch instead of UB:
>
> %a = add i32 %x, 1
> %c = icmp eq i32 %a, %poison
> br i1 %c, label %bb1, label %bb2
> bb1:
> %b = add i32 %x, 1
> %d = call i32 @bar(i32 %b)
> ->
> bb1:
> %d = call i32 @bar(i32 % poison)
>
> GVN will perform this kind of transformation: it concludes that %a,
> %b, and %poison are all equal and picks one representative value.
> However, these values are equal only when they are not poison.
Okay; so the problem is that an instruction that is value-equivalent to a poison value is not itself necessarily poison?
> If
> %poison is indeed poison, then the transformation is wrong because
> before it was passing an ok value to bar() and after the
> transformation it is passing poison.
> On the other hand, if branching on poison is UB, the original program
> was executing UB already because %poison (and therefore %c) were
> poison. So the transformation is ok.
>
>
> >> Discussion on select
> >> ====================
> >> Select is a tricky instruction to define semantics for. There are
> >> multiple views of select's purpose that are contradictory:
> >> 1) Select should be equivalent to arithmetic (e.g., allow
> >> 'select
> >> %c, true, %x' -> 'or %c, %x' and arithmetic -> select)
> >> 2) br + phi -> select should be allowed (simplifyCFG)
> >> 3) Select -> br + phi should be allowed
> >>
> >> Since we really want to have 2) since that's simplifyCFG, we
> >> propose
> >> to make 'select %c, %a, %b' poison if any of the following holds:
> >> - %c is poison
> >> - %c = true and %a is poison
> >> - %c = false and %b is poison
> >>
> >> This disallows 3) and some transformations of 1). Since 3) is only
> >> performed in CodeGenPrepare, we can safely ignore it (no
> >> aggressive
> >> optimizations are run afterwards).
> >
> > This strikes me as a dangerous game to play. CGP's transformations
> > need to be semantically sound (even if they are anti-canonical).
> > In part, this is because our IR-level analyses are used by CGP.
> > Moreover, targets after CGP run IR-level transformations, and
> > having different semantic rules there is going to make code reuse
> > hard in subtle ways. Which brings up another issue: We currently
> > have undef at the MI level; do you propose changing that, and if
> > so, how?
>
> It is sound to do the transformation at IR level if you freeze the
> condition.
> My suggestion was to avoid introducing overhead in CGP. This is the
> current state of affairs and it seems to work right now. I'm not
> shocked to see the IR changing the semantics throughout the
> pipeline, since while the compiler proceeds, the type of
> transformations done also change.
> But I have to say that my understanding of LLVM after CGP is very
> limited. I was not aware of the code reuse from IR-level analyses.
> I agree this needs to be scrutinized carefully. Alternatively, we
> can just introduce freeze and pay the price (likely low anyway).
I think we'd need to do this to ensure consistency; I don't think that the price would be high, especially because we soon drop into different representations and the IR is used only for analysis (for pointer aliasing, etc.).
>
> Regarding undef at MI level, we are not proposing any change. I
> don't see any reason right now to change it since it seems that
> optimizations at MI level are fine with just having undef. There's
> no nsw/nuw stuff there and undef seems very useful.
We've already started propagating nsw/nuw into the SDAG, and as we move toward GlobalISel, we'll have them at the MI layer as well. I think we'll need to consider how to propagate this information to the MI layer directly.
-Hal
> Poison is lowered into undef. And freeze is lowered into this pair of
> copy nodes that seems to stop propagation of undef (to ensure all
> uses see the same value). I don't know enough about MI to know if
> there's a better way to lower freeze, though.
>
> Thanks,
> Nuno
>
>
--
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory
More information about the llvm-dev
mailing list