Nicolai Hähnle via llvm-dev
2020-Jul-13 19:57 UTC
[llvm-dev] (When) Do function calls read/latch/freeze their parameters?
Hi, We're looking at what may be a real-life bug encountered by our compiler related to `undef` values and function calls. The input program effectively contains the expression clamp(v, x, x) expecting that the result will be equal to `x`, even when `v` is read from uninitialized memory. In the input language, `clamp` is a built-in, so this expectation is somewhat reasonable. In our compiler, the clamp gets replaced by the logically equivalent corresponding sequence of icmp/select instructions, which leads to multiple reads from v, which changes the result when v is undef. We should be able to fix this in our compiler by inserting a freeze instruction, but to me this raises a more complicated point around function inlining that is illustrated by this example: https://alive2.llvm.org/ce/z/wcYxCB (I don't know if the output of Alive2 is meaningful here or if there are limitations around function calls). Function inlining in LLVM currently does *not* introduce freezes. However, calls to intrinsics such as llvm.minimum.* etc. are presumably expected to introduce freezes. So if we think of intrinsics as being implemented by library functions (as is de facto the case with the `clamp` example above), should those library functions be treated differently by inlining? Should such functions be written with explicit `freeze`s in the beginning? Does this mean it would make sense to expose `freeze` as an intrinsic accessible from C/C++ in Clang, so that such library functions can be written in a high-level language? As you can see, I unfortunately have more questions than answers right now ;) Cheers, Nicolai -- Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.
Nuno Lopes via llvm-dev
2020-Jul-13 21:56 UTC
[llvm-dev] (When) Do function calls read/latch/freeze their parameters?
Hi, Inlining doesn't need to introduce freeze. But each function must know that they may get inlined. Alive2 proves transformations for "normal" input values, undef values, poison values, and combinations of these. (we could do things the other way around: inline adds freeze, functions assume inputs are "normal", but that is a bit pessimistic, and would likely result in too many freezes) I agree that expansions of intrinsics like "llvm.minimum.*" probably need to introduce freezes if done at IR level. If done at assembly level no, as there's no LLVM IR-style undef value in assembly. At least not in the ISAs I'm aware :) Your clamp should introduce freeze as well. To remove unneeded freezes, we could tag functions with a no-more-IPOs tag after the last IPO in the pipeline. Each function could then assume that the input was non-poison and non-undef. There's a new attribute for arguments under review, I think name noundef, that may allow us to get rid of undef as well, but I didn't follow the last proposed semantics closely to be sure. Nuno P.S.: Alive2 doesn't support inlining at the moment FYI. Only intra-procedural optimizations are supported ATM. -----Original Message----- From: Nicolai Hähnle Sent: 13 July 2020 20:58 Subject: [llvm-dev] (When) Do function calls read/latch/freeze their parameters? Hi, We're looking at what may be a real-life bug encountered by our compiler related to `undef` values and function calls. The input program effectively contains the expression clamp(v, x, x) expecting that the result will be equal to `x`, even when `v` is read from uninitialized memory. In the input language, `clamp` is a built-in, so this expectation is somewhat reasonable. In our compiler, the clamp gets replaced by the logically equivalent corresponding sequence of icmp/select instructions, which leads to multiple reads from v, which changes the result when v is undef. We should be able to fix this in our compiler by inserting a freeze instruction, but to me this raises a more complicated point around function inlining that is illustrated by this example: https://alive2.llvm.org/ce/z/wcYxCB (I don't know if the output of Alive2 is meaningful here or if there are limitations around function calls). Function inlining in LLVM currently does *not* introduce freezes. However, calls to intrinsics such as llvm.minimum.* etc. are presumably expected to introduce freezes. So if we think of intrinsics as being implemented by library functions (as is de facto the case with the `clamp` example above), should those library functions be treated differently by inlining? Should such functions be written with explicit `freeze`s in the beginning? Does this mean it would make sense to expose `freeze` as an intrinsic accessible from C/C++ in Clang, so that such library functions can be written in a high-level language? As you can see, I unfortunately have more questions than answers right now ;) Cheers, Nicolai
Johannes Doerfert via llvm-dev
2020-Jul-14 20:14 UTC
[llvm-dev] (When) Do function calls read/latch/freeze their parameters?
On 7/13/20 2:57 PM, Nicolai Hähnle via llvm-dev wrote:> calls to intrinsics such as llvm.minimum.* etc. are > presumably expected to introduce freezes.I can see how lowering/implementing intrinsics might require `freeze` but as Nuno mentioned, I doubt "inlining" (as in our inliner pass) requires this.
Johannes Doerfert via llvm-dev
2020-Jul-14 20:16 UTC
[llvm-dev] (When) Do function calls read/latch/freeze their parameters?
On 7/13/20 4:56 PM, Nuno Lopes via llvm-dev wrote:> There's a new attribute for arguments under review, I think name noundef,Was merged: https://reviews.llvm.org/rG89f1ad88b3f1ecf32e797247b9eab5662ed4bcf4 ``` |noundef| This attribute applies to parameters and return values. If the value representation contains any undefined or poison bits, the behavior is undefined. Note that this does not refer to padding introduced by the type’s storage representation. ``` Next step is to make existing attributes not create UB but produce poison if violated. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200714/1ecfa619/attachment.html>
Nicolai Hähnle via llvm-dev
2020-Jul-15 08:52 UTC
[llvm-dev] (When) Do function calls read/latch/freeze their parameters?
On Tue, Jul 14, 2020 at 10:15 PM Johannes Doerfert <johannesdoerfert at gmail.com> wrote:> On 7/13/20 2:57 PM, Nicolai Hähnle via llvm-dev wrote: > > calls to intrinsics such as llvm.minimum.* etc. are > > presumably expected to introduce freezes. > > I can see how lowering/implementing intrinsics might require `freeze` but > as Nuno mentioned, I doubt "inlining" (as in our inliner pass) requires > this.Yes, this makes sense to me. Thanks! Cheers, Nicolai -- Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.