[llvm] d9a2360 - LangRef: mention that willreturn can cause time-traveling UB (#214229)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 01:07:15 PDT 2026


Author: Ralf Jung
Date: 2026-09-25T08:07:05Z
New Revision: d9a236056a778276b286d6df818fecc5766603a6

URL: https://github.com/llvm/llvm-project/commit/d9a236056a778276b286d6df818fecc5766603a6
DIFF: https://github.com/llvm/llvm-project/commit/d9a236056a778276b286d6df818fecc5766603a6.diff

LOG: LangRef: mention that willreturn can cause time-traveling UB (#214229)

I think with #192992, the only remaining possible source of
time-traveling UB in LLVM are `willreturn` annotations emitted by the
frontend. So let's add a note about that.

I think ideally we'd also say somewhere "UB cannot time-travel except if
you put `willreturn` on a function that has observable behavior", but I
am not sure what would be a good place for that.

Cc @nikic @dtcxzyw @gonzalobg

Added: 
    

Modified: 
    llvm/docs/LangRef.md
    llvm/docs/UndefinedBehavior.md

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 4966065f2207c..43cef3fada731 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -2529,6 +2529,12 @@ fn -> other_fn -> other_fn ; fn is norecurse
     If an invocation of an annotated function does not return control back
     to a point in the call stack, the behavior is undefined.
 
+    If the annotated function has observable behavior (such as I/O or a volatile
+    access), note that the annotation can cause UB to time-travel around such
+    behavior, i.e., code that is after the function can cause UB to occur before
+    the observable behavior of the function. See the {doc}`UB documentation
+    <UndefinedBehavior>` for further details.
+
 `nosync`
 :   This function attribute indicates that the function does not introduce any
     *synchronizes-with* edges in the sense of the memory model.

diff  --git a/llvm/docs/UndefinedBehavior.md b/llvm/docs/UndefinedBehavior.md
index e25d29ec22ed7..ee5e8aee2aa01 100644
--- a/llvm/docs/UndefinedBehavior.md
+++ b/llvm/docs/UndefinedBehavior.md
@@ -77,9 +77,10 @@ most of the supported architectures.
 
 ### Time Travel
 
-Immediate UB in LLVM IR allows the so-called time travelling. What this means
+When using the `willreturn` attribute,
+immediate UB in LLVM IR allows so-called time traveling. 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.
+its observable behavior, including I/O that notionally occurred "before" the UB.
 For example, the following function triggers UB after calling `printf`:
 
 ```llvm
@@ -89,9 +90,8 @@ define void @fn() {
 }
 ```
 
-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:
+Since we know that `printf` will always return, it is legal to remove the call
+to `printf` altogether and optimize the function to simply:
 
 ```llvm
 define void @fn() {
@@ -99,6 +99,18 @@ define void @fn() {
 }
 ```
 
+In other words, the UB time-traveled to before the `printf`.
+
+Without `willreturn`, UB in LLVM will never exhibit time-traveling around
+observable behavior. This means frontends can avoid time-traveling UB by only
+putting `willreturn` on functions without observable behavior.
+
+Note that non-volatile memory accesses are *not* considered observable, even if
+they are atomic. Similarly, fences are not considered observable. LLVM can
+infer `willreturn` for such non-observable operations. UB can therefore still
+be reordered arbitrarily around such operations; that is not considered time
+traveling.
+
 ## Deferred UB
 
 Deferred UB is a lighter form of UB. It enables instructions to be executed


        


More information about the llvm-commits mailing list