[Mlir-commits] [mlir] [mlir][IR] Add builtin `TokenType` (PR #195640)

Matthias Springer llvmlistbot at llvm.org
Tue May 12 02:46:19 PDT 2026


================
@@ -0,0 +1,104 @@
+# Tokens
+
+[TOC]
+
+## Overview
+
+Intuitively, a *token* value is a pointer to an operation (via an OpResult)
+or a pointer to a region (via an entry block argument). A token cannot be
+forwarded: a token def-use chain cannot be obscured by ops with forwarding
+semantics such as `arith.select` or `cf.br`. This allows you to always walk
+back from a use and say "this token came from *that* specific op". 
+
+A token is an SSA value that has the builtin token type. The token type is
+parameterless, opaque and prints as `token`. A token carries no runtime data.
+Apart from the structural contract below, tokens are like any other SSA values.
+
+## Design Rationale
+
+The token type allows operations to refer to another operation without a new
+parallel def-use system for operations. The existing def-use machinery for SSA
+values can be reused. Moreover, no changes were needed for the generic op
+syntax, the bytecode infrastructure and core C++ APIs around `Operation`.
+
+As with regular use-def chains, a token def-use chain is unidirectional. A
+token use points to the token's definition. (But not the other way around.)
+Transformations can remove the use of a token without having to touch or
+inspect the definition of the token. (Whether such a transformation is correct
+depends on the semantics of the token-producing and token-consuming ops.)
+
+Token-producing and token-consuming ops are subject to standard transformations
+such as CSE, DCE and hoisting. If such transformations are not desirable due to
+op semantics, common IR design patterns can be employed. To give a few examples:
+Terminators or ops with side effects are not CSE'd or DCE'd. Region block
+arguments semantically belong to the enclosing op and are never CSE'd, DCE'd or
+hoisted. Non-speculatability may also prevent hoisting.
----------------
matthias-springer wrote:

I also wrote this with the `tf_executor.NextIteration.Sink` example in mind.

For a handwritten pass / pattern, you can make sure that it respects the semantics / invariants (1:1 mapping) of the source/sink op. But what about standard transformations such as CSE, DCE, hoisting, etc.? This paragraph says that you can work with terminators, side effects, etc. to make CSE, DCE, hoisting, etc. respect your op semantics / invariants.

To be fair, this is orthogonal to tokens. You may need some of these mechanisms anyway, e.g., to make sure that an op (even without token semantics) is not hoisted from the `tf_executor.graph` region.


https://github.com/llvm/llvm-project/pull/195640


More information about the Mlir-commits mailing list