|  | ====================================== | 
|  | LLVM IR Undefined Behavior (UB) Manual | 
|  | ====================================== | 
|  |  | 
|  | .. contents:: | 
|  | :local: | 
|  | :depth: 2 | 
|  |  | 
|  | Abstract | 
|  | ======== | 
|  | This document describes the undefined behavior (UB) in LLVM's IR, including | 
|  | undef and poison values, as well as the ``freeze`` instruction. | 
|  | We also provide guidelines on when to use each form of UB. | 
|  |  | 
|  |  | 
|  | Introduction | 
|  | ============ | 
|  | Undefined behavior (UB) is used to specify the behavior of corner cases for | 
|  | which we don't wish to specify the concrete results. UB is also used to provide | 
|  | additional constraints to the optimizers (e.g., assumptions that the frontend | 
|  | guarantees through the language type system or the runtime). | 
|  | For example, we could specify the result of division by zero as zero, but | 
|  | since we are not really interested in the result, we say it is UB. | 
|  |  | 
|  | There exist two forms of undefined behavior in LLVM: immediate UB and deferred | 
|  | UB. The latter comes in two flavors: undef and poison values. | 
|  | There is also a ``freeze`` instruction to tame the propagation of deferred UB. | 
|  | The lattice of values in LLVM is: | 
|  | immediate UB > poison > undef > freeze(poison) > concrete value. | 
|  |  | 
|  | We explain each of the concepts in detail below. | 
|  |  | 
|  |  | 
|  | Immediate UB | 
|  | ============ | 
|  | Immediate UB is the most severe form of UB. It should be avoided whenever | 
|  | possible. | 
|  | Immediate UB should be used only for operations that trap in most CPUs supported | 
|  | by LLVM. | 
|  | Examples include division by zero, dereferencing a null pointer, etc. | 
|  |  | 
|  | The reason that immediate UB should be avoided is that it makes optimizations | 
|  | such as hoisting a lot harder. | 
|  | Consider the following example: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @f(i1 %c, i32 %v) { | 
|  | br i1 %c, label %then, label %else | 
|  |  | 
|  | then: | 
|  | %div = udiv i32 3, %v | 
|  | br label %ret | 
|  |  | 
|  | else: | 
|  | br label %ret | 
|  |  | 
|  | ret: | 
|  | %r = phi i32 [ %div, %then ], [ 0, %else ] | 
|  | ret i32 %r | 
|  | } | 
|  |  | 
|  | We might be tempted to simplify this function by removing the branching and | 
|  | executing the division speculatively because ``%c`` is true most of times. | 
|  | We would obtain the following IR: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @f(i1 %c, i32 %v) { | 
|  | %div = udiv i32 3, %v | 
|  | %r = select i1 %c, i32 %div, i32 0 | 
|  | ret i32 %r | 
|  | } | 
|  |  | 
|  | However, this transformation is not correct! Since division triggers UB | 
|  | when the divisor is zero, we can only execute speculatively if we are sure we | 
|  | don't hit that condition. | 
|  | The function above, when called as ``f(false, 0)``, would return 0 before the | 
|  | optimization, and triggers UB after being optimized. | 
|  |  | 
|  | This example highlights why we minimize the cases that trigger immediate UB | 
|  | as much as possible. | 
|  | As a rule of thumb, use immediate UB only for the cases that trap the CPU for | 
|  | most of the supported architectures. | 
|  |  | 
|  |  | 
|  | Time Travel | 
|  | ----------- | 
|  | Immediate UB in LLVM IR allows the so-called time travelling. What this means | 
|  | is that if a program triggers UB, then we are not required to preserve any of | 
|  | its observable behavior, including I/O. | 
|  | For example, the following function triggers UB after calling ``printf``: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define void @fn() { | 
|  | call void @printf(...) willreturn | 
|  | unreachable | 
|  | } | 
|  |  | 
|  | Since we know that ``printf`` will always return, and because LLVM's UB can | 
|  | time-travel, it is legal to remove the call to ``printf`` altogether and | 
|  | optimize the function to simply: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define void @fn() { | 
|  | unreachable | 
|  | } | 
|  |  | 
|  |  | 
|  | Deferred UB | 
|  | =========== | 
|  | Deferred UB is a lighter form of UB. It enables instructions to be executed | 
|  | speculatively while marking some corner cases as having erroneous values. | 
|  | Deferred UB should be used for cases where the semantics offered by common | 
|  | CPUs differ, but the CPU does not trap. | 
|  |  | 
|  | As an example, consider the shift instructions. The x86 and ARM architectures | 
|  | offer different semantics when the shift amount is equal to or greater than | 
|  | the bitwidth. | 
|  | We could solve this tension in one of two ways: 1) pick one of the x86/ARM | 
|  | semantics for LLVM, which would make the code emitted for the other architecture | 
|  | slower; 2) define that case as yielding ``poison``. | 
|  | LLVM chose the latter option. For frontends for languages like C or C++ | 
|  | (e.g., clang), they can map shifts in the source program directly to a shift in | 
|  | LLVM IR, since the semantics of C and C++ define such shifts as UB. | 
|  | For languages that offer strong semantics, they must use the value of the shift | 
|  | conditionally, e.g.: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @x86_shift(i32 %a, i32 %b) { | 
|  | %mask = and i32 %b, 31 | 
|  | %shift = shl i32 %a, %mask | 
|  | ret i32 %shift | 
|  | } | 
|  |  | 
|  |  | 
|  | There are two deferred UB values in LLVM: ``undef`` and ``poison``, which we | 
|  | describe next. | 
|  |  | 
|  |  | 
|  | Undef Values | 
|  | ------------ | 
|  | .. warning:: | 
|  | Undef values are deprecated and should be used only when strictly necessary. | 
|  | Uses of undef values should be restricted to representing loads of | 
|  | uninitialized memory. This is the only part of the IR semantics that cannot | 
|  | be replaced with alternatives yet (work in ongoing). | 
|  |  | 
|  | An undef value represents any value of a given type. Moreover, each use of | 
|  | an instruction that depends on undef can observe a different value. | 
|  | For example: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn() { | 
|  | %add = add i32 undef, 0 | 
|  | %ret = add i32 %add, %add | 
|  | ret i32 %ret | 
|  | } | 
|  |  | 
|  | Unsurprisingly, the first addition yields ``undef``. | 
|  | However, the result of the second addition is more subtle. We might be tempted | 
|  | to think that it yields an even number. But it might not be! | 
|  | Since each (transitive) use of ``undef`` can observe a different value, | 
|  | the second addition is equivalent to ``add i32 undef, undef``, which is | 
|  | equivalent to ``undef``. | 
|  | Hence, the function above is equivalent to: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn() { | 
|  | ret i32 undef | 
|  | } | 
|  |  | 
|  | Each call to this function may observe a different value, namely any 32-bit | 
|  | number (even and odd). | 
|  |  | 
|  | Because each use of undef can observe a different value, some optimizations | 
|  | are wrong if we are not sure a value is not undef. | 
|  | Consider a function that multiplies a number by 2: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn(i32 %v) { | 
|  | %mul2 = mul i32 %v, 2 | 
|  | ret i32 %mul2 | 
|  | } | 
|  |  | 
|  | This function is guaranteed to return an even number, even if ``%v`` is | 
|  | undef. | 
|  | However, as we've seen above, the following function does not: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn(i32 %v) { | 
|  | %mul2 = add i32 %v, %v | 
|  | ret i32 %mul2 | 
|  | } | 
|  |  | 
|  | This optimization is wrong just because undef values exist, even if they are | 
|  | not used in this part of the program as LLVM has no way to tell if ``%v`` is | 
|  | undef or not. | 
|  |  | 
|  | Looking at the value lattice, ``undef`` values can only be replaced with either | 
|  | a ``freeze`` instruction or a concrete value. | 
|  | A consequence is that giving undef as an operand to an instruction that triggers | 
|  | UB for some values of that operand makes the program UB. For example, | 
|  | ``udiv %x, undef`` is UB since we replace undef with 0 (``udiv %x, 0``), | 
|  | becoming obvious that it is UB. | 
|  |  | 
|  |  | 
|  | Poison Values | 
|  | ------------- | 
|  | Poison values are a stronger form of deferred UB than undef. They still | 
|  | allow instructions to be executed speculatively, but they taint the whole | 
|  | expression DAG (with some exceptions), akin to floating point NaN values. | 
|  |  | 
|  | Example: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn(i32 %a, i32 %b, i32 %c) { | 
|  | %add = add nsw i32 %a, %b | 
|  | %ret = add nsw i32 %add, %c | 
|  | ret i32 %ret | 
|  | } | 
|  |  | 
|  | The ``nsw`` attribute in the additions indicates that the operation yields | 
|  | poison if there is a signed overflow. | 
|  | If the first addition overflows, ``%add`` is poison and thus ``%ret`` is also | 
|  | poison since it taints the whole expression DAG. | 
|  |  | 
|  | Poison values can be replaced with any value of type (undef, concrete values, | 
|  | or a ``freeze`` instruction). | 
|  |  | 
|  |  | 
|  | Propagation of Poison Through Select | 
|  | ------------------------------------ | 
|  | Most instructions return poison if any of their inputs is poison. | 
|  | A notable exception is the ``select`` instruction, which is poison if and | 
|  | only if the condition is poison or the selected value is poison. | 
|  | This means that ``select`` acts as a barrier for poison propagation, which | 
|  | impacts which optimizations can be performed. | 
|  |  | 
|  | For example, consider the following function: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i1 @fn(i32 %x, i32 %y) { | 
|  | %cmp1 = icmp ne i32 %x, 0 | 
|  | %cmp2 = icmp ugt i32 %x, %y | 
|  | %and = select i1 %cmp1, i1 %cmp2, i1 false | 
|  | ret i1 %and | 
|  | } | 
|  |  | 
|  | It is not correct to optimize the ``select`` into an ``and`` because when | 
|  | ``%cmp1`` is false, the ``select`` is only poison if ``%x`` is poison, while | 
|  | the ``and`` below is poison if either ``%x`` or ``%y`` are poison. | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i1 @fn(i32 %x, i32 %y) { | 
|  | %cmp1 = icmp ne i32 %x, 0 | 
|  | %cmp2 = icmp ugt i32 %x, %y | 
|  | %and = and i1 %cmp1, %cmp2     ;; poison if %x or %y are poison | 
|  | ret i1 %and | 
|  | } | 
|  |  | 
|  | However, the optimization is possible if all operands of the values are used in | 
|  | the condition (notice the flipped operands in the ``select``): | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i1 @fn(i32 %x, i32 %y) { | 
|  | %cmp1 = icmp ne i32 %x, 0 | 
|  | %cmp2 = icmp ugt i32 %x, %y | 
|  | %and = select i1 %cmp2, i1 %cmp1, i1 false | 
|  | ; ok to replace with: | 
|  | %and = and i1 %cmp1, %cmp2 | 
|  | ret i1 %and | 
|  | } | 
|  |  | 
|  |  | 
|  | The Freeze Instruction | 
|  | ====================== | 
|  | Both undef and poison values sometimes propagate too much down an expression | 
|  | DAG. Undef values because each transitive use can observe a different value, | 
|  | and poison values because they make the whole DAG poison. | 
|  | There are some cases where it is important to stop such propagation. | 
|  | This is where the ``freeze`` instruction comes in. | 
|  |  | 
|  | Take the following example function: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn(i32 %n, i1 %c) { | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop: | 
|  | %i = phi i32 [ 0, %entry ], [ %i2, %loop.end ] | 
|  | %cond = icmp ule i32 %i, %n | 
|  | br i1 %cond, label %loop.cont, label %exit | 
|  |  | 
|  | loop.cont: | 
|  | br i1 %c, label %then, label %else | 
|  |  | 
|  | then: | 
|  | ... | 
|  | br label %loop.end | 
|  |  | 
|  | else: | 
|  | ... | 
|  | br label %loop.end | 
|  |  | 
|  | loop.end: | 
|  | %i2 = add i32 %i, 1 | 
|  | br label %loop | 
|  |  | 
|  | exit: | 
|  | ... | 
|  | } | 
|  |  | 
|  | Imagine we want to perform loop unswitching on the loop above since the branch | 
|  | condition inside the loop is loop invariant. | 
|  | We would obtain the following IR: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn(i32 %n, i1 %c) { | 
|  | entry: | 
|  | br i1 %c, label %then, label %else | 
|  |  | 
|  | then: | 
|  | %i = phi i32 [ 0, %entry ], [ %i2, %then.cont ] | 
|  | %cond = icmp ule i32 %i, %n | 
|  | br i1 %cond, label %then.cont, label %exit | 
|  |  | 
|  | then.cont: | 
|  | ... | 
|  | %i2 = add i32 %i, 1 | 
|  | br label %then | 
|  |  | 
|  | else: | 
|  | %i3 = phi i32 [ 0, %entry ], [ %i4, %else.cont ] | 
|  | %cond = icmp ule i32 %i3, %n | 
|  | br i1 %cond, label %else.cont, label %exit | 
|  |  | 
|  | else.cont: | 
|  | ... | 
|  | %i4 = add i32 %i3, 1 | 
|  | br label %else | 
|  |  | 
|  | exit: | 
|  | ... | 
|  | } | 
|  |  | 
|  | There is a subtle catch: when the function is called with ``%n`` being zero, | 
|  | the original function did not branch on ``%c``, while the optimized one does. | 
|  | Branching on a deferred UB value is immediate UB, hence the transformation is | 
|  | wrong in general because ``%c`` may be undef or poison. | 
|  |  | 
|  | Cases like this need a way to tame deferred UB values. This is exactly what the | 
|  | ``freeze`` instruction is for! | 
|  | When given a concrete value as argument, ``freeze`` is a no-op, returning the | 
|  | argument as-is. When given an undef or poison value, ``freeze`` returns a | 
|  | non-deterministic value of the type. | 
|  | This is not the same as undef: the value returned by ``freeze`` is the same | 
|  | for all users. | 
|  |  | 
|  | Branching on a value returned by ``freeze`` is always safe since it either | 
|  | evaluates to true or false consistently. | 
|  | We can make the loop unswitching optimization above correct as follows: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn(i32 %n, i1 %c) { | 
|  | entry: | 
|  | %c2 = freeze i1 %c | 
|  | br i1 %c2, label %then, label %else | 
|  | ... | 
|  | } | 
|  |  | 
|  |  | 
|  | Writing Tests Without Undefined Behavior | 
|  | ======================================== | 
|  |  | 
|  | When writing tests, it is important to ensure that they don't trigger UB | 
|  | unnecessarily. Some automated test reduces sometimes use undef or poison | 
|  | values as dummy values, but this is considered a bad practice if this leads | 
|  | to triggering UB. | 
|  |  | 
|  | For example, imagine that we want to write a test and we don't care about the | 
|  | particular divisor value because our optimization kicks in regardless: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn(i8 %a) { | 
|  | %div = udiv i8 %a, poison | 
|  | ... | 
|  | } | 
|  |  | 
|  | The issue with this test is that it triggers immediate UB. This prevents | 
|  | verification tools like Alive from validating the correctness of the | 
|  | optimization. Hence, it is considered a bad practice to have tests with | 
|  | unnecessary immediate UB (unless that is exactly what the test is for). | 
|  | The test above should use a dummy function argument instead of using poison: | 
|  |  | 
|  | .. code-block:: llvm | 
|  |  | 
|  | define i32 @fn(i8 %a, i8 %dummy) { | 
|  | %div = udiv i8 %a, %dummy | 
|  | ... | 
|  | } | 
|  |  | 
|  | Common sources of immediate UB in tests include branching on undef/poison | 
|  | conditions and dereferencing undef/poison/null pointers. | 
|  |  | 
|  | .. note:: | 
|  | If you need a placeholder value to pass as an argument to an instruction | 
|  | that may trigger UB, add a new argument to the function rather than using | 
|  | undef or poison. | 
|  |  | 
|  |  | 
|  | Summary | 
|  | ======= | 
|  | Undefined behavior (UB) in LLVM IR consists of two well-defined concepts: | 
|  | immediate and deferred UB (undef and poison values). | 
|  | Passing deferred UB values to certain operations leads to immediate UB. | 
|  | This can be avoided in some cases through the use of the ``freeze`` | 
|  | instruction. | 
|  |  | 
|  | The lattice of values in LLVM is: | 
|  | immediate UB > poison > undef > freeze(poison) > concrete value. | 
|  | It is only valid to transform values from the left to the right (e.g., a poison | 
|  | value can be replaced with a concrete value, but not the other way around). | 
|  |  | 
|  | Undef is now deprecated and should be used only to represent loads of | 
|  | uninitialized memory. |