Motivation
LLVM currently has a noundef
attribute, which triggers immediate undefined behavior if a value containing undef or poison bits is passed/returned. There is also !noundef
load metadata with the same semantics.
This attribute is leveraged by many optimizations that would otherwise be illegal or have to introduce freeze instructions.
Unfortunately, some frontends like Rust cannot emit noundef
in some fairly common cases. For example, Rust enums (tagged unions in C terms) may only be partially initialized, depending on which enum member is active.
However, Rust could use a nopoison
attribute for all values, because it does not expose any poison semantics. I believe this is also true of pretty much all other frontends (including Clang), which only use immediate undefined behavior in their semantics, not poison propagation.
While nopoison
is weaker than noundef
and enables less optimizations, it still covers some important cases. For example, select Cond, undef, X
can be folded to X
if we know that X
is not poison – it doesn’t matter whether it can be undef. The same holds for all other places that use either isGuaranteedNotToBePoison() or impliesPoison().
Proposal
Add a nopoison
argument and return attribute, with the following wording (copied from noundef):
This attribute applies to parameters and return values. If the value representation contains any poison bits, the behavior is undefined. Note that this does not refer to padding introduced by the type’s storage representation.
Also add a !nopoison !{}
load metadata with the same semantics.
Once support for undef has been removed (or at least disallowed inside function bodies), the current noundef
attribute would be removed and only nopoison
would remain.
Interaction of noundef and nopoison
This proposal suggests to leave the current semantics of noundef alone: That is, noundef
continues to imply that the value is both not undef and not poison. Specifying both the noundef
and nopoison
attributes at the same time is equivalent to specifying just noundef
.
An alternative would be to separate these, and say that noundef
only implies that the value is not undef, but can be poison. We do (since recently) make that separation in our internal queries, but I don’t think there is a use-case for exposing this to the attribute system. I’d rather avoid the extra churn for an attribute that will go away in the future anyway.