[llvm-dev] RFC: Killing undef and spreading poison

Hal Finkel via llvm-dev llvm-dev at lists.llvm.org
Tue Nov 8 13:00:24 PST 2016


----- Original Message -----

> From: "Eli via llvm-dev Friedman" <llvm-dev at lists.llvm.org>
> To: "Nuno Lopes" <nuno.lopes at ist.utl.pt>, "Chandler Carruth"
> <chandlerc at google.com>, llvm-dev at lists.llvm.org
> Cc: "John Regehr" <regehr at cs.utah.edu>, "Yoonseung Kim"
> <yoonseung.kim at sf.snu.ac.kr>, "Youngju Song"
> <youngju.song at sf.snu.ac.kr>
> Sent: Tuesday, November 8, 2016 2:48:04 PM
> Subject: Re: [llvm-dev] RFC: Killing undef and spreading poison

> On 11/8/2016 10:47 AM, Nuno Lopes wrote:

> > Hi Chandler,
> 

> > Thanks for your feedback!
> 
> > I ’ m still trying to get to the bottom of your concerns and how to
> > best address them.
> 

> > As far as I understand, your main concern is that the following
> > should be equivalent to a no-op (thanks Sanjoy for the example!):
> 
> > i32* ptr = ...
> 
> > %tmp = load i32, i32* %ptr
> 
> > store i32 %tmp, i32* %ptr
> 

> > So introducing a store of the loaded value should be ok, but under
> > our proposal it ’ s not. Just to clarify: is this actually your
> > main
> > concern?
> 

> > I believe many parts of LLVM already interpret poison as a
> > per-value
> > attribute, including when it comes to loads. Take the following
> > function as an example:
> 
> > define i16 @g(i8 %in) {
> 
> > %a = alloca i32
> 
> > %v = add nsw i8 127, %in
> 
> > %ptr = bitcast i32* %a to i8*
> 
> > %ptr1 = getelementptr i8, i8* %ptr, i32 1
> 
> > store i8 %v, i8* %ptr1
> 
> > %ptr16 = bitcast i32* %a to i16*
> 
> > %load = load i16, i16* %ptr16
> 
> > ret i16 %load
> 
> > }
> 

> > This program stores 8 bits, and leaves the remaining 24 bits
> > uninitialized. It then loads 16 bits, half initialized to %v, half
> > uninitialized. SROA transforms the above function to:
> 
> > define i16 @g(i8 %in) {
> 
> > %v = add nsw i8 127, %in
> 
> > %1 = zext i8 %v to i16
> 
> > %2 = shl i16 %1, 8
> 
> > %3 = and i16 undef, 255
> 
> > %4 = or i16 %3, %2
> 
> > ret i16 %4
> 
> > }
> 

> > SROA gets rid of the alloca/store/load instructions and replaces
> > those with an OR of undef and shifted %v.
> 
> > If I call g() with %in=1, then the addition overflows and %v is
> > poison. Under LLVM semantics, all instructions return poison if
> > given poison as input. Therefore the whole function can be folded
> > to
> > “ ret i16 poison ” (if we had a poison value in IR, or otherwise
> > fold to “ add nsw i16 INT_MAX, 1 ” ).
> 
> > So, to justify the correctness of SROA, the load in the original
> > program had to be widening the poison from the stored i8 value and
> > return a i16 poison (i.e., %load had to be poison if %v was
> > poison).
> > Therefore, we can conclude that in current semantics, loads already
> > widen poison from bit-representation into value-wise
> > representation,
> > which makes the insertion of a load-store round-trip illegal in
> > general.
> 

> > Please let me know what you think. I may be missing some important
> > detail.
> 

> Well, I wouldn't pay too much attention to what LangRef currently
> says about poison, considering that the current model isn't actually
> consistent.

> It's possible we could tweak your model a little to make poison a
> bit-wise property, so an i32 can be partially poison, sort of like
> how undef currently works. Then we can consider on an operation by
> operation basis how it propagates poison bits. In other words, let's
> pretend every Value has type <n x i1> for the purpose of poison
> until we actually do math on it.

> Under this model, we can say a non-vector icmp with any poisoned bit
> as input returns poison, but a load produces a value whose bits are
> poison only where the input is poison. We can say "freeze(load i32)"
> does the same thing as "bitcast(freeze(load <32 x i1>) to i32)". We
> can define lshr and trunc to allow merging two i8 loads into an i16
> load. Not sure what the rules for arithmetic and logic operations
> would be off the top of my head; there are some tradeoffs here.

> I'm not sure this is the right approach (this model is more
> complicated, and we probably lose a bit of optimization power in
> some cases), but it's definitely nicer from the perspective of SROA
> and GVN.

I agree. I think that we need a bitwise model for tracking poison/undef. The bitwise operations will propagate it bitwise, same for memory accesses, and the other operations can (be assumed to) propagate it to all bits. 

-Hal 

> -Eli
> --
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a
> Linux Foundation Collaborative Project
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

-- 

Hal Finkel 
Lead, Compiler Technology and Programming Languages 
Leadership Computing Facility 
Argonne National Laboratory 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161108/b3ba8603/attachment.html>


More information about the llvm-dev mailing list