[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