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

Ralf Jung via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 01:00:13 PDT 2026


https://github.com/RalfJung updated https://github.com/llvm/llvm-project/pull/214229

>From 696dca0f7f969c9086c2fb570b46d1e741b5bf37 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post at ralfj.de>
Date: Wed, 5 Aug 2026 15:10:12 +0200
Subject: [PATCH] LangRef: mention that willreturn can cause time-traveling UB

---
 llvm/docs/LangRef.md           |  6 ++++++
 llvm/docs/UndefinedBehavior.md | 22 +++++++++++++++++-----
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 4966065f2207c0..43cef3fada731f 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 e25d29ec22ed75..15f0d1fdc4ea60 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