[llvm-dev] (When) Do function calls read/latch/freeze their parameters?

Nuno Lopes via llvm-dev llvm-dev at lists.llvm.org
Mon Jul 13 14:56:10 PDT 2020


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



More information about the llvm-dev mailing list