[llvm-branch-commits] [llvm] [LLVM][docs] Finish MyST migration for remaining docs (batch 11) (PR #223100)
Reid Kleckner via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Sep 13 20:02:35 PDT 2026
https://github.com/rnk updated https://github.com/llvm/llvm-project/pull/223100
>From a13af687c8b79726b759aff781ef5420afee6125 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Fri, 11 Sep 2026 17:30:27 +0000
Subject: [PATCH 1/4] [LLVM][docs] Rename reST docs to Markdown (batch 11)
---
llvm/docs/{MarkedUpDisassembly.rst => MarkedUpDisassembly.md} | 0
llvm/docs/{MeetupGuidelines.rst => MeetupGuidelines.md} | 0
llvm/docs/{MemTagSanitizer.rst => MemTagSanitizer.md} | 0
...axationAnnotations.rst => MemoryModelRelaxationAnnotations.md} | 0
llvm/docs/{PCSectionsMetadata.rst => PCSectionsMetadata.md} | 0
llvm/docs/{Projects.rst => Projects.md} | 0
llvm/docs/Proposals/{GitHubMove.rst => GitHubMove.md} | 0
llvm/docs/Proposals/{TestSuite.rst => TestSuite.md} | 0
.../Proposals/{VectorPredication.rst => VectorPredication.md} | 0
llvm/docs/{QualGroup.rst => QualGroup.md} | 0
llvm/docs/{ReleaseProcess.rst => ReleaseProcess.md} | 0
.../{ScudoHardenedAllocator.rst => ScudoHardenedAllocator.md} | 0
llvm/docs/{Security.rst => Security.md} | 0
...rityTransparencyReports.rst => SecurityTransparencyReports.md} | 0
llvm/docs/{SegmentedStacks.rst => SegmentedStacks.md} | 0
llvm/docs/{StackMaps.rst => StackMaps.md} | 0
llvm/docs/{Statepoints.rst => Statepoints.md} | 0
llvm/docs/{SupportPolicy.rst => SupportPolicy.md} | 0
llvm/docs/{SystemLibrary.rst => SystemLibrary.md} | 0
llvm/docs/TableGen/{BackEnds.rst => BackEnds.md} | 0
llvm/docs/TableGen/{BackGuide.rst => BackGuide.md} | 0
llvm/docs/TableGen/{ProgRef.rst => ProgRef.md} | 0
llvm/docs/{TransformMetadata.rst => TransformMetadata.md} | 0
llvm/docs/{TypeMetadata.rst => TypeMetadata.md} | 0
llvm/docs/{UndefinedBehavior.rst => UndefinedBehavior.md} | 0
llvm/docs/{VectorizationPlan.rst => VectorizationPlan.md} | 0
llvm/docs/{XRay.rst => XRay.md} | 0
llvm/docs/{XRayExample.rst => XRayExample.md} | 0
llvm/docs/{XRayFDRFormat.rst => XRayFDRFormat.md} | 0
llvm/docs/{YamlIO.rst => YamlIO.md} | 0
30 files changed, 0 insertions(+), 0 deletions(-)
rename llvm/docs/{MarkedUpDisassembly.rst => MarkedUpDisassembly.md} (100%)
rename llvm/docs/{MeetupGuidelines.rst => MeetupGuidelines.md} (100%)
rename llvm/docs/{MemTagSanitizer.rst => MemTagSanitizer.md} (100%)
rename llvm/docs/{MemoryModelRelaxationAnnotations.rst => MemoryModelRelaxationAnnotations.md} (100%)
rename llvm/docs/{PCSectionsMetadata.rst => PCSectionsMetadata.md} (100%)
rename llvm/docs/{Projects.rst => Projects.md} (100%)
rename llvm/docs/Proposals/{GitHubMove.rst => GitHubMove.md} (100%)
rename llvm/docs/Proposals/{TestSuite.rst => TestSuite.md} (100%)
rename llvm/docs/Proposals/{VectorPredication.rst => VectorPredication.md} (100%)
rename llvm/docs/{QualGroup.rst => QualGroup.md} (100%)
rename llvm/docs/{ReleaseProcess.rst => ReleaseProcess.md} (100%)
rename llvm/docs/{ScudoHardenedAllocator.rst => ScudoHardenedAllocator.md} (100%)
rename llvm/docs/{Security.rst => Security.md} (100%)
rename llvm/docs/{SecurityTransparencyReports.rst => SecurityTransparencyReports.md} (100%)
rename llvm/docs/{SegmentedStacks.rst => SegmentedStacks.md} (100%)
rename llvm/docs/{StackMaps.rst => StackMaps.md} (100%)
rename llvm/docs/{Statepoints.rst => Statepoints.md} (100%)
rename llvm/docs/{SupportPolicy.rst => SupportPolicy.md} (100%)
rename llvm/docs/{SystemLibrary.rst => SystemLibrary.md} (100%)
rename llvm/docs/TableGen/{BackEnds.rst => BackEnds.md} (100%)
rename llvm/docs/TableGen/{BackGuide.rst => BackGuide.md} (100%)
rename llvm/docs/TableGen/{ProgRef.rst => ProgRef.md} (100%)
rename llvm/docs/{TransformMetadata.rst => TransformMetadata.md} (100%)
rename llvm/docs/{TypeMetadata.rst => TypeMetadata.md} (100%)
rename llvm/docs/{UndefinedBehavior.rst => UndefinedBehavior.md} (100%)
rename llvm/docs/{VectorizationPlan.rst => VectorizationPlan.md} (100%)
rename llvm/docs/{XRay.rst => XRay.md} (100%)
rename llvm/docs/{XRayExample.rst => XRayExample.md} (100%)
rename llvm/docs/{XRayFDRFormat.rst => XRayFDRFormat.md} (100%)
rename llvm/docs/{YamlIO.rst => YamlIO.md} (100%)
diff --git a/llvm/docs/MarkedUpDisassembly.rst b/llvm/docs/MarkedUpDisassembly.md
similarity index 100%
rename from llvm/docs/MarkedUpDisassembly.rst
rename to llvm/docs/MarkedUpDisassembly.md
diff --git a/llvm/docs/MeetupGuidelines.rst b/llvm/docs/MeetupGuidelines.md
similarity index 100%
rename from llvm/docs/MeetupGuidelines.rst
rename to llvm/docs/MeetupGuidelines.md
diff --git a/llvm/docs/MemTagSanitizer.rst b/llvm/docs/MemTagSanitizer.md
similarity index 100%
rename from llvm/docs/MemTagSanitizer.rst
rename to llvm/docs/MemTagSanitizer.md
diff --git a/llvm/docs/MemoryModelRelaxationAnnotations.rst b/llvm/docs/MemoryModelRelaxationAnnotations.md
similarity index 100%
rename from llvm/docs/MemoryModelRelaxationAnnotations.rst
rename to llvm/docs/MemoryModelRelaxationAnnotations.md
diff --git a/llvm/docs/PCSectionsMetadata.rst b/llvm/docs/PCSectionsMetadata.md
similarity index 100%
rename from llvm/docs/PCSectionsMetadata.rst
rename to llvm/docs/PCSectionsMetadata.md
diff --git a/llvm/docs/Projects.rst b/llvm/docs/Projects.md
similarity index 100%
rename from llvm/docs/Projects.rst
rename to llvm/docs/Projects.md
diff --git a/llvm/docs/Proposals/GitHubMove.rst b/llvm/docs/Proposals/GitHubMove.md
similarity index 100%
rename from llvm/docs/Proposals/GitHubMove.rst
rename to llvm/docs/Proposals/GitHubMove.md
diff --git a/llvm/docs/Proposals/TestSuite.rst b/llvm/docs/Proposals/TestSuite.md
similarity index 100%
rename from llvm/docs/Proposals/TestSuite.rst
rename to llvm/docs/Proposals/TestSuite.md
diff --git a/llvm/docs/Proposals/VectorPredication.rst b/llvm/docs/Proposals/VectorPredication.md
similarity index 100%
rename from llvm/docs/Proposals/VectorPredication.rst
rename to llvm/docs/Proposals/VectorPredication.md
diff --git a/llvm/docs/QualGroup.rst b/llvm/docs/QualGroup.md
similarity index 100%
rename from llvm/docs/QualGroup.rst
rename to llvm/docs/QualGroup.md
diff --git a/llvm/docs/ReleaseProcess.rst b/llvm/docs/ReleaseProcess.md
similarity index 100%
rename from llvm/docs/ReleaseProcess.rst
rename to llvm/docs/ReleaseProcess.md
diff --git a/llvm/docs/ScudoHardenedAllocator.rst b/llvm/docs/ScudoHardenedAllocator.md
similarity index 100%
rename from llvm/docs/ScudoHardenedAllocator.rst
rename to llvm/docs/ScudoHardenedAllocator.md
diff --git a/llvm/docs/Security.rst b/llvm/docs/Security.md
similarity index 100%
rename from llvm/docs/Security.rst
rename to llvm/docs/Security.md
diff --git a/llvm/docs/SecurityTransparencyReports.rst b/llvm/docs/SecurityTransparencyReports.md
similarity index 100%
rename from llvm/docs/SecurityTransparencyReports.rst
rename to llvm/docs/SecurityTransparencyReports.md
diff --git a/llvm/docs/SegmentedStacks.rst b/llvm/docs/SegmentedStacks.md
similarity index 100%
rename from llvm/docs/SegmentedStacks.rst
rename to llvm/docs/SegmentedStacks.md
diff --git a/llvm/docs/StackMaps.rst b/llvm/docs/StackMaps.md
similarity index 100%
rename from llvm/docs/StackMaps.rst
rename to llvm/docs/StackMaps.md
diff --git a/llvm/docs/Statepoints.rst b/llvm/docs/Statepoints.md
similarity index 100%
rename from llvm/docs/Statepoints.rst
rename to llvm/docs/Statepoints.md
diff --git a/llvm/docs/SupportPolicy.rst b/llvm/docs/SupportPolicy.md
similarity index 100%
rename from llvm/docs/SupportPolicy.rst
rename to llvm/docs/SupportPolicy.md
diff --git a/llvm/docs/SystemLibrary.rst b/llvm/docs/SystemLibrary.md
similarity index 100%
rename from llvm/docs/SystemLibrary.rst
rename to llvm/docs/SystemLibrary.md
diff --git a/llvm/docs/TableGen/BackEnds.rst b/llvm/docs/TableGen/BackEnds.md
similarity index 100%
rename from llvm/docs/TableGen/BackEnds.rst
rename to llvm/docs/TableGen/BackEnds.md
diff --git a/llvm/docs/TableGen/BackGuide.rst b/llvm/docs/TableGen/BackGuide.md
similarity index 100%
rename from llvm/docs/TableGen/BackGuide.rst
rename to llvm/docs/TableGen/BackGuide.md
diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.md
similarity index 100%
rename from llvm/docs/TableGen/ProgRef.rst
rename to llvm/docs/TableGen/ProgRef.md
diff --git a/llvm/docs/TransformMetadata.rst b/llvm/docs/TransformMetadata.md
similarity index 100%
rename from llvm/docs/TransformMetadata.rst
rename to llvm/docs/TransformMetadata.md
diff --git a/llvm/docs/TypeMetadata.rst b/llvm/docs/TypeMetadata.md
similarity index 100%
rename from llvm/docs/TypeMetadata.rst
rename to llvm/docs/TypeMetadata.md
diff --git a/llvm/docs/UndefinedBehavior.rst b/llvm/docs/UndefinedBehavior.md
similarity index 100%
rename from llvm/docs/UndefinedBehavior.rst
rename to llvm/docs/UndefinedBehavior.md
diff --git a/llvm/docs/VectorizationPlan.rst b/llvm/docs/VectorizationPlan.md
similarity index 100%
rename from llvm/docs/VectorizationPlan.rst
rename to llvm/docs/VectorizationPlan.md
diff --git a/llvm/docs/XRay.rst b/llvm/docs/XRay.md
similarity index 100%
rename from llvm/docs/XRay.rst
rename to llvm/docs/XRay.md
diff --git a/llvm/docs/XRayExample.rst b/llvm/docs/XRayExample.md
similarity index 100%
rename from llvm/docs/XRayExample.rst
rename to llvm/docs/XRayExample.md
diff --git a/llvm/docs/XRayFDRFormat.rst b/llvm/docs/XRayFDRFormat.md
similarity index 100%
rename from llvm/docs/XRayFDRFormat.rst
rename to llvm/docs/XRayFDRFormat.md
diff --git a/llvm/docs/YamlIO.rst b/llvm/docs/YamlIO.md
similarity index 100%
rename from llvm/docs/YamlIO.rst
rename to llvm/docs/YamlIO.md
>From 2cc0aefc413074a1f1f548c238ffff96c2d84241 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Fri, 11 Sep 2026 17:30:39 +0000
Subject: [PATCH 2/4] [LLVM][docs] Convert remaining reST docs with rst2myst
(batch 11)
---
llvm/docs/MarkedUpDisassembly.md | 55 +-
llvm/docs/MeetupGuidelines.md | 67 +-
llvm/docs/MemTagSanitizer.md | 68 +-
llvm/docs/MemoryModelRelaxationAnnotations.md | 519 +--
llvm/docs/PCSectionsMetadata.md | 137 +-
llvm/docs/Projects.md | 312 +-
llvm/docs/Proposals/GitHubMove.md | 1363 ++++----
llvm/docs/Proposals/TestSuite.md | 472 ++-
llvm/docs/Proposals/VectorPredication.md | 58 +-
llvm/docs/QualGroup.md | 304 +-
llvm/docs/ReleaseProcess.md | 188 +-
llvm/docs/ScudoHardenedAllocator.md | 156 +-
llvm/docs/Security.md | 248 +-
llvm/docs/SecurityTransparencyReports.md | 538 ++-
llvm/docs/SegmentedStacks.md | 71 +-
llvm/docs/StackMaps.md | 386 +--
llvm/docs/Statepoints.md | 694 ++--
llvm/docs/SupportPolicy.md | 204 +-
llvm/docs/SystemLibrary.md | 10 +-
llvm/docs/TableGen/BackEnds.md | 1394 ++++----
llvm/docs/TableGen/BackGuide.md | 926 +++--
llvm/docs/TableGen/ProgRef.md | 2991 +++++++++--------
llvm/docs/TransformMetadata.md | 434 ++-
llvm/docs/TypeMetadata.md | 293 +-
llvm/docs/UndefinedBehavior.md | 474 ++-
llvm/docs/VectorizationPlan.md | 129 +-
llvm/docs/XRay.md | 347 +-
llvm/docs/XRayExample.md | 429 ++-
llvm/docs/XRayFDRFormat.md | 324 +-
llvm/docs/YamlIO.md | 1477 ++++----
30 files changed, 7249 insertions(+), 7819 deletions(-)
diff --git a/llvm/docs/MarkedUpDisassembly.md b/llvm/docs/MarkedUpDisassembly.md
index b7843818b70eb..b3fc4da1c5527 100644
--- a/llvm/docs/MarkedUpDisassembly.md
+++ b/llvm/docs/MarkedUpDisassembly.md
@@ -1,10 +1,6 @@
-=======================================
-LLVM's Optional Rich Disassembly Output
-=======================================
+# LLVM's Optional Rich Disassembly Output
-
-Introduction
-============
+## Introduction
LLVM's default disassembly output is raw text. To allow consumers more ability
to introspect the instructions' textual representation or to reformat for a more
@@ -21,23 +17,21 @@ mismatches between consumers and producers. That is, the syntax generally does
not carry semantics beyond "this text has an annotation," so consumers can
simply ignore annotations they do not understand or do not care about.
-After calling ``LLVMCreateDisasm()`` to create a disassembler context the
+After calling `LLVMCreateDisasm()` to create a disassembler context the
optional output is enable with this call:
-.. code-block:: c
-
- LLVMSetDisasmOptions(DC, LLVMDisassembler_Option_UseMarkup);
+```c
+LLVMSetDisasmOptions(DC, LLVMDisassembler_Option_UseMarkup);
+```
-Then subsequent calls to ``LLVMDisasmInstruction()`` will return output strings
+Then subsequent calls to `LLVMDisasmInstruction()` will return output strings
with the marked up annotations.
-Instruction Annotations
-=======================
+## Instruction Annotations
-.. _contextual markups:
+(contextual-markups)=
-Contextual markups
-------------------
+### Contextual markups
Annotated assembly display will supply contextual markup to help clients more
efficiently implement things like pretty printers. Most markup will be target
@@ -46,13 +40,13 @@ specific knowledge.
Annotated assembly goes through the normal instruction printer, but optionally
includes contextual tags on portions of the instruction string. An annotation
-is any '<' '>' delimited section of text(1).
-
-.. code-block:: bat
+is any '\<' '>' delimited section of text(1).
- annotation: '<' tag-name tag-modifier-list ':' annotated-text '>'
- tag-name: identifier
- tag-modifier-list: comma delimited identifier list
+```bat
+annotation: '<' tag-name tag-modifier-list ':' annotated-text '>'
+tag-name: identifier
+tag-modifier-list: comma delimited identifier list
+```
The tag-name is an identifier which gives the type of the annotation. For the
first pass, this will be very simple, with memory references, registers, and
@@ -68,17 +62,16 @@ clients.
For example, a possible annotation of an ARM load of a stack-relative location
might be annotated as:
-.. code-block:: text
+```text
+ldr <reg gpr:r0>, <mem regoffset:[<reg gpr:sp>, <imm:#4>]>
+```
- ldr <reg gpr:r0>, <mem regoffset:[<reg gpr:sp>, <imm:#4>]>
+1: For assembly dialects in which '\<' and/or '>' are legal tokens, a literal token is escaped by following immediately with a repeat of the character. For example, a literal '\<' character is output as '\<<' in an annotated assembly string.
-
-1: For assembly dialects in which '<' and/or '>' are legal tokens, a literal token is escaped by following immediately with a repeat of the character. For example, a literal '<' character is output as '<<' in an annotated assembly string.
-
-C API Details
--------------
+### C API Details
The intended consumers of this information use the C API, therefore the new C
API function for the disassembler will be added to provide an option to produce
-disassembled instructions with annotations, ``LLVMSetDisasmOptions()`` and the
-``LLVMDisassembler_Option_UseMarkup`` option (see above).
+disassembled instructions with annotations, `LLVMSetDisasmOptions()` and the
+`LLVMDisassembler_Option_UseMarkup` option (see above).
+
diff --git a/llvm/docs/MeetupGuidelines.md b/llvm/docs/MeetupGuidelines.md
index 493593eadfb5f..33fa2b4cd4668 100644
--- a/llvm/docs/MeetupGuidelines.md
+++ b/llvm/docs/MeetupGuidelines.md
@@ -1,82 +1,75 @@
-=====================================
-How to start LLVM Social in your town
-=====================================
+# How to start LLVM Social in your town
Here are several ideas you can take into account when designing your specific
LLVM Social.
Before you start, it is essential to make sure that the meetup is as welcoming
as any other event related to LLVM. Therefore you shall follow LLVM's
-`Code of Conduct <https://llvm.org/docs/CodeOfConduct.html>`_.
+[Code of Conduct](https://llvm.org/docs/CodeOfConduct.html).
Other than that - your mileage may vary. Please adapt your social to what works
best for your specific situation.
-General suggestions
--------------------
+## General suggestions
-* We highly recommend that you join the official LLVM meetup organization. In
+- We highly recommend that you join the official LLVM meetup organization. In
addition to covering the cost of the meetup, all LLVM meetups are advertised
together and easily found by potential attendees. Please contact
- tanyalattner at llvm.org for more details.
-* Beware of cultural differences: what works well in one region may not work in
+ <mailto:tanyalattner at llvm.org> for more details.
+- Beware of cultural differences: what works well in one region may not work in
other part of the world.
-* Do not be alone to organize the meetup. Try to work with a couple other
+- Do not be alone to organize the meetup. Try to work with a couple other
organizers. This is more motivating as an organizer, and this makes the
meetup more resilient over time.
-* Each event can have a different form such as a social event, or
+- Each event can have a different form such as a social event, or
a hackathon/workshop, or a 'mini-conference' with one or more talks. You do
not have to stick to one format forever.
-* Whatever format you choose, `LLVM Weekly <http://llvmweekly.org/>`_ is an
+- Whatever format you choose, [LLVM Weekly](http://llvmweekly.org/) is an
excellent topic starter: go through the 3-4 recent LLVM Weekly posts and
prepare a list of the most interesting/notable news and discuss them with the
group.
-Advertisement
--------------
+## Advertisement
-* Try to advertise via similar meetups/user groups
-* Advertise your meetup on the mailing lists (llvm-dev, cfe-dev, lldb-dev,
+- Try to advertise via similar meetups/user groups
+- Advertise your meetup on the mailing lists (llvm-dev, cfe-dev, lldb-dev,
...). Feel free to post to all of them, or at least to llvm-dev.
But as these mailing lists have high traffic and some LLVM developers are not
very active on them, you may reach more interested people using the mailing
feature from meetup.com.
-* Advertise the meetup on Twitter and mention
- `@llvmweekly <http://twitter.com/llvmweekly>`_ and
- `@llvmorg <http://twitter.com/llvmorg>`_.
-* Announce the next meetup in advance, and remind in one week or so.
+- Advertise the meetup on Twitter and mention
+ [@llvmweekly](http://twitter.com/llvmweekly) and
+ [@llvmorg](http://twitter.com/llvmorg).
+- Announce the next meetup in advance, and remind in one week or so.
-Tech talks
-----------
+## Tech talks
-* It’s a great idea to have several talks scheduled for several upcoming
+- It’s a great idea to have several talks scheduled for several upcoming
meetups to get the ball rolling.
-* Keep looking for speakers far in advance, ideally you should have 2-3
+- Keep looking for speakers far in advance, ideally you should have 2-3
speakers ready in the pipeline.
-* Try to record the talks if possible. It adds visibility to the meetup and
+- Try to record the talks if possible. It adds visibility to the meetup and
just a good idea in general. Any modern smartphone or tablet should work, but
you can also get a camera. Though, it is recommended to get an external
microphone for better sound.
-Where to host the meetup?
--------------------------
+## Where to host the meetup?
-* Look around for bars/café with projectors.
-* Talk to tech companies in the area.
-* Some co-working spaces provide their facilities for non-profit (i.e., you do
+- Look around for bars/café with projectors.
+- Talk to tech companies in the area.
+- Some co-working spaces provide their facilities for non-profit (i.e., you do
not charge attendees any fees) meetups.
-* Ask nearby universities or university departments.
+- Ask nearby universities or university departments.
-How to pick the date?
----------------------
+## How to pick the date?
-* Make sure you do not clash with the similar meetups in the city (e.g.,
+- Make sure you do not clash with the similar meetups in the city (e.g.,
C++ user groups).
-* Prefer not to have a meetup the same week when the other similar meetups
+- Prefer not to have a meetup the same week when the other similar meetups
happen (e.g., it’s not a good idea to have LLVM meetup on Thursday after
C++ meetup on Wednesday).
-* Meetups on weekends may attract people who live far away from the city,
+- Meetups on weekends may attract people who live far away from the city,
but the people who live in the city may not attend.
-* Make a poll, but beware that not every responder will join (we had ~20 votes
+- Make a poll, but beware that not every responder will join (we had ~20 votes
on the poll, while only ~8 people attended).
diff --git a/llvm/docs/MemTagSanitizer.md b/llvm/docs/MemTagSanitizer.md
index 8fba126cd4c37..f54bec6188eab 100644
--- a/llvm/docs/MemTagSanitizer.md
+++ b/llvm/docs/MemTagSanitizer.md
@@ -1,18 +1,14 @@
-================
-MemTagSanitizer
-================
+# MemTagSanitizer
-
-Introduction
-============
+## Introduction
**Note:** this page describes a tool under development. Part of this
-functionality is planned but not implemented. Hardware capable of
+functionality is planned but not implemented. Hardware capable of
running MemTagSanitizer does not exist as of Oct 2019.
MemTagSanitizer is a fast memory error detector and **a code hardening
-tool** based on the Armv8.5-A `Memory Tagging Extension`_. It
-detects a similar class of errors as `AddressSanitizer`_ or `HardwareAssistedAddressSanitizer`_, but with
+tool** based on the Armv8.5-A [Memory Tagging Extension][memory tagging extension]. It
+detects a similar class of errors as [AddressSanitizer][addresssanitizer] or [HardwareAssistedAddressSanitizer][hardwareassistedaddresssanitizer], but with
**much** lower overhead.
MemTagSanitizer overhead is expected to be in low single digits, both
@@ -22,37 +18,33 @@ MemTagSanitizer is code hardening in production binaries, where it is
expected to be a strong mitigation for both stack and heap-based
memory bugs.
+## Usage
-Usage
-=====
-
-Compile and link your program with the ``-fsanitize=memtag`` flag. This
+Compile and link your program with the `-fsanitize=memtag` flag. This
will only work when targeting AArch64 Android with the memory tagging extension.
-One possible way to achieve that is to add ``--target=aarch64-linux-android -march=armv8+memtag``
+One possible way to achieve that is to add `--target=aarch64-linux-android -march=armv8+memtag`
to your compilation flags.
Note that doing this will override existing flags of the same type. Assuming that
you are already targeting AArch64 Android, an alternative is to add
-``-Xclang -target-feature -Xclang +mte`` to your compilation flags. This
+`-Xclang -target-feature -Xclang +mte` to your compilation flags. This
adds the memory tagging feature, without changing anything else.
-Implementation
-==============
+## Implementation
-See `HardwareAssistedAddressSanitizer`_ for a general overview of a
-tag-based approach to memory safety. MemTagSanitizer follows a
+See [HardwareAssistedAddressSanitizer][hardwareassistedaddresssanitizer] for a general overview of a
+tag-based approach to memory safety. MemTagSanitizer follows a
similar implementation strategy, but with the tag storage (shadow)
provided by the hardware.
A quick overview of MTE hardware capabilities:
-* Every 16 aligned bytes of memory can be assigned a 4-bit Allocation Tag.
-* Every pointer can have a 4-bit Address Tag that is in its most significant byte.
-* Most memory access instructions generate an exception if Address Tag != Allocation Tag.
-* Special instructions are provided for fast tag manipulation.
+- Every 16 aligned bytes of memory can be assigned a 4-bit Allocation Tag.
+- Every pointer can have a 4-bit Address Tag that is in its most significant byte.
+- Most memory access instructions generate an exception if Address Tag != Allocation Tag.
+- Special instructions are provided for fast tag manipulation.
-Stack instrumentation
-=====================
+## Stack instrumentation
Stack-based memory errors are detected by updating Allocation Tag for
each local variable to a random value at the start of its lifetime,
@@ -71,31 +63,29 @@ For this reason MemTagSanitizer generates at most one random tag per
function, called a "base tag". Other stack variables, if there are
any, are assigned tags at a fixed offset from the base.
-Please refer to `this document
-<https://github.com/google/sanitizers/wiki/Stack-instrumentation-with-ARM-Memory-Tagging-Extension-(MTE)>`_
+Please refer to [this document](<https://github.com/google/sanitizers/wiki/Stack-instrumentation-with-ARM-Memory-Tagging-Extension-(MTE)>)
for more details about stack instrumentation.
-Heap tagging
-============
+## Heap tagging
**Note:** this part is not implemented as of Oct 2019.
-MemTagSanitizer will use :doc:`ScudoHardenedAllocator`
+MemTagSanitizer will use {doc}`ScudoHardenedAllocator`
with additional code to update memory tags when
-* New memory is obtained from the system.
-* An allocation is freed.
+- New memory is obtained from the system.
+- An allocation is freed.
There is no need to change Allocation Tags for the bulk of the
allocated memory in malloc(), as long as a pointer with the matching
Address Tag is returned.
-More information
-================
+## More information
+
+- [LLVM Developer Meeting 2018 talk on Memory Tagging](https://llvm.org/devmtg/2018-10/slides/Serebryany-Stepanov-Tsyrklevich-Memory-Tagging-Slides-LLVM-2018.pdf)
+- [Memory Tagging Whitepaper](https://arxiv.org/pdf/1802.09517.pdf)
-* `LLVM Developer Meeting 2018 talk on Memory Tagging <https://llvm.org/devmtg/2018-10/slides/Serebryany-Stepanov-Tsyrklevich-Memory-Tagging-Slides-LLVM-2018.pdf>`_
-* `Memory Tagging Whitepaper <https://arxiv.org/pdf/1802.09517.pdf>`_
+[addresssanitizer]: https://clang.llvm.org/docs/AddressSanitizer.html
+[hardwareassistedaddresssanitizer]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
+[memory tagging extension]: https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a
-.. _Memory Tagging Extension: https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a
-.. _AddressSanitizer: https://clang.llvm.org/docs/AddressSanitizer.html
-.. _HardwareAssistedAddressSanitizer: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
diff --git a/llvm/docs/MemoryModelRelaxationAnnotations.md b/llvm/docs/MemoryModelRelaxationAnnotations.md
index a009a5a97331d..81fe32c85083f 100644
--- a/llvm/docs/MemoryModelRelaxationAnnotations.md
+++ b/llvm/docs/MemoryModelRelaxationAnnotations.md
@@ -1,19 +1,15 @@
-===================================
-Memory Model Relaxation Annotations
-===================================
+# Memory Model Relaxation Annotations
-
-Introduction
-============
+## Introduction
Memory Model Relaxation Annotations (MMRAs) are target-defined properties
on instructions that can be used to selectively relax constraints placed
by the memory model. For example:
-* The use of ``VulkanMemoryModel`` in a SPIRV program allows certain
- memory operations to be reordered across ``acquire`` or ``release``
+- The use of `VulkanMemoryModel` in a SPIRV program allows certain
+ memory operations to be reordered across `acquire` or `release`
operations.
-* OpenCL APIs expose primitives to only fence a specific set of address
+- OpenCL APIs expose primitives to only fence a specific set of address
spaces. Carrying that information to the backend can enable the
use of faster synchronization instructions, rather than fencing all
address spaces everytime.
@@ -23,327 +19,335 @@ memory model.
As such, they are attached to an operation using LLVM metadata which
can always be dropped without affecting correctness.
-Definitions
-===========
+## Definitions
memory operation
- A load, a store, an atomic, or a function call that is marked as
- accessing memory.
+
+: A load, a store, an atomic, or a function call that is marked as
+ accessing memory.
synchronizing operation
- An instruction that synchronizes memory with other threads (e.g.
- an atomic or a fence).
-tag
- Metadata attached to a memory or synchronizing operation
- that represents some target-defined property regarding memory
- synchronization.
+: An instruction that synchronizes memory with other threads (e.g.
+ an atomic or a fence).
- An operation may have multiple tags that each represent a different
- property.
+tag
- A tag is composed of a pair of metadata string: a *prefix* and a *suffix*.
+: Metadata attached to a memory or synchronizing operation
+ that represents some target-defined property regarding memory
+ synchronization.
- In LLVM IR, the pair is represented using a metadata tuple.
- In other cases (comments, documentation, etc.), we may use the
- ``prefix:suffix`` notation.
- For example:
+ An operation may have multiple tags that each represent a different
+ property.
- .. code-block::
- :caption: Example: Tags in Metadata
+ A tag is composed of a pair of metadata string: a *prefix* and a *suffix*.
- !0 = !{!"scope", !"workgroup"} # scope:workgroup
- !1 = !{!"scope", !"device"} # scope:device
- !2 = !{!"scope", !"system"} # scope:system
+ In LLVM IR, the pair is represented using a metadata tuple.
+ In other cases (comments, documentation, etc.), we may use the
+ `prefix:suffix` notation.
+ For example:
- .. note::
+ ```{code-block}
+ :caption: 'Example: Tags in Metadata'
- The only semantics relevant to the optimizer is the
- "compatibility" relation defined below. All other
- semantics are target defined.
+ !0 = !{!"scope", !"workgroup"} # scope:workgroup
+ !1 = !{!"scope", !"device"} # scope:device
+ !2 = !{!"scope", !"system"} # scope:system
+ ```
- Tags can also be organised in lists to allow operations
- to specify all of the tags they belong to. Such a list
- is referred to as a "set of tags".
+ :::{note}
+ The only semantics relevant to the optimizer is the
+ "compatibility" relation defined below. All other
+ semantics are target defined.
+ :::
- .. code-block::
- :caption: Example: Set of Tags in Metadata
+ Tags can also be organised in lists to allow operations
+ to specify all of the tags they belong to. Such a list
+ is referred to as a "set of tags".
- !0 = !{!"scope", !"workgroup"}
- !1 = !{!"sync-as", !"private"}
- !2 = !{!0, !2}
+ ```{code-block}
+ :caption: 'Example: Set of Tags in Metadata'
- .. note::
+ !0 = !{!"scope", !"workgroup"}
+ !1 = !{!"sync-as", !"private"}
+ !2 = !{!0, !2}
+ ```
- If an operation does not have MMRA metadata, it's treated as if
- it has an empty list (``!{}``) of tags.
+ :::{note}
+ If an operation does not have MMRA metadata, it's treated as if
+ it has an empty list (`!{}`) of tags.
+ :::
- Note that it is not an error if a tag is not recognized by the
- instruction it is applied to, or by the current target.
- Such tags are simply ignored.
+ Note that it is not an error if a tag is not recognized by the
+ instruction it is applied to, or by the current target.
+ Such tags are simply ignored.
- Both synchronizing operations and memory operations can have
- zero or more tags attached to them using the ``!mmra`` syntax.
+ Both synchronizing operations and memory operations can have
+ zero or more tags attached to them using the `!mmra` syntax.
- For the sake of readability in examples below,
- we use a (non-functional) short syntax to represent MMMRA metadata:
+ For the sake of readability in examples below,
+ we use a (non-functional) short syntax to represent MMMRA metadata:
- .. code-block::
- :caption: Short Syntax Example
+ ```{code-block}
+ :caption: Short Syntax Example
- store %ptr1 # foo:bar
- store %ptr1 !mmra !{!"foo", !"bar"}
+ store %ptr1 # foo:bar
+ store %ptr1 !mmra !{!"foo", !"bar"}
+ ```
- These two notations can be used in this document and are strictly
- equivalent. However, only the second version is functional.
+ These two notations can be used in this document and are strictly
+ equivalent. However, only the second version is functional.
compatibility
- Two sets of tags are said to be *compatible* iff, for every unique
- tag prefix P present in at least one set:
- - the other set contains no tag with prefix P, or
- - at least one tag with prefix P is common to both sets.
+: Two sets of tags are said to be *compatible* iff, for every unique
+ tag prefix P present in at least one set:
- The above definition implies that an empty set is always compatible
- with any other set. This is an important property as it ensures that
- if a transform drops the metadata on an operation, it can never affect
- correctness. In other words, the memory model cannot be relaxed further
- by deleting metadata from instructions.
+ - the other set contains no tag with prefix P, or
+ - at least one tag with prefix P is common to both sets.
-.. _HappensBefore:
+ The above definition implies that an empty set is always compatible
+ with any other set. This is an important property as it ensures that
+ if a transform drops the metadata on an operation, it can never affect
+ correctness. In other words, the memory model cannot be relaxed further
+ by deleting metadata from instructions.
-The *happens-before* Relation
-==============================
+(happensbefore)=
+
+## The *happens-before* Relation
Compatibility checks can be used to opt out of the *happens-before* relation
established between two instructions.
Ordering
- When two instructions' metadata are not compatible, any program order
- between them are not in *happens-before*.
- For example, consider two tags ``foo:bar`` and
- ``foo:baz`` exposed by a target:
+: When two instructions' metadata are not compatible, any program order
+ between them are not in *happens-before*.
- .. code-block::
+ For example, consider two tags `foo:bar` and
+ `foo:baz` exposed by a target:
- A: store %ptr1 # foo:bar
- B: store %ptr2 # foo:baz
- X: store atomic release %ptr3 # foo:bar
+ ```
+ A: store %ptr1 # foo:bar
+ B: store %ptr2 # foo:baz
+ X: store atomic release %ptr3 # foo:bar
+ ```
- In the above figure, ``A`` is compatible with ``X``, and hence ``A``
- happens-before ``X``. But ``B`` is not compatible with
- ``X``, and hence it is not happens-before ``X``.
+ In the above figure, `A` is compatible with `X`, and hence `A`
+ happens-before `X`. But `B` is not compatible with
+ `X`, and hence it is not happens-before `X`.
Synchronization
- If an synchronizing operation has one or more tags, then whether it
- synchronizes-with and participates in the ``seq_cst`` order with
- other operations is target dependent.
- Whether the following example synchronizes with another sequence depends
- on the target-defined semantics of ``foo:bar`` and ``foo:bux``.
+: If an synchronizing operation has one or more tags, then whether it
+ synchronizes-with and participates in the `seq_cst` order with
+ other operations is target dependent.
- .. code-block::
+ Whether the following example synchronizes with another sequence depends
+ on the target-defined semantics of `foo:bar` and `foo:bux`.
- fence release # foo:bar
- store atomic %ptr1 # foo:bux
+ ```
+ fence release # foo:bar
+ store atomic %ptr1 # foo:bux
+ ```
-Examples
---------
+### Examples
Example 1:
- .. code-block::
- A: store ptr addrspace(1) %ptr2 # sync-as:1 vulkan:nonprivate
- B: store atomic release ptr addrspace(1) %ptr3 # sync-as:0 vulkan:nonprivate
+: ```
+ A: store ptr addrspace(1) %ptr2 # sync-as:1 vulkan:nonprivate
+ B: store atomic release ptr addrspace(1) %ptr3 # sync-as:0 vulkan:nonprivate
+ ```
- A and B are not ordered relative to each other
- (no *happens-before*) because their sets of tags are not compatible.
+ A and B are not ordered relative to each other
+ (no *happens-before*) because their sets of tags are not compatible.
- Note that the ``sync-as`` value does not have to match the ``addrspace`` value.
- e.g. In Example 1, a store-release to a location in ``addrspace(1)`` wants to
- only synchronize with operations happening in ``addrspace(0)``.
+ Note that the `sync-as` value does not have to match the `addrspace` value.
+ e.g. In Example 1, a store-release to a location in `addrspace(1)` wants to
+ only synchronize with operations happening in `addrspace(0)`.
Example 2:
- .. code-block::
- A: store ptr addrspace(1) %ptr2 # sync-as:1 vulkan:nonprivate
- B: store atomic release ptr addrspace(1) %ptr3 # sync-as:1 vulkan:nonprivate
+: ```
+ A: store ptr addrspace(1) %ptr2 # sync-as:1 vulkan:nonprivate
+ B: store atomic release ptr addrspace(1) %ptr3 # sync-as:1 vulkan:nonprivate
+ ```
- The ordering of A and B is unaffected because their set of tags are
- compatible.
+ The ordering of A and B is unaffected because their set of tags are
+ compatible.
- Note that A and B may or may not be in *happens-before* due to other reasons.
+ Note that A and B may or may not be in *happens-before* due to other reasons.
Example 3:
- .. code-block::
- A: store ptr addrspace(1) %ptr2 # sync-as:1 vulkan:nonprivate
- B: store atomic release ptr addrspace(1) %ptr3 # vulkan:nonprivate
+: ```
+ A: store ptr addrspace(1) %ptr2 # sync-as:1 vulkan:nonprivate
+ B: store atomic release ptr addrspace(1) %ptr3 # vulkan:nonprivate
+ ```
- The ordering of A and B is unaffected because their set of tags are
- compatible.
+ The ordering of A and B is unaffected because their set of tags are
+ compatible.
Example 4:
- .. code-block::
- A: store ptr addrspace(1) %ptr2 # sync-as:1
- B: store atomic release ptr addrspace(1) %ptr3 # sync-as:2
+: ```
+ A: store ptr addrspace(1) %ptr2 # sync-as:1
+ B: store atomic release ptr addrspace(1) %ptr3 # sync-as:2
+ ```
- A and B do not have to be ordered relative to each other
- (no *happens-before*) because their sets of tags are not compatible.
+ A and B do not have to be ordered relative to each other
+ (no *happens-before*) because their sets of tags are not compatible.
-Use-cases
-=========
+## Use-cases
-SPIRV ``NonPrivatePointer``
----------------------------
+### SPIRV `NonPrivatePointer`
MMRAs can support the SPIRV capability
-``VulkanMemoryModel``, where synchronizing operations only affect
-memory operations that specify ``NonPrivatePointer`` semantics.
+`VulkanMemoryModel`, where synchronizing operations only affect
+memory operations that specify `NonPrivatePointer` semantics.
The example below is generated from a SPIRV program using the
following recipe:
-- Add ``vulkan:nonprivate`` to every synchronizing operation.
-- Add ``vulkan:nonprivate`` to every non-atomic memory operation
- that is marked ``NonPrivatePointer``.
-- Add ``vulkan:private`` to tags of every non-atomic memory operation
- that is not marked ``NonPrivatePointer``.
-
-.. code-block::
-
- Thread T1:
- A: store %ptr1 # vulkan:nonprivate
- B: store %ptr2 # vulkan:private
- X: store atomic release %ptr3 # vulkan:nonprivate
-
- Thread T2:
- Y: load atomic acquire %ptr3 # vulkan:nonprivate
- C: load %ptr2 # vulkan:private
- D: load %ptr1 # vulkan:nonprivate
-
-Compatibility ensures that operation ``A`` is ordered
-relative to ``X`` while operation ``D`` is ordered relative to ``Y``.
-If ``X`` synchronizes with ``Y``, then ``A`` happens-before ``D``.
-No such relation can be inferred about operations ``B`` and ``C``.
-
-.. note::
- The `Vulkan Memory Model <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#memory-model-non-private>`_
- considers all atomic operation non-private.
-
- Whether ``vulkan:nonprivate`` would be specified on atomic operations is
- an implementation detail, as an atomic operation is always ``nonprivate``.
- The implementation may choose to be explicit and emit IR with
- ``vulkan:nonprivate`` on every atomic operation, or it could choose to
- only emit ``vulkan::private`` and assume ``vulkan:nonprivate``
- by default.
-
-Operations marked with ``vulkan:private`` effectively opt out of the
+- Add `vulkan:nonprivate` to every synchronizing operation.
+- Add `vulkan:nonprivate` to every non-atomic memory operation
+ that is marked `NonPrivatePointer`.
+- Add `vulkan:private` to tags of every non-atomic memory operation
+ that is not marked `NonPrivatePointer`.
+
+```
+Thread T1:
+ A: store %ptr1 # vulkan:nonprivate
+ B: store %ptr2 # vulkan:private
+ X: store atomic release %ptr3 # vulkan:nonprivate
+
+Thread T2:
+ Y: load atomic acquire %ptr3 # vulkan:nonprivate
+ C: load %ptr2 # vulkan:private
+ D: load %ptr1 # vulkan:nonprivate
+```
+
+Compatibility ensures that operation `A` is ordered
+relative to `X` while operation `D` is ordered relative to `Y`.
+If `X` synchronizes with `Y`, then `A` happens-before `D`.
+No such relation can be inferred about operations `B` and `C`.
+
+:::{note}
+The [Vulkan Memory Model](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#memory-model-non-private)
+considers all atomic operation non-private.
+
+Whether `vulkan:nonprivate` would be specified on atomic operations is
+an implementation detail, as an atomic operation is always `nonprivate`.
+The implementation may choose to be explicit and emit IR with
+`vulkan:nonprivate` on every atomic operation, or it could choose to
+only emit `vulkan::private` and assume `vulkan:nonprivate`
+by default.
+:::
+
+Operations marked with `vulkan:private` effectively opt out of the
happens-before order in a SPIRV program since they are incompatible
with every synchronizing operation. Note that SPIRV operations that
-are not marked ``NonPrivatePointer`` are not entirely private to the
+are not marked `NonPrivatePointer` are not entirely private to the
thread --- they are implicitly synchronized at the start or end of a
thread by the Vulkan *system-synchronizes-with* relationship. This
example assumes that the target-defined semantics of
-``vulkan:private`` correctly implements this property.
+`vulkan:private` correctly implements this property.
This scheme is general enough to express the interoperability of SPIRV
programs with other environments.
-.. code-block::
-
- Thread T1:
- A: store %ptr1 # vulkan:nonprivate
- X: store atomic release %ptr2 # vulkan:nonprivate
+```
+Thread T1:
+A: store %ptr1 # vulkan:nonprivate
+X: store atomic release %ptr2 # vulkan:nonprivate
- Thread T2:
- Y: load atomic acquire %ptr2 # foo:bar
- B: load %ptr1
+Thread T2:
+Y: load atomic acquire %ptr2 # foo:bar
+B: load %ptr1
+```
-In the above example, thread ``T1`` originates from a SPIRV program
-while thread ``T2`` originates from a non-SPIRV program. Whether ``X``
-can synchronize with ``Y`` is target defined. If ``X`` synchronizes
-with ``Y``, then ``A`` happens before ``B`` (because A/X and
+In the above example, thread `T1` originates from a SPIRV program
+while thread `T2` originates from a non-SPIRV program. Whether `X`
+can synchronize with `Y` is target defined. If `X` synchronizes
+with `Y`, then `A` happens before `B` (because A/X and
Y/B are compatible).
-Implementation Example
-~~~~~~~~~~~~~~~~~~~~~~
+#### Implementation Example
-Consider the implementation of SPIRV ``NonPrivatePointer`` on a target
+Consider the implementation of SPIRV `NonPrivatePointer` on a target
where all memory operations are cached, and the entire cache is
-flushed or invalidated at a ``release`` or ``acquire`` respectively. A
+flushed or invalidated at a `release` or `acquire` respectively. A
possible scheme is that when translating a SPIRV program, memory
-operations marked ``NonPrivatePointer`` should not be cached, and the
-cache contents should not be touched during an ``acquire`` and
-``release`` operation.
+operations marked `NonPrivatePointer` should not be cached, and the
+cache contents should not be touched during an `acquire` and
+`release` operation.
-This could be implemented using the tags that share the ``vulkan:`` prefix,
+This could be implemented using the tags that share the `vulkan:` prefix,
as follows:
- For memory operations:
- - Operations with ``vulkan:nonprivate`` should bypass the cache.
- - Operations with ``vulkan:private`` should be cached.
+ - Operations with `vulkan:nonprivate` should bypass the cache.
+ - Operations with `vulkan:private` should be cached.
- Operations that specify neither or both should conservatively
bypass the cache to ensure correctness.
- For synchronizing operations:
- - Operations with ``vulkan:nonprivate`` should not flush or
+ - Operations with `vulkan:nonprivate` should not flush or
invalidate the cache.
- - Operations with ``vulkan:private`` should flush or invalidate the cache.
+ - Operations with `vulkan:private` should flush or invalidate the cache.
- Operations that specify neither or both should conservatively
flush or invalidate the cache to ensure correctness.
-.. note::
- In such an implementation, dropping the metadata on an operation, while
- not affecting correctness, may have big performance implications.
- e.g. an operation bypasses the cache when it shouldn't.
+:::{note}
+In such an implementation, dropping the metadata on an operation, while
+not affecting correctness, may have big performance implications.
+e.g. an operation bypasses the cache when it shouldn't.
+:::
-Memory Types
-------------
+### Memory Types
MMRAs may express the selective synchronization of
different memory types.
-As an example, a target may expose an ``sync-as:<N>`` tag to
+As an example, a target may expose an `sync-as:<N>` tag to
pass information about which address spaces are synchronized by the
execution of a synchronizing operation.
-.. note::
- Address spaces are used here as a common example, but this concept
- can apply for other "memory types". What "memory types" means here is
- up to the target.
-
-.. code-block::
-
- # let 1 = global address space
- # let 3 = local address space
-
- Thread T1:
- A: store %ptr1 # sync-as:1
- B: store %ptr2 # sync-as:3
- X: store atomic release ptr addrspace(0) %ptr3 # sync-as:3
-
- Thread T2:
- Y: load atomic acquire ptr addrspace(0) %ptr3 # sync-as:3
- C: load %ptr2 # sync-as:3
- D: load %ptr1 # sync-as:1
-
-In the above figure, ``X`` and ``Y`` are atomic operations on a
-location in the ``global`` address space. If ``X`` synchronizes with
-``Y``, then ``B`` happens-before ``C`` in the ``local`` address
-space. But no such statement can be made about operations ``A`` and
-``D``, although they are performed on a location in the ``global``
+:::{note}
+Address spaces are used here as a common example, but this concept
+can apply for other "memory types". What "memory types" means here is
+up to the target.
+:::
+
+```
+# let 1 = global address space
+# let 3 = local address space
+
+Thread T1:
+A: store %ptr1 # sync-as:1
+B: store %ptr2 # sync-as:3
+X: store atomic release ptr addrspace(0) %ptr3 # sync-as:3
+
+Thread T2:
+Y: load atomic acquire ptr addrspace(0) %ptr3 # sync-as:3
+C: load %ptr2 # sync-as:3
+D: load %ptr1 # sync-as:1
+```
+
+In the above figure, `X` and `Y` are atomic operations on a
+location in the `global` address space. If `X` synchronizes with
+`Y`, then `B` happens-before `C` in the `local` address
+space. But no such statement can be made about operations `A` and
+`D`, although they are performed on a location in the `global`
address space.
-Implementation Example: Adding Address Space Information to Fences
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#### Implementation Example: Adding Address Space Information to Fences
Languages such as OpenCL C provide fence operations such as
-``atomic_work_item_fence`` that can take an explicit address
+`atomic_work_item_fence` that can take an explicit address
space to fence.
By default, LLVM has no means to carry that information in the IR, so
@@ -354,28 +358,26 @@ performance impact in high-performance applications.
MMRAs may be used to preserve that information at the IR level, all the
way through code generation. For example, a fence that only affects the
-global address space ``addrspace(1)`` may be lowered as
-
-.. code-block::
+global address space `addrspace(1)` may be lowered as
- fence release # sync-as:1
+```
+fence release # sync-as:1
+```
-and the target may use the presence of ``sync-as:1`` to infer that it
+and the target may use the presence of `sync-as:1` to infer that it
must only emit instruction to fence the global address space.
Note that as MMRAs are opt in, a fence that does not have MMRA metadata
could still be lowered conservatively, so this optimization would only
apply if the front-end emits the MMRA metadata on the fence instructions.
-Additional Topics
-=================
+## Additional Topics
-.. note::
+:::{note}
+The following sections are informational.
+:::
- The following sections are informational.
-
-Performance Impact
-------------------
+### Performance Impact
MMRAs are a way to capture optimization opportunities in the program.
But when an operation mentions no tags or conflicting tags,
@@ -391,10 +393,9 @@ Note that targets can always choose to ignore (or even drop) MMRAs
and revert to the default behavior/codegen heuristics without
affecting correctness.
-Consequences of the Absence of *happens-before*
------------------------------------------------
+### Consequences of the Absence of *happens-before*
-In the :ref:`happens-before<HappensBefore>` section, we defined how an
+In the {ref}`happens-before<HappensBefore>` section, we defined how an
*happens-before* relation between two instruction can be broken
by leveraging compatibility between MMRAs. When the instructions
are incompatible and there is no *happens-before* relation, we say
@@ -422,8 +423,7 @@ In the absence of *happens-before*, there is no such requirement and
no waiting or flushing is required. This may noticeably speed up
execution in some cases.
-Combining Operations
---------------------
+### Combining Operations
If a pass can combine multiple memory or synchronizing operations
into one, it needs to be able to combine MMRAs. One possible way to
@@ -432,9 +432,9 @@ achieve this is by doing a prefix-wise union of the tag sets.
Let A and B be two tags set, and U be the prefix-wise union of A and B.
For every unique tag prefix P present in A or B:
-* If either A or B has no tags with prefix P, no tags with prefix
+- If either A or B has no tags with prefix P, no tags with prefix
P are added to U.
-* If both A and B have at least one tag with prefix P, all tags with prefix
+- If both A and B have at least one tag with prefix P, all tags with prefix
P from both sets are added to U.
Passes should avoid aggressively combining MMRAs, as this can result
@@ -449,31 +449,32 @@ of combining the MMRAs can use the prefix-wise union described above.
Examples:
-.. code-block::
-
- A: store release %ptr1 # foo:x, foo:y, bar:x
- B: store release %ptr2 # foo:x, bar:y
-
- # Unique prefixes P = [foo, bar]
- # "foo:x" is common to A and B so it's added to U.
- # "bar:x" != "bar:y" so it's not added to U.
- U: store release %ptr3 # foo:x
+```
+A: store release %ptr1 # foo:x, foo:y, bar:x
+B: store release %ptr2 # foo:x, bar:y
-.. code-block::
+# Unique prefixes P = [foo, bar]
+# "foo:x" is common to A and B so it's added to U.
+# "bar:x" != "bar:y" so it's not added to U.
+U: store release %ptr3 # foo:x
+```
- A: store release %ptr1 # foo:x, foo:y
- B: store release %ptr2 # foo:x, bux:y
+```
+A: store release %ptr1 # foo:x, foo:y
+B: store release %ptr2 # foo:x, bux:y
- # Unique prefixes P = [foo, bux]
- # "foo:x" is common to A and B so it's added to U.
- # No tags have the prefix "bux" in A.
- U: store release %ptr3 # foo:x
+# Unique prefixes P = [foo, bux]
+# "foo:x" is common to A and B so it's added to U.
+# No tags have the prefix "bux" in A.
+U: store release %ptr3 # foo:x
+```
-.. code-block::
+```
+A: store release %ptr1
+B: store release %ptr2 # foo:x, bar:y
- A: store release %ptr1
- B: store release %ptr2 # foo:x, bar:y
+# Unique prefixes P = [foo, bar]
+# No tags with "foo" or "bar" in A, so no tags added.
+U: store release %ptr3
+```
- # Unique prefixes P = [foo, bar]
- # No tags with "foo" or "bar" in A, so no tags added.
- U: store release %ptr3
diff --git a/llvm/docs/PCSectionsMetadata.md b/llvm/docs/PCSectionsMetadata.md
index 222fa0726a0b0..22b29f43af29a 100644
--- a/llvm/docs/PCSectionsMetadata.md
+++ b/llvm/docs/PCSectionsMetadata.md
@@ -1,126 +1,113 @@
-=========================
-LLVM PC Sections Metadata
-=========================
+# LLVM PC Sections Metadata
-
-Introduction
-============
+## Introduction
PC Sections Metadata can be attached to instructions and functions, for which
addresses, viz. program counters (PCs), are to be emitted in specially encoded
-binary sections. Metadata is assigned as an ``MDNode`` of the ``MD_pcsections``
-(``!pcsections``) kind; the following section describes the metadata format.
+binary sections. Metadata is assigned as an `MDNode` of the `MD_pcsections`
+(`!pcsections`) kind; the following section describes the metadata format.
-Metadata Format
-===============
+## Metadata Format
-An arbitrary number of interleaved ``MDString`` and constant operators can be
-added, where a new ``MDString`` always denotes a section name, followed by an
+An arbitrary number of interleaved `MDString` and constant operators can be
+added, where a new `MDString` always denotes a section name, followed by an
arbitrary number of auxiliary constant data encoded along the PC of the
-instruction or function. The first operator must be a ``MDString`` denoting the
+instruction or function. The first operator must be a `MDString` denoting the
first section.
-.. code-block:: none
-
- !0 = !{
- !"<section#1>"
- [ , !1 ... ]
- [ !"<section#2">
- [ , !2 ... ]
- ... ]
- }
- !1 = !{ iXX <aux-consts#1>, ... }
- !2 = !{ iXX <aux-consts#2>, ... }
- ...
-
-The occurrence of ``section#1``, ``section#2``, ..., ``section#N`` in the
+```none
+!0 = !{
+ !"<section#1>"
+ [ , !1 ... ]
+ [ !"<section#2">
+ [ , !2 ... ]
+ ... ]
+}
+!1 = !{ iXX <aux-consts#1>, ... }
+!2 = !{ iXX <aux-consts#2>, ... }
+...
+```
+
+The occurrence of `section#1`, `section#2`, ..., `section#N` in the
metadata causes the backend to emit the PC for the associated instruction or
function to all named sections. For each emitted PC in a section #N, the
-constants ``aux-consts#N`` in the tuple ``!N`` will be emitted after the PC.
+constants `aux-consts#N` in the tuple `!N` will be emitted after the PC.
Multiple tuples with constant data may be provided after a section name string
-(e.g. ``!0 = !{"s1", !1, !2}``), and a single constant tuple may be reused for
-different sections (e.g. ``!0 = !{"s1", !1, "s2", !1}``).
+(e.g. `!0 = !{"s1", !1, !2}`), and a single constant tuple may be reused for
+different sections (e.g. `!0 = !{"s1", !1, "s2", !1}`).
-Binary Encoding
-===============
+## Binary Encoding
*Instructions* result in emitting a single PC, and *functions* result in
emission of the start of the function and a 32-bit size. This is followed by
the auxiliary constants that followed the respective section name in the
-``MD_pcsections`` metadata.
+`MD_pcsections` metadata.
-To avoid relocations in the final binary, each PC address stored at ``entry``
-is a relative relocation, computed as ``pc - entry``. To decode, a user has to
-compute ``entry + *entry``.
+To avoid relocations in the final binary, each PC address stored at `entry`
+is a relative relocation, computed as `pc - entry`. To decode, a user has to
+compute `entry + *entry`.
The size of each entry depends on the code model. With large and medium sized
code models, the entry size matches pointer size. For any smaller code model
the entry size is just 32 bits.
-Encoding Options
-----------------
+### Encoding Options
-Optional encoding options can be passed in the first ``MDString`` operator:
-``<section>!<options>``. The following options are available:
+Optional encoding options can be passed in the first `MDString` operator:
+`<section>!<options>`. The following options are available:
- * ``C`` -- Compress constant integers of size 2-8 bytes as ULEB128; this
- includes the function size (but excludes the PC entry).
+> - `C` -- Compress constant integers of size 2-8 bytes as ULEB128; this
+> includes the function size (but excludes the PC entry).
-For example, ``foo!C`` will emit into section ``foo`` with all constants
+For example, `foo!C` will emit into section `foo` with all constants
encoded as ULEB128.
-Guarantees on Code Generation
-=============================
+## Guarantees on Code Generation
-Attaching ``!pcsections`` metadata to LLVM IR instructions *shall not* affect
+Attaching `!pcsections` metadata to LLVM IR instructions *shall not* affect
optimizations or code generation outside the requested PC sections.
While relying on LLVM IR metadata to request PC sections makes the above
guarantee relatively trivial, propagation of metadata through the optimization
and code generation pipeline has the following guarantees.
-Metadata Propagation
---------------------
+### Metadata Propagation
In general, LLVM *does not make any guarantees* about preserving IR metadata
-(attached to an ``Instruction``) through IR transformations. When using PC
-sections metadata, this guarantee is unchanged, and ``!pcsections`` metadata is
+(attached to an `Instruction`) through IR transformations. When using PC
+sections metadata, this guarantee is unchanged, and `!pcsections` metadata is
remains *optional* until lowering to machine IR (MIR).
-Note for Code Generation
-------------------------
+### Note for Code Generation
As with other LLVM IR metadata, there are no requirements for LLVM IR
-transformation passes to preserve ``!pcsections`` metadata, with the following
+transformation passes to preserve `!pcsections` metadata, with the following
exceptions:
- * The ``AtomicExpandPass`` shall preserve ``!pcsections`` metadata
- according to the below rules 1-4.
+> - The `AtomicExpandPass` shall preserve `!pcsections` metadata
+> according to the below rules 1-4.
-When translating LLVM IR to MIR, the ``!pcsections`` metadata shall be copied
-from the source ``Instruction`` to the target ``MachineInstr`` (set with
-``MachineInstr::setPCSections()``). The instruction selectors and MIR
+When translating LLVM IR to MIR, the `!pcsections` metadata shall be copied
+from the source `Instruction` to the target `MachineInstr` (set with
+`MachineInstr::setPCSections()`). The instruction selectors and MIR
optimization passes shall preserve PC sections metadata as follows:
- 1. Replacements will preserve PC sections metadata of the replaced
- instruction.
-
- 2. Duplications will preserve PC sections metadata of the copied
- instruction.
+> 1. Replacements will preserve PC sections metadata of the replaced
+> instruction.
+> 2. Duplications will preserve PC sections metadata of the copied
+> instruction.
+> 3. Merging will preserve PC sections metadata of one of the two
+> instructions (no guarantee on which instruction's metadata is used).
+> 4. Deletions will lose PC sections metadata.
- 3. Merging will preserve PC sections metadata of one of the two
- instructions (no guarantee on which instruction's metadata is used).
+This is similar to debug info, and the `BuildMI()` helper provides a
+convenient way to propagate debug info and `!pcsections` metadata in the
+`MIMetadata` bundle.
- 4. Deletions will lose PC sections metadata.
+### Note for Metadata Users
-This is similar to debug info, and the ``BuildMI()`` helper provides a
-convenient way to propagate debug info and ``!pcsections`` metadata in the
-``MIMetadata`` bundle.
-
-Note for Metadata Users
------------------------
-
-Use cases for ``!pcsections`` metadata should either be fully tolerant to
-missing metadata, or the passes inserting ``!pcsections`` metadata should run
+Use cases for `!pcsections` metadata should either be fully tolerant to
+missing metadata, or the passes inserting `!pcsections` metadata should run
*after* all LLVM IR optimization passes to preserve the metadata until being
translated to MIR.
+
diff --git a/llvm/docs/Projects.md b/llvm/docs/Projects.md
index db15bba4b87de..0896364892227 100644
--- a/llvm/docs/Projects.md
+++ b/llvm/docs/Projects.md
@@ -1,255 +1,241 @@
-========================
-Creating an LLVM Project
-========================
+# Creating an LLVM Project
-
-Overview
-========
+## Overview
The LLVM build system is designed to facilitate the building of third party
-projects that use LLVM header files, libraries, and tools. In order to use
-these facilities, a ``Makefile`` from a project must do the following things:
+projects that use LLVM header files, libraries, and tools. In order to use
+these facilities, a `Makefile` from a project must do the following things:
-* Set ``make`` variables. There are several variables that a ``Makefile`` needs
+- Set `make` variables. There are several variables that a `Makefile` needs
to set to use the LLVM build system:
- * ``PROJECT_NAME`` - The name by which your project is known.
- * ``LLVM_SRC_ROOT`` - The root of the LLVM source tree.
- * ``LLVM_OBJ_ROOT`` - The root of the LLVM object tree.
- * ``PROJ_SRC_ROOT`` - The root of the project's source tree.
- * ``PROJ_OBJ_ROOT`` - The root of the project's object tree.
- * ``PROJ_INSTALL_ROOT`` - The root installation directory.
- * ``LEVEL`` - The relative path from the current directory to the
- project's root ``($PROJ_OBJ_ROOT)``.
+ - `PROJECT_NAME` - The name by which your project is known.
+ - `LLVM_SRC_ROOT` - The root of the LLVM source tree.
+ - `LLVM_OBJ_ROOT` - The root of the LLVM object tree.
+ - `PROJ_SRC_ROOT` - The root of the project's source tree.
+ - `PROJ_OBJ_ROOT` - The root of the project's object tree.
+ - `PROJ_INSTALL_ROOT` - The root installation directory.
+ - `LEVEL` - The relative path from the current directory to the
+ project's root `($PROJ_OBJ_ROOT)`.
-* Include ``Makefile.config`` from ``$(LLVM_OBJ_ROOT)``.
+- Include `Makefile.config` from `$(LLVM_OBJ_ROOT)`.
-* Include ``Makefile.rules`` from ``$(LLVM_SRC_ROOT)``.
+- Include `Makefile.rules` from `$(LLVM_SRC_ROOT)`.
There are two ways that you can set all of these variables:
-* You can write your own ``Makefiles`` which hard-code these values.
-
-* You can use the pre-made LLVM sample project. This sample project includes
- ``Makefiles``, a configure script that can be used to configure the location
+- You can write your own `Makefiles` which hard-code these values.
+- You can use the pre-made LLVM sample project. This sample project includes
+ `Makefiles`, a configure script that can be used to configure the location
of LLVM, and the ability to support multiple object directories from a single
source directory.
If you want to devise your own build system, studying other projects and LLVM
-``Makefiles`` will probably provide enough information on how to write your own
-``Makefiles``.
+`Makefiles` will probably provide enough information on how to write your own
+`Makefiles`.
-Source Tree Layout
-==================
+## Source Tree Layout
In order to use the LLVM build system, you will want to organize your source
-code so that it can benefit from the build system's features. Mainly, you want
+code so that it can benefit from the build system's features. Mainly, you want
your source tree layout to look similar to the LLVM source tree layout.
Underneath your top level directory, you should have the following directories:
**lib**
- This subdirectory should contain all of your library source code. For each
- library that you build, you will have one directory in **lib** that will
- contain that library's source code.
-
- Libraries can be object files, archives, or dynamic libraries. The **lib**
- directory is just a convenient place for libraries as it places them all in
- a directory from which they can be linked later.
+> This subdirectory should contain all of your library source code. For each
+> library that you build, you will have one directory in **lib** that will
+> contain that library's source code.
+>
+> Libraries can be object files, archives, or dynamic libraries. The **lib**
+> directory is just a convenient place for libraries as it places them all in
+> a directory from which they can be linked later.
**include**
- This subdirectory should contain any header files that are global to your
- project. By global, we mean that they are used by more than one library or
- executable of your project.
-
- By placing your header files in **include**, they will be found
- automatically by the LLVM build system. For example, if you have a file
- **include/jazz/note.h**, then your source files can include it simply with
- **#include "jazz/note.h"**.
+> This subdirectory should contain any header files that are global to your
+> project. By global, we mean that they are used by more than one library or
+> executable of your project.
+>
+> By placing your header files in **include**, they will be found
+> automatically by the LLVM build system. For example, if you have a file
+> **include/jazz/note.h**, then your source files can include it simply with
+> **#include "jazz/note.h"**.
**tools**
- This subdirectory should contain all of your source code for executables.
- For each program that you build, you will have one directory in **tools**
- that will contain that program's source code.
+> This subdirectory should contain all of your source code for executables.
+> For each program that you build, you will have one directory in **tools**
+> that will contain that program's source code.
**test**
- This subdirectory should contain tests that verify that your code works
- correctly. Automated tests are especially useful.
-
- Currently, the LLVM build system provides basic support for tests. The LLVM
- system provides the following:
+> This subdirectory should contain tests that verify that your code works
+> correctly. Automated tests are especially useful.
+>
+> Currently, the LLVM build system provides basic support for tests. The LLVM
+> system provides the following:
-* LLVM contains regression tests in ``llvm/test``. These tests are run by the
- :doc:`Lit <CommandGuide/lit>` testing tool. This test procedure uses ``RUN``
- lines in the actual test case to determine how to run the test. See the
- :doc:`TestingGuide` for more details.
+- LLVM contains regression tests in `llvm/test`. These tests are run by the
+ {doc}`Lit <CommandGuide/lit>` testing tool. This test procedure uses `RUN`
+ lines in the actual test case to determine how to run the test. See the
+ {doc}`TestingGuide` for more details.
-* LLVM contains an optional package called ``llvm-test``, which provides
+- LLVM contains an optional package called `llvm-test`, which provides
benchmarks and programs that are known to compile with the Clang front
end. You can use these programs to test your code, gather statistical
information, and compare it to the current LLVM performance statistics.
- Currently, there is no way to hook your tests directly into the ``llvm/test``
+ Currently, there is no way to hook your tests directly into the `llvm/test`
testing harness. You will simply need to find a way to use the source
provided within that directory on your own.
Typically, you will want to build your **lib** directory first followed by your
**tools** directory.
-Writing LLVM Style Makefiles
-============================
+## Writing LLVM Style Makefiles
The LLVM build system provides a convenient way to build libraries and
-executables. Most of your project Makefiles will only need to define a few
-variables. Below is a list of the variables one can set and what they can
+executables. Most of your project Makefiles will only need to define a few
+variables. Below is a list of the variables one can set and what they can
do:
-Required Variables
-------------------
-
-``LEVEL``
+### Required Variables
- This variable is the relative path from this ``Makefile`` to the top
- directory of your project's source code. For example, if your source code
- is in ``/tmp/src``, then the ``Makefile`` in ``/tmp/src/jump/high``
- would set ``LEVEL`` to ``"../.."``.
+`LEVEL`
-Variables for Building Subdirectories
--------------------------------------
+> This variable is the relative path from this `Makefile` to the top
+> directory of your project's source code. For example, if your source code
+> is in `/tmp/src`, then the `Makefile` in `/tmp/src/jump/high`
+> would set `LEVEL` to `"../.."`.
-``DIRS``
+### Variables for Building Subdirectories
- This is a space separated list of subdirectories that should be built. They
- will be built, one at a time, in the order specified.
+`DIRS`
-``PARALLEL_DIRS``
+> This is a space separated list of subdirectories that should be built. They
+> will be built, one at a time, in the order specified.
- This is a list of directories that can be built in parallel. These will be
- built after the directories in DIRS have been built.
+`PARALLEL_DIRS`
-``OPTIONAL_DIRS``
+> This is a list of directories that can be built in parallel. These will be
+> built after the directories in DIRS have been built.
- This is a list of directories that can be built if they exist, but will not
- cause an error if they do not exist. They are built serially in the order
- in which they are listed.
+`OPTIONAL_DIRS`
-Variables for Building Libraries
---------------------------------
+> This is a list of directories that can be built if they exist, but will not
+> cause an error if they do not exist. They are built serially in the order
+> in which they are listed.
-``LIBRARYNAME``
+### Variables for Building Libraries
- This variable contains the base name of the library that will be built. For
- example, to build a library named ``libsample.a``, ``LIBRARYNAME`` should
- be set to ``sample``.
+`LIBRARYNAME`
-``BUILD_ARCHIVE``
+> This variable contains the base name of the library that will be built. For
+> example, to build a library named `libsample.a`, `LIBRARYNAME` should
+> be set to `sample`.
- By default, a library is a ``.o`` file that is linked directly into a
- program. To build an archive (also known as a static library), set the
- ``BUILD_ARCHIVE`` variable.
+`BUILD_ARCHIVE`
-``SHARED_LIBRARY``
+> By default, a library is a `.o` file that is linked directly into a
+> program. To build an archive (also known as a static library), set the
+> `BUILD_ARCHIVE` variable.
- If ``SHARED_LIBRARY`` is defined in your Makefile, a shared (or dynamic)
- library will be built.
+`SHARED_LIBRARY`
-Variables for Building Programs
--------------------------------
+> If `SHARED_LIBRARY` is defined in your Makefile, a shared (or dynamic)
+> library will be built.
-``TOOLNAME``
+### Variables for Building Programs
- This variable contains the name of the program that will be built. For
- example, to build an executable named ``sample``, ``TOOLNAME`` should be set
- to ``sample``.
+`TOOLNAME`
-``USEDLIBS``
+> This variable contains the name of the program that will be built. For
+> example, to build an executable named `sample`, `TOOLNAME` should be set
+> to `sample`.
- This variable holds a space separated list of libraries that should be
- linked into the program. These libraries must be libraries that come from
- your **lib** directory. The libraries must be specified without their
- ``lib`` prefix. For example, to link ``libsample.a``, you would set
- ``USEDLIBS`` to ``sample.a``.
+`USEDLIBS`
- Note that this works only for statically linked libraries.
+> This variable holds a space separated list of libraries that should be
+> linked into the program. These libraries must be libraries that come from
+> your **lib** directory. The libraries must be specified without their
+> `lib` prefix. For example, to link `libsample.a`, you would set
+> `USEDLIBS` to `sample.a`.
+>
+> Note that this works only for statically linked libraries.
-``LLVMLIBS``
+`LLVMLIBS`
- This variable holds a space separated list of libraries that should be
- linked into the program. These libraries must be LLVM libraries. The
- libraries must be specified without their ``lib`` prefix. For example, to
- link with a driver that performs an IR transformation you might set
- ``LLVMLIBS`` to this minimal set of libraries ``LLVMSupport.a LLVMCore.a
- LLVMBitReader.a LLVMAsmParser.a LLVMAnalysis.a LLVMTransformUtils.a
- LLVMScalarOpts.a LLVMTarget.a``.
+> This variable holds a space separated list of libraries that should be
+> linked into the program. These libraries must be LLVM libraries. The
+> libraries must be specified without their `lib` prefix. For example, to
+> link with a driver that performs an IR transformation you might set
+> `LLVMLIBS` to this minimal set of libraries `LLVMSupport.a LLVMCore.a
+> LLVMBitReader.a LLVMAsmParser.a LLVMAnalysis.a LLVMTransformUtils.a
+> LLVMScalarOpts.a LLVMTarget.a`.
+>
+> Note that this works only for statically linked libraries. LLVM is split
+> into a large number of static libraries, and the list of libraries you
+> require may be much longer than the list above. To see a full list of
+> libraries use: `llvm-config --libs all`. Using `LINK_COMPONENTS` as
+> described below, obviates the need to set `LLVMLIBS`.
- Note that this works only for statically linked libraries. LLVM is split
- into a large number of static libraries, and the list of libraries you
- require may be much longer than the list above. To see a full list of
- libraries use: ``llvm-config --libs all``. Using ``LINK_COMPONENTS`` as
- described below, obviates the need to set ``LLVMLIBS``.
+`LINK_COMPONENTS`
-``LINK_COMPONENTS``
+> This variable holds a space separated list of components that the LLVM
+> `Makefiles` pass to the `llvm-config` tool to generate a link line for
+> the program. For example, to link with all LLVM libraries use
+> `LINK_COMPONENTS = all`.
- This variable holds a space separated list of components that the LLVM
- ``Makefiles`` pass to the ``llvm-config`` tool to generate a link line for
- the program. For example, to link with all LLVM libraries use
- ``LINK_COMPONENTS = all``.
+`LIBS`
-``LIBS``
+> To link dynamic libraries, add `-l<library base name>` to the `LIBS`
+> variable. The LLVM build system will look in the same places for dynamic
+> libraries as it does for static libraries.
+>
+> For example, to link `libsample.so`, you would have the following line in
+> your `Makefile`:
+>
+> > ```makefile
+> > LIBS += -lsample
+> > ```
- To link dynamic libraries, add ``-l<library base name>`` to the ``LIBS``
- variable. The LLVM build system will look in the same places for dynamic
- libraries as it does for static libraries.
+Note that `LIBS` must occur in the Makefile after the inclusion of
+`Makefile.common`.
- For example, to link ``libsample.so``, you would have the following line in
- your ``Makefile``:
+### Miscellaneous Variables
- .. code-block:: makefile
+`CFLAGS` & `CPPFLAGS`
- LIBS += -lsample
+> This variable can be used to add options to the C and C++ compiler,
+> respectively. It is typically used to add options that tell the compiler
+> the location of additional directories to search for header files.
+>
+> It is highly suggested that you append to `CFLAGS` and `CPPFLAGS` as
+> opposed to overwriting them. The LLVM `Makefiles` may already have
+> useful options in them that you may not want to overwrite.
-Note that ``LIBS`` must occur in the Makefile after the inclusion of
-``Makefile.common``.
-
-Miscellaneous Variables
------------------------
-
-``CFLAGS`` & ``CPPFLAGS``
-
- This variable can be used to add options to the C and C++ compiler,
- respectively. It is typically used to add options that tell the compiler
- the location of additional directories to search for header files.
-
- It is highly suggested that you append to ``CFLAGS`` and ``CPPFLAGS`` as
- opposed to overwriting them. The LLVM ``Makefiles`` may already have
- useful options in them that you may not want to overwrite.
-
-Placement of Object Code
-========================
+## Placement of Object Code
The final location of built libraries and executables will depend upon whether
-you do a ``Debug``, ``Release``, or ``Profile`` build.
+you do a `Debug`, `Release`, or `Profile` build.
Libraries
- All libraries (static and dynamic) will be stored in
- ``PROJ_OBJ_ROOT/<type>/lib``, where *type* is ``Debug``, ``Release``, or
- ``Profile`` for a debug, optimized, or profiled build, respectively.
+> All libraries (static and dynamic) will be stored in
+> `PROJ_OBJ_ROOT/<type>/lib`, where *type* is `Debug`, `Release`, or
+> `Profile` for a debug, optimized, or profiled build, respectively.
Executables
- All executables will be stored in ``PROJ_OBJ_ROOT/<type>/bin``, where *type*
- is ``Debug``, ``Release``, or ``Profile`` for a debug, optimized, or
- profiled build, respectively.
+> All executables will be stored in `PROJ_OBJ_ROOT/<type>/bin`, where *type*
+> is `Debug`, `Release`, or `Profile` for a debug, optimized, or
+> profiled build, respectively.
-Further Help
-============
+## Further Help
If you have any questions or need any help creating an LLVM project, the LLVM
-team would be more than happy to help. You can always post your questions to
-the `Discourse forums
-<https://discourse.llvm.org>`_.
+team would be more than happy to help. You can always post your questions to
+the [Discourse forums](https://discourse.llvm.org).
+
diff --git a/llvm/docs/Proposals/GitHubMove.md b/llvm/docs/Proposals/GitHubMove.md
index 76a871af3559e..100e38c24b8fb 100644
--- a/llvm/docs/Proposals/GitHubMove.md
+++ b/llvm/docs/Proposals/GitHubMove.md
@@ -1,25 +1,19 @@
-==============================
-Moving LLVM Projects to GitHub
-==============================
+# Moving LLVM Projects to GitHub
-Current Status
-==============
+## Current Status
-We are planning to complete the transition to GitHub by Oct 21, 2019. See
-the GitHub migration `status page <https://llvm.org/GitHubMigrationStatus.html>`_
+We are planning to complete the transition to GitHub by Oct 21, 2019. See
+the GitHub migration [status page](https://llvm.org/GitHubMigrationStatus.html)
for the latest updates and instructions for how to migrate your workflows.
-
-Introduction
-============
+## Introduction
This is a proposal to move our current revision control system from our own
hosted Subversion to GitHub. Below are the financial and technical arguments as
to why we are proposing such a move and how people (and validation
infrastructure) will continue to work with a Git-based LLVM.
-What This Proposal is *Not* About
-=================================
+## What This Proposal is *Not* About
Changing the development policy.
@@ -31,11 +25,9 @@ Contributors will continue to earn commit access on demand under the Developer
Policy, except that that a GitHub account will be required instead of SVN
username/password-hash.
-Why Git, and Why GitHub?
-========================
+## Why Git, and Why GitHub?
-Why Move At All?
-----------------
+### Why Move At All?
This discussion began because we currently host our own Subversion server
and Git mirror on a voluntary basis. The LLVM Foundation sponsors the server and
@@ -50,8 +42,7 @@ We should take advantage of one of the services out there (GitHub, GitLab,
and BitBucket, among others) that offer better service (24/7 stability, disk
space, Git server, code browsing, forking facilities, etc) for free.
-Why Git?
---------
+### Why Git?
Many new coders nowadays start with Git, and a lot of people have never used
SVN, CVS, or anything else. Websites like GitHub have changed the landscape
@@ -64,19 +55,18 @@ through the Git-SVN integration.
Git allows you to:
-* Commit, squash, merge, and fork locally without touching the remote server.
-* Maintain local branches, enabling multiple threads of development.
-* Collaborate on these branches (e.g. through your own fork of llvm on GitHub).
-* Inspect the repository history (blame, log, bisect) without Internet access.
-* Maintain remote forks and branches on Git hosting services and
+- Commit, squash, merge, and fork locally without touching the remote server.
+- Maintain local branches, enabling multiple threads of development.
+- Collaborate on these branches (e.g. through your own fork of llvm on GitHub).
+- Inspect the repository history (blame, log, bisect) without Internet access.
+- Maintain remote forks and branches on Git hosting services and
integrate back to the main repository.
In addition, because Git seems to be replacing many OSS projects' version
control systems, there are many tools that are built over Git.
Future tooling may support Git first (if not only).
-Why GitHub?
------------
+### Why GitHub?
GitHub, like GitLab and BitBucket, provides free code hosting for open source
projects. Any of these could replace the code-hosting infrastructure that we
@@ -87,15 +77,14 @@ distribute the contents of the repositories depending on region and load.
GitHub has one important advantage over GitLab and
BitBucket: it offers read-write **SVN** access to the repository
-(https://github.com/blog/626-announcing-svn-support).
+(<https://github.com/blog/626-announcing-svn-support>).
This would enable people to continue working post-migration as though our code
were still canonically in an SVN repository.
In addition, there are already multiple LLVM mirrors on GitHub, indicating that
part of our community has already settled there.
-On Managing Revision Numbers with Git
--------------------------------------
+### On Managing Revision Numbers with Git
The current SVN repository hosts all the LLVM sub-projects alongside each other.
A single revision number (e.g. r123456) thus identifies a consistent version of
@@ -109,17 +98,17 @@ past discussions about Git:
- "The 'branch' I most care about is mainline, and losing the ability to say
'fixed in r1234' (with some sort of monotonically increasing number) would
- be a tragic loss." [LattnerRevNum]_
+ be a tragic loss." [^cite_lattnerrevnum]
- "I like those results sorted by time and the chronology should be obvious, but
timestamps are incredibly cumbersome and make it difficult to verify that a
- given checkout matches a given set of results." [TrickRevNum]_
+ given checkout matches a given set of results." [^cite_trickrevnum]
- "There is still the major regression with unreadable version numbers.
Given the amount of Bugzilla traffic with 'Fixed in...', that's a
- non-trivial issue." [JSonnRevNum]_
-- "Sequential IDs are important for LNT and llvmlab bisection tool." [MatthewsRevNum]_.
+ non-trivial issue." [^cite_jsonnrevnum]
+- "Sequential IDs are important for LNT and llvmlab bisection tool." [^cite_matthewsrevnum].
However, Git can emulate this increasing revision number:
-``git rev-list --count <commit-hash>``. This identifier is unique only
+`git rev-list --count <commit-hash>`. This identifier is unique only
within a single branch, but this means the tuple `(num, branch-name)` uniquely
identifies a commit.
@@ -127,35 +116,31 @@ We can thus use this revision number to ensure that e.g. `clang -v` reports a
user-friendly revision number (e.g. `main-12345` or `4.0-5321`), addressing
the objections raised above with respect to this aspect of Git.
-What About Branches and Merges?
--------------------------------
+### What About Branches and Merges?
In contrast to SVN, Git makes branching easy. Git's commit history is
represented as a DAG, a departure from SVN's linear history. However, we propose
to mandate making merge commits illegal in our canonical Git repository.
Unfortunately, GitHub does not support server side hooks to enforce such a
-policy. We must rely on the community to avoid pushing merge commits.
+policy. We must rely on the community to avoid pushing merge commits.
GitHub offers a feature called `Status Checks`: a branch protected by
`status checks` requires commits to be explicitly allowed before the push can happen.
We could supply a pre-push hook on the client side that would run and check the
-history, before allowing the commit being pushed [statuschecks]_.
+history, before allowing the commit being pushed [^cite_statuschecks].
However this solution would be somewhat fragile (how do you update a script
installed on every developer machine?) and prevents SVN access to the
repository.
-What About Commit Emails?
--------------------------
+### What About Commit Emails?
We will need a new bot to send emails for each commit. This proposal leaves the
email format unchanged besides the commit URL.
-Straw Man Migration Plan
-========================
+## Straw Man Migration Plan
-Step #1 : Before The Move
--------------------------
+### Step #1 : Before The Move
1. Update docs to mention the move, so people are aware of what is going on.
2. Set up a read-only version of the GitHub project, mirroring our current SVN
@@ -164,15 +149,14 @@ Step #1 : Before The Move
umbrella repository update (if the multirepo is selected) or the read-only
Git views for the sub-projects (if the monorepo is selected).
-Step #2 : Git Move
-------------------
+### Step #2 : Git Move
4. Update the buildbots to pick up updates and commits from the GitHub
repository. Not all bots have to migrate at this point, but it'll help
provide infrastructure testing.
5. Update Phabricator to pick up commits from the GitHub repository.
6. LNT and llvmlab have to be updated: they rely on unique monotonically
- increasing integer across branch [MatthewsRevNum]_.
+ increasing integer across branch [^cite_matthewsrevnum].
7. Instruct downstream integrators to pick up commits from the GitHub
repository.
8. Review and prepare an update for the LLVM documentation.
@@ -184,29 +168,25 @@ owners.
The migration will pause here until all dependencies have cleared, and all
problems have been solved.
-Step #3: Write Access Move
---------------------------
+### Step #3: Write Access Move
-9. Collect developers' GitHub account information, and add them to the project.
+09. Collect developers' GitHub account information, and add them to the project.
10. Switch the SVN repository to read-only and allow pushes to the GitHub repository.
11. Update the documentation.
12. Mirror Git to SVN.
-Step #4 : Post Move
--------------------
+### Step #4 : Post Move
13. Archive the SVN repository.
14. Update links on the LLVM website pointing to viewvc/klaus/phab etc. to
point to GitHub instead.
-GitHub Repository Description
-=============================
+## GitHub Repository Description
-Monorepo
-----------------
+### Monorepo
-The LLVM git repository hosted at https://github.com/llvm/llvm-project contains all
-sub-projects in a single source tree. It is often referred to as a monorepo and
+The LLVM git repository hosted at <https://github.com/llvm/llvm-project> contains all
+sub-projects in a single source tree. It is often referred to as a monorepo and
mimics an export of the current SVN repository, with each sub-project having its
own top-level directory. Not all sub-projects are used for building toolchains.
For example, www/ and test-suite/ are not part of the monorepo.
@@ -214,138 +194,132 @@ For example, www/ and test-suite/ are not part of the monorepo.
Putting all sub-projects in a single checkout makes cross-project refactoring
naturally simple:
- * New sub-projects can be trivially split out for better reuse and/or layering
- (e.g., to allow libSupport and/or LIT to be used by runtimes without adding a
- dependency on LLVM).
- * Changing an API in LLVM and upgrading the sub-projects will always be done in
- a single commit, designing away a common source of temporary build breakage.
- * Moving code across sub-project (during refactoring for instance) in a single
- commit enables accurate `git blame` when tracking code change history.
- * Tooling based on `git grep` works natively across sub-projects, allowing to
- easier find refactoring opportunities across projects (for example reusing a
- datastructure initially in LLDB by moving it into libSupport).
- * Having all the sources present encourages maintaining the other sub-projects
- when changing API.
+> - New sub-projects can be trivially split out for better reuse and/or layering
+> (e.g., to allow libSupport and/or LIT to be used by runtimes without adding a
+> dependency on LLVM).
+> - Changing an API in LLVM and upgrading the sub-projects will always be done in
+> a single commit, designing away a common source of temporary build breakage.
+> - Moving code across sub-project (during refactoring for instance) in a single
+> commit enables accurate `git blame` when tracking code change history.
+> - Tooling based on `git grep` works natively across sub-projects, allowing to
+> easier find refactoring opportunities across projects (for example reusing a
+> datastructure initially in LLDB by moving it into libSupport).
+> - Having all the sources present encourages maintaining the other sub-projects
+> when changing API.
Finally, the monorepo maintains the property of the existing SVN repository that
the sub-projects move synchronously, and a single revision number (or commit
hash) identifies the state of the development across all projects.
-.. _build_single_project:
+(build-single-project)=
-Building a single sub-project
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#### Building a single sub-project
Even though there is a single source tree, you are not required to build
-all sub-projects together. It is trivial to configure builds for a single
+all sub-projects together. It is trivial to configure builds for a single
sub-project.
-For example::
+For example:
- mkdir build && cd build
- # Configure only LLVM (default)
- cmake path/to/monorepo
- # Configure LLVM and lld
- cmake path/to/monorepo -DLLVM_ENABLE_PROJECTS=lld
- # Configure LLVM and clang
- cmake path/to/monorepo -DLLVM_ENABLE_PROJECTS=clang
+```
+mkdir build && cd build
+# Configure only LLVM (default)
+cmake path/to/monorepo
+# Configure LLVM and lld
+cmake path/to/monorepo -DLLVM_ENABLE_PROJECTS=lld
+# Configure LLVM and clang
+cmake path/to/monorepo -DLLVM_ENABLE_PROJECTS=clang
+```
-.. _git-svn-mirror:
+(git-svn-mirror)=
-Outstanding Questions
----------------------
+### Outstanding Questions
-Read-only sub-project mirrors
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#### Read-only sub-project mirrors
With the Monorepo, it is undecided whether the existing single-subproject
-mirrors (e.g. https://git.llvm.org/git/compiler-rt.git) will continue to
+mirrors (e.g. <https://git.llvm.org/git/compiler-rt.git>) will continue to
be maintained.
-Read/write SVN bridge
-^^^^^^^^^^^^^^^^^^^^^
+#### Read/write SVN bridge
-GitHub supports a read/write SVN bridge for its repositories. However,
+GitHub supports a read/write SVN bridge for its repositories. However,
there have been issues with this bridge working correctly in the past,
so it's not clear if this is something that will be supported going forward.
-Monorepo Drawbacks
-------------------
-
- * Using the monolithic repository may add overhead for those contributing to a
- standalone sub-project, particularly on runtimes like libcxx and compiler-rt
- that don't rely on LLVM; currently, a fresh clone of libcxx is only 15MB (vs.
- 1GB for the monorepo), and the commit rate of LLVM may cause more frequent
- `git push` collisions when upstreaming. Affected contributors may be able to
- use the SVN bridge or the single-subproject Git mirrors. However, it's
- undecided if these projects will continue to be maintained.
- * Using the monolithic repository may add overhead for those *integrating* a
- standalone sub-project, even if they aren't contributing to it, due to the
- same disk space concern as the point above. The availability of the
- sub-project Git mirrors would addresses this.
- * Preservation of the existing read/write SVN-based workflows relies on the
- GitHub SVN bridge, which is an extra dependency. Maintaining this locks us
- into GitHub and could restrict future workflow changes.
-
-Workflows
-^^^^^^^^^
-
- * :ref:`Checkout/Clone a Single Project, without Commit Access <workflow-checkout-commit>`.
- * :ref:`Checkout/Clone Multiple Projects, with Commit Access <workflow-monocheckout-multicommit>`.
- * :ref:`Commit an API Change in LLVM and Update the Sub-projects <workflow-cross-repo-commit>`.
- * :ref:`Branching/Stashing/Updating for Local Development or Experiments <workflow-mono-branching>`.
- * :ref:`Bisecting <workflow-mono-bisecting>`.
-
-Workflow Before/After
-=====================
+### Monorepo Drawbacks
+
+> - Using the monolithic repository may add overhead for those contributing to a
+> standalone sub-project, particularly on runtimes like libcxx and compiler-rt
+> that don't rely on LLVM; currently, a fresh clone of libcxx is only 15MB (vs.
+> 1GB for the monorepo), and the commit rate of LLVM may cause more frequent
+> `git push` collisions when upstreaming. Affected contributors may be able to
+> use the SVN bridge or the single-subproject Git mirrors. However, it's
+> undecided if these projects will continue to be maintained.
+> - Using the monolithic repository may add overhead for those *integrating* a
+> standalone sub-project, even if they aren't contributing to it, due to the
+> same disk space concern as the point above. The availability of the
+> sub-project Git mirrors would addresses this.
+> - Preservation of the existing read/write SVN-based workflows relies on the
+> GitHub SVN bridge, which is an extra dependency. Maintaining this locks us
+> into GitHub and could restrict future workflow changes.
+
+#### Workflows
+
+> - {ref}`Checkout/Clone a Single Project, without Commit Access <workflow-checkout-commit>`.
+> - {ref}`Checkout/Clone Multiple Projects, with Commit Access <workflow-monocheckout-multicommit>`.
+> - {ref}`Commit an API Change in LLVM and Update the Sub-projects <workflow-cross-repo-commit>`.
+> - {ref}`Branching/Stashing/Updating for Local Development or Experiments <workflow-mono-branching>`.
+> - {ref}`Bisecting <workflow-mono-bisecting>`.
+
+## Workflow Before/After
This section goes through a few examples of workflows, intended to illustrate
how end-users or developers would interact with the repository for
various use-cases.
-.. _workflow-checkout-commit:
-
-Checkout/Clone a Single Project, with Commit Access
----------------------------------------------------
+(workflow-checkout-commit)=
-Currently
-^^^^^^^^^
+### Checkout/Clone a Single Project, with Commit Access
-::
+#### Currently
- # direct SVN checkout
- svn co https://user@llvm.org/svn/llvm-project/llvm/trunk llvm
- # or using the read-only Git view, with git-svn
- git clone https://llvm.org/git/llvm.git
- cd llvm
- git svn init https://llvm.org/svn/llvm-project/llvm/trunk --username=<username>
- git config svn-remote.svn.fetch :refs/remotes/origin/main
- git svn rebase -l # -l avoids fetching ahead of the git mirror.
+```
+# direct SVN checkout
+svn co https://user@llvm.org/svn/llvm-project/llvm/trunk llvm
+# or using the read-only Git view, with git-svn
+git clone https://llvm.org/git/llvm.git
+cd llvm
+git svn init https://llvm.org/svn/llvm-project/llvm/trunk --username=<username>
+git config svn-remote.svn.fetch :refs/remotes/origin/main
+git svn rebase -l # -l avoids fetching ahead of the git mirror.
+```
Commits are performed using `svn commit` or with the sequence `git commit` and
`git svn dcommit`.
-.. _workflow-multicheckout-nocommit:
+(workflow-multicheckout-nocommit)=
-Monorepo Variant
-^^^^^^^^^^^^^^^^
+#### Monorepo Variant
With the monorepo variant, there are a few options, depending on your
constraints. First, you could just clone the full repository:
-git clone https://github.com/llvm/llvm-project.git
+git clone <https://github.com/llvm/llvm-project.git>
At this point you have every sub-project (llvm, clang, lld, lldb, ...), which
-:ref:`doesn't imply you have to build all of them <build_single_project>`. You
+{ref}`doesn't imply you have to build all of them <build_single_project>`. You
can still build only compiler-rt for instance. In this way it's not different
from someone who would check out all the projects with SVN today.
If you want to avoid checking out all the sources, you can hide the other
-directories using a Git sparse checkout::
+directories using a Git sparse checkout:
- git config core.sparseCheckout true
- echo /compiler-rt > .git/info/sparse-checkout
- git read-tree -mu HEAD
+```
+git config core.sparseCheckout true
+echo /compiler-rt > .git/info/sparse-checkout
+git read-tree -mu HEAD
+```
The data for all sub-projects is still in your `.git` directory, but in your
checkout, you only see `compiler-rt`.
@@ -357,9 +331,11 @@ care about. If you are using sparse checkout, the files from other projects
won't appear on your disk. The only effect is that your commit hash changes.
You can check whether the changes in the last fetch are relevant to your commit
-by running::
+by running:
- git log origin/main@{1}..origin/main -- libcxx
+```
+git log origin/main@{1}..origin/main -- libcxx
+```
This command can be hidden in a script so that `git llvmpush` would perform all
these steps, fail only if such a dependent change exists, and show immediately
@@ -368,66 +344,66 @@ the change that prevented the push. An immediate repeat of the command would
Note that today with SVN or git-svn, this step is not possible since the
"rebase" implicitly happens while committing (unless a conflict occurs).
-Checkout/Clone Multiple Projects, with Commit Access
-----------------------------------------------------
+### Checkout/Clone Multiple Projects, with Commit Access
Let's look how to assemble llvm+clang+libcxx at a given revision.
-Currently
-^^^^^^^^^
-
-::
-
- svn co https://llvm.org/svn/llvm-project/llvm/trunk llvm -r $REVISION
- cd llvm/tools
- svn co https://llvm.org/svn/llvm-project/clang/trunk clang -r $REVISION
- cd ../projects
- svn co https://llvm.org/svn/llvm-project/libcxx/trunk libcxx -r $REVISION
-
-Or using git-svn::
-
- git clone https://llvm.org/git/llvm.git
- cd llvm/
- git svn init https://llvm.org/svn/llvm-project/llvm/trunk --username=<username>
- git config svn-remote.svn.fetch :refs/remotes/origin/main
- git svn rebase -l
- git checkout `git svn find-rev -B r258109`
- cd tools
- git clone https://llvm.org/git/clang.git
- cd clang/
- git svn init https://llvm.org/svn/llvm-project/clang/trunk --username=<username>
- git config svn-remote.svn.fetch :refs/remotes/origin/main
- git svn rebase -l
- git checkout `git svn find-rev -B r258109`
- cd ../../projects/
- git clone https://llvm.org/git/libcxx.git
- cd libcxx
- git svn init https://llvm.org/svn/llvm-project/libcxx/trunk --username=<username>
- git config svn-remote.svn.fetch :refs/remotes/origin/main
- git svn rebase -l
- git checkout `git svn find-rev -B r258109`
+#### Currently
+
+```
+svn co https://llvm.org/svn/llvm-project/llvm/trunk llvm -r $REVISION
+cd llvm/tools
+svn co https://llvm.org/svn/llvm-project/clang/trunk clang -r $REVISION
+cd ../projects
+svn co https://llvm.org/svn/llvm-project/libcxx/trunk libcxx -r $REVISION
+```
+
+Or using git-svn:
+
+```
+git clone https://llvm.org/git/llvm.git
+cd llvm/
+git svn init https://llvm.org/svn/llvm-project/llvm/trunk --username=<username>
+git config svn-remote.svn.fetch :refs/remotes/origin/main
+git svn rebase -l
+git checkout `git svn find-rev -B r258109`
+cd tools
+git clone https://llvm.org/git/clang.git
+cd clang/
+git svn init https://llvm.org/svn/llvm-project/clang/trunk --username=<username>
+git config svn-remote.svn.fetch :refs/remotes/origin/main
+git svn rebase -l
+git checkout `git svn find-rev -B r258109`
+cd ../../projects/
+git clone https://llvm.org/git/libcxx.git
+cd libcxx
+git svn init https://llvm.org/svn/llvm-project/libcxx/trunk --username=<username>
+git config svn-remote.svn.fetch :refs/remotes/origin/main
+git svn rebase -l
+git checkout `git svn find-rev -B r258109`
+```
Note that the list would be longer with more sub-projects.
-.. _workflow-monocheckout-multicommit:
+(workflow-monocheckout-multicommit)=
-Monorepo Variant
-^^^^^^^^^^^^^^^^
+#### Monorepo Variant
The repository contains natively the source for every sub-projects at the right
-revision, which makes this straightforward::
+revision, which makes this straightforward:
- git clone https://github.com/llvm/llvm-project.git
- cd llvm-projects
- git checkout $REVISION
+```
+git clone https://github.com/llvm/llvm-project.git
+cd llvm-projects
+git checkout $REVISION
+```
As before, at this point clang, llvm, and libcxx are stored in directories
alongside each other.
-.. _workflow-cross-repo-commit:
+(workflow-cross-repo-commit)=
-Commit an API Change in LLVM and Update the Sub-projects
---------------------------------------------------------
+### Commit an API Change in LLVM and Update the Sub-projects
Today this is possible, even though not common (at least not documented) for
subversion users and for git-svn users. For example, few Git users try to update
@@ -440,67 +416,74 @@ the umbrella repo's updater bot to group all of them into a single revision.
The monorepo variant handles this natively.
-Branching/Stashing/Updating for Local Development or Experiments
-----------------------------------------------------------------
+### Branching/Stashing/Updating for Local Development or Experiments
-Currently
-^^^^^^^^^
+#### Currently
SVN does not allow this use case, but developers that are currently using
git-svn can do it. Let's look in practice what it means when dealing with
multiple sub-projects.
-To update the repository to tip of trunk::
+To update the repository to tip of trunk:
- git pull
- cd tools/clang
- git pull
- cd ../../projects/libcxx
- git pull
+```
+git pull
+cd tools/clang
+git pull
+cd ../../projects/libcxx
+git pull
+```
-To create a new branch::
+To create a new branch:
- git checkout -b MyBranch
- cd tools/clang
- git checkout -b MyBranch
- cd ../../projects/libcxx
- git checkout -b MyBranch
+```
+git checkout -b MyBranch
+cd tools/clang
+git checkout -b MyBranch
+cd ../../projects/libcxx
+git checkout -b MyBranch
+```
-To switch branches::
+To switch branches:
- git checkout AnotherBranch
- cd tools/clang
- git checkout AnotherBranch
- cd ../../projects/libcxx
- git checkout AnotherBranch
+```
+git checkout AnotherBranch
+cd tools/clang
+git checkout AnotherBranch
+cd ../../projects/libcxx
+git checkout AnotherBranch
+```
-.. _workflow-mono-branching:
+(workflow-mono-branching)=
-Monorepo Variant
-^^^^^^^^^^^^^^^^
+#### Monorepo Variant
Regular Git commands are sufficient, because everything is in a single
repository:
-To update the repository to tip of trunk::
+To update the repository to tip of trunk:
- git pull
+```
+git pull
+```
-To create a new branch::
+To create a new branch:
- git checkout -b MyBranch
+```
+git checkout -b MyBranch
+```
-To switch branches::
+To switch branches:
- git checkout AnotherBranch
+```
+git checkout AnotherBranch
+```
-Bisecting
----------
+### Bisecting
Assuming a developer is looking for a bug in clang (or lld, or lldb, ...).
-Currently
-^^^^^^^^^
+#### Currently
SVN does not have builtin bisection support, but the single revision across
sub-projects makes it possible to script around.
@@ -509,156 +492,160 @@ Using the existing Git read-only view of the repositories, it is possible to use
the native Git bisection script over the llvm repository, and use some scripting
to synchronize the clang repository to match the llvm revision.
-.. _workflow-mono-bisecting:
+(workflow-mono-bisecting)=
-Monorepo Variant
-^^^^^^^^^^^^^^^^
+#### Monorepo Variant
Bisecting on the monorepo is straightforward, and very similar to the above,
except that the bisection script does not need to include the
`git submodule update` step.
The same example, finding which commit introduces a regression where clang-3.9
-crashes but not clang-3.8 passes, will look like::
+crashes but not clang-3.8 passes, will look like:
- git bisect start releases/3.9.x releases/3.8.x
- git bisect run ./bisect_script.sh
+```
+git bisect start releases/3.9.x releases/3.8.x
+git bisect run ./bisect_script.sh
+```
-With the `bisect_script.sh` script being::
+With the `bisect_script.sh` script being:
- #!/bin/sh
- cd $BUILD_DIR
+```
+#!/bin/sh
+cd $BUILD_DIR
- ninja clang || exit 125 # an exit code of 125 asks "git bisect"
- # to "skip" the current commit
+ninja clang || exit 125 # an exit code of 125 asks "git bisect"
+ # to "skip" the current commit
- ./bin/clang some_crash_test.cpp
+./bin/clang some_crash_test.cpp
+```
Also, since the monorepo handles commits update across multiple projects, you're
less like to encounter a build failure where a commit change an API in LLVM and
another later one "fixes" the build in clang.
-Moving Local Branches to the Monorepo
-=====================================
+## Moving Local Branches to the Monorepo
Suppose you have been developing against the existing LLVM git
-mirrors. You have one or more git branches that you want to migrate
+mirrors. You have one or more git branches that you want to migrate
to the "final monorepo".
The simplest way to migrate such branches is with the
-``migrate-downstream-fork.py`` tool at
-https://github.com/jyknight/llvm-git-migration.
-
-Basic migration
----------------
-
-Basic instructions for ``migrate-downstream-fork.py`` are in the
-Python script and are expanded on below to a more general recipe::
-
- # Make a repository which will become your final local mirror of the
- # monorepo.
- mkdir my-monorepo
- git -C my-monorepo init
-
- # Add a remote to the monorepo.
- git -C my-monorepo remote add upstream/monorepo https://github.com/llvm/llvm-project.git
-
- # Add remotes for each git mirror you use, from upstream as well as
- # your local mirror. All projects are listed here but you need only
- # import those for which you have local branches.
- my_projects=( clang
- clang-tools-extra
- compiler-rt
- debuginfo-tests
- libcxx
- libcxxabi
- libunwind
- lld
- lldb
- llvm
- openmp
- polly )
- for p in ${my_projects[@]}; do
- git -C my-monorepo remote add upstream/split/${p} https://github.com/llvm-mirror/${p}.git
- git -C my-monorepo remote add local/split/${p} https://my.local.mirror.org/${p}.git
- done
-
- # Pull in all the commits.
- git -C my-monorepo fetch --all
-
- # Run migrate-downstream-fork to rewrite local branches on top of
- # the upstream monorepo.
- (
- cd my-monorepo
- migrate-downstream-fork.py \
- refs/remotes/local \
- refs/tags \
- --new-repo-prefix=refs/remotes/upstream/monorepo \
- --old-repo-prefix=refs/remotes/upstream/split \
- --source-kind=split \
- --revmap-out=monorepo-map.txt
- )
-
- # Octopus-merge the resulting local split histories to unify them.
-
- # Assumes local work on local split mirrors is on main (and
- # upstream is presumably represented by some other branch like
- # upstream/main).
- my_local_branch="main"
-
- git -C my-monorepo branch --no-track local/octopus/main \
- $(git -C my-monorepo merge-base refs/remotes/upstream/monorepo/main \
- refs/remotes/local/split/llvm/${my_local_branch})
- git -C my-monorepo checkout local/octopus/${my_local_branch}
-
- subproject_branches=()
- for p in ${my_projects[@]}; do
- subproject_branch=${p}/local/monorepo/${my_local_branch}
- git -C my-monorepo branch ${subproject_branch} \
- refs/remotes/local/split/${p}/${my_local_branch}
- if [[ "${p}" != "llvm" ]]; then
- subproject_branches+=( ${subproject_branch} )
- fi
- done
-
- git -C my-monorepo merge ${subproject_branches[@]}
-
- for p in ${my_projects[@]}; do
- subproject_branch=${p}/local/monorepo/${my_local_branch}
- git -C my-monorepo branch -d ${subproject_branch}
- done
-
- # Create local branches for upstream monorepo branches.
- for ref in $(git -C my-monorepo for-each-ref --format="%(refname)" \
- refs/remotes/upstream/monorepo); do
- upstream_branch=${ref#refs/remotes/upstream/monorepo/}
- git -C my-monorepo branch upstream/${upstream_branch} ${ref}
- done
-
-The above gets you to a state like the following::
-
- U1 - U2 - U3 <- upstream/main
- \ \ \
- \ \ - Llld1 - Llld2 -
- \ \ \
- \ - Lclang1 - Lclang2-- Lmerge <- local/octopus/main
- \ /
- - Lllvm1 - Lllvm2-----
+`migrate-downstream-fork.py` tool at
+<https://github.com/jyknight/llvm-git-migration>.
+
+### Basic migration
+
+Basic instructions for `migrate-downstream-fork.py` are in the
+Python script and are expanded on below to a more general recipe:
+
+```
+# Make a repository which will become your final local mirror of the
+# monorepo.
+mkdir my-monorepo
+git -C my-monorepo init
+
+# Add a remote to the monorepo.
+git -C my-monorepo remote add upstream/monorepo https://github.com/llvm/llvm-project.git
+
+# Add remotes for each git mirror you use, from upstream as well as
+# your local mirror. All projects are listed here but you need only
+# import those for which you have local branches.
+my_projects=( clang
+ clang-tools-extra
+ compiler-rt
+ debuginfo-tests
+ libcxx
+ libcxxabi
+ libunwind
+ lld
+ lldb
+ llvm
+ openmp
+ polly )
+for p in ${my_projects[@]}; do
+ git -C my-monorepo remote add upstream/split/${p} https://github.com/llvm-mirror/${p}.git
+ git -C my-monorepo remote add local/split/${p} https://my.local.mirror.org/${p}.git
+done
+
+# Pull in all the commits.
+git -C my-monorepo fetch --all
+
+# Run migrate-downstream-fork to rewrite local branches on top of
+# the upstream monorepo.
+(
+ cd my-monorepo
+ migrate-downstream-fork.py \
+ refs/remotes/local \
+ refs/tags \
+ --new-repo-prefix=refs/remotes/upstream/monorepo \
+ --old-repo-prefix=refs/remotes/upstream/split \
+ --source-kind=split \
+ --revmap-out=monorepo-map.txt
+)
+
+# Octopus-merge the resulting local split histories to unify them.
+
+# Assumes local work on local split mirrors is on main (and
+# upstream is presumably represented by some other branch like
+# upstream/main).
+my_local_branch="main"
+
+git -C my-monorepo branch --no-track local/octopus/main \
+ $(git -C my-monorepo merge-base refs/remotes/upstream/monorepo/main \
+ refs/remotes/local/split/llvm/${my_local_branch})
+git -C my-monorepo checkout local/octopus/${my_local_branch}
+
+subproject_branches=()
+for p in ${my_projects[@]}; do
+ subproject_branch=${p}/local/monorepo/${my_local_branch}
+ git -C my-monorepo branch ${subproject_branch} \
+ refs/remotes/local/split/${p}/${my_local_branch}
+ if [[ "${p}" != "llvm" ]]; then
+ subproject_branches+=( ${subproject_branch} )
+ fi
+done
+
+git -C my-monorepo merge ${subproject_branches[@]}
+
+for p in ${my_projects[@]}; do
+ subproject_branch=${p}/local/monorepo/${my_local_branch}
+ git -C my-monorepo branch -d ${subproject_branch}
+done
+
+# Create local branches for upstream monorepo branches.
+for ref in $(git -C my-monorepo for-each-ref --format="%(refname)" \
+ refs/remotes/upstream/monorepo); do
+ upstream_branch=${ref#refs/remotes/upstream/monorepo/}
+ git -C my-monorepo branch upstream/${upstream_branch} ${ref}
+done
+```
+
+The above gets you to a state like the following:
+
+```
+U1 - U2 - U3 <- upstream/main
+ \ \ \
+ \ \ - Llld1 - Llld2 -
+ \ \ \
+ \ - Lclang1 - Lclang2-- Lmerge <- local/octopus/main
+ \ /
+ - Lllvm1 - Lllvm2-----
+```
Each branched component has its branch rewritten on top of the
monorepo and all components are unified by a giant octopus merge.
If additional active local branches need to be preserved, the above
-operations following the assignment to ``my_local_branch`` should be
-done for each branch. Ref paths will need to be updated to map the
-local branch to the corresponding upstream branch. If local branches
+operations following the assignment to `my_local_branch` should be
+done for each branch. Ref paths will need to be updated to map the
+local branch to the corresponding upstream branch. If local branches
have no corresponding upstream branch, then the creation of
-``local/octopus/<local branch>`` need not use ``git-merge-base`` to
+`local/octopus/<local branch>` need not use `git-merge-base` to
pinpoint its root commit; it may simply be branched from the
-appropriate component branch (say, ``llvm/local_release_X``).
+appropriate component branch (say, `llvm/local_release_X`).
-Zipping local history
----------------------
+### Zipping local history
The octopus merge is suboptimal for many cases, because walking back
through the history of one component leaves the other components fixed
@@ -667,417 +654,433 @@ at a history that likely makes things unbuildable.
Some downstream users track the order commits were made to subprojects
with some kind of "umbrella" project that imports the project git
mirrors as submodules, similar to the multirepo umbrella proposed
-above. Such an umbrella repository looks something like this::
+above. Such an umbrella repository looks something like this:
- UM1 ---- UM2 -- UM3 -- UM4 ---- UM5 ---- UM6 ---- UM7 ---- UM8 <- main
- | | | | | | |
- Lllvm1 Llld1 Lclang1 Lclang2 Lllvm2 Llld2 Lmyproj1
+```
+ UM1 ---- UM2 -- UM3 -- UM4 ---- UM5 ---- UM6 ---- UM7 ---- UM8 <- main
+ | | | | | | |
+Lllvm1 Llld1 Lclang1 Lclang2 Lllvm2 Llld2 Lmyproj1
+```
The vertical bars represent submodule updates to a particular local
-commit in the project mirror. ``UM3`` in this case is a commit of
+commit in the project mirror. `UM3` in this case is a commit of
some local umbrella repository state that is not a submodule update,
-perhaps a ``README`` or project build script update. Commit ``UM8``
-updates a submodule of local project ``myproj``.
+perhaps a `README` or project build script update. Commit `UM8`
+updates a submodule of local project `myproj`.
-The tool ``zip-downstream-fork.py`` at
-https://github.com/greened/llvm-git-migration/tree/zip can be used to
+The tool `zip-downstream-fork.py` at
+<https://github.com/greened/llvm-git-migration/tree/zip> can be used to
convert the umbrella history into a monorepo-based history with
-commits in the order implied by submodule updates::
-
- U1 - U2 - U3 <- upstream/main
- \ \ \
- \ -----\--------------- local/zip--.
- \ \ \ |
- - Lllvm1 - Llld1 - UM3 - Lclang1 - Lclang2 - Lllvm2 - Llld2 - Lmyproj1 <-'
-
-
-The ``U*`` commits represent upstream commits to the monorepo main
-branch. Each submodule update in the local ``UM*`` commits brought in
-a subproject tree at some local commit. The trees in the ``L*1``
-commits represent merges from upstream. These result in edges from
-the ``U*`` commits to their corresponding rewritten ``L*1`` commits.
-The ``L*2`` commits did not do any merges from upstream.
-
-Note that the merge from ``U2`` to ``Lclang1`` appears redundant, but
-if, say, ``U3`` changed some files in upstream clang, the ``Lclang1``
-commit appearing after the ``Llld1`` commit would actually represent a
-clang tree *earlier* in the upstream clang history. We want the
-``local/zip`` branch to accurately represent the state of our umbrella
-history and so the edge ``U2 -> Lclang1`` is a visual reminder of what
-clang's tree actually looks like in ``Lclang1``.
-
-Even so, the edge ``U3 -> Llld1`` could be problematic for future
-merges from upstream. git will think that we've already merged from
-``U3``, and we have, except for the state of the clang tree. One
-possible mitigation strategy is to manually diff clang between ``U2``
-and ``U3`` and apply those updates to ``local/zip``. Another,
+commits in the order implied by submodule updates:
+
+```
+U1 - U2 - U3 <- upstream/main
+ \ \ \
+ \ -----\--------------- local/zip--.
+ \ \ \ |
+ - Lllvm1 - Llld1 - UM3 - Lclang1 - Lclang2 - Lllvm2 - Llld2 - Lmyproj1 <-'
+```
+
+The `U*` commits represent upstream commits to the monorepo main
+branch. Each submodule update in the local `UM*` commits brought in
+a subproject tree at some local commit. The trees in the `L*1`
+commits represent merges from upstream. These result in edges from
+the `U*` commits to their corresponding rewritten `L*1` commits.
+The `L*2` commits did not do any merges from upstream.
+
+Note that the merge from `U2` to `Lclang1` appears redundant, but
+if, say, `U3` changed some files in upstream clang, the `Lclang1`
+commit appearing after the `Llld1` commit would actually represent a
+clang tree *earlier* in the upstream clang history. We want the
+`local/zip` branch to accurately represent the state of our umbrella
+history and so the edge `U2 -> Lclang1` is a visual reminder of what
+clang's tree actually looks like in `Lclang1`.
+
+Even so, the edge `U3 -> Llld1` could be problematic for future
+merges from upstream. git will think that we've already merged from
+`U3`, and we have, except for the state of the clang tree. One
+possible mitigation strategy is to manually diff clang between `U2`
+and `U3` and apply those updates to `local/zip`. Another,
possibly simpler strategy is to freeze local work on downstream
branches and merge all submodules from the latest upstream before
-running ``zip-downstream-fork.py``. If downstream merged each project
+running `zip-downstream-fork.py`. If downstream merged each project
from upstream in lockstep without any intervening local commits, then
-things should be fine without any special action. We anticipate this
+things should be fine without any special action. We anticipate this
to be the common case.
-The tree for ``Lclang1`` outside of clang will represent the state of
-things at ``U3`` since all of the upstream projects not participating
+The tree for `Lclang1` outside of clang will represent the state of
+things at `U3` since all of the upstream projects not participating
in the umbrella history should be in a state respecting the commit
-``U3``. The trees for llvm and lld should correctly represent commits
-``Lllvm1`` and ``Llld1``, respectively.
+`U3`. The trees for llvm and lld should correctly represent commits
+`Lllvm1` and `Llld1`, respectively.
-Commit ``UM3`` changed files not related to submodules and we need
-somewhere to put them. It is not safe in general to put them in the
+Commit `UM3` changed files not related to submodules and we need
+somewhere to put them. It is not safe in general to put them in the
monorepo root directory because they may conflict with files in the
-monorepo. Let's assume we want them in a directory ``local`` in the
+monorepo. Let's assume we want them in a directory `local` in the
monorepo.
**Example 1: Umbrella looks like the monorepo**
For this example, we'll assume that each subproject appears in its own
top-level directory in the umbrella, just as they do in the monorepo .
-Let's also assume that we want the files in directory ``myproj`` to
-appear in ``local/myproj``.
-
-Given the above run of ``migrate-downstream-fork.py``, a recipe to
-create the zipped history is below::
-
- # Import any non-LLVM repositories the umbrella references.
- git -C my-monorepo remote add localrepo \
- https://my.local.mirror.org/localrepo.git
- git fetch localrepo
-
- subprojects=( clang clang-tools-extra compiler-rt debuginfo-tests libclc
- libcxx libcxxabi libunwind lld lldb llgo llvm openmp
- parallel-libs polly pstl )
-
- # Import histories for upstream split projects (this was probably
- # already done for the ``migrate-downstream-fork.py`` run).
- for project in ${subprojects[@]}; do
- git remote add upstream/split/${project} \
- https://github.com/llvm-mirror/${subproject}.git
- git fetch umbrella/split/${project}
- done
-
- # Import histories for downstream split projects (this was probably
- # already done for the ``migrate-downstream-fork.py`` run).
- for project in ${subprojects[@]}; do
- git remote add local/split/${project} \
- https://my.local.mirror.org/${subproject}.git
- git fetch local/split/${project}
- done
-
- # Import umbrella history.
- git -C my-monorepo remote add umbrella \
- https://my.local.mirror.org/umbrella.git
- git fetch umbrella
-
- # Put myproj in local/myproj
- echo "myproj local/myproj" > my-monorepo/submodule-map.txt
-
- # Rewrite history
- (
- cd my-monorepo
- zip-downstream-fork.py \
- refs/remotes/umbrella \
- --new-repo-prefix=refs/remotes/upstream/monorepo \
- --old-repo-prefix=refs/remotes/upstream/split \
- --revmap-in=monorepo-map.txt \
- --revmap-out=zip-map.txt \
- --subdir=local \
- --submodule-map=submodule-map.txt \
- --update-tags
- )
-
- # Create the zip branch (assuming umbrella main is wanted).
- git -C my-monorepo branch --no-track local/zip/main refs/remotes/umbrella/main
+Let's also assume that we want the files in directory `myproj` to
+appear in `local/myproj`.
+
+Given the above run of `migrate-downstream-fork.py`, a recipe to
+create the zipped history is below:
+
+```
+# Import any non-LLVM repositories the umbrella references.
+git -C my-monorepo remote add localrepo \
+ https://my.local.mirror.org/localrepo.git
+git fetch localrepo
+
+subprojects=( clang clang-tools-extra compiler-rt debuginfo-tests libclc
+ libcxx libcxxabi libunwind lld lldb llgo llvm openmp
+ parallel-libs polly pstl )
+
+# Import histories for upstream split projects (this was probably
+# already done for the ``migrate-downstream-fork.py`` run).
+for project in ${subprojects[@]}; do
+ git remote add upstream/split/${project} \
+ https://github.com/llvm-mirror/${subproject}.git
+ git fetch umbrella/split/${project}
+done
+
+# Import histories for downstream split projects (this was probably
+# already done for the ``migrate-downstream-fork.py`` run).
+for project in ${subprojects[@]}; do
+ git remote add local/split/${project} \
+ https://my.local.mirror.org/${subproject}.git
+ git fetch local/split/${project}
+done
+
+# Import umbrella history.
+git -C my-monorepo remote add umbrella \
+ https://my.local.mirror.org/umbrella.git
+git fetch umbrella
+
+# Put myproj in local/myproj
+echo "myproj local/myproj" > my-monorepo/submodule-map.txt
+
+# Rewrite history
+(
+ cd my-monorepo
+ zip-downstream-fork.py \
+ refs/remotes/umbrella \
+ --new-repo-prefix=refs/remotes/upstream/monorepo \
+ --old-repo-prefix=refs/remotes/upstream/split \
+ --revmap-in=monorepo-map.txt \
+ --revmap-out=zip-map.txt \
+ --subdir=local \
+ --submodule-map=submodule-map.txt \
+ --update-tags
+ )
+
+ # Create the zip branch (assuming umbrella main is wanted).
+ git -C my-monorepo branch --no-track local/zip/main refs/remotes/umbrella/main
+```
Note that if the umbrella has submodules to non-LLVM repositories,
-``zip-downstream-fork.py`` needs to know about them to be able to
-rewrite commits. That is why the first step above is to fetch commits
+`zip-downstream-fork.py` needs to know about them to be able to
+rewrite commits. That is why the first step above is to fetch commits
from such repositories.
-With ``--update-tags`` the tool will migrate annotated tags pointing
-to submodule commits that were inlined into the zipped history. If
+With `--update-tags` the tool will migrate annotated tags pointing
+to submodule commits that were inlined into the zipped history. If
the umbrella pulled in an upstream commit that happened to have a tag
pointing to it, that tag will be migrated, which is almost certainly
-not what is wanted. The tag can always be moved back to its original
-commit after rewriting, or the ``--update-tags`` option may be
+not what is wanted. The tag can always be moved back to its original
+commit after rewriting, or the `--update-tags` option may be
discarded and any local tags would then be migrated manually.
**Example 2: Nested sources layout**
The tool handles nested submodules (e.g. llvm is a submodule in
-umbrella and clang is a submodule in llvm). The file
-``submodule-map.txt`` is a list of pairs, one per line. The first
+umbrella and clang is a submodule in llvm). The file
+`submodule-map.txt` is a list of pairs, one per line. The first
pair item describes the path to a submodule in the umbrella
-repository. The second pair item describes the path where trees for
+repository. The second pair item describes the path where trees for
that submodule should be written in the zipped history.
Let's say your umbrella repository is actually the llvm repository and
it has submodules in the "nested sources" layout (clang in
-tools/clang, etc.). Let's also say ``projects/myproj`` is a submodule
-pointing to some downstream repository. The submodule map file should
+tools/clang, etc.). Let's also say `projects/myproj` is a submodule
+pointing to some downstream repository. The submodule map file should
look like this (we still want myproj mapped the same way as
-previously)::
-
- tools/clang clang
- tools/clang/tools/extra clang-tools-extra
- projects/compiler-rt compiler-rt
- projects/debuginfo-tests debuginfo-tests
- projects/libclc libclc
- projects/libcxx libcxx
- projects/libcxxabi libcxxabi
- projects/libunwind libunwind
- tools/lld lld
- tools/lldb lldb
- projects/openmp openmp
- tools/polly polly
- projects/myproj local/myproj
+previously):
+
+```
+tools/clang clang
+tools/clang/tools/extra clang-tools-extra
+projects/compiler-rt compiler-rt
+projects/debuginfo-tests debuginfo-tests
+projects/libclc libclc
+projects/libcxx libcxx
+projects/libcxxabi libcxxabi
+projects/libunwind libunwind
+tools/lld lld
+tools/lldb lldb
+projects/openmp openmp
+tools/polly polly
+projects/myproj local/myproj
+```
If a submodule path does not appear in the map, the tools assumes it
-should be placed in the same place in the monorepo. That means if you
+should be placed in the same place in the monorepo. That means if you
use the "nested sources" layout in your umrella, you *must* provide
map entries for all of the projects in your umbrella (except llvm).
Otherwise trees from submodule updates will appear underneath llvm in
the zippped history.
Because llvm is itself the umbrella, we use --subdir to write its
-content into ``llvm`` in the zippped history::
-
- # Import any non-LLVM repositories the umbrella references.
- git -C my-monorepo remote add localrepo \
- https://my.local.mirror.org/localrepo.git
- git fetch localrepo
-
- subprojects=( clang clang-tools-extra compiler-rt debuginfo-tests libclc
- libcxx libcxxabi libunwind lld lldb llgo llvm openmp
- parallel-libs polly pstl )
-
- # Import histories for upstream split projects (this was probably
- # already done for the ``migrate-downstream-fork.py`` run).
- for project in ${subprojects[@]}; do
- git remote add upstream/split/${project} \
- https://github.com/llvm-mirror/${subproject}.git
- git fetch umbrella/split/${project}
- done
-
- # Import histories for downstream split projects (this was probably
- # already done for the ``migrate-downstream-fork.py`` run).
- for project in ${subprojects[@]}; do
- git remote add local/split/${project} \
- https://my.local.mirror.org/${subproject}.git
- git fetch local/split/${project}
- done
-
- # Import umbrella history. We want this under a different refspec
- # so zip-downstream-fork.py knows what it is.
- git -C my-monorepo remote add umbrella \
- https://my.local.mirror.org/llvm.git
- git fetch umbrella
-
- # Create the submodule map.
- echo "tools/clang clang" > my-monorepo/submodule-map.txt
- echo "tools/clang/tools/extra clang-tools-extra" >> my-monorepo/submodule-map.txt
- echo "projects/compiler-rt compiler-rt" >> my-monorepo/submodule-map.txt
- echo "projects/debuginfo-tests debuginfo-tests" >> my-monorepo/submodule-map.txt
- echo "projects/libclc libclc" >> my-monorepo/submodule-map.txt
- echo "projects/libcxx libcxx" >> my-monorepo/submodule-map.txt
- echo "projects/libcxxabi libcxxabi" >> my-monorepo/submodule-map.txt
- echo "projects/libunwind libunwind" >> my-monorepo/submodule-map.txt
- echo "tools/lld lld" >> my-monorepo/submodule-map.txt
- echo "tools/lldb lldb" >> my-monorepo/submodule-map.txt
- echo "projects/openmp openmp" >> my-monorepo/submodule-map.txt
- echo "tools/polly polly" >> my-monorepo/submodule-map.txt
- echo "projects/myproj local/myproj" >> my-monorepo/submodule-map.txt
-
- # Rewrite history
- (
- cd my-monorepo
- zip-downstream-fork.py \
- refs/remotes/umbrella \
- --new-repo-prefix=refs/remotes/upstream/monorepo \
- --old-repo-prefix=refs/remotes/upstream/split \
- --revmap-in=monorepo-map.txt \
- --revmap-out=zip-map.txt \
- --subdir=llvm \
- --submodule-map=submodule-map.txt \
- --update-tags
- )
-
- # Create the zip branch (assuming umbrella main is wanted).
- git -C my-monorepo branch --no-track local/zip/main refs/remotes/umbrella/main
-
-
-Comments at the top of ``zip-downstream-fork.py`` describe in more
+content into `llvm` in the zippped history:
+
+```
+# Import any non-LLVM repositories the umbrella references.
+git -C my-monorepo remote add localrepo \
+ https://my.local.mirror.org/localrepo.git
+git fetch localrepo
+
+subprojects=( clang clang-tools-extra compiler-rt debuginfo-tests libclc
+ libcxx libcxxabi libunwind lld lldb llgo llvm openmp
+ parallel-libs polly pstl )
+
+# Import histories for upstream split projects (this was probably
+# already done for the ``migrate-downstream-fork.py`` run).
+for project in ${subprojects[@]}; do
+ git remote add upstream/split/${project} \
+ https://github.com/llvm-mirror/${subproject}.git
+ git fetch umbrella/split/${project}
+done
+
+# Import histories for downstream split projects (this was probably
+# already done for the ``migrate-downstream-fork.py`` run).
+for project in ${subprojects[@]}; do
+ git remote add local/split/${project} \
+ https://my.local.mirror.org/${subproject}.git
+ git fetch local/split/${project}
+done
+
+# Import umbrella history. We want this under a different refspec
+# so zip-downstream-fork.py knows what it is.
+git -C my-monorepo remote add umbrella \
+ https://my.local.mirror.org/llvm.git
+git fetch umbrella
+
+# Create the submodule map.
+echo "tools/clang clang" > my-monorepo/submodule-map.txt
+echo "tools/clang/tools/extra clang-tools-extra" >> my-monorepo/submodule-map.txt
+echo "projects/compiler-rt compiler-rt" >> my-monorepo/submodule-map.txt
+echo "projects/debuginfo-tests debuginfo-tests" >> my-monorepo/submodule-map.txt
+echo "projects/libclc libclc" >> my-monorepo/submodule-map.txt
+echo "projects/libcxx libcxx" >> my-monorepo/submodule-map.txt
+echo "projects/libcxxabi libcxxabi" >> my-monorepo/submodule-map.txt
+echo "projects/libunwind libunwind" >> my-monorepo/submodule-map.txt
+echo "tools/lld lld" >> my-monorepo/submodule-map.txt
+echo "tools/lldb lldb" >> my-monorepo/submodule-map.txt
+echo "projects/openmp openmp" >> my-monorepo/submodule-map.txt
+echo "tools/polly polly" >> my-monorepo/submodule-map.txt
+echo "projects/myproj local/myproj" >> my-monorepo/submodule-map.txt
+
+# Rewrite history
+(
+ cd my-monorepo
+ zip-downstream-fork.py \
+ refs/remotes/umbrella \
+ --new-repo-prefix=refs/remotes/upstream/monorepo \
+ --old-repo-prefix=refs/remotes/upstream/split \
+ --revmap-in=monorepo-map.txt \
+ --revmap-out=zip-map.txt \
+ --subdir=llvm \
+ --submodule-map=submodule-map.txt \
+ --update-tags
+ )
+
+ # Create the zip branch (assuming umbrella main is wanted).
+ git -C my-monorepo branch --no-track local/zip/main refs/remotes/umbrella/main
+```
+
+Comments at the top of `zip-downstream-fork.py` describe in more
detail how the tool works and various implications of its operation.
-Importing local repositories
-----------------------------
+### Importing local repositories
You may have additional repositories that integrate with the LLVM
-ecosystem, essentially extending it with new tools. If such
+ecosystem, essentially extending it with new tools. If such
repositories are tightly coupled with LLVM, it may make sense to
import them into your local mirror of the monorepo.
If such repositories participated in the umbrella repository used
during the zipping process above, they will automatically be added to
-the monorepo. For downstream repositories that don't participate in
-an umbrella setup, the ``import-downstream-repo.py`` tool at
-https://github.com/greened/llvm-git-migration/tree/import can help with
-getting them into the monorepo. A recipe follows::
-
- # Import downstream repo history into the monorepo.
- git -C my-monorepo remote add myrepo https://my.local.mirror.org/myrepo.git
- git fetch myrepo
-
- my_local_tags=( refs/tags/release
- refs/tags/hotfix )
-
- (
- cd my-monorepo
- import-downstream-repo.py \
- refs/remotes/myrepo \
- ${my_local_tags[@]} \
- --new-repo-prefix=refs/remotes/upstream/monorepo \
- --subdir=myrepo \
- --tag-prefix="myrepo-"
- )
-
- # Preserve release branches.
- for ref in $(git -C my-monorepo for-each-ref --format="%(refname)" \
- refs/remotes/myrepo/release); do
- branch=${ref#refs/remotes/myrepo/}
- git -C my-monorepo branch --no-track myrepo/${branch} ${ref}
- done
-
- # Preserve main.
- git -C my-monorepo branch --no-track myrepo/main refs/remotes/myrepo/main
-
- # Merge main.
- git -C my-monorepo checkout local/zip/main # Or local/octopus/main
- git -C my-monorepo merge myrepo/main
+the monorepo. For downstream repositories that don't participate in
+an umbrella setup, the `import-downstream-repo.py` tool at
+<https://github.com/greened/llvm-git-migration/tree/import> can help with
+getting them into the monorepo. A recipe follows:
+
+```
+# Import downstream repo history into the monorepo.
+git -C my-monorepo remote add myrepo https://my.local.mirror.org/myrepo.git
+git fetch myrepo
+
+my_local_tags=( refs/tags/release
+ refs/tags/hotfix )
+
+(
+ cd my-monorepo
+ import-downstream-repo.py \
+ refs/remotes/myrepo \
+ ${my_local_tags[@]} \
+ --new-repo-prefix=refs/remotes/upstream/monorepo \
+ --subdir=myrepo \
+ --tag-prefix="myrepo-"
+ )
+
+ # Preserve release branches.
+ for ref in $(git -C my-monorepo for-each-ref --format="%(refname)" \
+ refs/remotes/myrepo/release); do
+ branch=${ref#refs/remotes/myrepo/}
+ git -C my-monorepo branch --no-track myrepo/${branch} ${ref}
+ done
+
+ # Preserve main.
+ git -C my-monorepo branch --no-track myrepo/main refs/remotes/myrepo/main
+
+ # Merge main.
+ git -C my-monorepo checkout local/zip/main # Or local/octopus/main
+ git -C my-monorepo merge myrepo/main
+```
You may want to merge other corresponding branches, for example
-``myrepo`` release branches if they were in lockstep with LLVM project
+`myrepo` release branches if they were in lockstep with LLVM project
releases.
-``--tag-prefix`` tells ``import-downstream-repo.py`` to rename
-annotated tags with the given prefix. Due to limitations with
-``fast_filter_branch.py``, unannotated tags cannot be renamed
-(``fast_filter_branch.py`` considers them branches, not tags). Since
+`--tag-prefix` tells `import-downstream-repo.py` to rename
+annotated tags with the given prefix. Due to limitations with
+`fast_filter_branch.py`, unannotated tags cannot be renamed
+(`fast_filter_branch.py` considers them branches, not tags). Since
the upstream monorepo had its tags rewritten with an "llvmorg-"
-prefix, name conflicts should not be an issue. ``--tag-prefix`` can
+prefix, name conflicts should not be an issue. `--tag-prefix` can
be used to more clearly indicate which tags correspond to various
imported repositories.
-Given this repository history::
-
- R1 - R2 - R3 <- main
- ^
- |
- release/1
-
-The above recipe results in a history like this::
-
- U1 - U2 - U3 <- upstream/main
- \ \ \
- \ -----\--------------- local/zip--.
- \ \ \ |
- - Lllvm1 - Llld1 - UM3 - Lclang1 - Lclang2 - Lllvm2 - Llld2 - Lmyproj1 - M1 <-'
- /
- R1 - R2 - R3 <-.
- ^ |
- | |
- myrepo-release/1 |
- |
- myrepo/main--'
-
-Commits ``R1``, ``R2`` and ``R3`` have trees that *only* contain blobs
-from ``myrepo``. If you require commits from ``myrepo`` to be
+Given this repository history:
+
+```
+R1 - R2 - R3 <- main
+ ^
+ |
+ release/1
+```
+
+The above recipe results in a history like this:
+
+```
+U1 - U2 - U3 <- upstream/main
+ \ \ \
+ \ -----\--------------- local/zip--.
+ \ \ \ |
+ - Lllvm1 - Llld1 - UM3 - Lclang1 - Lclang2 - Lllvm2 - Llld2 - Lmyproj1 - M1 <-'
+ /
+ R1 - R2 - R3 <-.
+ ^ |
+ | |
+ myrepo-release/1 |
+ |
+ myrepo/main--'
+```
+
+Commits `R1`, `R2` and `R3` have trees that *only* contain blobs
+from `myrepo`. If you require commits from `myrepo` to be
interleaved with commits on local project branches (for example,
-interleaved with ``llvm1``, ``llvm2``, etc. above) and myrepo doesn't
+interleaved with `llvm1`, `llvm2`, etc. above) and myrepo doesn't
appear in an umbrella repository, a new tool will need to be
-developed. Creating such a tool would involve:
+developed. Creating such a tool would involve:
-1. Modifying ``fast_filter_branch.py`` to optionally take a
+1. Modifying `fast_filter_branch.py` to optionally take a
revlist directly rather than generating it itself
-
2. Creating a tool to generate an interleaved ordering of local
- commits based on some criteria (``zip-downstream-fork.py`` uses the
+ commits based on some criteria (`zip-downstream-fork.py` uses the
umbrella history as its criterion)
-
3. Generating such an ordering and feeding it to
- ``fast_filter_branch.py`` as a revlist
+ `fast_filter_branch.py` as a revlist
Some care will also likely need to be taken to handle merge commits,
to ensure the parents of such commits migrate correctly.
-Scrubbing the Local Monorepo
-----------------------------
+### Scrubbing the Local Monorepo
Once all of the migrating, zipping and importing is done, it's time to
-clean up. The python tools use ``git-fast-import`` which leaves a lot
+clean up. The python tools use `git-fast-import` which leaves a lot
of cruft around and we want to shrink our new monorepo mirror as much
-as possible. Here is one way to do it::
-
- git -C my-monorepo checkout main
-
- # Delete branches we no longer need. Do this for any other branches
- # you merged above.
- git -C my-monorepo branch -D local/zip/main || true
- git -C my-monorepo branch -D local/octopus/main || true
-
- # Remove remotes.
- git -C my-monorepo remote remove upstream/monorepo
-
- for p in ${my_projects[@]}; do
- git -C my-monorepo remote remove upstream/split/${p}
- git -C my-monorepo remote remove local/split/${p}
- done
-
- git -C my-monorepo remote remove localrepo
- git -C my-monorepo remote remove umbrella
- git -C my-monorepo remote remove myrepo
-
- # Add anything else here you don't need. refs/tags/release is
- # listed below assuming tags have been rewritten with a local prefix.
- # If not, remove it from this list.
- refs_to_clean=(
- refs/original
- refs/remotes
- refs/tags/backups
- refs/tags/release
- )
-
- git -C my-monorepo for-each-ref --format="%(refname)" ${refs_to_clean[@]} |
- xargs -n1 --no-run-if-empty git -C my-monorepo update-ref -d
-
- git -C my-monorepo reflog expire --all --expire=now
-
- # fast_filter_branch.py might have gc running in the background.
- while ! git -C my-monorepo \
- -c gc.reflogExpire=0 \
- -c gc.reflogExpireUnreachable=0 \
- -c gc.rerereresolved=0 \
- -c gc.rerereunresolved=0 \
- -c gc.pruneExpire=now \
- gc --prune=now; do
- continue
- done
-
- # Takes a LOOOONG time!
- git -C my-monorepo repack -A -d -f --depth=250 --window=250
-
- git -C my-monorepo prune-packed
- git -C my-monorepo prune
-
-You should now have a trim monorepo. Upload it to your git server and
+as possible. Here is one way to do it:
+
+```
+git -C my-monorepo checkout main
+
+# Delete branches we no longer need. Do this for any other branches
+# you merged above.
+git -C my-monorepo branch -D local/zip/main || true
+git -C my-monorepo branch -D local/octopus/main || true
+
+# Remove remotes.
+git -C my-monorepo remote remove upstream/monorepo
+
+for p in ${my_projects[@]}; do
+ git -C my-monorepo remote remove upstream/split/${p}
+ git -C my-monorepo remote remove local/split/${p}
+done
+
+git -C my-monorepo remote remove localrepo
+git -C my-monorepo remote remove umbrella
+git -C my-monorepo remote remove myrepo
+
+# Add anything else here you don't need. refs/tags/release is
+# listed below assuming tags have been rewritten with a local prefix.
+# If not, remove it from this list.
+refs_to_clean=(
+ refs/original
+ refs/remotes
+ refs/tags/backups
+ refs/tags/release
+)
+
+git -C my-monorepo for-each-ref --format="%(refname)" ${refs_to_clean[@]} |
+ xargs -n1 --no-run-if-empty git -C my-monorepo update-ref -d
+
+git -C my-monorepo reflog expire --all --expire=now
+
+# fast_filter_branch.py might have gc running in the background.
+while ! git -C my-monorepo \
+ -c gc.reflogExpire=0 \
+ -c gc.reflogExpireUnreachable=0 \
+ -c gc.rerereresolved=0 \
+ -c gc.rerereunresolved=0 \
+ -c gc.pruneExpire=now \
+ gc --prune=now; do
+ continue
+done
+
+# Takes a LOOOONG time!
+git -C my-monorepo repack -A -d -f --depth=250 --window=250
+
+git -C my-monorepo prune-packed
+git -C my-monorepo prune
+```
+
+You should now have a trim monorepo. Upload it to your git server and
happy hacking!
-References
-==========
+## References
+
+[^cite_lattnerrevnum]: Chris Lattner, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041739.html>
+
+[^cite_trickrevnum]: Andrew Trick, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041721.html>
+
+[^cite_jsonnrevnum]: Joerg Sonnenberger, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041688.html>
+
+[^cite_matthewsrevnum]: Chris Matthews, <http://lists.llvm.org/pipermail/cfe-dev/2016-July/049886.html>
+
+[^cite_statuschecks]: GitHub status-checks, <https://help.github.com/articles/about-required-status-checks/>
-.. [LattnerRevNum] Chris Lattner, http://lists.llvm.org/pipermail/llvm-dev/2011-July/041739.html
-.. [TrickRevNum] Andrew Trick, http://lists.llvm.org/pipermail/llvm-dev/2011-July/041721.html
-.. [JSonnRevNum] Joerg Sonnenberger, http://lists.llvm.org/pipermail/llvm-dev/2011-July/041688.html
-.. [MatthewsRevNum] Chris Matthews, http://lists.llvm.org/pipermail/cfe-dev/2016-July/049886.html
-.. [statuschecks] GitHub status-checks, https://help.github.com/articles/about-required-status-checks/
diff --git a/llvm/docs/Proposals/TestSuite.md b/llvm/docs/Proposals/TestSuite.md
index 3cccefb1ff129..e606312049d54 100644
--- a/llvm/docs/Proposals/TestSuite.md
+++ b/llvm/docs/Proposals/TestSuite.md
@@ -1,10 +1,6 @@
-=====================
-Test-Suite Extensions
-=====================
+# Test-Suite Extensions
-
-Abstract
-========
+## Abstract
These are ideas for additional programs, benchmarks, applications and
algorithms that could be added to the LLVM Test-Suite.
@@ -15,21 +11,18 @@ Most probably, the reason why the programs below have not been added to
the test-suite yet is that nobody has found time to do it. But there
might be other issues as well, such as
- * Licensing (Support can still be added as external module,
- like for the SPEC benchmarks)
-
- * Language (in particular, there is no official LLVM frontend
- for FORTRAN yet)
+> - Licensing (Support can still be added as external module,
+> : like for the SPEC benchmarks)
+> - Language (in particular, there is no official LLVM frontend
+> : for FORTRAN yet)
+> - Parallelism (currently, all programs in test-suite use
+> : one thread only)
- * Parallelism (currently, all programs in test-suite use
- one thread only)
+## Benchmarks
-Benchmarks
-==========
+### SPEC CPU 2017
-SPEC CPU 2017
--------------
-https://www.spec.org/cpu2017/
+<https://www.spec.org/cpu2017/>
The following have not been included yet because they contain Fortran
code.
@@ -38,281 +31,272 @@ In case of cactuBSSN only a small portion is Fortran. The hosts's
Fortran compiler could be used for these parts.
Note that CMake's Ninja generator has difficulties with Fortran. See the
-`CMake documentation <https://cmake.org/cmake/help/v3.13/generator/Ninja.html#fortran-support>`_
+[CMake documentation](https://cmake.org/cmake/help/v3.13/generator/Ninja.html#fortran-support)
for details.
- * 503.bwaves_r/603.bwaves_s
- * 507.cactuBSSN_r
- * 521.wrf_r/621.wrf_s
- * 527.cam4_r/627.cam4_s
- * 628.pop2_s
- * 548.exchange2_r/648.exchange2_s
- * 549.fotonik3d_r/649.fotonik3d_s
- * 554.roms_r/654.roms_s
-
-SPEC OMP2012
-------------
-https://www.spec.org/omp2012/
-
- * 350.md
- * 351.bwaves
- * 352.nab
- * 357.bt331
- * 358.botsalgn
- * 359.botsspar
- * 360.ilbdc
- * 362.fma3d
- * 363.swim
- * 367.imagick
- * 370.mgrid331
- * 371.applu331
- * 372.smithwa
- * 376.kdtree
-
-OpenCV
-------
-https://opencv.org/
-
-OpenMP 4.x SIMD Benchmarks
---------------------------
-https://github.com/flwende/simd_benchmarks
-
-PWM-benchmarking
-----------------
-https://github.com/tbepler/PWM-benchmarking
-
-SLAMBench
----------
-https://github.com/pamela-project/slambench
-
-FireHose
---------
-http://firehose.sandia.gov/
-
-A Benchmark for the C/C++ Standard Library
-------------------------------------------
-https://github.com/hiraditya/std-benchmark
-
-OpenBenchmarking.org CPU / Processor Suite
-------------------------------------------
-https://openbenchmarking.org/suite/pts/cpu
+> - 503.bwaves_r/603.bwaves_s
+> - 507.cactuBSSN_r
+> - 521.wrf_r/621.wrf_s
+> - 527.cam4_r/627.cam4_s
+> - 628.pop2_s
+> - 548.exchange2_r/648.exchange2_s
+> - 549.fotonik3d_r/649.fotonik3d_s
+> - 554.roms_r/654.roms_s
+
+### SPEC OMP2012
+
+<https://www.spec.org/omp2012/>
+
+> - 350.md
+> - 351.bwaves
+> - 352.nab
+> - 357.bt331
+> - 358.botsalgn
+> - 359.botsspar
+> - 360.ilbdc
+> - 362.fma3d
+> - 363.swim
+> - 367.imagick
+> - 370.mgrid331
+> - 371.applu331
+> - 372.smithwa
+> - 376.kdtree
+
+### OpenCV
+
+<https://opencv.org/>
+
+### OpenMP 4.x SIMD Benchmarks
+
+<https://github.com/flwende/simd_benchmarks>
+
+### PWM-benchmarking
+
+<https://github.com/tbepler/PWM-benchmarking>
+
+### SLAMBench
+
+<https://github.com/pamela-project/slambench>
+
+### FireHose
+
+<http://firehose.sandia.gov/>
+
+### A Benchmark for the C/C++ Standard Library
+
+<https://github.com/hiraditya/std-benchmark>
+
+### OpenBenchmarking.org CPU / Processor Suite
+
+<https://openbenchmarking.org/suite/pts/cpu>
This is a subset of the
-`Phoronix Test Suite <https://github.com/phoronix-test-suite/phoronix-test-suite/>`_
+[Phoronix Test Suite](https://github.com/phoronix-test-suite/phoronix-test-suite/)
and is itself a collection of benchmark suites
-Parboil Benchmarks
-------------------
-http://impact.crhc.illinois.edu/parboil/parboil.aspx
+### Parboil Benchmarks
-MachSuite
----------
-https://breagen.github.io/MachSuite/
+<http://impact.crhc.illinois.edu/parboil/parboil.aspx>
-Rodinia
--------
-http://lava.cs.virginia.edu/Rodinia/download_links.htm
+### MachSuite
+
+<https://breagen.github.io/MachSuite/>
+
+### Rodinia
+
+<http://lava.cs.virginia.edu/Rodinia/download_links.htm>
Rodinia has already been partially included in
MultiSource/Benchmarks/Rodinia. Benchmarks still missing are:
- * streamcluster
- * particlefilter
- * nw
- * nn
- * myocyte
- * mummergpu
- * lud
- * leukocyte
- * lavaMD
- * kmeans
- * hotspot3D
- * heartwall
- * cfd
- * bfs
- * b+tree
-
-vecmathlib tests harness
-------------------------
-https://bitbucket.org/eschnett/vecmathlib/wiki/Home
-
-PARSEC
-------
-http://parsec.cs.princeton.edu/
-
-Graph500 reference implementations
-----------------------------------
-https://github.com/graph500/graph500/tree/v2-spec
-
-NAS Parallel Benchmarks
------------------------
-https://www.nas.nasa.gov/publications/npb.html
+> - streamcluster
+> - particlefilter
+> - nw
+> - nn
+> - myocyte
+> - mummergpu
+> - lud
+> - leukocyte
+> - lavaMD
+> - kmeans
+> - hotspot3D
+> - heartwall
+> - cfd
+> - bfs
+> - b+tree
+
+### vecmathlib tests harness
+
+<https://bitbucket.org/eschnett/vecmathlib/wiki/Home>
+
+### PARSEC
+
+<http://parsec.cs.princeton.edu/>
+
+### Graph500 reference implementations
+
+<https://github.com/graph500/graph500/tree/v2-spec>
+
+### NAS Parallel Benchmarks
+
+<https://www.nas.nasa.gov/publications/npb.html>
The official benchmark is written in Fortran, but an unofficial
C-translation is available as well:
-https://github.com/benchmark-subsetting/NPB3.0-omp-C
+<https://github.com/benchmark-subsetting/NPB3.0-omp-C>
-DARPA HPCS SSCA#2 C/OpenMP reference implementation
----------------------------------------------------
-http://www.highproductivity.org/SSCABmks.htm
+### DARPA HPCS SSCA#2 C/OpenMP reference implementation
+
+<http://www.highproductivity.org/SSCABmks.htm>
This web site does not exist any more, but there seems to be a copy of
some of the benchmarks
-https://github.com/gtcasl/hpc-benchmarks/tree/master/SSCA2v2.2
+<https://github.com/gtcasl/hpc-benchmarks/tree/master/SSCA2v2.2>
+
+### Kokkos
+
+<https://github.com/kokkos/kokkos-kernels/tree/master/perf_test>
+<https://github.com/kokkos/kokkos/tree/master/benchmarks>
+
+### PolyMage
-Kokkos
-------
-https://github.com/kokkos/kokkos-kernels/tree/master/perf_test
-https://github.com/kokkos/kokkos/tree/master/benchmarks
+<https://github.com/bondhugula/polymage-benchmarks>
-PolyMage
---------
-https://github.com/bondhugula/polymage-benchmarks
+### PolyBench
-PolyBench
----------
-https://sourceforge.net/projects/polybench/
+<https://sourceforge.net/projects/polybench/>
A modified version of Polybench 3.2 is already presented in
SingleSource/Benchmarks/Polybench. A newer version 4.2.1 is available.
-High Performance Geometric Multigrid
-------------------------------------
-https://crd.lbl.gov/departments/computer-science/PAR/research/hpgmg/
+### High Performance Geometric Multigrid
-RAJA Performance Suite
-----------------------
-https://github.com/LLNL/RAJAPerf
+<https://crd.lbl.gov/departments/computer-science/PAR/research/hpgmg/>
-CORAL-2 Benchmarks
-------------------
-https://asc.llnl.gov/coral-2-benchmarks/
+### RAJA Performance Suite
+
+<https://github.com/LLNL/RAJAPerf>
+
+### CORAL-2 Benchmarks
+
+<https://asc.llnl.gov/coral-2-benchmarks/>
Many of its programs have already been integrated in
MultiSource/Benchmarks/DOE-ProxyApps-C and
MultiSource/Benchmarks/DOE-ProxyApps-C++.
- * Nekbone
- * QMCPack
- * LAMMPS
- * Kripke
- * Quicksilver
- * PENNANT
- * Big Data Analytic Suite
- * Deep Learning Suite
- * Stream
- * Stride
- * ML/DL micro-benchmark
- * Pynamic
- * ACME
- * VPIC
- * Laghos
- * Parallel Integer Sort
- * Havoq
-
-NWChem
-------
-http://www.nwchem-sw.org/index.php/Benchmarks
-
-TVM
-----
-https://github.com/dmlc/tvm/tree/main/apps/benchmark
-
-HydroBench
-----------
-https://github.com/HydroBench/Hydro
-
-ParRes
-------
-https://github.com/ParRes/Kernels/tree/default/Cxx11
-
-Applications/Libraries
-======================
-
-GnuPG
------
-https://gnupg.org/
-
-Blitz++
--------
-https://sourceforge.net/projects/blitz/
-
-FFmpeg
-------
-https://ffmpeg.org/
-
-FreePOOMA
----------
-http://www.nongnu.org/freepooma/
-
-FTensors
---------
-http://www.wlandry.net/Projects/FTensor
-
-rawspeed
---------
-https://github.com/darktable-org/rawspeed
+> - Nekbone
+> - QMCPack
+> - LAMMPS
+> - Kripke
+> - Quicksilver
+> - PENNANT
+> - Big Data Analytic Suite
+> - Deep Learning Suite
+> - Stream
+> - Stride
+> - ML/DL micro-benchmark
+> - Pynamic
+> - ACME
+> - VPIC
+> - Laghos
+> - Parallel Integer Sort
+> - Havoq
+
+### NWChem
+
+<http://www.nwchem-sw.org/index.php/Benchmarks>
+
+### TVM
+
+<https://github.com/dmlc/tvm/tree/main/apps/benchmark>
+
+### HydroBench
+
+<https://github.com/HydroBench/Hydro>
+
+### ParRes
+
+<https://github.com/ParRes/Kernels/tree/default/Cxx11>
+
+## Applications/Libraries
+
+### GnuPG
+
+<https://gnupg.org/>
+
+### Blitz++
+
+<https://sourceforge.net/projects/blitz/>
+
+### FFmpeg
+
+<https://ffmpeg.org/>
+
+### FreePOOMA
+
+<http://www.nongnu.org/freepooma/>
+
+### FTensors
+
+<http://www.wlandry.net/Projects/FTensor>
+
+### rawspeed
+
+<https://github.com/darktable-org/rawspeed>
Its test dataset is 756 MB in size, which is too large to be included
into the test-suite repository.
-C++ Performance Benchmarks
---------------------------
-https://gitlab.com/chriscox/CppPerformanceBenchmarks
+### C++ Performance Benchmarks
+
+<https://gitlab.com/chriscox/CppPerformanceBenchmarks>
+
+## Generic Algorithms
-Generic Algorithms
-==================
+### Image processing
-Image processing
-----------------
+#### Resampling
-Resampling
-``````````
+> - Bilinear
+> - Bicubic
+> - Lanczos
- * Bilinear
- * Bicubic
- * Lanczos
+#### Dither
-Dither
-``````
+> - Threshold
+> - Random
+> - Halftone
+> - Bayer
+> - Floyd-Steinberg
+> - Jarvis
+> - Stucki
+> - Burkes
+> - Sierra
+> - Atkinson
+> - Gradient-based
- * Threshold
- * Random
- * Halftone
- * Bayer
- * Floyd-Steinberg
- * Jarvis
- * Stucki
- * Burkes
- * Sierra
- * Atkinson
- * Gradient-based
+#### Feature detection
-Feature detection
-`````````````````
+> - Harris
+> - Histogram of Oriented Gradients
- * Harris
- * Histogram of Oriented Gradients
+#### Color conversion
-Color conversion
-````````````````
+> - RGB to grayscale
+> - HSL to RGB
- * RGB to grayscale
- * HSL to RGB
+### Graph
-Graph
------
+#### Search Algorithms
-Search Algorithms
-`````````````````
+> - Breadth-First-Search
+> - Depth-First-Search
+> - Dijkstra's algorithm
+> - A-Star
- * Breadth-First-Search
- * Depth-First-Search
- * Dijkstra's algorithm
- * A-Star
+#### Spanning Tree
-Spanning Tree
-`````````````
+> - Kruskal's algorithm
+> - Prim's algorithm
- * Kruskal's algorithm
- * Prim's algorithm
diff --git a/llvm/docs/Proposals/VectorPredication.md b/llvm/docs/Proposals/VectorPredication.md
index 8fa6f92f425b8..db0456c0c1d3a 100644
--- a/llvm/docs/Proposals/VectorPredication.md
+++ b/llvm/docs/Proposals/VectorPredication.md
@@ -1,49 +1,41 @@
-==========================
-Vector Predication Roadmap
-==========================
+# Vector Predication Roadmap
-
-Motivation
-==========
+## Motivation
This proposal defines a roadmap towards native vector predication in LLVM,
specifically for vector instructions with a mask and/or an explicit vector
-length. LLVM currently has no target-independent means to model predicated
+length. LLVM currently has no target-independent means to model predicated
vector instructions for modern SIMD ISAs such as AVX512, ARM SVE, the RISC-V V
-extension and NEC SX-Aurora. Only some predicated vector operations, such as
-masked loads and stores, are available through intrinsics [MaskedIR]_.
+extension and NEC SX-Aurora. Only some predicated vector operations, such as
+masked loads and stores, are available through intrinsics [^cite_maskedir].
The Vector Predication (VP) extensions is a concrete RFC and prototype
-implementation to achieve native vector predication in LLVM. The VP prototype
+implementation to achieve native vector predication in LLVM. The VP prototype
and all related discussions can be found in the VP patch on Phabricator
-[VPRFC]_.
+[^cite_vprfc].
-Roadmap
-=======
+## Roadmap
-1. IR-level VP intrinsics
--------------------------
+### 1. IR-level VP intrinsics
- There is a consensus on the semantics/instruction set of VP.
- VP intrinsics and attributes are available on IR level.
-- TTI has capability flags for VP (``supportsVP()``?,
- ``haveActiveVectorLength()``?).
+- TTI has capability flags for VP (`supportsVP()`?,
+ `haveActiveVectorLength()`?).
Result: VP usable for IR-level vectorizers (LV, VPlan, RegionVectorizer),
potential integration in Clang with builtins.
-2. CodeGen support
-------------------
+### 2. CodeGen support
- VP intrinsics translate to first-class SDNodes
- (eg ``llvm.vp.fdiv.* -> vp_fdiv``).
+ (eg `llvm.vp.fdiv.* -> vp_fdiv`).
- VP legalization (legalize explicit vector length to mask (AVX512), legalize VP
SDNodes to pre-existing ones (SSE, NEON)).
Result: Backend development based on VP SDNodes.
-3. Lift InstSimplify/InstCombine/DAGCombiner to VP
---------------------------------------------------
+### 3. Lift InstSimplify/InstCombine/DAGCombiner to VP
- Introduce PredicatedInstruction, PredicatedBinaryOperator, .. helper classes
that match standard vector IR and VP intrinsics.
@@ -55,31 +47,29 @@ Result: Backend development based on VP SDNodes.
Result: Optimization of VP intrinsics on par with standard vector instructions.
-4. Deprecate llvm.masked.* / llvm.experimental.reduce.*
--------------------------------------------------------
+### 4. Deprecate llvm.masked.\* / llvm.experimental.reduce.\*
-- Modernize llvm.masked.* / llvm.experimental.reduce* by translating to VP.
+- Modernize llvm.masked.\* / llvm.experimental.reduce\* by translating to VP.
- DCE transitional APIs.
Result: VP has superseded earlier vector intrinsics.
-5. Predicated IR Instructions
------------------------------
+### 5. Predicated IR Instructions
- Vector instructions have an optional mask and vector length parameter. These
lower to VP SDNodes (from Stage 2).
- Phase out VP intrinsics, only keeping those that are not equivalent to
- vectorized scalar instructions (reduce, shuffles, ..)
+ vectorized scalar instructions (reduce, shuffles, ..)
- InstCombine/InstSimplify expect predication in regular Instructions (Stage (3)
has laid the groundwork).
Result: Native vector predication in IR.
-References
-==========
+## References
+
+[^cite_maskedir]: `llvm.masked.*` intrinsics,
+ <https://llvm.org/docs/LangRef.html#masked-vector-load-and-store-intrinsics>
-.. [MaskedIR] `llvm.masked.*` intrinsics,
- https://llvm.org/docs/LangRef.html#masked-vector-load-and-store-intrinsics
+[^cite_vprfc]: RFC: Prototype & Roadmap for vector predication in LLVM,
+ <https://reviews.llvm.org/D57504>
-.. [VPRFC] RFC: Prototype & Roadmap for vector predication in LLVM,
- https://reviews.llvm.org/D57504
diff --git a/llvm/docs/QualGroup.md b/llvm/docs/QualGroup.md
index e2efa6d60490e..f3b2c17b27183 100644
--- a/llvm/docs/QualGroup.md
+++ b/llvm/docs/QualGroup.md
@@ -1,52 +1,46 @@
-========================
-LLVM Qualification Group
-========================
+# LLVM Qualification Group
-Introduction
-============
+## Introduction
-The LLVM Qualification Group is an open working group within the LLVM community.
-It was created to coordinate efforts around enabling the use of LLVM components
-in safety-critical applications governed by functional safety standards
-such as IEC 61508 (for general E/E/PE systems), IEC 62304 (medical devices),
+The LLVM Qualification Group is an open working group within the LLVM community.
+It was created to coordinate efforts around enabling the use of LLVM components
+in safety-critical applications governed by functional safety standards
+such as IEC 61508 (for general E/E/PE systems), IEC 62304 (medical devices),
ISO 26262 (automotive), DO-178C (aerospace), and EN 50716 (railways).
-Motivation
-==========
+## Motivation
LLVM is increasingly used in safety-critical domains (e.g., automotive, aerospace, medical),
-but currently lacks a shared structure to address the specific needs of functional safety,
-such as systematic assurance arguments, tool qualification artifacts, and their associated
+but currently lacks a shared structure to address the specific needs of functional safety,
+such as systematic assurance arguments, tool qualification artifacts, and their associated
documentation.
A more open, upstream, reusable, and collaborative approach would benefit the wider ecosystem.
This group serves as a public forum for those interested in improving LLVM’s suitability for
use in such environments.
-Goals
-=====
+## Goals
The Qualification Group aims to:
-* Facilitate open discussion around tool confidence and qualification practices
-* Identify areas for upstream improvements (e.g., traceability hooks, quality evidence)
-* Share safety-relevant documentation and argumentation templates
-* Coordinate efforts across users and vendors working toward similar goals
-* Act as a point of contact for safety-related collaboration
+- Facilitate open discussion around tool confidence and qualification practices
+- Identify areas for upstream improvements (e.g., traceability hooks, quality evidence)
+- Share safety-relevant documentation and argumentation templates
+- Coordinate efforts across users and vendors working toward similar goals
+- Act as a point of contact for safety-related collaboration
The group is non-enforcing and does not control any part of the codebase.
All technical decisions remain subject to the standard LLVM review and governance process.
-Group Composition
-=================
+## Group Composition
-Group Members
--------------
+### Group Members
The members of the LLVM Qualification Group represent a diverse cross-section of the LLVM community, including individual contributors, researchers, vendor representatives, and experts in the field of software qualification, including reliability, quality, safety, and/or security.
-They meet the criteria for inclusion described in the sub-sections below and are identified as `active contributors <#contribution-principles>`_.
+They meet the criteria for inclusion described in the sub-sections below and are identified as [active contributors](#contribution-principles).
Knowing their handles help us keep track of who’s who across platforms, coordinate activities, and recognize contributions.
+```{eval-rst}
.. list-table::
:widths: 20 20 20 20 20
:header-rows: 1
@@ -87,81 +81,77 @@ Knowing their handles help us keep track of who’s who across platforms, coordi
- quarkz99
- zakyHermawan
+```
Organizations are limited to three representatives within the group to maintain diversity.
-Participation
--------------
+### Participation
There are several ways to participate:
-* Join discussions on the `LLVM Discourse <https://discourse.llvm.org/>`_ forum, under the "Community" category.
-* Engage in conversations on the LLVM Community Discord in the `#fusa-qual-wg <https://discord.com/channels/636084430946959380/1389362444169773117>`_ channel. Note: You need to join the community's `Discord chat server <https://llvm.org/docs/GettingInvolved.html#discord>`_ first.
-* Join our monthly sync-up calls. Details on working sessions and meeting minutes are shared on the :doc:`GettingInvolved` page.
-* Contribute ideas, feedback, or patches via GitHub, Discourse, or directly in working documents.
+- Join discussions on the [LLVM Discourse](https://discourse.llvm.org/) forum, under the "Community" category.
+- Engage in conversations on the LLVM Community Discord in the [#fusa-qual-wg](https://discord.com/channels/636084430946959380/1389362444169773117) channel. Note: You need to join the community's [Discord chat server](https://llvm.org/docs/GettingInvolved.html#discord) first.
+- Join our monthly sync-up calls. Details on working sessions and meeting minutes are shared on the {doc}`GettingInvolved` page.
+- Contribute ideas, feedback, or patches via GitHub, Discourse, or directly in working documents.
-Contribution Principles
------------------------
+### Contribution Principles
We understand that most members contribute in a limited capacity due to their primary responsibilities. This initiative is volunteer-driven, and we operate with the following shared principles:
-* **Acknowledgement of limited bandwidth:** We recognize that no one is working full-time on this group, and participation will vary based on individual availability and priorities.
-* **Small and consistent contributions are valuable:** We believe that steady ongoing contributions, even if minimal, are crucial for long-term success, as long as there is coordination and respect for each other's time. Even small contributions (e.g., a few hours per month) can significantly advance the group's goals and have an impact.
-* **Realistic progress expectations:** Given the voluntary nature and no full-time involvement, we expect our progress to be slow. This group was initiated in July 2025. Concrete outcomes in 1-2 years would be considered excellent for this type of cross-company and voluntary collaboration.
-* **Respect for differing capacities:** We value every member’s engagement, whether large or small, often or sporadically, as it all contributes to the overall effort. Even contributions that may seem small, such as sharing an idea or pointing out a relevant resource, are meaningful and important.
+- **Acknowledgement of limited bandwidth:** We recognize that no one is working full-time on this group, and participation will vary based on individual availability and priorities.
+- **Small and consistent contributions are valuable:** We believe that steady ongoing contributions, even if minimal, are crucial for long-term success, as long as there is coordination and respect for each other's time. Even small contributions (e.g., a few hours per month) can significantly advance the group's goals and have an impact.
+- **Realistic progress expectations:** Given the voluntary nature and no full-time involvement, we expect our progress to be slow. This group was initiated in July 2025. Concrete outcomes in 1-2 years would be considered excellent for this type of cross-company and voluntary collaboration.
+- **Respect for differing capacities:** We value every member’s engagement, whether large or small, often or sporadically, as it all contributes to the overall effort. Even contributions that may seem small, such as sharing an idea or pointing out a relevant resource, are meaningful and important.
However, we need a balance between flexibility, structure, and enough organization to move forward together. Thus, to support coordination and clarity, the group distinguishes between **active contributors** and **observers / interested participants**.
**Active contributors** are members who provide regular and substantive contributions to the group’s work. This includes ongoing engagement in at least one of the following:
-* Participation in sync-ups or asynchronous discussions (via Discord or Discourse),
-* Contributions to qualification artifacts, methodologies, documentation, structured reviews, or feedback on proposals and drafts,
-* Analysis, research activities, or support for coordination, outreach, or other working tasks.
+- Participation in sync-ups or asynchronous discussions (via Discord or Discourse),
+- Contributions to qualification artifacts, methodologies, documentation, structured reviews, or feedback on proposals and drafts,
+- Analysis, research activities, or support for coordination, outreach, or other working tasks.
-Active contribution implies sustained engagement that meaningfully advances the group’s objectives. Participation may be synchronous or asynchronous, depending on availability. Participation status reflects current bandwidth and coordination needs and may be updated during the `biannual membership review <#membership-review>`_.
+Active contribution implies sustained engagement that meaningfully advances the group’s objectives. Participation may be synchronous or asynchronous, depending on availability. Participation status reflects current bandwidth and coordination needs and may be updated during the [biannual membership review](#membership-review).
-**Observers**, or **interested participants** are anyone who follows the group’s work and may participate when availability allows.
-This is an open status and does not require the `nomination process <#nomination-process>`_ used for active contributors.
-Observers remain welcome to attend meetings, provide feedback, and contribute at any time.
+**Observers**, or **interested participants** are anyone who follows the group’s work and may participate when availability allows.
+This is an open status and does not require the [nomination process](#nomination-process) used for active contributors.
+Observers remain welcome to attend meetings, provide feedback, and contribute at any time.
Moreover, observer status does not imply reduced importance or access within the group.
-Membership Criteria
--------------------
+### Membership Criteria
Membership in the LLVM Qualification Group is intended for individuals with relevant experience or active engagement in qualification-related efforts. Categories include:
**Individual Contributors**
- * Experience in software/tool qualification (e.g., reliability, quality, safety, security); OR
- * Active involvement in LLVM-related qualification efforts; OR
- * Significant LLVM contributions related to qualification in the past year (code, discussion, resolving related challenges).
+> - Experience in software/tool qualification (e.g., reliability, quality, safety, security); OR
+> - Active involvement in LLVM-related qualification efforts; OR
+> - Significant LLVM contributions related to qualification in the past year (code, discussion, resolving related challenges).
**Researchers**
- * Active research, publication, or development of methodologies, frameworks, or tools aimed at improving LLVM quality and reliability.
+> - Active research, publication, or development of methodologies, frameworks, or tools aimed at improving LLVM quality and reliability.
**Vendor Contacts**
- * Represent organizations building or using LLVM-based tools in safety-critical environments; OR
- * Require involvement due to organizational role in qualification or compliance.
+> - Represent organizations building or using LLVM-based tools in safety-critical environments; OR
+> - Require involvement due to organizational role in qualification or compliance.
-Nomination Process
-------------------
+### Nomination Process
Individuals may nominate themselves or be nominated by an existing member. Nominations should:
-* Explain the nominee’s background and relevance to qualification efforts.
-* Be submitted via this form: `Participant Introduction & Membership <https://forms.gle/cE1kHjqkKNtafUrD7>`_
-* Be communicated to an active LLVM Qualification Group member (e.g., on the Discord channel).
+- Explain the nominee’s background and relevance to qualification efforts.
+- Be submitted via this form: [Participant Introduction & Membership](https://forms.gle/cE1kHjqkKNtafUrD7)
+- Be communicated to an active LLVM Qualification Group member (e.g., on the Discord channel).
-This nomination process applies to becoming an **active contributor**. People who simply wish to
-follow the group’s work or participate occasionally may do so as observers / interested participants,
+This nomination process applies to becoming an **active contributor**. People who simply wish to
+follow the group’s work or participate occasionally may do so as observers / interested participants,
without a formal nomination process.
Nominations are discussed within the group. If consensus is reached, the nominee is accepted. Otherwise, a majority vote will decide.
-Membership Review
------------------
+### Membership Review
To ensure the group remains active and focused, member participation is reviewed every six months. Inactive members may be removed following this review.
@@ -169,52 +159,46 @@ During the biannual membership review, members who have not participated in disc
This transition is procedural and does not restrict participation. Members may resume **active contributor** status at any time when their engagement increases.
-Decision Making
----------------
+### Decision Making
The LLVM Qualification Working Group aims to make decisions transparently, collaboratively, and without unnecessary formality. The goal is to maintain efficiency while encouraging broad participation and mutual understanding.
This section describes the lightweight process used to handle proposals and decisions within the group. It may be revised as the group evolves and gains experience.
-Principles
-^^^^^^^^^^
+#### Principles
-* **Consensus first:** The preferred mode of decision-making is consensus through open discussion (primarily on Discord or during sync-up meetings).
-* **Inclusiveness and respect:** All viewpoints are encouraged, and members are expected to contribute constructively toward reaching a shared understanding.
-* **Transparency:** Discussions leading to a decision should be visible to the group and, whenever appropriate, summarized in public channels (e.g., Discourse meeting notes, Discord channel, documentation updates).
+- **Consensus first:** The preferred mode of decision-making is consensus through open discussion (primarily on Discord or during sync-up meetings).
+- **Inclusiveness and respect:** All viewpoints are encouraged, and members are expected to contribute constructively toward reaching a shared understanding.
+- **Transparency:** Discussions leading to a decision should be visible to the group and, whenever appropriate, summarized in public channels (e.g., Discourse meeting notes, Discord channel, documentation updates).
-Consensus and Time Limits
-^^^^^^^^^^^^^^^^^^^^^^^^^
+#### Consensus and Time Limits
Discussions remain open until a clear consensus emerges, meaning no sustained objections have been raised after reasonable discussion.
To prevent open-ended debates, if no new viewpoints are expressed after an agreed period (e.g., 2 weeks), the moderator (typically the person who started the discussion thread) may take one of the following actions:
-* **Summarize the apparent consensus** and close the discussion, or
-* **Postpone the topic** to the next sync-up meeting if the outcome remains unclear, or
-* **Call for a short vote** to confirm the group’s position.
+- **Summarize the apparent consensus** and close the discussion, or
+- **Postpone the topic** to the next sync-up meeting if the outcome remains unclear, or
+- **Call for a short vote** to confirm the group’s position.
-Voting Procedure
-^^^^^^^^^^^^^^^^
+#### Voting Procedure
When consensus cannot be reached or when a clear yes/no decision is needed:
-* The moderator may call for a **simple vote** using emoji reactions on Discord or a similar visible method.
-* A decision passes if it receives a **majority (>50%)** of votes among **participants who voted.** Non-votes are **not counted** in the total.
-* To ensure decisions reflect the collective position of the group, **at least three-quarters of the total core members** must participate in the vote for it to be considered valid.
-* If results are evenly split **(50/50)**, or if participation falls below this threshold, the topic may be postponed to the next sync-up meeting for further discussion.
+- The moderator may call for a **simple vote** using emoji reactions on Discord or a similar visible method.
+- A decision passes if it receives a **majority (>50%)** of votes among **participants who voted.** Non-votes are **not counted** in the total.
+- To ensure decisions reflect the collective position of the group, **at least three-quarters of the total core members** must participate in the vote for it to be considered valid.
+- If results are evenly split **(50/50)**, or if participation falls below this threshold, the topic may be postponed to the next sync-up meeting for further discussion.
-Documentation
-^^^^^^^^^^^^^
+#### Documentation
Final decisions should be briefly documented (e.g., in meeting minutes, the corresponding GitHub issue, or Discord discussion thread). Once stable, the resulting policy or outcome may be reflected in this documentation for reference.
-Working Group artifacts
-=======================
+## Working Group artifacts
The LLVM Qualification Working Group develops and maintains its public
artifacts and working materials in the
-`fusa-qual-wg directory of the llvm-wgs repository <https://github.com/llvm/llvm-wgs/tree/main/fusa-qual-wg>`_.
+[fusa-qual-wg directory of the llvm-wgs repository](https://github.com/llvm/llvm-wgs/tree/main/fusa-qual-wg).
**This directory is the central location for the group's technical outputs**,
including qualification guidance, documentation templates, analyses,
@@ -231,67 +215,61 @@ application.
Feedback and contributions are welcome through the standard GitHub review
process and the group's public discussion channels.
-Current Topics & Backlog
-========================
+## Current Topics & Backlog
Our working group is actively engaged in discussions about the project's
-direction and tackling technical challenges. You can find our current
-discussions, challenges, and the project backlog in the following
-document: `Backlog <https://docs.google.com/document/d/10YZZ72ba09Ck_OiJaP9C4-7DeUiveaIKTE3IkaSKjzA/edit?usp=sharing>`_
+direction and tackling technical challenges. You can find our current
+discussions, challenges, and the project backlog in the following
+document: [Backlog](https://docs.google.com/document/d/10YZZ72ba09Ck_OiJaP9C4-7DeUiveaIKTE3IkaSKjzA/edit?usp=sharing)
This document serves as our central hub for all ongoing topics and will
-be updated regularly to reflect our progress. We welcome your
+be updated regularly to reflect our progress. We welcome your
contributions and feedback.
-Meeting Materials
-=================
+## Meeting Materials
Meeting agendas, minutes, and supporting materials are published to ensure transparency and continuity.
Upcoming and past meeting agendas, and meeting minutes are published in a dedicated thread
-on the LLVM Discourse forum: `Meeting Agendas and Minutes <https://discourse.llvm.org/t/llvm-qualification-wg-sync-ups-meeting-minutes/87148>`_
+on the LLVM Discourse forum: [Meeting Agendas and Minutes](https://discourse.llvm.org/t/llvm-qualification-wg-sync-ups-meeting-minutes/87148)
Slides used to support discussions during sync-up meetings are stored in a
-`dedicated Google Drive folder <https://drive.google.com/drive/u/1/folders/1nu3JAanE0gqQDll0S9ofVy4FOFezc6Mm>`_.
+[dedicated Google Drive folder](https://drive.google.com/drive/u/1/folders/1nu3JAanE0gqQDll0S9ofVy4FOFezc6Mm).
Note that the naming convention for these slides is *YYYYMM*\_llvm_qual_wg.
While Discourse is our active communication channel for agendas and announcements,
the `llvm-wgs` repository is our durable, central location for both WG artifacts and meeting records.
-The `meeting directory in the llvm-wgs repository <https://github.com/llvm/llvm-wgs/tree/main/fusa-qual-wg/meetings>`_
+The [meeting directory in the llvm-wgs repository](https://github.com/llvm/llvm-wgs/tree/main/fusa-qual-wg/meetings)
provides the long-term archive of the working group's meeting records. It contains:
-* `archived meeting materials <https://github.com/llvm/llvm-wgs/tree/main/fusa-qual-wg/meetings/materials>`_, and
-* `archived meeting agendas and minutes <https://github.com/llvm/llvm-wgs/tree/main/fusa-qual-wg/meetings/minutes>`_.
+- [archived meeting materials](https://github.com/llvm/llvm-wgs/tree/main/fusa-qual-wg/meetings/materials), and
+- [archived meeting agendas and minutes](https://github.com/llvm/llvm-wgs/tree/main/fusa-qual-wg/meetings/minutes).
-AI Transcription Policy
-=======================
+## AI Transcription Policy
-Objective
----------
+### Objective
The LLVM Qualification Group may enable AI auto-transcription (currently using Gemini) during sync-up calls in order to:
-* Make complex discussions easier to follow.
-* Reduce the effort of manual note-taking.
-* Support inclusivity for participants who are not native English speakers.
+- Make complex discussions easier to follow.
+- Reduce the effort of manual note-taking.
+- Support inclusivity for participants who are not native English speakers.
-Usage
------
+### Usage
The purpose of auto-transcripts is to:
-* Ensure participants can remain engaged during the sync-up meeting (particularly helpful for non-native English speakers or when audio clarity is limited).
-* Serve as an aid for preparing the meeting minutes that are published on Discourse:
- `Meeting Agendas and Minutes <https://discourse.llvm.org/t/llvm-qualification-wg-sync-ups-meeting-minutes/87148>`_
+- Ensure participants can remain engaged during the sync-up meeting (particularly helpful for non-native English speakers or when audio clarity is limited).
+- Serve as an aid for preparing the meeting minutes that are published on Discourse:
+ [Meeting Agendas and Minutes](https://discourse.llvm.org/t/llvm-qualification-wg-sync-ups-meeting-minutes/87148)
Additional safeguards include:
-* Transcript files are private to the note-taker(s) and never circulated to attendees or the public.
-* Transcript files are permanently deleted once the minutes are posted.
-* The meeting chair or scribe remains responsible for reviewing the transcript, ensuring accuracy, and editing out sensitive details in the official minutes.
+- Transcript files are private to the note-taker(s) and never circulated to attendees or the public.
+- Transcript files are permanently deleted once the minutes are posted.
+- The meeting chair or scribe remains responsible for reviewing the transcript, ensuring accuracy, and editing out sensitive details in the official minutes.
-Vendor Retention
-----------------
+### Vendor Retention
Long-term storage or model-training settings are disabled on the account used for organizing the working group calls.
@@ -299,73 +277,69 @@ However, according to Google’s Gemini documentation, even with all history fea
This retention period cannot currently be shortened.
-Consent
--------
+### Consent
-* At the start of each sync-up, participants will be asked if they are comfortable with enabling auto-transcription.
-* If any participant objects, auto-transcription will be disabled for that meeting.
-* Participants may also request at any point that parts of the discussion not be transcribed.
+- At the start of each sync-up, participants will be asked if they are comfortable with enabling auto-transcription.
+- If any participant objects, auto-transcription will be disabled for that meeting.
+- Participants may also request at any point that parts of the discussion not be transcribed.
-Recordings
-----------
+### Recordings
-* Meetings are not recorded by default.
-* Exceptions are made only when explicit approval from attendees is obtained (e.g., for a special-hosted demo).
+- Meetings are not recorded by default.
+- Exceptions are made only when explicit approval from attendees is obtained (e.g., for a special-hosted demo).
-Transparency & Feedback
------------------------
+### Transparency & Feedback
We want to ensure this practice remains transparent and comfortable for everyone. If any group members have concerns (e.g., about names appearing in transcripts or minutes), they are encouraged to raise them on Discourse or Discord so they can be addressed.
-Code of Conduct
-===============
+## Code of Conduct
-We are committed to fostering a respectful, inclusive, and constructive environment
-where contributors from diverse backgrounds and organizations can collaborate
-on qualification-related efforts in the LLVM ecosystem.
+We are committed to fostering a respectful, inclusive, and constructive environment
+where contributors from diverse backgrounds and organizations can collaborate
+on qualification-related efforts in the LLVM ecosystem.
To support this goal, we adopt the following principles:
-Let's Build This Together
--------------------------
-This is a space for shared ownership and mutual learning. If you're here, you belong.
+### Let's Build This Together
+
+This is a space for shared ownership and mutual learning. If you're here, you belong.
Help us shape a group where trust, technical rigor, and collaboration go hand in hand.
-Respect and Inclusion
----------------------
-* Treat all participants with respect and dignity, regardless of background, experience level, employer, or role in the community.
-* Be welcoming and supportive. We value a diversity of opinions and expertise.
-* Assume good intent, and ask questions before drawing conclusions.
-
-Constructive Collaboration
---------------------------
-* Keep discussions focused, technical, and solution-oriented.
-* Provide thoughtful, actionable feedback. Avoid sarcasm, dismissive remarks, or personal criticism.
-* Recognize that contributors have different constraints and priorities. Seek alignment, not perfection.
-
-Transparency and Openness
--------------------------
-* Share relevant information openly to enable others to contribute effectively.
-* Document decisions and rationales so others can understand and build on them.
-* Clearly distinguish between personal opinions, organizational positions, and community consensus.
-
-Unacceptable Behavior
----------------------
+### Respect and Inclusion
+
+- Treat all participants with respect and dignity, regardless of background, experience level, employer, or role in the community.
+- Be welcoming and supportive. We value a diversity of opinions and expertise.
+- Assume good intent, and ask questions before drawing conclusions.
+
+### Constructive Collaboration
+
+- Keep discussions focused, technical, and solution-oriented.
+- Provide thoughtful, actionable feedback. Avoid sarcasm, dismissive remarks, or personal criticism.
+- Recognize that contributors have different constraints and priorities. Seek alignment, not perfection.
+
+### Transparency and Openness
+
+- Share relevant information openly to enable others to contribute effectively.
+- Document decisions and rationales so others can understand and build on them.
+- Clearly distinguish between personal opinions, organizational positions, and community consensus.
+
+### Unacceptable Behavior
+
We will not tolerate:
-* Harassment, discrimination, or exclusionary behavior.
-* Disruptive conduct in meetings or communication channels.
-* Using this group for marketing, lobbying, or promoting non-collaborative commercial agendas.
+- Harassment, discrimination, or exclusionary behavior.
+- Disruptive conduct in meetings or communication channels.
+- Using this group for marketing, lobbying, or promoting non-collaborative commercial agendas.
-Safety and Trust
-----------------
-* We aim to build qualification artifacts that others can trust. Similarly, we aim to be trustworthy collaborators.
-* If you see something concerning, speak up respectfully or contact the group organizer(s) privately.
-* We follow the LLVM Community :doc:`Code of Conduct <CodeOfConduct>`, which applies across all official LLVM communication spaces.
+### Safety and Trust
-Contact
-=======
+- We aim to build qualification artifacts that others can trust. Similarly, we aim to be trustworthy collaborators.
+- If you see something concerning, speak up respectfully or contact the group organizer(s) privately.
+- We follow the LLVM Community {doc}`Code of Conduct <CodeOfConduct>`, which applies across all official LLVM communication spaces.
+
+## Contact
For more information or to get involved:
-* Refer to our initial `RFC: Proposal to Establish a Safety Group in LLVM <https://discourse.llvm.org/t/rfc-proposal-to-establish-a-safety-group-in-llvm/86916>`_ on the LLVM Discourse forum.
-* Join the conversation on the LLVM Community Discord in the `#fusa-qual-wg <https://discord.com/channels/636084430946959380/1389362444169773117>`_ channel.
+- Refer to our initial [RFC: Proposal to Establish a Safety Group in LLVM](https://discourse.llvm.org/t/rfc-proposal-to-establish-a-safety-group-in-llvm/86916) on the LLVM Discourse forum.
+- Join the conversation on the LLVM Community Discord in the [#fusa-qual-wg](https://discord.com/channels/636084430946959380/1389362444169773117) channel.
+
diff --git a/llvm/docs/ReleaseProcess.md b/llvm/docs/ReleaseProcess.md
index 6b8d988860e99..d210c5a69649c 100644
--- a/llvm/docs/ReleaseProcess.md
+++ b/llvm/docs/ReleaseProcess.md
@@ -1,29 +1,21 @@
-=============================
-How To Validate a New Release
-=============================
+# How To Validate a New Release
-
-Introduction
-============
+## Introduction
This document contains information about testing the release candidates that
will ultimately be the next LLVM release. For more information on how to
-manage the actual release, please refer to :doc:`HowToReleaseLLVM`.
+manage the actual release, please refer to {doc}`HowToReleaseLLVM`.
-Overview of the Release Process
--------------------------------
+### Overview of the Release Process
Once the release process starts, the Release Manager will ask for volunteers,
and it'll be the role of each volunteer to:
-* Test and benchmark the previous release
-
-* Test and benchmark each release candidate, comparing to the previous release
+- Test and benchmark the previous release
+- Test and benchmark each release candidate, comparing to the previous release
and candidates
-
-* Identify, reduce and report every regression found during tests and benchmarks
-
-* Make sure the critical bugs get fixed and merged to the next release candidate
+- Identify, reduce and report every regression found during tests and benchmarks
+- Make sure the critical bugs get fixed and merged to the next release candidate
Not all bugs or regressions are show-stoppers and it's a bit of a grey area what
should be fixed before the next candidate and what can wait until the next
@@ -31,102 +23,93 @@ release.
It'll depend on:
-* The severity of the bug, how many people it affects and if it's a regression
+- The severity of the bug, how many people it affects and if it's a regression
or a known bug. Known bugs are "unsupported features" and some bugs can be
disabled if they have been implemented recently.
-
-* The stage in the release. Less critical bugs should be considered to be
+- The stage in the release. Less critical bugs should be considered to be
fixed between RC1 and RC2, but not so much at the end of it.
-
-* If it's a correctness or a performance regression. Performance regression
+- If it's a correctness or a performance regression. Performance regression
tends to be taken more lightly than correctness.
-.. _scripts:
+(scripts)=
-Scripts
-=======
+## Scripts
-The scripts are in the ``utils/release`` directory.
+The scripts are in the `utils/release` directory.
-test-release.sh
----------------
+### test-release.sh
This script will check-out, configure and compile LLVM+Clang (+ most add-ons,
-like ``compiler-rt``, ``libcxx``, ``libomp`` and ``clang-extra-tools``) in
+like `compiler-rt`, `libcxx`, `libomp` and `clang-extra-tools`) in
three stages, and will test the final stage.
It'll have installed the final binaries on the Phase3/Releasei(+Asserts)
directory, and that's the one you should use for the test-suite and other
external tests.
-To run the script on a specific release candidate run::
+To run the script on a specific release candidate run:
- ./test-release.sh \
- -release 3.3 \
- -rc 1 \
- -no-64bit \
- -test-asserts \
- -no-compare-files
+```
+./test-release.sh \
+ -release 3.3 \
+ -rc 1 \
+ -no-64bit \
+ -test-asserts \
+ -no-compare-files
+```
Each system will require different options. For instance, x86_64 will
-obviously not need ``-no-64bit`` while 32-bit systems will, or the script will
+obviously not need `-no-64bit` while 32-bit systems will, or the script will
fail.
The important flags to get right are:
-* On the pre-release, you should change ``-rc 1`` to ``-final``. On RC2,
- change it to ``-rc 2`` and so on.
-
-* On non-release testing, you can use ``-final`` in conjunction with
- ``-no-checkout``, but you'll have to create the ``final`` directory by hand
- and link the correct source dir to ``final/llvm.src``.
-
-* For release candidates, you need ``-test-asserts``, or it won't create a
+- On the pre-release, you should change `-rc 1` to `-final`. On RC2,
+ change it to `-rc 2` and so on.
+- On non-release testing, you can use `-final` in conjunction with
+ `-no-checkout`, but you'll have to create the `final` directory by hand
+ and link the correct source dir to `final/llvm.src`.
+- For release candidates, you need `-test-asserts`, or it won't create a
"Release+Asserts" directory, which is needed for release testing and
benchmarking. This will take twice as long.
-
-* On the final candidate you just need Release builds, and that's the binary
+- On the final candidate you just need Release builds, and that's the binary
directory you'll have to pack.
-
-* On macOS, you must export ``MACOSX_DEPLOYMENT_TARGET=10.9`` before running
+- On macOS, you must export `MACOSX_DEPLOYMENT_TARGET=10.9` before running
the script.
This script builds three phases of Clang+LLVM twice each (Release and
Release+Asserts), so use screen or nohup to avoid headaches, since it'll take
a long time.
-Use the ``--help`` option to see all the options and chose it according to
+Use the `--help` option to see all the options and chose it according to
your needs.
-
-findRegressions-nightly.py
---------------------------
+### findRegressions-nightly.py
TODO
-.. _test-suite:
+(test-suite)=
-Test Suite
-==========
+## Test Suite
-
-Follow the `LNT Quick Start Guide
-<https://llvm.org/docs/lnt/quickstart.html>`__ link on how to set-up the
+Follow the [LNT Quick Start Guide](https://llvm.org/docs/lnt/quickstart.html) link on how to set-up the
test-suite
The binary location you'll have to use for testing is inside the
-``rcN/Phase3/Release+Asserts/llvmCore-REL-RC.install``.
+`rcN/Phase3/Release+Asserts/llvmCore-REL-RC.install`.
Link that directory to an easier location and run the test-suite.
An example on the run command line, assuming you created a link from the correct
-install directory to ``~/devel/llvm/install``::
-
- ./sandbox/bin/python sandbox/bin/lnt runtest \
- nt \
- -j4 \
- --sandbox sandbox \
- --test-suite ~/devel/llvm/test/test-suite \
- --cc ~/devel/llvm/install/bin/clang \
- --cxx ~/devel/llvm/install/bin/clang++
+install directory to `~/devel/llvm/install`:
+
+```
+./sandbox/bin/python sandbox/bin/lnt runtest \
+ nt \
+ -j4 \
+ --sandbox sandbox \
+ --test-suite ~/devel/llvm/test/test-suite \
+ --cc ~/devel/llvm/install/bin/clang \
+ --cxx ~/devel/llvm/install/bin/clang++
+```
It should have no new regressions, compared to the previous release or release
candidate. You don't need to fix all the bugs in the test-suite, since they're
@@ -140,11 +123,9 @@ as blocker, and all the other bugs as important, but not necessarily blocking
the release to proceed. They can be set as "known failures" and to be
fixed on a future date.
-.. _pre-release-process:
-
-Pre-Release Process
-===================
+(pre-release-process)=
+## Pre-Release Process
When the release process is announced on the mailing list, you should prepare
for the testing, by applying the same testing you'll do on the release
@@ -152,27 +133,22 @@ candidates, on the previous release.
You should:
-* Download the previous release sources from
- https://llvm.org/releases/download.html.
-
-* Run the test-release.sh script on ``final`` mode (change ``-rc 1`` to
- ``-final``).
-
-* Once all three stages are done, it'll test the final stage.
-
-* Using the ``Phase3/Release+Asserts/llvmCore-MAJ.MIN-final.install`` base,
+- Download the previous release sources from
+ <https://llvm.org/releases/download.html>.
+- Run the test-release.sh script on `final` mode (change `-rc 1` to
+ `-final`).
+- Once all three stages are done, it'll test the final stage.
+- Using the `Phase3/Release+Asserts/llvmCore-MAJ.MIN-final.install` base,
run the test-suite.
-If the final phase's ``make check-all`` failed, it's a good idea to also test
+If the final phase's `make check-all` failed, it's a good idea to also test
the intermediate stages by going on the obj directory and running
-``make check-all`` to find if there's at least one stage that passes (helps
+`make check-all` to find if there's at least one stage that passes (helps
when reducing the error for bug report purposes).
-.. _release-process:
-
-Release Process
-===============
+(release-process)=
+## Release Process
When the Release Manager sends you the release candidate, download all sources,
unzip on the same directory (there will be sym-links from the appropriate places
@@ -180,44 +156,36 @@ to them), and run the release test as above.
You should:
-* Download the current candidate sources from where the release manager points
- you (ex. https://llvm.org/pre-releases/3.3/rc1/).
-
-* Repeat the steps above with ``-rc 1``, ``-rc 2`` etc modes and run the
+- Download the current candidate sources from where the release manager points
+ you (ex. <https://llvm.org/pre-releases/3.3/rc1/>).
+- Repeat the steps above with `-rc 1`, `-rc 2` etc modes and run the
test-suite the same way.
-
-* Compare the results, report all errors on Bugzilla and publish the binary blob
+- Compare the results, report all errors on Bugzilla and publish the binary blob
where the release manager can grab it.
Once the release manager announces that the latest candidate is the good one,
-you have to pack the ``Release`` (no Asserts) install directory on ``Phase3``
+you have to pack the `Release` (no Asserts) install directory on `Phase3`
and that will be the official binary.
-* Rename (or link) ``clang+llvm-REL-ARCH-ENV`` to the .install directory
-
-* Tar that into the same name with ``.tar.gz`` extension from outside the
+- Rename (or link) `clang+llvm-REL-ARCH-ENV` to the .install directory
+- Tar that into the same name with `.tar.gz` extension from outside the
directory
+- Make it available for the release manager to download
-* Make it available for the release manager to download
-
-.. _bug-reporting:
-
-Bug Reporting Process
-=====================
+(bug-reporting)=
+## Bug Reporting Process
If you found regressions or failures when comparing a release candidate with the
previous release, follow the rules below:
-* Critical bugs on compilation should be fixed as soon as possible, possibly
+- Critical bugs on compilation should be fixed as soon as possible, possibly
before releasing the binary blobs.
-
-* Check-all tests should be fixed before the next release candidate, but can
+- Check-all tests should be fixed before the next release candidate, but can
wait until the test-suite run is finished.
-
-* Bugs in the test suite or unimportant check-all tests can be fixed in between
+- Bugs in the test suite or unimportant check-all tests can be fixed in between
release candidates.
-
-* New features or recent big changes, when close to the release, should have
+- New features or recent big changes, when close to the release, should have
done in a way that it's easy to disable. If they misbehave, prefer disabling
them than releasing an unstable (but untested) binary package.
+
diff --git a/llvm/docs/ScudoHardenedAllocator.md b/llvm/docs/ScudoHardenedAllocator.md
index 7ac6522f90a49..a1982c978ef0b 100644
--- a/llvm/docs/ScudoHardenedAllocator.md
+++ b/llvm/docs/ScudoHardenedAllocator.md
@@ -1,28 +1,23 @@
-========================
-Scudo Hardened Allocator
-========================
+# Scudo Hardened Allocator
-
-Introduction
-============
+## Introduction
The Scudo Hardened Allocator is a user-mode allocator, originally based on LLVM
Sanitizers'
-`CombinedAllocator <https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/sanitizer_common/sanitizer_allocator_combined.h>`_.
+[CombinedAllocator](https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/sanitizer_common/sanitizer_allocator_combined.h).
It aims at providing additional mitigation against heap based vulnerabilities,
while maintaining good performance. Scudo is currently the default allocator in
-`Fuchsia <https://fuchsia.dev/>`_, and in `Android <https://www.android.com/>`_
+[Fuchsia](https://fuchsia.dev/), and in [Android](https://www.android.com/)
since Android 11.
The name "Scudo" comes from the Italian word for
-`shield <https://www.collinsdictionary.com/dictionary/italian-english/scudo>`_
+[shield](https://www.collinsdictionary.com/dictionary/italian-english/scudo)
(and Escudo in Spanish).
-Design
-======
+## Design
+
+### Allocator
-Allocator
----------
Scudo was designed with security in mind, but aims at striking a good balance
between security and performance. It was designed to be highly tunable and
configurable, and while we provide some default configurations, we encourage
@@ -35,17 +30,14 @@ The allocator combines several components that serve distinct purposes:
sizes by carving reserved memory regions into blocks of identical size. There
are currently two Primary allocators implemented, specific to 32- and 64-bit
architectures. It is configurable via compile time options.
-
- the Secondary allocator: slower, it services larger allocation sizes via the
memory mapping primitives of the underlying operating system. Secondary backed
allocations are surrounded by Guard Pages. It is also configurable via compile
time options.
-
- the thread specific data Registry: defines how local caches operate for each
thread. There are currently two models implemented: the exclusive model where
each thread holds its own caches (using the ELF TLS); or the shared model
where threads share a fixed size pool of caches.
-
- the Quarantine: offers a way to delay the deallocation operations, preventing
blocks to be immediately available for reuse. Blocks held will be recycled
once certain size criteria are reached. This is essentially a delayed freelist
@@ -53,14 +45,13 @@ The allocator combines several components that serve distinct purposes:
costly in terms of performance and memory footprint, is mostly controlled by
runtime options and is disabled by default.
-Allocations Header
-------------------
+### Allocations Header
+
Every chunk of heap memory returned to an application by the allocator will be
preceded by a header. This has two purposes:
- being to store various information about the chunk, that can be leveraged to
ensure consistency of the heap operations;
-
- being able to detect potential corruption. For this purpose, the header is
checksummed and corruption of the header will be detected when said header is
accessed (note that if the corrupted header is not accessed, the corruption
@@ -70,18 +61,13 @@ The following information is stored in the header:
- the class ID for that chunk, which identifies the region where the chunk
resides for Primary backed allocations, or 0 for Secondary backed allocations;
-
- the state of the chunk (available, allocated or quarantined);
-
- the allocation type (malloc, new, new[] or memalign), to detect potential
mismatches in the allocation APIs used;
-
- the size (Primary) or unused bytes amount (Secondary) for that chunk, which is
necessary for reallocation or sized-deallocation operations;
-
- the offset of the chunk, which is the distance in bytes from the beginning of
the returned chunk to the beginning of the backend allocation (the "block");
-
- the 16-bit checksum;
This header fits within 8 bytes on all platforms supported, and contributes to a
@@ -97,8 +83,8 @@ as two consecutive chunks could belong to different threads. We work on local
copies and use compare-exchange primitives to update the headers in the heap
memory, and avoid any type of double-fetching.
-Randomness
-----------
+### Randomness
+
Randomness is a critical factor to the additional security provided by the
allocator. The allocator trusts the memory mapping primitives of the OS to
provide pages at (mostly) non-predictable locations in memory, as well as the
@@ -107,8 +93,8 @@ incorrect, the security will be greatly reduced. Scudo further randomizes how
blocks are allocated in the Primary, can randomize how caches are assigned to
threads.
-Memory reclaiming
------------------
+### Memory reclaiming
+
Primary and Secondary allocators have different behaviors with regard to
reclaiming. While Secondary mapped allocations can be unmapped on deallocation,
it isn't the case for the Primary, which could lead to a steady growth of the
@@ -118,23 +104,22 @@ released: this generally means they won't count towards the RSS of a process and
be zero filled on subsequent accesses). This is done in the deallocation path,
and several options exist to tune this behavior.
-Usage
-=====
+## Usage
+
+### Platform
-Platform
---------
If using Fuchsia or an Android version greater than 11, your memory allocations
are already service by Scudo (note that Android Svelte configurations still use
jemalloc).
-Library
--------
+### Library
+
The allocator static library can be built from the LLVM tree thanks to the
-``scudo_standalone`` CMake rule. The associated tests can be exercised thanks to
-the ``check-scudo_standalone`` CMake rule.
+`scudo_standalone` CMake rule. The associated tests can be exercised thanks to
+the `check-scudo_standalone` CMake rule.
Linking the static library to your project can require the use of the
-``whole-archive`` linker flag (or equivalent), depending on your linker.
+`whole-archive` linker flag (or equivalent), depending on your linker.
Additional flags might also be necessary.
Your linked binary should now make use of the Scudo allocation and deallocation
@@ -142,49 +127,46 @@ functions.
You may also build Scudo like this:
-.. code:: console
-
- cd $LLVM/compiler-rt/lib
- clang++ -fPIC -std=c++17 -msse4.2 -O2 -pthread -shared \
- -I scudo/standalone/include \
- scudo/standalone/*.cpp \
- -o $HOME/libscudo.so
+```console
+cd $LLVM/compiler-rt/lib
+clang++ -fPIC -std=c++17 -msse4.2 -O2 -pthread -shared \
+ -I scudo/standalone/include \
+ scudo/standalone/*.cpp \
+ -o $HOME/libscudo.so
+```
and then use it with existing binaries as follows:
-.. code:: console
+```console
+LD_PRELOAD=$HOME/libscudo.so ./a.out
+```
- LD_PRELOAD=$HOME/libscudo.so ./a.out
+### Clang
-Clang
------
With a recent version of Clang (post rL317337), the "old" version of the
allocator can be linked with a binary at compilation using the
-``-fsanitize=scudo`` command-line argument, if the target platform is supported.
+`-fsanitize=scudo` command-line argument, if the target platform is supported.
Currently, the only other sanitizer Scudo is compatible with is UBSan
-(eg: ``-fsanitize=scudo,undefined``). Compiling with Scudo will also enforce
+(eg: `-fsanitize=scudo,undefined`). Compiling with Scudo will also enforce
PIE for the output binary.
We will transition this to the standalone Scudo version in the future.
-Options
--------
+### Options
+
Several aspects of the allocator can be configured on a per process basis
through the following ways:
-- at compile time, by defining ``SCUDO_DEFAULT_OPTIONS`` to the options string
+- at compile time, by defining `SCUDO_DEFAULT_OPTIONS` to the options string
you want set by default;
-
-- by defining a ``__scudo_default_options`` function in one's program that
+- by defining a `__scudo_default_options` function in one's program that
returns the options string to be parsed. Said function must have the following
- prototype: ``extern "C" const char* __scudo_default_options(void)``, with a
+ prototype: `extern "C" const char* __scudo_default_options(void)`, with a
default visibility. This will override the compile time define;
-
- through the environment variable SCUDO_OPTIONS, containing the options string
to be parsed. Options defined this way will override any definition made
- through ``__scudo_default_options``.
-
-- via the standard ``mallopt`` `API <https://man7.org/linux/man-pages/man3/mallopt.3.html>`_,
+ through `__scudo_default_options`.
+- via the standard `mallopt` [API](https://man7.org/linux/man-pages/man3/mallopt.3.html),
using parameters that are Scudo specific.
When dealing with the options string, it follows a syntax similar to ASan, where
@@ -192,21 +174,21 @@ distinct options can be assigned in the same string, separated by colons.
For example, using the environment variable:
-.. code:: console
-
- SCUDO_OPTIONS="delete_size_mismatch=false:release_to_os_interval_ms=-1" ./a.out
+```console
+SCUDO_OPTIONS="delete_size_mismatch=false:release_to_os_interval_ms=-1" ./a.out
+```
Or using the function:
-.. code:: cpp
-
- extern "C" const char *__scudo_default_options() {
- return "delete_size_mismatch=false:release_to_os_interval_ms=-1";
- }
-
+```cpp
+extern "C" const char *__scudo_default_options() {
+ return "delete_size_mismatch=false:release_to_os_interval_ms=-1";
+}
+```
The following "string" options are available:
+```{eval-rst}
+---------------------------------+----------------+-------------------------------------------------+
| Option | Default | Description |
+---------------------------------+----------------+-------------------------------------------------+
@@ -264,13 +246,15 @@ The following "string" options are available:
| | | the scudo_malloc_set_track_allocation_stacks |
| | | function. |
+---------------------------------+----------------+-------------------------------------------------+
+```
Additional flags can be specified, for example if Scudo if compiled with
-`GWP-ASan <https://llvm.org/docs/GwpAsan.html>`_ support.
+[GWP-ASan](https://llvm.org/docs/GwpAsan.html) support.
The following "mallopt" options are available (options are defined in
-``include/scudo/interface.h``):
+`include/scudo/interface.h`):
+```{eval-rst}
+---------------------------+-------------------------------------------------------+
| Option | Description |
+---------------------------+-------------------------------------------------------+
@@ -308,52 +292,46 @@ The following "mallopt" options are available (options are defined in
| M_TSDS_COUNT_MAX | Increases the maximum number of TSDs that can be used |
| | up to the limit specified at compile time. |
+---------------------------+-------------------------------------------------------+
+```
-Error Types
-===========
+## Error Types
The allocator will output an error message, and potentially terminate the
process, when an unexpected behavior is detected. The output usually starts with
-``"Scudo ERROR:"`` followed by a short summary of the problem that occurred as
+`"Scudo ERROR:"` followed by a short summary of the problem that occurred as
well as the pointer(s) involved. Once again, Scudo is meant to be a mitigation,
and might not be the most useful of tools to help you root-cause the issue,
-please consider `ASan <https://github.com/google/sanitizers/wiki/AddressSanitizer>`_
+please consider [ASan](https://github.com/google/sanitizers/wiki/AddressSanitizer)
for this purpose.
Here is a list of the current error messages and their potential cause:
-- ``"corrupted chunk header"``: the checksum verification of the chunk header
+- `"corrupted chunk header"`: the checksum verification of the chunk header
has failed. This is likely due to one of two things: the header was
overwritten (partially or totally), or the pointer passed to the function is
not a chunk at all;
-
-- ``"race on chunk header"``: two different threads are attempting to manipulate
+- `"race on chunk header"`: two different threads are attempting to manipulate
the same header at the same time. This is usually symptomatic of a
race-condition or general lack of locking when performing operations on that
chunk;
-
-- ``"invalid chunk state"``: the chunk is not in the expected state for a given
+- `"invalid chunk state"`: the chunk is not in the expected state for a given
operation, eg: it is not allocated when trying to free it, or it's not
quarantined when trying to recycle it, etc. A double-free is the typical
reason this error would occur;
-
-- ``"misaligned pointer"``: we strongly enforce basic alignment requirements, 8
+- `"misaligned pointer"`: we strongly enforce basic alignment requirements, 8
bytes on 32-bit platforms, 16 bytes on 64-bit platforms. If a pointer passed
to our functions does not fit those, something is definitely wrong.
-
-- ``"allocation type mismatch"``: when the optional deallocation type mismatch
+- `"allocation type mismatch"`: when the optional deallocation type mismatch
check is enabled, a deallocation function called on a chunk has to match the
type of function that was called to allocate it. Security implications of such
a mismatch are not necessarily obvious but situational at best;
-
-- ``"invalid sized delete"``: when the C++14 sized delete operator is used, and
+- `"invalid sized delete"`: when the C++14 sized delete operator is used, and
the optional check enabled, this indicates that the size passed when
deallocating a chunk is not congruent with the one requested when allocating
- it. This is likely to be a `compiler issue <https://software.intel.com/en-us/forums/intel-c-compiler/topic/783942>`_,
+ it. This is likely to be a [compiler issue](https://software.intel.com/en-us/forums/intel-c-compiler/topic/783942),
as was the case with Intel C++ Compiler, or some type confusion on the object
being deallocated;
-
-- ``"RSS limit exhausted"``: the maximum RSS optionally specified has been
+- `"RSS limit exhausted"`: the maximum RSS optionally specified has been
exceeded;
Several other error messages relate to parameter checking on the libc allocation
diff --git a/llvm/docs/Security.md b/llvm/docs/Security.md
index 9c586437d25c1..108532838faad 100644
--- a/llvm/docs/Security.md
+++ b/llvm/docs/Security.md
@@ -1,6 +1,4 @@
-============================
-LLVM Security Response Group
-============================
+# LLVM Security Response Group
The LLVM Security Response Group has the following goals:
@@ -8,79 +6,74 @@ The LLVM Security Response Group has the following goals:
2. Organize fixes, code reviews, and release management for said issues.
3. Allow distributors time to investigate and deploy fixes before wide dissemination of vulnerabilities or mitigation shortcomings.
4. Ensure timely notification and release to vendors who package and distribute LLVM-based toolchains and projects.
-5. Ensure timely notification to users of LLVM-based toolchains whose compiled code is security-sensitive, through the `CVE process`_.
+5. Ensure timely notification to users of LLVM-based toolchains whose compiled code is security-sensitive, through the [CVE process][cve process].
*Note*: these goals ensure timely action, provide disclosure timing when issues are reported, and respect vendors' / packagers' / users' constraints.
The LLVM Security Response Group is private. It is composed of trusted LLVM contributors. Its discussions remain within the LLVM Security Response Group (plus issue reporter and key experts) while an issue is being investigated. After an issue becomes public, the entirety of the group’s discussions pertaining to that issue also become public.
-.. _report-security-issue:
+(report-security-issue)=
-How to report a security issue?
-===============================
+## How to report a security issue?
-To report a security issue in any of the LLVM projects, please use the `report a vulnerability`_ feature in the `llvm/llvm-security-repo`_ repository on github, under the "Security" tab.
+To report a security issue in any of the LLVM projects, please use the [report a vulnerability][report a vulnerability] feature in the [llvm/llvm-security-repo][llvm/llvm-security-repo] repository on github, under the "Security" tab.
-We aim to acknowledge your report within two business days since you first reach out. If you do not receive any response by then, you can escalate by posting on the `Discourse forums`_ asking to get in touch with someone from the LLVM Security Response Group. **The escalation mailing list is public**: avoid discussing or mentioning the specific issue when posting on it.
+We aim to acknowledge your report within two business days since you first reach out. If you do not receive any response by then, you can escalate by posting on the [Discourse forums][discourse forums] asking to get in touch with someone from the LLVM Security Response Group. **The escalation mailing list is public**: avoid discussing or mentioning the specific issue when posting on it.
+## Group Composition
-Group Composition
-=================
-
-Security Response Group Members
--------------------------------
+### Security Response Group Members
The members of the group represent a wide cross-section of the community, and
meet the criteria for inclusion below. The list is in the format
`* ${full_name} (${affiliation}) [${github_username}]`. If a github
username for an individual isn't available, the brackets will be empty.
-* Abhay Kanhere (Apple) [@AbhayKanhere]
-* Ahmed Bougacha (Apple) [@ahmedbougacha]
-* Artur Pilipenko (Azul Systems Inc) []
-* Boovaragavan Dasarathan (Nvidia) [@mrragava]
-* Dimitry Andric (individual; FreeBSD) [@DimitryAndric]
-* Ed Maste (individual; FreeBSD) [@emaste]
-* Gabor Spaits (HighTec EDV Systeme) [@spaits]
-* George Burgess IV (Google) [@gburgessiv]
-* Kristof Beyls (ARM) [@kbeyls]
-* Mario Cupelli (HighTec EDV Systeme) [@mariocup]
-* Matthew Riley (Google) [@mmdriley]
-* Matthew Voss (Sony) [@ormris]
-* Nikhil Gupta (Nvidia) []
-* Oliver Hunt (Apple) [@ojhunt]
-* Peter Smith (ARM) [@smithp35]
-* Pietro Albini (Oxide Computer Company; Rust) [@pietroalbini]
-* Serge Guelton (Mozilla) [@serge-sans-paille]
-* Sergey Zverev (Intel) [@offsake]
-* Shayne Hiet-Block (Microsoft) [@GreatKeeper]
-* Tim Penge (Sony) [@tpenge]
-* Tulio Magno Quites Machado Filho (Red Hat) [@tuliom]
-* Will Huhn (Intel) [@wphuhn-intel]
-* Yvan Roux (ST) [@yroux]
-
-Criteria
---------
-
-* Nominees for LLVM Security Response Group membership should fall in one of these groups:
+- Abhay Kanhere (Apple) [@AbhayKanhere]
+- Ahmed Bougacha (Apple) [@ahmedbougacha]
+- Artur Pilipenko (Azul Systems Inc) []
+- Boovaragavan Dasarathan (Nvidia) [@mrragava]
+- Dimitry Andric (individual; FreeBSD) [@DimitryAndric]
+- Ed Maste (individual; FreeBSD) [@emaste]
+- Gabor Spaits (HighTec EDV Systeme) [@spaits]
+- George Burgess IV (Google) [@gburgessiv]
+- Kristof Beyls (ARM) [@kbeyls]
+- Mario Cupelli (HighTec EDV Systeme) [@mariocup]
+- Matthew Riley (Google) [@mmdriley]
+- Matthew Voss (Sony) [@ormris]
+- Nikhil Gupta (Nvidia) []
+- Oliver Hunt (Apple) [@ojhunt]
+- Peter Smith (ARM) [@smithp35]
+- Pietro Albini (Oxide Computer Company; Rust) [@pietroalbini]
+- Serge Guelton (Mozilla) [@serge-sans-paille]
+- Sergey Zverev (Intel) [@offsake]
+- Shayne Hiet-Block (Microsoft) [@GreatKeeper]
+- Tim Penge (Sony) [@tpenge]
+- Tulio Magno Quites Machado Filho (Red Hat) [@tuliom]
+- Will Huhn (Intel) [@wphuhn-intel]
+- Yvan Roux (ST) [@yroux]
+
+### Criteria
+
+- Nominees for LLVM Security Response Group membership should fall in one of these groups:
- Individual contributors:
- + Specializes in fixing compiler-based security related issues or often participates in their exploration and resolution.
- + Has a track record of finding security vulnerabilities and responsible disclosure of those vulnerabilities.
- + Is a compiler expert who has specific interests in knowing about, resolving, and preventing future security vulnerabilities.
- + Has actively contributed non-trivial code to the LLVM project in the last year.
+ - Specializes in fixing compiler-based security related issues or often participates in their exploration and resolution.
+ - Has a track record of finding security vulnerabilities and responsible disclosure of those vulnerabilities.
+ - Is a compiler expert who has specific interests in knowing about, resolving, and preventing future security vulnerabilities.
+ - Has actively contributed non-trivial code to the LLVM project in the last year.
- Researchers:
- + Has a track record of finding security vulnerabilities and responsible disclosure of those vulnerabilities.
- + Is a compiler expert who has specific interests in knowing about, resolving, and preventing future security vulnerabilities.
+ - Has a track record of finding security vulnerabilities and responsible disclosure of those vulnerabilities.
+ - Is a compiler expert who has specific interests in knowing about, resolving, and preventing future security vulnerabilities.
- Vendor contacts:
- + Represents an organization or company which ships products that include their own copy of LLVM. Due to their position in the organization, the nominee has a reasonable need to know about security issues and disclosure embargoes.
+ - Represents an organization or company which ships products that include their own copy of LLVM. Due to their position in the organization, the nominee has a reasonable need to know about security issues and disclosure embargoes.
-* Additionally, the following are necessary but not sufficient criteria for membership in the LLVM Security Response Group:
+- Additionally, the following are necessary but not sufficient criteria for membership in the LLVM Security Response Group:
- If already in the LLVM Security Response Group, has actively participated in one (if any) security issue in the last year.
- If already in the LLVM Security Response Group, has actively participated in most membership discussions in the last year.
@@ -89,120 +82,103 @@ Criteria
- When nominated as a vendor contact, their position with that vendor remains the same as when originally nominated.
- Nominees are trusted by existing LLVM Security Response Group members to keep communications embargoed while still active.
-Nomination process
-------------------
+### Nomination process
Anyone who feels they meet these criteria can nominate themselves, or may be nominated by a third party such as an existing LLVM Security Response Group member. The nomination should state whether the nominee is nominated as an individual, researcher, or as a vendor contact. It should clearly describe the grounds for nomination.
-For the moment, nominations are generally proposed, discussed, and voted on using a GitHub pull request. An `example nomination is available here`_. The use of pull requests helps keep membership discussions open, transparent, and easily accessible to LLVM developers in many ways. If, for any reason, a fully-world-readable nomination seems inappropriate, you may reach out to the LLVM Security Response Group via the `report a vulnerability`_ route, and a discussion can be had about the best way to approach nomination, given the constraints that individuals are under.
+For the moment, nominations are generally proposed, discussed, and voted on using a GitHub pull request. An [example nomination is available here][example nomination is available here]. The use of pull requests helps keep membership discussions open, transparent, and easily accessible to LLVM developers in many ways. If, for any reason, a fully-world-readable nomination seems inappropriate, you may reach out to the LLVM Security Response Group via the [report a vulnerability][report a vulnerability] route, and a discussion can be had about the best way to approach nomination, given the constraints that individuals are under.
-Choosing new members
---------------------
+### Choosing new members
If a nomination for LLVM Security Response Group membership is supported by a majority of existing LLVM Security Response Group members, then it carries within five business days unless an existing member of the Security Response Group objects. If an objection is raised, the LLVM Security Response Group members should discuss the matter and try to come to consensus; failing this, the nomination will succeed only by a two-thirds supermajority vote of the LLVM Security Response Group.
-Accepting membership
---------------------
+### Accepting membership
-Before new LLVM Security Response Group membership is finalized, the successful nominee should accept membership and agree to abide by this security policy, particularly `Privileges and Responsibilities of LLVM Security Response Group Members`_ below.
+Before new LLVM Security Response Group membership is finalized, the successful nominee should accept membership and agree to abide by this security policy, particularly [Privileges and Responsibilities of LLVM Security Response Group Members] below.
-Keeping Membership Current
---------------------------
+### Keeping Membership Current
-* At least every six months, the LLVM Security Response Group applies the above criteria. The membership list is pruned accordingly.
-* Any LLVM Security Response Group member can ask that the criteria be applied within the next five business days.
-* If a member of the LLVM Security Response Group does not act in accordance with the letter and spirit of this policy, then their LLVM Security Response Group membership can be revoked by a majority vote of the members, not including the person under consideration for revocation. After a member calls for a revocation vote, voting will be open for five business days.
-* Emergency suspension: an LLVM Security Response Group member who blatantly disregards the LLVM Security Policy may have their membership temporarily suspended on the request of any two members. In such a case, the requesting members should notify the LLVM Security Response Group with a description of the offense. At this point, membership will be temporarily suspended for five business days, pending outcome of the vote for permanent revocation.
-* The LLVM Board may remove any member from the LLVM Security Response Group.
+- At least every six months, the LLVM Security Response Group applies the above criteria. The membership list is pruned accordingly.
+- Any LLVM Security Response Group member can ask that the criteria be applied within the next five business days.
+- If a member of the LLVM Security Response Group does not act in accordance with the letter and spirit of this policy, then their LLVM Security Response Group membership can be revoked by a majority vote of the members, not including the person under consideration for revocation. After a member calls for a revocation vote, voting will be open for five business days.
+- Emergency suspension: an LLVM Security Response Group member who blatantly disregards the LLVM Security Policy may have their membership temporarily suspended on the request of any two members. In such a case, the requesting members should notify the LLVM Security Response Group with a description of the offense. At this point, membership will be temporarily suspended for five business days, pending outcome of the vote for permanent revocation.
+- The LLVM Board may remove any member from the LLVM Security Response Group.
-Transparency Report
--------------------
+### Transparency Report
Every year, the LLVM Security Response Group must publish a transparency report. The intent of this report is to keep the community informed by summarizing the disclosures that have been made public in the last year. It shall contain a list of all public disclosures, as well as statistics on time to fix issues, length of embargo periods, and so on.
-The transparency reports are published at :doc:`SecurityTransparencyReports`.
-
+The transparency reports are published at {doc}`SecurityTransparencyReports`.
-Privileges and Responsibilities of LLVM Security Response Group Members
-=======================================================================
+## Privileges and Responsibilities of LLVM Security Response Group Members
-Access
-------
+### Access
-LLVM Security Response Group members will be subscribed to a private `Discussion Medium`_. It will be used for technical discussions of security issues, as well as process discussions about matters such as disclosure timelines and group membership. Members have access to all security issues.
+LLVM Security Response Group members will be subscribed to a private [Discussion Medium]. It will be used for technical discussions of security issues, as well as process discussions about matters such as disclosure timelines and group membership. Members have access to all security issues.
-Confidentiality
----------------
+### Confidentiality
Members of the LLVM Security Response Group will be expected to treat LLVM security issue information shared with the group as confidential until publicly disclosed:
-* Members should not disclose security issue information to non-members unless both members are employed by the same vendor of a LLVM based product, in which case information can be shared within that organization on a need-to-know basis and handled as confidential information normally is within that organization.
-* If the LLVM Security Response Group agrees, designated members may share issues with vendors of non-LLVM based products if their product suffers from the same issue. The non-LLVM vendor should be asked to respect the issue’s embargo date, and to not share the information beyond the need-to-know people within their organization.
-* If the LLVM Security Response Group agrees, key experts can be brought in to help address particular issues. The key expert should be asked to respect the issue’s embargo date, and to not share the information.
+- Members should not disclose security issue information to non-members unless both members are employed by the same vendor of a LLVM based product, in which case information can be shared within that organization on a need-to-know basis and handled as confidential information normally is within that organization.
+- If the LLVM Security Response Group agrees, designated members may share issues with vendors of non-LLVM based products if their product suffers from the same issue. The non-LLVM vendor should be asked to respect the issue’s embargo date, and to not share the information beyond the need-to-know people within their organization.
+- If the LLVM Security Response Group agrees, key experts can be brought in to help address particular issues. The key expert should be asked to respect the issue’s embargo date, and to not share the information.
-Disclosure
-----------
+### Disclosure
Following the process below, the LLVM Security Response Group decides on embargo date for public disclosure for each Security issue. An embargo may be lifted before the agreed-upon date if all vendors planning to ship a fix have already done so, and if the reporter does not object.
-Collaboration
--------------
+### Collaboration
Members of the LLVM Security Response Group are expected to:
-* Promptly share any LLVM vulnerabilities they become aware of.
-* Volunteer to drive issues forward.
-* Help evaluate the severity of incoming issues.
-* Help write and review patches to address security issues.
-* Participate in the member nomination and removal processes.
+- Promptly share any LLVM vulnerabilities they become aware of.
+- Volunteer to drive issues forward.
+- Help evaluate the severity of incoming issues.
+- Help write and review patches to address security issues.
+- Participate in the member nomination and removal processes.
-.. _security-group-discussion-medium:
+(security-group-discussion-medium)=
-Discussion Medium
-=================
+## Discussion Medium
The medium used to host LLVM Security Response Group discussions is security-sensitive. It should therefore run on infrastructure which can meet our security expectations.
-We use `GitHub's mechanism to privately report security vulnerabilities`_ to have security discussions:
+We use [GitHub's mechanism to privately report security vulnerabilities][github's mechanism to privately report security vulnerabilities] to have security discussions:
-* File security issues.
-* Discuss security improvements to LLVM.
+- File security issues.
+- Discuss security improvements to LLVM.
We also occasionally need to discuss logistics of the LLVM Security Response Group itself:
-* Nominate new members.
-* Propose member removal.
-* Suggest policy changes.
+- Nominate new members.
+- Propose member removal.
+- Suggest policy changes.
-We often have these discussions publicly, in our :ref:`monthly public sync-up call <online-sync-ups>` and on the Discourse forums. For internal or confidential discussions, we also use a private mailing list.
+We often have these discussions publicly, in our {ref}`monthly public sync-up call <online-sync-ups>` and on the Discourse forums. For internal or confidential discussions, we also use a private mailing list.
-Process
-=======
+## Process
The following process occurs on the discussion medium for each reported issue:
-* A security issue reporter (not necessarily an LLVM contributor) reports an issue.
-* Within two business days, a member of the LLVM Security Response Group is put in charge of driving the issue to an acceptable resolution. This champion doesn’t need to be the same person for each issue. This person can self-nominate.
-* Members of the LLVM Security Response Group discuss in which circumstances (if any) an issue is relevant to security, and determine if it is a security issue.
-* Negotiate an embargo date for public disclosure, with a default minimum time limit of ninety days.
-* LLVM Security Response Group members can recommend that key experts be pulled in to specific issue discussions. The key expert can be pulled in unless there are objections from other LLVM Security Response Group members.
-* Patches are written and reviewed.
-* Backporting security patches from recent versions to old versions cannot always work. It is up to the LLVM Security Response Group to decide if such backporting should be done, and how far back.
-* The LLVM Security Response Group figures out how the LLVM project’s own releases, as well as individual vendors’ releases, can be timed to patch the issue simultaneously.
-* Embargo date can be delayed or pulled forward at the LLVM Security Response Group’s discretion.
-* The issue champion obtains a CVE entry from MITRE_.
-* Once the embargo expires, the patch is posted publicly according to LLVM’s usual code review process.
-* All security issues (as well as nomination / removal discussions) become public within approximately fourteen weeks of the fix landing in the LLVM repository. Precautions should be taken to avoid disclosing particularly sensitive data included in the report (e.g. username and password pairs).
-
-
-Changes to the Policy
-=====================
+- A security issue reporter (not necessarily an LLVM contributor) reports an issue.
+- Within two business days, a member of the LLVM Security Response Group is put in charge of driving the issue to an acceptable resolution. This champion doesn’t need to be the same person for each issue. This person can self-nominate.
+- Members of the LLVM Security Response Group discuss in which circumstances (if any) an issue is relevant to security, and determine if it is a security issue.
+- Negotiate an embargo date for public disclosure, with a default minimum time limit of ninety days.
+- LLVM Security Response Group members can recommend that key experts be pulled in to specific issue discussions. The key expert can be pulled in unless there are objections from other LLVM Security Response Group members.
+- Patches are written and reviewed.
+- Backporting security patches from recent versions to old versions cannot always work. It is up to the LLVM Security Response Group to decide if such backporting should be done, and how far back.
+- The LLVM Security Response Group figures out how the LLVM project’s own releases, as well as individual vendors’ releases, can be timed to patch the issue simultaneously.
+- Embargo date can be delayed or pulled forward at the LLVM Security Response Group’s discretion.
+- The issue champion obtains a CVE entry from [MITRE][mitre].
+- Once the embargo expires, the patch is posted publicly according to LLVM’s usual code review process.
+- All security issues (as well as nomination / removal discussions) become public within approximately fourteen weeks of the fix landing in the LLVM repository. Precautions should be taken to avoid disclosing particularly sensitive data included in the report (e.g. username and password pairs).
+
+## Changes to the Policy
The LLVM Security Policy may be changed by majority vote of the LLVM Security Response Group. Such changes also need to be approved by the LLVM Board.
-
-What is considered a security issue?
-====================================
+## What is considered a security issue?
We define "security-sensitive" to mean that a discovered bug or vulnerability
may require coordinated disclosure, and therefore should be reported to the LLVM
@@ -223,23 +199,23 @@ as security-sensitive but need significant work to get to the stage where that's
manageable. The LLVM community will need to decide whether it wants to invest in
making these parts of the code securable, and maintain these security properties
over time. In all cases the LLVM Security Response Group
-`should be consulted <security-group-discussion-medium_>`__, since they'll be
+[should be consulted][security-group-discussion-medium], since they'll be
responding to security issues filed against these parts of the codebase.
The security-sensitive parts of the LLVM Project currently are the following:
-* Code generation: most miscompilations are not security sensitive. However, a
+- Code generation: most miscompilations are not security sensitive. However, a
miscompilation where there are clear indications that it can result in the
produced binary becoming significantly easier to exploit could be considered
security sensitive, and should be reported to the security response group.
-* Run-time libraries: only parts of the run-time libraries are considered
+- Run-time libraries: only parts of the run-time libraries are considered
security-sensitive. The parts that are not considered security-sensitive are
documented below.
The following parts of the LLVM Project are currently treated as non-security
sensitive:
-* LLVM's language frontends, analyzers, optimizers, and code generators for
+- LLVM's language frontends, analyzers, optimizers, and code generators for
which a malicious input can cause undesirable behavior. For example, a
maliciously crafted C, Rust or bitcode input file can cause arbitrary code to
execute in LLVM. These parts of LLVM haven't been hardened, and handling
@@ -247,18 +223,19 @@ sensitive:
more readily perform malicious things. For example, vulnerabilities in clang,
clangd, or the LLVM optimizer in a JIT caused by untrusted inputs are not
security-sensitive.
-* The following parts of the run-time libraries are explicitly not considered
+
+- The following parts of the run-time libraries are explicitly not considered
security-sensitive:
- * parts of the run-time libraries that are not meant to be included in
+ - parts of the run-time libraries that are not meant to be included in
production binaries. For example, most sanitizers are not considered
security-sensitive as they are meant to be used during development only, not
in production.
- * for libc and libc++: if a user calls library functionality in an undefined
+ - for libc and libc++: if a user calls library functionality in an undefined
or otherwise incorrect way, this will most likely not be considered a
security issue, unless the libc/libc++ documentation explicitly promises to
harden or catch that specific undefined behaviour or incorrect usage.
- * unwinding and exception handling: the implementations are not hardened
+ - unwinding and exception handling: the implementations are not hardened
against malformed or malicious unwind or exception handling data. This is
not considered security sensitive.
@@ -268,11 +245,12 @@ in-scope for this security process or not, err towards assuming that it is. The
Security Response Group might agree or disagree and will explain its rationale
in the report, as well as update this document through the above process.
-.. _CVE process: https://cve.mitre.org
-.. _report a vulnerability: https://github.com/llvm/llvm-security-repo/security/advisories/new
-.. _llvm/llvm-security-repo: https://github.com/llvm/llvm-security-repo/security
-.. _GitHub's mechanism to privately report security vulnerabilities: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability
-.. _GitHub security: https://help.github.com/en/articles/about-maintainer-security-advisories
-.. _Discourse forums: https://discourse.llvm.org
-.. _MITRE: https://cve.mitre.org
-.. _example nomination is available here: https://github.com/llvm/llvm-project/pull/92174
+[cve process]: https://cve.mitre.org
+[discourse forums]: https://discourse.llvm.org
+[example nomination is available here]: https://github.com/llvm/llvm-project/pull/92174
+[github security]: https://help.github.com/en/articles/about-maintainer-security-advisories
+[github's mechanism to privately report security vulnerabilities]: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability
+[llvm/llvm-security-repo]: https://github.com/llvm/llvm-security-repo/security
+[mitre]: https://cve.mitre.org
+[report a vulnerability]: https://github.com/llvm/llvm-security-repo/security/advisories/new
+
diff --git a/llvm/docs/SecurityTransparencyReports.md b/llvm/docs/SecurityTransparencyReports.md
index 711e6d8ae6b88..6cdb1fd2fbddb 100644
--- a/llvm/docs/SecurityTransparencyReports.md
+++ b/llvm/docs/SecurityTransparencyReports.md
@@ -1,6 +1,12 @@
-========================================
-LLVM Security Group Transparency Reports
-========================================
+---
+substitutions:
+ br: |-
+ ```{raw} html
+ <br/>
+ ```
+---
+
+# LLVM Security Group Transparency Reports
This page lists the yearly LLVM Security Response group transparency reports.
@@ -18,52 +24,48 @@ Each Chromium issue has 3 URLs, the first is the original URL recorded in
previous transparency reports. The second is the redirect URL to the archive.
The third is to the GitHub archive issue.
-2021
-----
+## 2021
-The :doc:`LLVM security group <Security>` was established on the 10th of July
-2020 by the act of the `initial
-commit <https://github.com/llvm/llvm-project/commit/7bf73bcf6d93>`_ describing
-the purpose of the group and the processes it follows. Many of the group's
+The {doc}`LLVM security group <Security>` was established on the 10th of July
+2020 by the act of the [initial
+commit](https://github.com/llvm/llvm-project/commit/7bf73bcf6d93) describing
+the purpose of the group and the processes it follows. Many of the group's
processes were still not well-defined enough for the group to operate well.
Over the course of 2021, the key processes were defined well enough to enable
the group to operate reasonably well:
-* We defined details on how to report security issues, see `this commit on
- 20th of May 2021 <https://github.com/llvm/llvm-project/commit/c9dbaa4c86d2>`_
-* We refined the nomination process for new group members, see `this
- commit on 30th of July 2021 <https://github.com/llvm/llvm-project/commit/4c98e9455aad>`_
-* We started writing an annual transparency report (you're reading the 2021
+- We defined details on how to report security issues, see [this commit on
+ 20th of May 2021](https://github.com/llvm/llvm-project/commit/c9dbaa4c86d2)
+- We refined the nomination process for new group members, see [this
+ commit on 30th of July 2021](https://github.com/llvm/llvm-project/commit/4c98e9455aad)
+- We started writing an annual transparency report (you're reading the 2021
report here).
Over the course of 2021, we had 2 people leave the LLVM Security group and 4
people join.
In 2021, the security group received 13 issue reports that were made publicly
-visible before 31st of December 2021. The security group judged 2 of these
+visible before 31st of December 2021. The security group judged 2 of these
reports to be security issues:
-* original: https://bugs.chromium.org/p/llvm/issues/detail?id=5
- redirect: https://issuetracker.google.com/issues/42410043 archive:
- https://github.com/llvm/llvm-project/issues/125709
-
-* original: https://bugs.chromium.org/p/llvm/issues/detail?id=11
- redirect: https://issuetracker.google.com/issues/42410002 archive:
- https://github.com/llvm/llvm-project/issues/127644
+- original: <https://bugs.chromium.org/p/llvm/issues/detail?id=5>
+ redirect: <https://issuetracker.google.com/issues/42410043> archive:
+ <https://github.com/llvm/llvm-project/issues/125709>
+- original: <https://bugs.chromium.org/p/llvm/issues/detail?id=11>
+ redirect: <https://issuetracker.google.com/issues/42410002> archive:
+ <https://github.com/llvm/llvm-project/issues/127644>
Both issues were addressed with source changes: #5 in clangd/vscode-clangd, and
-#11 in llvm-project. No dedicated LLVM release was made for either.
+#11 in llvm-project. No dedicated LLVM release was made for either.
We believe that with the publishing of this first annual transparency report,
the security group now has implemented all necessary processes for the group to
operate as promised. The group's processes can be improved further, and we do
expect further improvements to get implemented in 2022. Many of the potential
-improvements end up being discussed on the `monthly public call on LLVM's
-security group <https://llvm.org/docs/GettingInvolved.html#online-sync-ups>`_.
+improvements end up being discussed on the [monthly public call on LLVM's
+security group](https://llvm.org/docs/GettingInvolved.html#online-sync-ups).
-
-2022
-----
+## 2022
In this section we report on the issues the group received in 2022, or on issues
that were received earlier, but were disclosed in 2022.
@@ -73,105 +75,84 @@ the time of writing this transparency report.
5 of these were judged to be security issues:
-* https://bugs.chromium.org/p/llvm/issues/detail?id=17 reports a miscompile in LLVM
+- <https://bugs.chromium.org/p/llvm/issues/detail?id=17> reports a miscompile in LLVM
that can result in the frame pointer and return address being overwritten. This
- was fixed. Redirect: https://issuetracker.google.com/issues/42410008 archive:
- https://github.com/llvm/llvm-project/issues/127645
-
-* https://bugs.chromium.org/p/llvm/issues/detail?id=19 reports a vulnerability in
+ was fixed. Redirect: <https://issuetracker.google.com/issues/42410008> archive:
+ <https://github.com/llvm/llvm-project/issues/127645>
+- <https://bugs.chromium.org/p/llvm/issues/detail?id=19> reports a vulnerability in
`std::filesystem::remove_all` in libc++. This was fixed.
- Redirect: https://issuetracker.google.com/issues/42410010 archive:
- https://github.com/llvm/llvm-project/issues/127647
-
-* https://bugs.chromium.org/p/llvm/issues/detail?id=23 reports a new Spectre
+ Redirect: <https://issuetracker.google.com/issues/42410010> archive:
+ <https://github.com/llvm/llvm-project/issues/127647>
+- <https://bugs.chromium.org/p/llvm/issues/detail?id=23> reports a new Spectre
gadget variant that Speculative Load Hardening (SLH) does not mitigate. No
extension to SLH was implemented to also mitigate against this variant.
- Redirect: https://issuetracker.google.com/issues/42410015 archive:
- https://github.com/llvm/llvm-project/issues/127648
-
-* https://bugs.chromium.org/p/llvm/issues/detail?id=30 reports missing memory
+ Redirect: <https://issuetracker.google.com/issues/42410015> archive:
+ <https://github.com/llvm/llvm-project/issues/127648>
+- <https://bugs.chromium.org/p/llvm/issues/detail?id=30> reports missing memory
safety protection on the (C++) exception handling path. A number of fixes
- were implemented. Redirect: https://issuetracker.google.com/issues/42410023
- archive: https://github.com/llvm/llvm-project/issues/127649
-
-* https://bugs.chromium.org/p/llvm/issues/detail?id=33 reports the RETBLEED
+ were implemented. Redirect: <https://issuetracker.google.com/issues/42410023>
+ archive: <https://github.com/llvm/llvm-project/issues/127649>
+- <https://bugs.chromium.org/p/llvm/issues/detail?id=33> reports the RETBLEED
vulnerability. The outcome was clang growing a new security hardening feature
- `-mfunction-return=thunk-extern`, see https://reviews.llvm.org/D129572.
- Redirect: https://issuetracker.google.com/issues/42410026 archive:
- https://github.com/llvm/llvm-project/issues/127650
-
+ `-mfunction-return=thunk-extern`, see <https://reviews.llvm.org/D129572>.
+ Redirect: <https://issuetracker.google.com/issues/42410026> archive:
+ <https://github.com/llvm/llvm-project/issues/127650>
No dedicated LLVM releases were made for any of the above issues.
-2023
-----
+## 2023
In this section we report on the issues the group received in 2023, or on issues
that were received earlier, but were disclosed in 2023.
9 of these were judged to be security issues:
- * https://bugs.chromium.org/p/llvm/issues/detail?id=36 reports the presence of
- .git folder in https://llvm.org/.git. Redirect:
- https://issuetracker.google.com/issues/42410029 archive:
- https://github.com/llvm/llvm-project/issues/131841
-
- * https://bugs.chromium.org/p/llvm/issues/detail?id=66 reports the presence of a
- GitHub Personal Access token in a DockerHub imaage. Redirect
- https://issuetracker.google.com/issues/42410060 archive:
- https://github.com/llvm/llvm-project/issues/131846
-
- * https://bugs.chromium.org/p/llvm/issues/detail?id=42 reports a potential gap
- in the Armv8.1-m BTI protection, involving a combination of large switch statements
- and __builtin_unreachable() in the default case. Redirect:
- https://issuetracker.google.com/issues/42410035 archive:
- https://github.com/llvm/llvm-project/issues/131848
-
- * https://bugs.chromium.org/p/llvm/issues/detail?id=43 reports a dependency
- on an old version of xml2js with a CVE filed against it. Redirect:
- https://issuetracker.google.com/issues/42410036 archive:
- https://github.com/llvm/llvm-project/issues/131849
-
- * https://bugs.chromium.org/p/llvm/issues/detail?id=45 reports a number of
- dependencies that have had vulnerabilities reported against them. Redirect:
- https://issuetracker.google.com/issues/42410038 archive:
- https://github.com/llvm/llvm-project/issues/131851
-
- * https://bugs.chromium.org/p/llvm/issues/detail?id=46 is related to
- issue 43. Redirect https://issuetracker.google.com/issues/42410039 archive:
- https://github.com/llvm/llvm-project/issues/131852
-
- * https://bugs.chromium.org/p/llvm/issues/detail?id=48 reports a buffer overflow in
- std::format from -fexperimental-library. Redirect:
- https://issuetracker.google.com/issues/42410041 archive:
- https://github.com/llvm/llvm-project/issues/131856
-
- * https://bugs.chromium.org/p/llvm/issues/detail?id=54 reports a memory leak in
- basic_string move assignment when built with libc++ versions <=6.0 and run against
- newer libc++ shared/dylibs. Redirect:
- https://issuetracker.google.com/issues/42410047 archive:
- https://github.com/llvm/llvm-project/issues/131857
-
- * https://bugs.chromium.org/p/llvm/issues/detail?id=56 reports an out
- of bounds buffer store introduced by LLVM backends, that regressed
- due to a procedural oversight. Redirect
- https://issuetracker.google.com/issues/42410049 archive:
- https://github.com/llvm/llvm-project/issues/131858
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=36> reports the presence of
+> .git folder in <https://llvm.org/.git>. Redirect:
+> <https://issuetracker.google.com/issues/42410029> archive:
+> <https://github.com/llvm/llvm-project/issues/131841>
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=66> reports the presence of a
+> GitHub Personal Access token in a DockerHub imaage. Redirect
+> <https://issuetracker.google.com/issues/42410060> archive:
+> <https://github.com/llvm/llvm-project/issues/131846>
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=42> reports a potential gap
+> in the Armv8.1-m BTI protection, involving a combination of large switch statements
+> and \_\_builtin_unreachable() in the default case. Redirect:
+> <https://issuetracker.google.com/issues/42410035> archive:
+> <https://github.com/llvm/llvm-project/issues/131848>
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=43> reports a dependency
+> on an old version of xml2js with a CVE filed against it. Redirect:
+> <https://issuetracker.google.com/issues/42410036> archive:
+> <https://github.com/llvm/llvm-project/issues/131849>
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=45> reports a number of
+> dependencies that have had vulnerabilities reported against them. Redirect:
+> <https://issuetracker.google.com/issues/42410038> archive:
+> <https://github.com/llvm/llvm-project/issues/131851>
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=46> is related to
+> issue 43. Redirect <https://issuetracker.google.com/issues/42410039> archive:
+> <https://github.com/llvm/llvm-project/issues/131852>
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=48> reports a buffer overflow in
+> std::format from -fexperimental-library. Redirect:
+> https://issuetracker.google.com/issues/42410041 archive:
+> https://github.com/llvm/llvm-project/issues/131856
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=54> reports a memory leak in
+> basic_string move assignment when built with libc++ versions \<=6.0 and run against
+> newer libc++ shared/dylibs. Redirect:
+> <https://issuetracker.google.com/issues/42410047> archive:
+> <https://github.com/llvm/llvm-project/issues/131857>
+> - <https://bugs.chromium.org/p/llvm/issues/detail?id=56> reports an out
+> of bounds buffer store introduced by LLVM backends, that regressed
+> due to a procedural oversight. Redirect
+> <https://issuetracker.google.com/issues/42410049> archive:
+> <https://github.com/llvm/llvm-project/issues/131858>
No dedicated LLVM releases were made for any of the above issues.
Over the course of 2023 we had one person join the LLVM Security Group.
-2024
-----
+## 2024
-.. |br| raw:: html
-
- <br/>
-
-
-Introduction
-^^^^^^^^^^^^
+### Introduction
In the first half of 2024, LLVM used the Chromium issue tracker to enable
reporting security issues responsibly. We switched over to using GitHub's
@@ -187,43 +168,41 @@ This transparency report doesn't necessarily mention all issues that were deemed
duplicates of other issues, or tickets only created to test the bug tracking
system.
-Security issues fixed under a coordinated disclosure process
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Security issues fixed under a coordinated disclosure process
This section lists the reported issues where we ended up implementing fixes
under a coordinated disclosure process. While we were still using the Chromium
issue tracker, we did not write security advisories for such issues. Since we
started using the GitHub issues tracker for security issues, we're now
publishing security advisories for those issues at
-https://github.com/llvm/llvm-security-repo/security/advisories/.
+<https://github.com/llvm/llvm-security-repo/security/advisories/>.
-1. “Unexpected behavior when using LTO and branch-protection together” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=58 |br|
- redirect: https://issuetracker.google.com/issues/42410051 |br|
- archive: https://github.com/llvm/llvm-project/issues/132185
+1. “Unexpected behavior when using LTO and branch-protection together” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=58> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410051> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132185>
2. “Security weakness in PCS for CMSE”
- (`CVE-2024-0151 <https://nvd.nist.gov/vuln/detail/CVE-2024-0151>`_) |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=68 |br|
- redirect: https://issuetracker.google.com/issues/42410062 |br|
- archive: https://github.com/llvm/llvm-project/issues/132186
+ ([CVE-2024-0151](https://nvd.nist.gov/vuln/detail/CVE-2024-0151)) {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=68> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410062> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132186>
3. “CMSE secure state may leak from stack to floating-point registers”
- (`CVE-2024-7883 <https://www.cve.org/cverecord?id=CVE-2024-7883>`_) |br|
+ ([CVE-2024-7883](https://www.cve.org/cverecord?id=CVE-2024-7883)) {{ br }}
Details are available at
- `GHSA-wh65-j229-6wfp <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-wh65-j229-6wfp>`_
-
-Supply chain security related issues and project services-related issues
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-1. “GitHub User Involved in xz backdoor may have attempted to change to clang in order to help hide the exploit” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=71 |br|
- redirect: https://issuetracker.google.com/issues/42410066 |br|
- archive: https://github.com/llvm/llvm-project/issues/132187
-2. “llvmbot account suspended due to suspicious login” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=72 |br|
- redirect: https://issuetracker.google.com/issues/42410067 |br|
- archive: https://github.com/llvm/llvm-project/issues/132243
-3. “.git Exposure” |br|
- GHSA-mr8r-vvrc-w6rq |br|
+ [GHSA-wh65-j229-6wfp](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-wh65-j229-6wfp)
+
+### Supply chain security related issues and project services-related issues
+
+1. “GitHub User Involved in xz backdoor may have attempted to change to clang in order to help hide the exploit” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=71> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410066> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132187>
+2. “llvmbot account suspended due to suspicious login” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=72> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410067> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132243>
+3. “.git Exposure” {{ br }}
+ GHSA-mr8r-vvrc-w6rq {{ br }}
The .git directory was accessible via web browsers under apt.llvm.org, a site
used to serve Debian/Ubuntu nightly packages. This issue has been addressed
by removing the directory, and is not considered a security issue for the
@@ -231,8 +210,8 @@ Supply chain security related issues and project services-related issues
the apt website, and was mirroring an open-source project maintained on
github (under opencollab/llvm-jenkins.debian.net). The issue is not believed
to have leaked any non-public information.
-4. “llvm/llvm-project repo potentially vulnerable to GITHUB\_TOKEN leaks” |br|
- GHSA-f5xj-84f9-mrw6 |br|
+4. “llvm/llvm-project repo potentially vulnerable to GITHUB_TOKEN leaks” {{ br }}
+ GHSA-f5xj-84f9-mrw6 {{ br }}
GitHub access tokens were being leaked in artifacts generated by GitHub
Actions workflows. The vulnerability was first reported publicly as
ArtiPACKED, generally applicable to GitHub projects, leading to an audit of
@@ -241,10 +220,10 @@ Supply chain security related issues and project services-related issues
affected, but only exposed tokens that were ephemeral and read-only, so was
not deemed a privilege escalation concern. The workflow was fixed in a
configuration change as PR
- `106310 <https://github.com/llvm/llvm-project/pull/106310>`_. Older exposed
+ [106310](https://github.com/llvm/llvm-project/pull/106310). Older exposed
tokens all expired, and the issue is closed as resolved.
-5. “RCE in Buildkite Pipeline” |br|
- GHSA-2j6q-qcfm-3wcx |br|
+5. “RCE in Buildkite Pipeline” {{ br }}
+ GHSA-2j6q-qcfm-3wcx {{ br }}
A Buildkite CI pipeline (llvm-project/rust-llvm-integrate-prototype) allowed
Remote Code Execution on the CI runner. The pipeline automatically runs a
test job when PRs are filed on the rust-lang/rust repo, but those PRs point
@@ -254,113 +233,109 @@ Supply chain security related issues and project services-related issues
been addressed with internal configuration changes by owners of the Buildkite
pipeline.
-Issues deemed to not require coordinated action before disclosing publicly
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-1. “Clang Address Sanitizer gives False Negative for Array Out of Bounds Compiled with Optimization” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=57 |br|
- redirect: https://issuetracker.google.com/issues/42410050 |br|
- archive: https://github.com/llvm/llvm-project/issues/132191
-2. “Found exposed .svn folder” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=59 |br|
- redirect: https://issuetracker.google.com/issues/42410052
- archive: https://github.com/llvm/llvm-project/issues/132192
-3. “Arbitrary code execution when combining SafeStack \+ dynamic stack allocations \+ \_\_builtin\_setjmp/longjmp” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=60 |br|
- redirect: https://issuetracker.google.com/issues/42410054
- archive: https://github.com/llvm/llvm-project/issues/132220
-4. “RISC-V: Constants are allocated in writeable .sdata section” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=61 |br|
- redirect: https://issuetracker.google.com/issues/42410055 |br|
- archive: https://github.com/llvm/llvm-project/issues/132223
-5. “Manifest File with Out-of-Date Dependencies with CVEs” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=62 |br|
- redirect: https://issuetracker.google.com/issues/42410056 |br|
- archive: https://github.com/llvm/llvm-project/issues/132225
-6. “Non-const derived ctor should fail compilation when having a consteval base ctor” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=67 |br|
- redirect: https://issuetracker.google.com/issues/42410061 |br|
- archive: https://github.com/llvm/llvm-project/issues/132226
-7. “Wrong assembly code generation. Branching to the corrupted "LR".” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=69 |br|
- redirect: https://issuetracker.google.com/issues/42410063 |br|
- archive: https://github.com/llvm/llvm-project/issues/132229
-8. “Security bug report” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=70 |br|
- redirect: https://issuetracker.google.com/issues/42410065 |br|
- archive: https://github.com/llvm/llvm-project/issues/132233
-9. “Using ASan with setuid binaries can lead to arbitrary file write and elevation of privileges” |br|
- Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=73 |br|
- redirect: https://issuetracker.google.com/issues/42410068 |br|
- archive: https://github.com/llvm/llvm-project/issues/132235
-10. “Interesting bugs for bool variable in clang projects and aarch64 modes outputting inaccurate results.” |br|
- GHSA-w7qc-292v-5xh6 |br|
+### Issues deemed to not require coordinated action before disclosing publicly
+
+01. “Clang Address Sanitizer gives False Negative for Array Out of Bounds Compiled with Optimization” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=57> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410050> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132191>
+02. “Found exposed .svn folder” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=59> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410052>
+ archive: <https://github.com/llvm/llvm-project/issues/132192>
+03. “Arbitrary code execution when combining SafeStack + dynamic stack allocations + \_\_builtin_setjmp/longjmp” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=60> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410054>
+ archive: <https://github.com/llvm/llvm-project/issues/132220>
+04. “RISC-V: Constants are allocated in writeable .sdata section” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=61> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410055> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132223>
+05. “Manifest File with Out-of-Date Dependencies with CVEs” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=62> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410056> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132225>
+06. “Non-const derived ctor should fail compilation when having a consteval base ctor” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=67> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410061> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132226>
+07. “Wrong assembly code generation. Branching to the corrupted "LR".” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=69> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410063> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132229>
+08. “Security bug report” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=70> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410065> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132233>
+09. “Using ASan with setuid binaries can lead to arbitrary file write and elevation of privileges” {{ br }}
+ Details are available at <https://bugs.chromium.org/p/llvm/issues/detail?id=73> {{ br }}
+ redirect: <https://issuetracker.google.com/issues/42410068> {{ br }}
+ archive: <https://github.com/llvm/llvm-project/issues/132235>
+10. “Interesting bugs for bool variable in clang projects and aarch64 modes outputting inaccurate results.” {{ br }}
+ GHSA-w7qc-292v-5xh6 {{ br }}
The issue reported is on a source code example having undefined behaviour
- (UB), somewhat similar to this: https://godbolt.org/z/vo4P7bPYr.
- Therefore, this issue was closed as not a security issue in the compiler. |br|
+ (UB), somewhat similar to this: <https://godbolt.org/z/vo4P7bPYr>.
+ Therefore, this issue was closed as not a security issue in the compiler. {{ br }}
As part of the analysis on this issue, it was deemed useful to document this
example of UB and similar cases to help users of compilers understand how UB
- in source code can lead to security issues. |br|
+ in source code can lead to security issues. {{ br }}
We concluded that probably the best option to do so is to create a regular
- public issue at https://github.com/llvm/llvm-project/issues, with the same
+ public issue at <https://github.com/llvm/llvm-project/issues>, with the same
title as the security issue, and to attach a PDF (which should easily be
created using a “print-to-pdf” method in the browser) containing all
comments. Such public tickets probably need some consistent way to indicate
they come from security issues that after analysis were deemed to be outside
the LLVM threat model or weren't accepted as a
needs-resolution-work-in-private security issue for other reasons. The LLVM
- Security Response group has so far not taken action to progress this idea. |br|
+ Security Response group has so far not taken action to progress this idea. {{ br }}
There was also a suggestion of potentially adding a short section in
- https://llsoftsec.github.io/llsoftsecbook/#compiler-introduced-security-vulnerabilities
+ <https://llsoftsec.github.io/llsoftsecbook/#compiler-introduced-security-vulnerabilities>
that summarizes a short example showing that type aliasing UB can and is
causing security vulnerabilities.
-11. “llvm-libc qsort can use very large amounts of stack if an attacker can control its input list” |br|
- GHSA-gw5j-473x-p29m |br|
+11. “llvm-libc qsort can use very large amounts of stack if an attacker can control its input list” {{ br }}
+ GHSA-gw5j-473x-p29m {{ br }}
If the llvm-libc `qsort` function is used in a context where its input list
comes from an attacker, then the attacker can craft a list that causes
`qsort`'s stack usage to be linear in the size of the input array,
- potentially overflowing the available memory region for the stack. |br|
+ potentially overflowing the available memory region for the stack. {{ br }}
After discussion with stakeholders, including maintainers for llvm-libc, the
conclusion was that this doesn't have to be processed as a security issue
needing coordinated disclosure. An improvement to `qsort`'s implementation
was implemented through pull request
- https://github.com/llvm/llvm-project/pull/110849.
-12. “VersionFromVCS.cmake may leak secrets in released builds” |br|
- GHSA-rcw6-jqvr-fcrx |br|
+ <https://github.com/llvm/llvm-project/pull/110849>.
+12. “VersionFromVCS.cmake may leak secrets in released builds” {{ br }}
+ GHSA-rcw6-jqvr-fcrx {{ br }}
The LLVM build system may leak secrets of VCS configuration into release
builds if the user clones the repo with an https link that contains their
- username and/or password. |br|
+ username and/or password. {{ br }}
Mitigations were implemented in
- https://github.com/llvm/llvm-project/pull/105220,
- https://github.com/llvm/llvm-project/commit/57dc09341e5eef758b1abce78822c51069157869.
+ <https://github.com/llvm/llvm-project/pull/105220>,
+ <https://github.com/llvm/llvm-project/commit/57dc09341e5eef758b1abce78822c51069157869>.
An issue was raised to suggest one more mitigation to be implemented at
- https://github.com/llvm/llvm-project/issues/109030.
+ <https://github.com/llvm/llvm-project/issues/109030>.
-Invalid issues
-^^^^^^^^^^^^^^
+### Invalid issues
The LLVM security group received 5 issues which were created accidentally or
were not related to the LLVM project. The subject lines for these were:
-* “Found this in my android”
-* “\[Not a new security issue\] Continued discussion for GHSA-w7qc-292v-5xh6”
-* “please delete it.”
-* “Please help me to delete it.”
-* “llvm code being used in malicious hacking of network and children's devices”
+- “Found this in my android”
+- “[Not a new security issue] Continued discussion for GHSA-w7qc-292v-5xh6”
+- “please delete it.”
+- “Please help me to delete it.”
+- “llvm code being used in malicious hacking of network and children's devices”
Furthermore, we had 2 tickets that were created to test the setup and workflow
as part of migrating to GitHub's “security advisory”-based reporting:
-1. “Test if new draft security advisory gets emailed to LLVM security group” |br|
+1. “Test if new draft security advisory gets emailed to LLVM security group” {{ br }}
GHSA-82m9-xvw3-rvpv
-2. “Test that a non-admin can create an advisory (no vulnerability).” |br|
+2. “Test that a non-admin can create an advisory (no vulnerability).” {{ br }}
GHSA-34gr-6c7h-cc93
-2025
-----
+## 2025
-Introduction
-^^^^^^^^^^^^
+### Introduction
2025 was the first year all reports were submitted using Github. We report on
the issues the group received in 2025, or on issues that were received
@@ -379,102 +354,98 @@ In 2025, we received 2 invalid issues that we believe that have been created
automatically and 1 issue appeared to be created using generative AI. That
issue was considered to be invalid.
-Security issues fixed under a coordinated disclosure process
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Security issues fixed under a coordinated disclosure process
This section lists the reported issues where we ended up implementing fixes
under a coordinated disclosure process. The security advisories for those
issues can be found at
-https://github.com/llvm/llvm-security-repo/security/advisories/.
+<https://github.com/llvm/llvm-security-repo/security/advisories/>.
-1. “CMSE secure state may leak from stack to floating-point registers” |br|
+1. “CMSE secure state may leak from stack to floating-point registers” {{ br }}
Details are available at
- `GHSA-wh65-j229-6wfp <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-wh65-j229-6wfp>`_
-2. “Binary executable injection vulnerability in clang-linker-wrapper.exe” |br|
+ [GHSA-wh65-j229-6wfp](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-wh65-j229-6wfp)
+2. “Binary executable injection vulnerability in clang-linker-wrapper.exe” {{ br }}
Details are available at
- `GHSA-hrx2-grgx-9vhg <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-hrx2-grgx-9vhg>`_
+ [GHSA-hrx2-grgx-9vhg](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-hrx2-grgx-9vhg)
-Supply chain security related issues and project services-related issues
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Supply chain security related issues and project services-related issues
1. “Critical Supply Chain Vulnerability in RockstarGames/llvm-project
- (CVE-2025-30066)” |br|
+ (CVE-2025-30066)” {{ br }}
Details are available at
- `GHSA-3fq9-qcq4-8jjr <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-3fq9-qcq4-8jjr>`_ |br|
+ [GHSA-3fq9-qcq4-8jjr](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-3fq9-qcq4-8jjr) {{ br }}
The issue had already been fixed with commit
- `6616acd80cd91 <https://github.com/llvm/llvm-project/commit/6616acd80cd91a0075e3cd481bb9a6d82fd4ea9e>`_.
+ [6616acd80cd91](https://github.com/llvm/llvm-project/commit/6616acd80cd91a0075e3cd481bb9a6d82fd4ea9e).
2. “CVE-2022-25883 and CVE-2022-3517 with respect to
- llvm-project/mlir/utils/vscode/package-lock.json” |br|
+ llvm-project/mlir/utils/vscode/package-lock.json” {{ br }}
Details are available at
- `GHSA-g72r-487m-m6hh <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-g72r-487m-m6hh>`_ |br|
+ [GHSA-g72r-487m-m6hh](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-g72r-487m-m6hh) {{ br }}
Packages have been updated with
- `PR 144479 <https://github.com/llvm/llvm-project/pull/144479>`_.
+ [PR 144479](https://github.com/llvm/llvm-project/pull/144479).
-Issues deemed to not require coordinated action before disclosing publicly
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Issues deemed to not require coordinated action before disclosing publicly
-1. “Coroutine Frame-Oriented Programming: A new exploitation method using C++ coroutines” |br|
- Details are available at
- `GHSA-v8pv-j8f5-qqcg <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-v8pv-j8f5-qqcg>`_ |br|
- The researchers shared a new exploitation method that leverages the
- implementation of C++ routines. Their
- `paper <https://www.usenix.org/conference/usenixsecurity25/presentation/bajo>`_
- describing the technique has been published and is available publicly.
-2. “Security Bug in String Assign Function (libc++)” |br|
- Details are available at
- `GHSA-m967-6j3p-jrwc <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-m967-6j3p-jrwc>`_ |br|
- There has been an agreement that the proof of concept had undefined
- behavior which makes it out of scope according to
- `the LLVM threat model <https://llvm.org/docs/Security.html#what-is-considered-a-security-issue>`_.
-3. “\[clangd\] heap-use-after-free in clangd when generating diagnostics” |br|
- Details are available at
- `GHSA-5426-9r4h-7whf <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-5426-9r4h-7whf>`_ |br|
- It has been agreed this report fell out of scope because it was caused by
- untrusted inputs, as described in
- `the LLVM threat model <https://llvm.org/docs/Security.html#what-is-considered-a-security-issue>`_.
-4. “A compiler optimization bug may cause signed integer overflow detection
- be bypassed” |br|
- Details are available at
- `GHSA-w6jm-h8j9-q33r <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-w6jm-h8j9-q33r>`_ |br|
- There has been an agreement that the PoC had undefined behavior which makes
- it out of scope according to
- `the LLVM threat model <https://llvm.org/docs/Security.html#what-is-considered-a-security-issue>`_.
-5. “libomp: Crash (OOB Write / ASan BUS Error) involving omp\_init\_lock under
- high concurrency” |br|
- Details are available at
- `GHSA-cfhc-jxq2-97mf <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-cfhc-jxq2-97mf>`_ |br|
- The group agreed to close this as not a security issue because the code
- was written without taking into consideration the expectations from the
- OpenMP specification.
-6. “\[MLIR\] head-use-after-free in mlir-lsp-server on completion request” |br|
- Details are available at
- `GHSA-8j9r-qc4r-q9fh <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-8j9r-qc4r-q9fh>`_ |br|
- This report fell out of scope because it was caused by untrusted inputs,
- as described in
- `the LLVM threat model <https://llvm.org/docs/Security.html#what-is-considered-a-security-issue>`_.
-7. “\[clangd/clang\] heap-buffer-overflow in clang/lib/Sema/SemaExprCXX.cpp:9144” |br|
- Details are available at
- `GHSA-qq8q-r524-8vw9 <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-qq8q-r524-8vw9>`_ |br|
- This issue and the following 3 were concluded to be outside of the
- `LLVM threat model <https://llvm.org/docs/Security.html#what-is-considered-a-security-issue>`_.
-8. “\[clangd\] heap-buffer-overflow in clang/lib/Sema/SemaExprCXX.cpp:8876” |br|
- Details are available at
- `GHSA-3xm9-vccr-fxx5 <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-3xm9-vccr-fxx5>`_
-9. “\[clangd/clang\] heap-use-after-free at clang/Sema/Ownership.h:81” |br|
- Details are available at
- `GHSA-qj36-2p7g-83gv <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-qj36-2p7g-83gv>`_
-10. “Clang 20.1.0 Compiler Internal Error (Crash) during AST Parsing of C++23” |br|
+01. “Coroutine Frame-Oriented Programming: A new exploitation method using C++ coroutines” {{ br }}
+ Details are available at
+ [GHSA-v8pv-j8f5-qqcg](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-v8pv-j8f5-qqcg) {{ br }}
+ The researchers shared a new exploitation method that leverages the
+ implementation of C++ routines. Their
+ [paper](https://www.usenix.org/conference/usenixsecurity25/presentation/bajo)
+ describing the technique has been published and is available publicly.
+02. “Security Bug in String Assign Function (libc++)” {{ br }}
+ Details are available at
+ [GHSA-m967-6j3p-jrwc](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-m967-6j3p-jrwc) {{ br }}
+ There has been an agreement that the proof of concept had undefined
+ behavior which makes it out of scope according to
+ [the LLVM threat model](https://llvm.org/docs/Security.html#what-is-considered-a-security-issue).
+03. “[clangd] heap-use-after-free in clangd when generating diagnostics” {{ br }}
+ Details are available at
+ [GHSA-5426-9r4h-7whf](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-5426-9r4h-7whf) {{ br }}
+ It has been agreed this report fell out of scope because it was caused by
+ untrusted inputs, as described in
+ [the LLVM threat model](https://llvm.org/docs/Security.html#what-is-considered-a-security-issue).
+04. “A compiler optimization bug may cause signed integer overflow detection
+ be bypassed” {{ br }}
Details are available at
- `GHSA-p2g2-89wf-7gcm <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-p2g2-89wf-7gcm>`_
-11. “Compiler-induced non-constant-time code” |br|
+ [GHSA-w6jm-h8j9-q33r](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-w6jm-h8j9-q33r) {{ br }}
+ There has been an agreement that the PoC had undefined behavior which makes
+ it out of scope according to
+ [the LLVM threat model](https://llvm.org/docs/Security.html#what-is-considered-a-security-issue).
+05. “libomp: Crash (OOB Write / ASan BUS Error) involving omp_init_lock under
+ high concurrency” {{ br }}
Details are available at
- `GHSA-627p-g235-23pm <https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-627p-g235-23pm>`_ |br|
+ [GHSA-cfhc-jxq2-97mf](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-cfhc-jxq2-97mf) {{ br }}
+ The group agreed to close this as not a security issue because the code
+ was written without taking into consideration the expectations from the
+ OpenMP specification.
+06. “[MLIR] head-use-after-free in mlir-lsp-server on completion request” {{ br }}
+ Details are available at
+ [GHSA-8j9r-qc4r-q9fh](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-8j9r-qc4r-q9fh) {{ br }}
+ This report fell out of scope because it was caused by untrusted inputs,
+ as described in
+ [the LLVM threat model](https://llvm.org/docs/Security.html#what-is-considered-a-security-issue).
+07. “[clangd/clang] heap-buffer-overflow in clang/lib/Sema/SemaExprCXX.cpp:9144” {{ br }}
+ Details are available at
+ [GHSA-qq8q-r524-8vw9](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-qq8q-r524-8vw9) {{ br }}
+ This issue and the following 3 were concluded to be outside of the
+ [LLVM threat model](https://llvm.org/docs/Security.html#what-is-considered-a-security-issue).
+08. “[clangd] heap-buffer-overflow in clang/lib/Sema/SemaExprCXX.cpp:8876” {{ br }}
+ Details are available at
+ [GHSA-3xm9-vccr-fxx5](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-3xm9-vccr-fxx5)
+09. “[clangd/clang] heap-use-after-free at clang/Sema/Ownership.h:81” {{ br }}
+ Details are available at
+ [GHSA-qj36-2p7g-83gv](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-qj36-2p7g-83gv)
+10. “Clang 20.1.0 Compiler Internal Error (Crash) during AST Parsing of C++23” {{ br }}
+ Details are available at
+ [GHSA-p2g2-89wf-7gcm](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-p2g2-89wf-7gcm)
+11. “Compiler-induced non-constant-time code” {{ br }}
+ Details are available at
+ [GHSA-627p-g235-23pm](https://github.com/llvm/llvm-security-repo/security/advisories/GHSA-627p-g235-23pm) {{ br }}
The reporters shared a pre-print article evaluating non-constant-time
code generated by Clang. We all agreed this did not need coordinated
disclosure because Clang offers no guarantees of constant-time code.
-Invalid issues
-^^^^^^^^^^^^^^
+### Invalid issues
The LLVM security group received 5 issues which were created accidentally or
were not related to the LLVM project. The subject lines for these were:
@@ -482,5 +453,6 @@ were not related to the LLVM project. The subject lines for these were:
1. “llvm-Bug”
2. “Potential Negative Number Used as Index”
3. “I was recently hacked... maybe you folks might know the dev?”
-4. “ASP.NETconfiguration: Creating Debug Binary in ``[](https://github.com/llvm/llvm-project/actions/workflows``”
-5. “ASP.NETconfiguration: Creating Debug Binary in ``[](https://github.com/llvm/llvm-project/actions/workflows``”
+4. “ASP.NETconfiguration: Creating Debug Binary in `[](https://github.com/llvm/llvm-project/actions/workflows`”
+5. “ASP.NETconfiguration: Creating Debug Binary in `[](https://github.com/llvm/llvm-project/actions/workflows`”
+
diff --git a/llvm/docs/SegmentedStacks.md b/llvm/docs/SegmentedStacks.md
index a688320a9b0bc..a23541379612d 100644
--- a/llvm/docs/SegmentedStacks.md
+++ b/llvm/docs/SegmentedStacks.md
@@ -1,10 +1,6 @@
-========================
-Segmented Stacks in LLVM
-========================
+# Segmented Stacks in LLVM
-
-Introduction
-============
+## Introduction
Segmented stack allows stack space to be allocated incrementally than as a
monolithic chunk (of some worst case size) at thread initialization. This is
@@ -12,64 +8,61 @@ done by allocating stack blocks (henceforth called *stacklets*) and linking them
into a doubly linked list. The function prologue is responsible for checking if
the current stacklet has enough space for the function to execute; and if not,
call into the libgcc runtime to allocate more stack space. Segmented stacks are
-enabled with the ``"split-stack"`` attribute on LLVM functions.
+enabled with the `"split-stack"` attribute on LLVM functions.
-The runtime functionality is `already there in libgcc
-<http://gcc.gnu.org/wiki/SplitStacks>`_.
+The runtime functionality is [already there in libgcc](http://gcc.gnu.org/wiki/SplitStacks).
-Implementation Details
-======================
+## Implementation Details
-.. _allocating stacklets:
+(allocating-stacklets)=
-Allocating Stacklets
---------------------
+### Allocating Stacklets
As mentioned above, the function prologue checks if the current stacklet has
enough space. The current approach is to use a slot in the TCB to store the
current stack limit (minus the amount of space needed to allocate a new block) -
-this slot's offset is again dictated by ``libgcc``. The generated
+this slot's offset is again dictated by `libgcc`. The generated
assembly looks like this on x86-64:
-.. code-block:: text
-
- leaq -8(%rsp), %r10
- cmpq %fs:112, %r10
- jg .LBB0_2
+```text
+ leaq -8(%rsp), %r10
+ cmpq %fs:112, %r10
+ jg .LBB0_2
- # More stack space needs to be allocated
- movabsq $8, %r10 # The amount of space needed
- movabsq $0, %r11 # The total size of arguments passed on stack
- callq __morestack
- ret # The reason for this extra return is explained below
- .LBB0_2:
- # Usual prologue continues here
+ # More stack space needs to be allocated
+ movabsq $8, %r10 # The amount of space needed
+ movabsq $0, %r11 # The total size of arguments passed on stack
+ callq __morestack
+ ret # The reason for this extra return is explained below
+.LBB0_2:
+ # Usual prologue continues here
+```
The size of function arguments on the stack needs to be passed to
-``__morestack`` (this function is implemented in ``libgcc``) since that number
+`__morestack` (this function is implemented in `libgcc`) since that number
of bytes has to be copied from the previous stacklet to the current one. This is
so that SP (and FP) relative addressing of function arguments work as expected.
-The unusual ``ret`` is needed to have the function which made a call to
-``__morestack`` return correctly. ``__morestack``, instead of returning, calls
-into ``.LBB0_2``. This is possible since both, the size of the ``ret``
-instruction and the PC of call to ``__morestack`` are known. When the function
-body returns, control is transferred back to ``__morestack``. ``__morestack``
+The unusual `ret` is needed to have the function which made a call to
+`__morestack` return correctly. `__morestack`, instead of returning, calls
+into `.LBB0_2`. This is possible since both, the size of the `ret`
+instruction and the PC of call to `__morestack` are known. When the function
+body returns, control is transferred back to `__morestack`. `__morestack`
then de-allocates the new stacklet, restores the correct SP value, and does a
second return, which returns control to the correct caller.
-Variable Sized Allocas
-----------------------
+### Variable Sized Allocas
-The section on `allocating stacklets`_ automatically assumes that every stack
-frame will be of fixed size. However, LLVM allows the use of the ``llvm.alloca``
+The section on [allocating stacklets] automatically assumes that every stack
+frame will be of fixed size. However, LLVM allows the use of the `llvm.alloca`
intrinsic to allocate dynamically sized blocks of memory on the stack. When
faced with such a variable-sized alloca, code is generated to:
-* Check if the current stacklet has enough space. If yes, just bump the SP, like
+- Check if the current stacklet has enough space. If yes, just bump the SP, like
in the normal case.
-* If not, generate a call to ``libgcc``, which allocates the memory from the
+- If not, generate a call to `libgcc`, which allocates the memory from the
heap.
The memory allocated from the heap is linked into a list in the current
stacklet, and freed along with the same. This prevents a memory leak.
+
diff --git a/llvm/docs/StackMaps.md b/llvm/docs/StackMaps.md
index 5d58759d95fb8..2d07a0aaa2c3c 100644
--- a/llvm/docs/StackMaps.md
+++ b/llvm/docs/StackMaps.md
@@ -1,17 +1,13 @@
-===================================
-Stack maps and patch points in LLVM
-===================================
+# Stack maps and patch points in LLVM
-
-Definitions
-===========
+## Definitions
In this document we refer to the "runtime" collectively as all
components that serve as the LLVM client, including the LLVM IR
generator, object code consumer, and code patcher.
-A stack map records the location of ``live values`` at a particular
-instruction address. These ``live values`` do not refer to all the
+A stack map records the location of `live values` at a particular
+instruction address. These `live values` do not refer to all the
LLVM values live across the stack map. Instead, they are only the
values that the runtime requires to be live at this point. For
example, they may be the values the runtime will need to resume
@@ -19,7 +15,7 @@ program execution at that point independent of the compiled function
containing the stack map.
LLVM emits stack map data into the object code within a designated
-:ref:`stackmap-section`. This stack map data contains a record for
+{ref}`stackmap-section`. This stack map data contains a record for
each stack map. The record stores the stack map's instruction address
and contains an entry for each mapped value. Each entry encodes a
value's location as a register, stack offset, or constant.
@@ -29,10 +25,9 @@ patching a new instruction sequence at run time. Patch points look
much like calls to LLVM. They take arguments that follow a calling
convention and may return a value. They also imply stack map
generation, which allows the runtime to locate the patchpoint and
-find the location of ``live values`` at that point.
+find the location of `live values` at that point.
-Motivation
-==========
+## Motivation
This functionality is currently experimental but is potentially useful
in a variety of settings, the most obvious being a runtime (JIT)
@@ -42,15 +37,14 @@ optimizing the retrieval of properties in dynamically typed languages
such as JavaScript.
The intrinsics documented here are currently used by the JavaScript
-compiler within the open source WebKit project, see the `FTL JIT
-<https://trac.webkit.org/wiki/FTLJIT>`_, but they are designed to be
+compiler within the open source WebKit project, see the [FTL JIT](https://trac.webkit.org/wiki/FTLJIT), but they are designed to be
used whenever stack maps or code patching are needed. Because the
intrinsics have experimental status, compatibility across LLVM
releases is not guaranteed.
The stack map functionality described in this document is separate
from the functionality described in
-:ref:`stack-map`. `GCFunctionMetadata` provides the location of
+{ref}`stack-map`. `GCFunctionMetadata` provides the location of
pointers into a collected heap captured by the `GCRoot` intrinsic,
which can also be considered a "stack map". Unlike the stack maps
defined above, the `GCFunctionMetadata` stack map interface does not
@@ -60,64 +54,58 @@ stack map. The stack maps described here could potentially provide
richer information to a garbage collecting runtime, but that usage
will not be discussed in this document.
-Intrinsics
-==========
+## Intrinsics
The following two kinds of intrinsics can be used to implement stack
-maps and patch points: ``llvm.experimental.stackmap`` and
-``llvm.experimental.patchpoint``. Both kinds of intrinsics generate a
+maps and patch points: `llvm.experimental.stackmap` and
+`llvm.experimental.patchpoint`. Both kinds of intrinsics generate a
stack map record, and they both allow some form of code patching. They
-can be used independently (i.e. ``llvm.experimental.patchpoint``
+can be used independently (i.e. `llvm.experimental.patchpoint`
implicitly generates a stack map without the need for an additional
-call to ``llvm.experimental.stackmap``). The choice of which to use
+call to `llvm.experimental.stackmap`). The choice of which to use
depends on whether it is necessary to reserve space for code patching
and whether any of the intrinsic arguments should be lowered according
-to calling conventions. ``llvm.experimental.stackmap`` does not
+to calling conventions. `llvm.experimental.stackmap` does not
reserve any space, nor does it expect any call arguments. If the
runtime patches code at the stack map's address, it will destructively
overwrite the program text. This is unlike
-``llvm.experimental.patchpoint``, which reserves space for in-place
+`llvm.experimental.patchpoint`, which reserves space for in-place
patching without overwriting surrounding code. The
-``llvm.experimental.patchpoint`` intrinsic also lowers a specified
+`llvm.experimental.patchpoint` intrinsic also lowers a specified
number of arguments according to its calling convention. This allows
patched code to make in-place function calls without marshaling.
Each instance of one of these intrinsics generates a stack map record
-in the :ref:`stackmap-section`. The record includes an ID, allowing
+in the {ref}`stackmap-section`. The record includes an ID, allowing
the runtime to uniquely identify the stack map, and the offset within
the code from the beginning of the enclosing function.
-'``llvm.experimental.stackmap``' Intrinsic
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Syntax:
-"""""""
+### '`llvm.experimental.stackmap`' Intrinsic
-::
+#### Syntax:
- declare void
- @llvm.experimental.stackmap(i64 <id>, i32 <numShadowBytes>, ...)
+```
+declare void
+ @llvm.experimental.stackmap(i64 <id>, i32 <numShadowBytes>, ...)
+```
-Overview:
-"""""""""
+#### Overview:
-The '``llvm.experimental.stackmap``' intrinsic records the location of
+The '`llvm.experimental.stackmap`' intrinsic records the location of
specified values in the stack map without generating any code.
-Operands:
-"""""""""
+#### Operands:
The first operand is an ID to be encoded within the stack map. The
second operand is the number of shadow bytes following the
intrinsic. These first two operands should be immediate, e.g. cannot
be passed as variables. The variable number of operands that follow are
-the ``live values`` for which locations will be recorded in the stack map.
+the `live values` for which locations will be recorded in the stack map.
To use this intrinsic as a bare-bones stack map, with no code patching
support, the number of shadow bytes can be set to zero.
-Semantics:
-""""""""""
+#### Semantics:
The stack map intrinsic generates no code in place, unless nops are
needed to cover its shadow (see below). However, its offset from
@@ -131,8 +119,8 @@ record without checking uniqueness.
LLVM guarantees a shadow of instructions following the stack map's
instruction offset during which neither the end of the basic block nor
-another call to ``llvm.experimental.stackmap`` or
-``llvm.experimental.patchpoint`` may occur. This allows the runtime to
+another call to `llvm.experimental.stackmap` or
+`llvm.experimental.patchpoint` may occur. This allows the runtime to
patch the code at this point in response to an event triggered from
outside the code. The code for instructions following the stack map
may be emitted in the stack map's shadow, and these instructions may
@@ -143,106 +131,101 @@ the runtime does not need to consider this corner case.
For example, a stack map with 8-byte shadow:
-.. code-block:: llvm
-
- call void @runtime()
- call void (i64, i32, ...) @llvm.experimental.stackmap(i64 77, i32 8,
- ptr %ptr)
- %val = load i64, ptr %ptr
- %add = add i64 %val, 3
- ret i64 %add
+```llvm
+call void @runtime()
+call void (i64, i32, ...) @llvm.experimental.stackmap(i64 77, i32 8,
+ ptr %ptr)
+%val = load i64, ptr %ptr
+%add = add i64 %val, 3
+ret i64 %add
+```
May require one byte of nop-padding:
-.. code-block:: none
-
- 0x00 callq _runtime
- 0x05 nop <--- stack map address
- 0x06 movq (%rdi), %rax
- 0x07 addq $3, %rax
- 0x0a popq %rdx
- 0x0b ret <---- end of 8-byte shadow
+```none
+0x00 callq _runtime
+0x05 nop <--- stack map address
+0x06 movq (%rdi), %rax
+0x07 addq $3, %rax
+0x0a popq %rdx
+0x0b ret <---- end of 8-byte shadow
+```
Now, if the runtime needs to invalidate the compiled code, it may
patch 8 bytes of code at the stack map's address at follows:
-.. code-block:: none
-
- 0x00 callq _runtime
- 0x05 movl $0xffff, %rax <--- patched code at stack map address
- 0x0a callq *%rax <---- end of 8-byte shadow
+```none
+0x00 callq _runtime
+0x05 movl $0xffff, %rax <--- patched code at stack map address
+0x0a callq *%rax <---- end of 8-byte shadow
+```
This way, after the normal call to the runtime returns, the code will
execute a patched call to a special entry point that can rebuild a
stack frame from the values located by the stack map.
-'``llvm.experimental.patchpoint.*``' Intrinsic
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### '`llvm.experimental.patchpoint.*`' Intrinsic
-Syntax:
-"""""""
+#### Syntax:
-::
+```
+declare void
+ @llvm.experimental.patchpoint.void(i64 <id>, i32 <numBytes>,
+ ptr <target>, i32 <numArgs>, ...)
+declare i64
+ @llvm.experimental.patchpoint.i64(i64 <id>, i32 <numBytes>,
+ ptr <target>, i32 <numArgs>, ...)
+```
- declare void
- @llvm.experimental.patchpoint.void(i64 <id>, i32 <numBytes>,
- ptr <target>, i32 <numArgs>, ...)
- declare i64
- @llvm.experimental.patchpoint.i64(i64 <id>, i32 <numBytes>,
- ptr <target>, i32 <numArgs>, ...)
+#### Overview:
-Overview:
-"""""""""
-
-The '``llvm.experimental.patchpoint.*``' intrinsics creates a function
-call to the specified ``<target>`` and records the location of specified
+The '`llvm.experimental.patchpoint.*`' intrinsics creates a function
+call to the specified `<target>` and records the location of specified
values in the stack map.
-Operands:
-"""""""""
+#### Operands:
The first operand is an ID, the second operand is the number of bytes
reserved for the patchable region, the third operand is the target
address of a function (optionally null), and the fourth operand
specifies how many of the following variable operands are considered
function call arguments. The remaining variable number of operands are
-the ``live values`` for which locations will be recorded in the stack
+the `live values` for which locations will be recorded in the stack
map.
-Semantics:
-""""""""""
+#### Semantics:
The patch point intrinsic generates a stack map. It also emits a
-function call to the address specified by ``<target>`` if the address
+function call to the address specified by `<target>` if the address
is not a constant null. The function call and its arguments are
lowered according to the calling convention specified at the
intrinsic's callsite. Variants of the intrinsic with non-void return
type also return a value according to calling convention.
-On PowerPC, note that ``<target>`` must be the ABI function pointer for the
+On PowerPC, note that `<target>` must be the ABI function pointer for the
intended target of the indirect call. Specifically, when compiling for the
-ELF V1 ABI, ``<target>`` is the function-descriptor address normally used as
+ELF V1 ABI, `<target>` is the function-descriptor address normally used as
the C/C++ function-pointer representation.
Requesting zero patch point arguments is valid. In this case, all
variable operands are handled just like
-``llvm.experimental.stackmap.*``. The difference is that space will
+`llvm.experimental.stackmap.*`. The difference is that space will
still be reserved for patching, a call will be emitted, and a return
value is allowed.
The location of the arguments are not normally recorded in the stack
map because they are already fixed by the calling convention. The
-remaining ``live values`` will have their location recorded, which
+remaining `live values` will have their location recorded, which
could be a register, stack location, or constant. A special calling
convention has been introduced for use with stack maps, anyregcc,
which forces the arguments to be loaded into registers but allows
those register to be dynamically allocated. These argument registers
will have their register locations recorded in the stack map in
-addition to the remaining ``live values``.
+addition to the remaining `live values`.
-The patch point also emits nops to cover at least ``<numBytes>`` of
+The patch point also emits nops to cover at least `<numBytes>` of
instruction encoding space. Hence, the client must ensure that
-``<numBytes>`` is enough to encode a call to the target address on the
+`<numBytes>` is enough to encode a call to the target address on the
supported targets. If the call target is constant null, then there is
no minimum requirement. A zero-byte null target patchpoint is
valid.
@@ -254,111 +237,111 @@ patching is not allowed. The runtime must patch all reserved bytes,
padding with nops if necessary.
This example shows a patch point reserving 15 bytes, with one argument
-in $rdi, and a return value in $rax per native calling convention:
-
-.. code-block:: llvm
+in \$rdi, and a return value in \$rax per native calling convention:
- %target = inttoptr i64 -281474976710654 to ptr
- %val = call i64 (i64, i32, ...)
- @llvm.experimental.patchpoint.i64(i64 78, i32 15,
- ptr %target, i32 1, ptr %ptr)
- %add = add i64 %val, 3
- ret i64 %add
+```llvm
+%target = inttoptr i64 -281474976710654 to ptr
+%val = call i64 (i64, i32, ...)
+ @llvm.experimental.patchpoint.i64(i64 78, i32 15,
+ ptr %target, i32 1, ptr %ptr)
+%add = add i64 %val, 3
+ret i64 %add
+```
May generate:
-.. code-block:: none
-
- 0x00 movabsq $0xffff000000000002, %r11 <--- patch point address
- 0x0a callq *%r11
- 0x0d nop
- 0x0e nop <--- end of reserved 15-bytes
- 0x0f addq $0x3, %rax
- 0x10 movl %rax, 8(%rsp)
+```none
+0x00 movabsq $0xffff000000000002, %r11 <--- patch point address
+0x0a callq *%r11
+0x0d nop
+0x0e nop <--- end of reserved 15-bytes
+0x0f addq $0x3, %rax
+0x10 movl %rax, 8(%rsp)
+```
Note that no stack map locations will be recorded. If the patched code
sequence does not need arguments fixed to specific calling convention
-registers, then the ``anyregcc`` convention may be used:
-
-.. code-block:: none
+registers, then the `anyregcc` convention may be used:
- %val = call anyregcc @llvm.experimental.patchpoint(i64 78, i32 15,
- ptr %target, i32 1,
- ptr %ptr)
+```none
+%val = call anyregcc @llvm.experimental.patchpoint(i64 78, i32 15,
+ ptr %target, i32 1,
+ ptr %ptr)
+```
The stack map now indicates the location of the %ptr argument and
return value:
-.. code-block:: none
-
- Stack Map: ID=78, Loc0=%r9 Loc1=%r8
+```none
+Stack Map: ID=78, Loc0=%r9 Loc1=%r8
+```
The patch code sequence may now use the argument that happened to be
allocated in %r8 and return a value allocated in %r9:
-.. code-block:: none
-
- 0x00 movslq 4(%r8) %r9 <--- patched code at patch point address
- 0x03 nop
- ...
- 0x0e nop <--- end of reserved 15-bytes
- 0x0f addq $0x3, %r9
- 0x10 movl %r9, 8(%rsp)
+```none
+0x00 movslq 4(%r8) %r9 <--- patched code at patch point address
+0x03 nop
+...
+0x0e nop <--- end of reserved 15-bytes
+0x0f addq $0x3, %r9
+0x10 movl %r9, 8(%rsp)
+```
-.. _stackmap-format:
+(stackmap-format)=
-Stack Map Format
-================
+## Stack Map Format
The existence of a stack map or patch point intrinsic within an LLVM
-Module forces code emission to create a :ref:`stackmap-section`. The
+Module forces code emission to create a {ref}`stackmap-section`. The
format of this section follows:
-.. code-block:: none
-
- Header {
- uint8 : Stack Map Version (current version is 3)
+```none
+Header {
+ uint8 : Stack Map Version (current version is 3)
+ uint8 : Reserved (expected to be 0)
+ uint16 : Reserved (expected to be 0)
+}
+uint32 : NumFunctions
+uint32 : NumConstants
+uint32 : NumRecords
+StkSizeRecord[NumFunctions] {
+ uint64 : Function Address
+ uint64 : Stack Size (or UINT64_MAX if not statically known)
+ uint64 : Record Count
+}
+Constants[NumConstants] {
+ uint64 : LargeConstant
+}
+StkMapRecord[NumRecords] {
+ uint64 : PatchPoint ID
+ uint32 : Instruction Offset
+ uint16 : Reserved (record flags)
+ uint16 : NumLocations
+ Location[NumLocations] {
+ uint8 : Register | Direct | Indirect | Constant | ConstantIndex
uint8 : Reserved (expected to be 0)
+ uint16 : Location Size
+ uint16 : Dwarf RegNum
uint16 : Reserved (expected to be 0)
+ int32 : Offset or SmallConstant
}
- uint32 : NumFunctions
- uint32 : NumConstants
- uint32 : NumRecords
- StkSizeRecord[NumFunctions] {
- uint64 : Function Address
- uint64 : Stack Size (or UINT64_MAX if not statically known)
- uint64 : Record Count
- }
- Constants[NumConstants] {
- uint64 : LargeConstant
- }
- StkMapRecord[NumRecords] {
- uint64 : PatchPoint ID
- uint32 : Instruction Offset
- uint16 : Reserved (record flags)
- uint16 : NumLocations
- Location[NumLocations] {
- uint8 : Register | Direct | Indirect | Constant | ConstantIndex
- uint8 : Reserved (expected to be 0)
- uint16 : Location Size
- uint16 : Dwarf RegNum
- uint16 : Reserved (expected to be 0)
- int32 : Offset or SmallConstant
- }
- uint32 : Padding (only if required to align to 8 byte)
- uint16 : Padding
- uint16 : NumLiveOuts
- LiveOuts[NumLiveOuts]
- uint16 : Dwarf RegNum
- uint8 : Reserved
- uint8 : Size in Bytes
- }
- uint32 : Padding (only if required to align to 8 byte)
+ uint32 : Padding (only if required to align to 8 byte)
+ uint16 : Padding
+ uint16 : NumLiveOuts
+ LiveOuts[NumLiveOuts]
+ uint16 : Dwarf RegNum
+ uint8 : Reserved
+ uint8 : Size in Bytes
}
+ uint32 : Padding (only if required to align to 8 byte)
+}
+```
The first byte of each location encodes a type that indicates how to
-interpret the ``RegNum`` and ``Offset`` fields as follows:
+interpret the `RegNum` and `Offset` fields as follows:
+```{eval-rst}
======== ========== =================== ===========================
Encoding Type Value Description
-------- ---------- ------------------- ---------------------------
@@ -368,18 +351,19 @@ Encoding Type Value Description
0x4 Constant Offset Small constant
0x5 ConstIndex Constants[Offset] Large constant
======== ========== =================== ===========================
+```
In the common case, a value is available in a register, and the
-``Offset`` field will be zero. Values spilled to the stack are encoded
-as ``Indirect`` locations. The runtime must load those values from a
-stack address, typically in the form ``[BP + Offset]``. If an
-``alloca`` value is passed directly to a stack map intrinsic, then
+`Offset` field will be zero. Values spilled to the stack are encoded
+as `Indirect` locations. The runtime must load those values from a
+stack address, typically in the form `[BP + Offset]`. If an
+`alloca` value is passed directly to a stack map intrinsic, then
LLVM may fold the frame index into the stack map as an optimization to
avoid allocating a register or stack slot. These frame indices will be
-encoded as ``Direct`` locations in the form ``BP + Offset``. LLVM may
+encoded as `Direct` locations in the form `BP + Offset`. LLVM may
also optimize constants by emitting them directly in the stack map,
-either in the ``Offset`` of a ``Constant`` location or in the constant
-pool, referred to by ``ConstantIndex`` locations.
+either in the `Offset` of a `Constant` location or in the constant
+pool, referred to by `ConstantIndex` locations.
At each callsite, a "liveout" register list is also recorded. These
are the registers that are live across the stackmap and therefore must
@@ -391,11 +375,11 @@ Each entry in the liveout register list contains a DWARF register
number and size in bytes. The stackmap format deliberately omits
specific subregister information. Instead the runtime must interpret
this information conservatively. For example, if the stackmap reports
-one byte at ``%rax``, then the value may be in either ``%al`` or
-``%ah``. It doesn't matter in practice, because the runtime will
-simply save ``%rax``. However, if the stackmap reports 16 bytes at
-``%ymm0``, then the runtime can safely optimize by saving only
-``%xmm0``.
+one byte at `%rax`, then the value may be in either `%al` or
+`%ah`. It doesn't matter in practice, because the runtime will
+simply save `%rax`. However, if the stackmap reports 16 bytes at
+`%ymm0`, then the runtime can safely optimize by saving only
+`%xmm0`.
The stack map format is a contract between an LLVM SVN revision and
the runtime. It is currently experimental and may change in the short
@@ -411,28 +395,26 @@ Stackmap support is currently only implemented for 64-bit
platforms. However, a 32-bit implementation should be able to use the
same format with an insignificant amount of wasted space.
-.. _stackmap-section:
+(stackmap-section)=
-Stack Map Section
-^^^^^^^^^^^^^^^^^
+### Stack Map Section
A JIT compiler can easily access this section by providing its own
memory manager via the LLVM C API
-``LLVMCreateSimpleMCJITMemoryManager()``. When creating the memory
+`LLVMCreateSimpleMCJITMemoryManager()`. When creating the memory
manager, the JIT provides a callback:
-``LLVMMemoryManagerAllocateDataSectionCallback()``. When LLVM creates
+`LLVMMemoryManagerAllocateDataSectionCallback()`. When LLVM creates
this section, it invokes the callback and passes the section name. The
JIT can record the in-memory address of the section at this time and
later parse it to recover the stack map data.
For MachO (e.g. on Darwin), the stack map section name is
-"__llvm_stackmaps". The segment name is "__LLVM_STACKMAPS".
+"\_\_llvm_stackmaps". The segment name is "\_\_LLVM_STACKMAPS".
For ELF (e.g. on Linux), the stack map section name is
-".llvm_stackmaps". The segment name is "__LLVM_STACKMAPS".
+".llvm_stackmaps". The segment name is "\_\_LLVM_STACKMAPS".
-Stack Map Usage
-===============
+## Stack Map Usage
The stack map support described in this document can be used to
precisely determine the location of values at a specific position in
@@ -474,10 +456,9 @@ also allow meta-data to be added to the intrinsic call to express
aliasing, thereby allowing optimizations to hoist certain loads above
stack maps.
-Direct Stack Map Entries
-^^^^^^^^^^^^^^^^^^^^^^^^
+### Direct Stack Map Entries
-As shown in :ref:`stackmap-section`, a Direct stack map location
+As shown in {ref}`stackmap-section`, a Direct stack map location
records the address of frame index. This address is itself the value
that the runtime requested. This differs from Indirect locations,
which refer to a stack locations from which the requested values must
@@ -486,11 +467,11 @@ while Indirect locations handle register spills.
For example:
-.. code-block:: none
-
- entry:
- %a = alloca i64...
- llvm.experimental.stackmap(i64 <ID>, i32 <shadowBytes>, ptr %a)
+```none
+entry:
+ %a = alloca i64...
+ llvm.experimental.stackmap(i64 <ID>, i32 <shadowBytes>, ptr %a)
+```
The runtime can determine this alloca's relative location on the
stack immediately after compilation, or at any time thereafter. This
@@ -505,11 +486,10 @@ transformations must not substitute the alloca with any intervening
value. This can be verified by the runtime simply by checking that the
stack map's location is a Direct location type.
-
-Supported Architectures
-=======================
+## Supported Architectures
Support for StackMap generation and the related intrinsics requires
-some code for each backend. Today, only a subset of LLVM's backends
-are supported. The currently supported architectures are X86_64,
+some code for each backend. Today, only a subset of LLVM's backends
+are supported. The currently supported architectures are X86_64,
PowerPC, AArch64 and SystemZ.
+
diff --git a/llvm/docs/Statepoints.md b/llvm/docs/Statepoints.md
index e4bc56dd58b95..5a39f643e0f00 100644
--- a/llvm/docs/Statepoints.md
+++ b/llvm/docs/Statepoints.md
@@ -1,49 +1,44 @@
-=====================================
-Garbage Collection Safepoints in LLVM
-=====================================
+# Garbage Collection Safepoints in LLVM
-
-Status
-=======
+## Status
This document describes a set of extensions to LLVM to support garbage
-collection. By now, these mechanisms are well proven with commercial java
+collection. By now, these mechanisms are well proven with commercial java
implementation with a fully relocating collector having shipped using them.
There are a couple places where bugs might still linger; these are called out
below.
They are still listed as "experimental" to indicate that no forward or backward
-compatibility guarantees are offered across versions. If your use case is such
+compatibility guarantees are offered across versions. If your use case is such
that you need some form of forward compatibility guarantee, please raise the
issue on the llvm-dev mailing list.
LLVM still supports an alternate mechanism for conservative garbage collection
-support using the ``gcroot`` intrinsic. The ``gcroot`` mechanism is mostly of
+support using the `gcroot` intrinsic. The `gcroot` mechanism is mostly of
historical interest at this point with one exception - its implementation of
shadow stacks has been used successfully by a number of language frontends and
is still supported.
-Overview & Core Concepts
-========================
+## Overview & Core Concepts
To collect dead objects, garbage collectors must be able to identify
any references to objects contained within executing code, and,
-depending on the collector, potentially update them. The collector
+depending on the collector, potentially update them. The collector
does not need this information at all points in code - that would make
the problem much harder - but only at well-defined points in the
execution known as 'safepoints' For most collectors, it is sufficient
-to track at least one copy of each unique pointer value. However, for
+to track at least one copy of each unique pointer value. However, for
a collector which wishes to relocate objects directly reachable from
running code, a higher standard is required.
One additional challenge is that the compiler may compute intermediate
results ("derived pointers") which point outside of the allocation or
-even into the middle of another allocation. The eventual use of this
+even into the middle of another allocation. The eventual use of this
intermediate value must yield an address within the bounds of the
allocation, but such "exterior derived pointers" may be visible to the
-collector. Given this, a garbage collector can not safely rely on the
+collector. Given this, a garbage collector can not safely rely on the
runtime value of an address to indicate the object it is associated
-with. If the garbage collector wishes to move any object, the
+with. If the garbage collector wishes to move any object, the
compiler must provide a mapping, for each pointer, to an indication of
its allocation.
@@ -51,97 +46,93 @@ To simplify the interaction between a collector and the compiled code,
most garbage collectors are organized in terms of three abstractions:
load barriers, store barriers, and safepoints.
-#. A load barrier is a bit of code executed immediately after the
+1. A load barrier is a bit of code executed immediately after the
machine load instruction, but before any use of the value loaded.
Depending on the collector, such a barrier may be needed for all
loads, merely loads of a particular type (in the original source
language), or none at all.
-
-#. Analogously, a store barrier is a code fragment that runs
+2. Analogously, a store barrier is a code fragment that runs
immediately before the machine store instruction, but after the
- computation of the value stored. The most common use of a store
+ computation of the value stored. The most common use of a store
barrier is to update a 'card table' in a generational garbage
collector.
-
-#. A safepoint is a location at which pointers visible to the compiled
+3. A safepoint is a location at which pointers visible to the compiled
code (i.e. currently in registers or on the stack) are allowed to
- change. After the safepoint completes, the actual pointer value
+ change. After the safepoint completes, the actual pointer value
may differ, but the 'object' (as seen by the source language)
pointed to will not.
- Note that the term 'safepoint' is somewhat overloaded. It refers to
- both the location at which the machine state is parsable and the
- coordination protocol involved in bring application threads to a
- point at which the collector can safely use that information. The
- term "statepoint" as used in this document refers exclusively to the
- former.
+> Note that the term 'safepoint' is somewhat overloaded. It refers to
+> both the location at which the machine state is parsable and the
+> coordination protocol involved in bring application threads to a
+> point at which the collector can safely use that information. The
+> term "statepoint" as used in this document refers exclusively to the
+> former.
This document focuses on the last item - compiler support for
-safepoints in generated code. We will assume that an outside
-mechanism has decided where to place safepoints. From our
-perspective, all safepoints will be function calls. To support
+safepoints in generated code. We will assume that an outside
+mechanism has decided where to place safepoints. From our
+perspective, all safepoints will be function calls. To support
relocation of objects directly reachable from values in compiled code,
the collector must be able to:
-#. identify every copy of a pointer (including copies introduced by
+1. identify every copy of a pointer (including copies introduced by
the compiler itself) at the safepoint,
-#. identify which object each pointer relates to, and
-#. potentially update each of those copies.
+2. identify which object each pointer relates to, and
+3. potentially update each of those copies.
This document describes the mechanism by which an LLVM based compiler
can provide this information to a language runtime/collector, and
ensure that all pointers can be read and updated if desired.
-Abstract Machine Model
-^^^^^^^^^^^^^^^^^^^^^^^
+### Abstract Machine Model
At a high level, LLVM has been extended to support compiling to an abstract
machine which extends the actual target with a non-integral pointer type
-suitable for representing a garbage collected reference to an object. In
+suitable for representing a garbage collected reference to an object. In
particular, such non-integral pointer type have no defined mapping to an
-integer representation. This semantic quirk allows the runtime to pick a
+integer representation. This semantic quirk allows the runtime to pick a
integer mapping for each point in the program allowing relocations of objects
without visible effects.
-This high level abstract machine model is used for most of the optimizer. As
+This high level abstract machine model is used for most of the optimizer. As
a result, transform passes do not need to be extended to look through explicit
-relocation sequence. Before starting code generation, we switch
-representations to an explicit form. The exact location chosen for lowering
+relocation sequence. Before starting code generation, we switch
+representations to an explicit form. The exact location chosen for lowering
is an implementation detail.
Note that most of the value of the abstract machine model comes for collectors
-which need to model potentially relocatable objects. For a compiler which
+which need to model potentially relocatable objects. For a compiler which
supports only a non-relocating collector, you may wish to consider starting
with the fully explicit form.
Warning: There is one currently known semantic hole in the definition of
-non-integral pointers which has not been addressed upstream. To work around
+non-integral pointers which has not been addressed upstream. To work around
this, you need to disable speculation of loads unless the memory type
-(non-integral pointer vs anything else) is known to unchanged. That is, it is
+(non-integral pointer vs anything else) is known to unchanged. That is, it is
not safe to speculate a load if doing causes a non-integral pointer value to
-be loaded as any other type or vice versa. In practice, this restriction is
+be loaded as any other type or vice versa. In practice, this restriction is
well isolated to isSafeToSpeculate in ValueTracking.cpp.
-Explicit Representation
-^^^^^^^^^^^^^^^^^^^^^^^
+### Explicit Representation
A frontend could directly generate this low level explicit form, but
-doing so may inhibit optimization. Instead, it is recommended that
+doing so may inhibit optimization. Instead, it is recommended that
compilers with relocating collectors target the abstract machine model just
described.
The heart of the explicit approach is to construct (or rewrite) the IR in a
manner where the possible updates performed by the garbage collector are
-explicitly visible in the IR. Doing so requires that we:
+explicitly visible in the IR. Doing so requires that we:
-#. create a new SSA value for each potentially relocated pointer, and
+1. create a new SSA value for each potentially relocated pointer, and
ensure that no uses of the original (non relocated) value is
reachable after the safepoint,
-#. specify the relocation in a way which is opaque to the compiler to
+2. specify the relocation in a way which is opaque to the compiler to
ensure that the optimizer can not introduce new uses of an
unrelocated value after a statepoint. This prevents the optimizer
from performing unsound optimizations.
-#. recording a mapping of live pointers (and the allocation they're
+3. recording a mapping of live pointers (and the allocation they're
associated with) for each statepoint.
At the most abstract level, inserting a safepoint can be thought of as
@@ -150,46 +141,46 @@ function which both calls the original target of the call, returns
its result, and returns updated values for any live pointers to
garbage collected objects.
- Note that the task of identifying all live pointers to garbage
- collected values, transforming the IR to expose a pointer giving the
- base object for every such live pointer, and inserting all the
- intrinsics correctly is explicitly out of scope for this document.
- The recommended approach is to use the :ref:`utility passes
- <statepoint-utilities>` described below.
+> Note that the task of identifying all live pointers to garbage
+> collected values, transforming the IR to expose a pointer giving the
+> base object for every such live pointer, and inserting all the
+> intrinsics correctly is explicitly out of scope for this document.
+> The recommended approach is to use the {ref}`utility passes
+> <statepoint-utilities>` described below.
This abstract function call is concretely represented by a sequence of
intrinsic calls known collectively as a "statepoint relocation sequence".
Let's consider a simple call in LLVM IR:
-.. code-block:: llvm
-
- declare void @foo()
- define ptr addrspace(1) @test1(ptr addrspace(1) %obj)
- gc "statepoint-example" {
- call void @foo()
- ret ptr addrspace(1) %obj
- }
+```llvm
+declare void @foo()
+define ptr addrspace(1) @test1(ptr addrspace(1) %obj)
+ gc "statepoint-example" {
+ call void @foo()
+ ret ptr addrspace(1) %obj
+}
+```
Depending on our language we may need to allow a safepoint during the execution
-of ``foo``. If so, we need to let the collector update local values in the
-current frame. If we don't, we'll be accessing a potential invalid reference
+of `foo`. If so, we need to let the collector update local values in the
+current frame. If we don't, we'll be accessing a potential invalid reference
once we eventually return from the call.
-In this example, we need to relocate the SSA value ``%obj``. Since we can't
-actually change the value in the SSA value ``%obj``, we need to introduce a new
-SSA value ``%obj.relocated`` which represents the potentially changed value of
-``%obj`` after the safepoint and update any following uses appropriately. The
+In this example, we need to relocate the SSA value `%obj`. Since we can't
+actually change the value in the SSA value `%obj`, we need to introduce a new
+SSA value `%obj.relocated` which represents the potentially changed value of
+`%obj` after the safepoint and update any following uses appropriately. The
resulting relocation sequence is:
-.. code-block:: llvm
-
- define ptr addrspace(1) @test(ptr addrspace(1) %obj)
- gc "statepoint-example" {
- %safepoint = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, ptr elementtype(void ()) @foo, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %obj)]
- %obj.relocated = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint, i32 0, i32 0)
- ret ptr addrspace(1) %obj.relocated
- }
+```llvm
+define ptr addrspace(1) @test(ptr addrspace(1) %obj)
+ gc "statepoint-example" {
+ %safepoint = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, ptr elementtype(void ()) @foo, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %obj)]
+ %obj.relocated = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint, i32 0, i32 0)
+ ret ptr addrspace(1) %obj.relocated
+}
+```
Ideally, this sequence would have been represented as a M argument, N
return value function (where M is the number of values being
@@ -198,96 +189,94 @@ value + each relocated value), but LLVM does not easily support such a
representation.
Instead, the statepoint intrinsic marks the actual site of the
-safepoint or statepoint. The statepoint returns a token value (which
-exists only at compile time). To get back the original return value
-of the call, we use the ``gc.result`` intrinsic. To get the relocation
-of each pointer in turn, we use the ``gc.relocate`` intrinsic with the
-appropriate index. Note that both the ``gc.relocate`` and ``gc.result`` are
-tied to the statepoint. The combination forms a "statepoint relocation
+safepoint or statepoint. The statepoint returns a token value (which
+exists only at compile time). To get back the original return value
+of the call, we use the `gc.result` intrinsic. To get the relocation
+of each pointer in turn, we use the `gc.relocate` intrinsic with the
+appropriate index. Note that both the `gc.relocate` and `gc.result` are
+tied to the statepoint. The combination forms a "statepoint relocation
sequence" and represents the entirety of a parseable call or 'statepoint'.
When lowered, this example would generate the following x86 assembly:
-.. code-block:: gas
-
- .globl test1
- .align 16, 0x90
- pushq %rax
- callq foo
- .Ltmp1:
- movq (%rsp), %rax # This load is redundant (oops!)
- popq %rdx
- retq
+```gas
+ .globl test1
+ .align 16, 0x90
+ pushq %rax
+ callq foo
+.Ltmp1:
+ movq (%rsp), %rax # This load is redundant (oops!)
+ popq %rdx
+ retq
+```
Each of the potentially relocated values has been spilled to the
stack, and a record of that location has been recorded to the
-:ref:`Stack Map section <stackmap-section>`. If the garbage collector
+{ref}`Stack Map section <stackmap-section>`. If the garbage collector
needs to update any of these pointers during the call, it knows
exactly what to change.
The relevant parts of the StackMap section for our example are:
-.. code-block:: gas
-
- # This describes the call site
- # Stack Maps: callsite 2882400000
- .quad 2882400000
- .long .Ltmp1-test1
- .short 0
- # .. 8 entries skipped ..
- # This entry describes the spill slot which is directly addressable
- # off RSP with offset 0. Given the value was spilled with a pushq,
- # that makes sense.
- # Stack Maps: Loc 8: Direct RSP [encoding: .byte 2, .byte 8, .short 7, .int 0]
- .byte 2
- .byte 8
- .short 7
- .long 0
-
-This example was taken from the tests for the :ref:`RewriteStatepointsForGC`
-utility pass. As such, its full StackMap can be easily examined with the
+```gas
+# This describes the call site
+# Stack Maps: callsite 2882400000
+ .quad 2882400000
+ .long .Ltmp1-test1
+ .short 0
+# .. 8 entries skipped ..
+# This entry describes the spill slot which is directly addressable
+# off RSP with offset 0. Given the value was spilled with a pushq,
+# that makes sense.
+# Stack Maps: Loc 8: Direct RSP [encoding: .byte 2, .byte 8, .short 7, .int 0]
+ .byte 2
+ .byte 8
+ .short 7
+ .long 0
+```
+
+This example was taken from the tests for the {ref}`RewriteStatepointsForGC`
+utility pass. As such, its full StackMap can be easily examined with the
following command.
-.. code-block:: bash
+```bash
+opt -rewrite-statepoints-for-gc test/Transforms/RewriteStatepointsForGC/basics.ll -S | llc -debug-only=stackmaps
+```
- opt -rewrite-statepoints-for-gc test/Transforms/RewriteStatepointsForGC/basics.ll -S | llc -debug-only=stackmaps
-
-Simplifications for Non-Relocating GCs
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Simplifications for Non-Relocating GCs
Some of the complexity in the previous example is unnecessary for a
-non-relocating collector. While a non-relocating collector still needs the
+non-relocating collector. While a non-relocating collector still needs the
information about which location contain live references, it doesn't need to
-represent explicit relocations. As such, the previously described explicit
-lowering can be simplified to remove all of the ``gc.relocate`` intrinsic
+represent explicit relocations. As such, the previously described explicit
+lowering can be simplified to remove all of the `gc.relocate` intrinsic
calls and leave uses in terms of the original reference value.
Here's the explicit lowering for the previous example for a non-relocating
collector:
-.. code-block:: llvm
-
- define void @manual_frame(ptr %a, ptr %b) gc "statepoint-example" {
- %alloca = alloca ptr
- %allocb = alloca ptr
- store ptr %a, ptr %alloca
- store ptr %b, ptr %allocb
- call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr %alloca, ptr %allocb)]
- ret void
- }
+```llvm
+define void @manual_frame(ptr %a, ptr %b) gc "statepoint-example" {
+ %alloca = alloca ptr
+ %allocb = alloca ptr
+ store ptr %a, ptr %alloca
+ store ptr %b, ptr %allocb
+ call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr %alloca, ptr %allocb)]
+ ret void
+}
+```
-Recording On Stack Regions
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Recording On Stack Regions
In addition to the explicit relocation form previously described, the
statepoint infrastructure also allows the listing of allocas within the gc
-pointer list. Allocas can be listed with or without additional explicit gc
+pointer list. Allocas can be listed with or without additional explicit gc
pointer values and relocations.
An alloca in the gc region of the statepoint operand list will cause the
address of the stack region to be listed in the stackmap for the statepoint.
-This mechanism can be used to describe explicit spill slots if desired. It
+This mechanism can be used to describe explicit spill slots if desired. It
then becomes the generator's responsibility to ensure that values are
spill/filled to/from the alloca as needed on either side of the safepoint.
Note that there is no way to indicate a corresponding base pointer for such
@@ -300,43 +289,41 @@ references provided that the collector can map from the location on the
stack to a heap map describing the internal layout of the references the
collector needs to process.
-WARNING: At the moment, this alternate form is not well exercised. It is
+WARNING: At the moment, this alternate form is not well exercised. It is
recommended to use this with caution and expect to have to fix a few bugs.
In particular, the RewriteStatepointsForGC utility pass does not do
anything for allocas today.
-Base & Derived Pointers
-^^^^^^^^^^^^^^^^^^^^^^^
+### Base & Derived Pointers
A "base pointer" is one which points to the starting address of an allocation
-(object). A "derived pointer" is one which is offset from a base pointer by
-some amount. When relocating objects, a garbage collector needs to be able
+(object). A "derived pointer" is one which is offset from a base pointer by
+some amount. When relocating objects, a garbage collector needs to be able
to relocate each derived pointer associated with an allocation to the same
offset from the new address.
"Interior derived pointers" remain within the bounds of the allocation
-they're associated with. As a result, the base object can be found at
+they're associated with. As a result, the base object can be found at
runtime provided the bounds of allocations are known to the runtime system.
"Exterior derived pointers" are outside the bounds of the associated object;
-they may even fall within *another* allocations address range. As a result,
+they may even fall within *another* allocations address range. As a result,
there is no way for a garbage collector to determine which allocation they
are associated with at runtime and compiler support is needed.
-The ``gc.relocate`` intrinsic supports an explicit operand for describing the
-allocation associated with a derived pointer. This operand is frequently
+The `gc.relocate` intrinsic supports an explicit operand for describing the
+allocation associated with a derived pointer. This operand is frequently
referred to as the base operand, but does not strictly speaking have to be
a base pointer, but it does need to lie within the bounds of the associated
-allocation. Some collectors may require that the operand be an actual base
+allocation. Some collectors may require that the operand be an actual base
pointer rather than merely an internal derived pointer. Note that during
lowering both the base and derived pointer operands are required to be live
over the associated call safepoint even if the base is otherwise unused
afterwards.
-.. _gc_transition_args:
+(gc-transition-args)=
-GC Transitions
-^^^^^^^^^^^^^^^^^^
+### GC Transitions
As a practical consideration, many garbage-collected systems allow code that is
collector-aware ("managed code") to call code that is not collector-aware
@@ -349,63 +336,63 @@ statepoint may be marked as a GC transition, and data that is necessary to
perform the transition (if any) may be provided as additional arguments to the
statepoint.
- Note that although in many cases statepoints may be inferred to be GC
- transitions based on the function symbols involved (e.g. a call from a
- function with GC strategy "foo" to a function with GC strategy "bar"),
- indirect calls that are also GC transitions must also be supported. This
- requirement is the driving force behind the decision to require that GC
- transitions are explicitly marked.
+> Note that although in many cases statepoints may be inferred to be GC
+> transitions based on the function symbols involved (e.g. a call from a
+> function with GC strategy "foo" to a function with GC strategy "bar"),
+> indirect calls that are also GC transitions must also be supported. This
+> requirement is the driving force behind the decision to require that GC
+> transitions are explicitly marked.
-Let's revisit the sample given above, this time treating the call to ``@foo``
+Let's revisit the sample given above, this time treating the call to `@foo`
as a GC transition. Depending on our target, the transition code may need to
access some extra state in order to inform the collector of the transition.
Let's assume a hypothetical GC--somewhat unimaginatively named "hypothetical-gc"
--that requires that a TLS variable must be written to before and after a call
to unmanaged code. The resulting relocation sequence is:
-.. code-block:: llvm
-
- @flag = thread_local global i32 0, align 4
+```llvm
+ at flag = thread_local global i32 0, align 4
- define i8 addrspace(1)* @test1(i8 addrspace(1) *%obj)
- gc "hypothetical-gc" {
+define i8 addrspace(1)* @test1(i8 addrspace(1) *%obj)
+ gc "hypothetical-gc" {
- %0 = call token (i64, i32, void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 1, i32* @Flag, i32 0, i8 addrspace(1)* %obj)
- %obj.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %0, i32 7, i32 7)
- ret i8 addrspace(1)* %obj.relocated
- }
+ %0 = call token (i64, i32, void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @foo, i32 0, i32 1, i32* @Flag, i32 0, i8 addrspace(1)* %obj)
+ %obj.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %0, i32 7, i32 7)
+ ret i8 addrspace(1)* %obj.relocated
+}
+```
During lowering, this will result in an instruction selection DAG that looks
something like:
-::
-
- CALLSEQ_START
- ...
- GC_TRANSITION_START (lowered i32 *@Flag), SRCVALUE i32* Flag
- STATEPOINT
- GC_TRANSITION_END (lowered i32 *@Flag), SRCVALUE i32 *Flag
- ...
- CALLSEQ_END
+```
+CALLSEQ_START
+...
+GC_TRANSITION_START (lowered i32 *@Flag), SRCVALUE i32* Flag
+STATEPOINT
+GC_TRANSITION_END (lowered i32 *@Flag), SRCVALUE i32 *Flag
+...
+CALLSEQ_END
+```
In order to generate the necessary transition code, the backend for each target
-supported by "hypothetical-gc" must be modified to lower ``GC_TRANSITION_START``
-and ``GC_TRANSITION_END`` nodes appropriately when the "hypothetical-gc"
+supported by "hypothetical-gc" must be modified to lower `GC_TRANSITION_START`
+and `GC_TRANSITION_END` nodes appropriately when the "hypothetical-gc"
strategy is in use for a particular function. Assuming that such lowering has
been added for X86, the generated assembly would be:
-.. code-block:: gas
-
- .globl test1
- .align 16, 0x90
- pushq %rax
- movl $1, %fs:Flag at TPOFF
- callq foo
- movl $0, %fs:Flag at TPOFF
- .Ltmp1:
- movq (%rsp), %rax # This load is redundant (oops!)
- popq %rdx
- retq
+```gas
+ .globl test1
+ .align 16, 0x90
+ pushq %rax
+ movl $1, %fs:Flag at TPOFF
+ callq foo
+ movl $0, %fs:Flag at TPOFF
+.Ltmp1:
+ movq (%rsp), %rax # This load is redundant (oops!)
+ popq %rdx
+ retq
+```
Note that the design as presented above is not fully implemented: in particular,
strategy-specific lowering is not present, and all GC transitions are emitted as
@@ -413,227 +400,221 @@ as single no-op before and after the call instruction. These no-ops are often
removed by the backend during dead machine instruction elimination.
Before the abstract machine model is lowered to the explicit statepoint model
-of relocations by the :ref:`RewriteStatepointsForGC` pass it is possible for
+of relocations by the {ref}`RewriteStatepointsForGC` pass it is possible for
any derived pointer to get its base pointer and offset from the base pointer
-by using the ``gc.get.pointer.base`` and the ``gc.get.pointer.offset``
+by using the `gc.get.pointer.base` and the `gc.get.pointer.offset`
intrinsics respectively. These intrinsics are inlined by the
-:ref:`RewriteStatepointsForGC` pass and must not be used after this pass.
+{ref}`RewriteStatepointsForGC` pass and must not be used after this pass.
+(statepoint-stackmap-format)=
-.. _statepoint-stackmap-format:
-
-Stack Map Format
-================
+## Stack Map Format
Locations for each pointer value which may need read and/or updated by
the runtime or collector are provided in a separate section of the
generated object file as specified in the PatchPoint documentation.
This special section is encoded per the
-:ref:`Stack Map format <stackmap-format>`.
+{ref}`Stack Map format <stackmap-format>`.
The general expectation is that a JIT compiler will parse and discard this
-format; it is not particularly memory efficient. If you need an alternate
+format; it is not particularly memory efficient. If you need an alternate
format (e.g. for an ahead of time compiler), see discussion under
-:ref: `open work items <OpenWork>` below.
+\:ref: `open work items <OpenWork>` below.
Each statepoint generates the following Locations:
-* Constant which describes the calling convention of the call target. This
- constant is a valid :ref:`calling convention identifier <callingconv>` for
+- Constant which describes the calling convention of the call target. This
+ constant is a valid {ref}`calling convention identifier <callingconv>` for
the version of LLVM used to generate the stackmap. No additional compatibility
guarantees are made for this constant over what LLVM provides elsewhere w.r.t.
these identifiers.
-* Constant which describes the flags passed to the statepoint intrinsic
-* Constant which describes number of following deopt *Locations* (not
- operands). Will be 0 if no "deopt" bundle is provided.
-* Variable number of Locations, one for each deopt parameter listed in the
- "deopt" operand bundle. At the moment, only deopt parameters with a bitwidth
- of 64 bits or less are supported. Values of a type larger than 64 bits can be
+- Constant which describes the flags passed to the statepoint intrinsic
+- Constant which describes number of following deopt *Locations* (not
+ operands). Will be 0 if no "deopt" bundle is provided.
+- Variable number of Locations, one for each deopt parameter listed in the
+ "deopt" operand bundle. At the moment, only deopt parameters with a bitwidth
+ of 64 bits or less are supported. Values of a type larger than 64 bits can be
specified and reported only if a) the value is constant at the call site, and
b) the constant can be represented with less than 64 bits (assuming zero
extension to the original bitwidth).
-* Variable number of relocation records, each of which consists of
- exactly two Locations. Relocation records are described in detail
+- Variable number of relocation records, each of which consists of
+ exactly two Locations. Relocation records are described in detail
below.
Each relocation record provides sufficient information for a collector to
-relocate one or more derived pointers. Each record consists of a pair of
-Locations. The second element in the record represents the pointer (or
-pointers) which need updated. The first element in the record provides a
+relocate one or more derived pointers. Each record consists of a pair of
+Locations. The second element in the record represents the pointer (or
+pointers) which need updated. The first element in the record provides a
pointer to the base of the object with which the pointer(s) being relocated is
-associated. This information is required for handling generalized derived
+associated. This information is required for handling generalized derived
pointers since a pointer may be outside the bounds of the original allocation,
-but still needs to be relocated with the allocation. Additionally:
+but still needs to be relocated with the allocation. Additionally:
-* It is guaranteed that the base pointer must also appear explicitly as a
+- It is guaranteed that the base pointer must also appear explicitly as a
relocation pair if used after the statepoint.
-* There may be fewer relocation records then gc parameters in the IR
+- There may be fewer relocation records then gc parameters in the IR
statepoint. Each *unique* pair will occur at least once; duplicates
are possible.
-* The Locations within each record may either be of pointer size or a
- multiple of pointer size. In the later case, the record must be
+- The Locations within each record may either be of pointer size or a
+ multiple of pointer size. In the later case, the record must be
interpreted as describing a sequence of pointers and their corresponding
base pointers. If the Location is of size N x sizeof(pointer), then
there will be N records of one pointer each contained within the Location.
Both Locations in a pair can be assumed to be of the same size.
Note that the Locations used in each section may describe the same
-physical location. e.g. A stack slot may appear as a deopt location,
+physical location. e.g. A stack slot may appear as a deopt location,
a gc base pointer, and a gc derived pointer.
The LiveOut section of the StkMapRecord will be empty for a statepoint
record.
-Safepoint Semantics & Verification
-==================================
+## Safepoint Semantics & Verification
The fundamental correctness property for the compiled code's
-correctness w.r.t. the garbage collector is a dynamic one. It must be
+correctness w.r.t. the garbage collector is a dynamic one. It must be
the case that there is no dynamic trace such that an operation
involving a potentially relocated pointer is observably-after a
-safepoint which could relocate it. 'observably-after' is this usage
+safepoint which could relocate it. 'observably-after' is this usage
means that an outside observer could observe this sequence of events
in a way which precludes the operation being performed before the
safepoint.
To understand why this 'observable-after' property is required,
consider a null comparison performed on the original copy of a
-relocated pointer. Assuming that control flow follows the safepoint,
+relocated pointer. Assuming that control flow follows the safepoint,
there is no way to observe externally whether the null comparison is
-performed before or after the safepoint. (Remember, the original
-Value is unmodified by the safepoint.) The compiler is free to make
+performed before or after the safepoint. (Remember, the original
+Value is unmodified by the safepoint.) The compiler is free to make
either scheduling choice.
The actual correctness property implemented is slightly stronger than
-this. We require that there be no *static path* on which a
+this. We require that there be no *static path* on which a
potentially relocated pointer is 'observably-after' it may have been
-relocated. This is slightly stronger than is strictly necessary (and
+relocated. This is slightly stronger than is strictly necessary (and
thus may disallow some otherwise valid programs), but greatly
simplifies reasoning about correctness of the compiled code.
By construction, this property will be upheld by the optimizer if
-correctly established in the source IR. This is a key invariant of
+correctly established in the source IR. This is a key invariant of
the design.
The existing IR Verifier pass has been extended to check most of the
local restrictions on the intrinsics mentioned in their respective
-documentation. The current implementation in LLVM does not check the
+documentation. The current implementation in LLVM does not check the
key relocation invariant, but this is ongoing work on developing such
-a verifier. Please ask on llvm-dev if you're interested in
+a verifier. Please ask on llvm-dev if you're interested in
experimenting with the current version.
-.. _statepoint-utilities:
+(statepoint-utilities)=
-Utility Passes for Safepoint Insertion
-======================================
+## Utility Passes for Safepoint Insertion
-.. _RewriteStatepointsForGC:
+(rewritestatepointsforgc)=
-RewriteStatepointsForGC
-^^^^^^^^^^^^^^^^^^^^^^^^
+### RewriteStatepointsForGC
The pass RewriteStatepointsForGC transforms a function's IR to lower from the
abstract machine model described above to the explicit statepoint model of
-relocations. To do this, it replaces all calls or invokes of functions which
-might contain a safepoint poll with a ``gc.statepoint`` and associated full
-relocation sequence, including all required ``gc.relocates``.
+relocations. To do this, it replaces all calls or invokes of functions which
+might contain a safepoint poll with a `gc.statepoint` and associated full
+relocation sequence, including all required `gc.relocates`.
-This pass only applies to GCStrategy instances where the ``UseRS4GC`` flag
+This pass only applies to GCStrategy instances where the `UseRS4GC` flag
is set. The two builtin GC strategies with this set are the
"statepoint-example" and "coreclr" strategies.
As an example, given this code:
-.. code-block:: llvm
-
- define ptr addrspace(1) @test1(ptr addrspace(1) %obj)
- gc "statepoint-example" {
- call void @foo()
- ret ptr addrspace(1) %obj
- }
+```llvm
+define ptr addrspace(1) @test1(ptr addrspace(1) %obj)
+ gc "statepoint-example" {
+ call void @foo()
+ ret ptr addrspace(1) %obj
+}
+```
The pass would produce this IR:
-.. code-block:: llvm
-
- define ptr addrspace(1) @test_rs4gc(ptr addrspace(1) %obj) gc "statepoint-example" {
- %statepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @foo, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(ptr addrspace(1) %obj) ]
- %obj.relocated = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %statepoint_token, i32 0, i32 0) ; (%obj, %obj)
- ret ptr addrspace(1) %obj.relocated
- }
+```llvm
+define ptr addrspace(1) @test_rs4gc(ptr addrspace(1) %obj) gc "statepoint-example" {
+ %statepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @foo, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(ptr addrspace(1) %obj) ]
+ %obj.relocated = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %statepoint_token, i32 0, i32 0) ; (%obj, %obj)
+ ret ptr addrspace(1) %obj.relocated
+}
+```
In the above examples, the addrspace(1) marker on the pointers is the mechanism
-that the ``statepoint-example`` GC strategy uses to distinguish references from
-non references. This is controlled via GCStrategy::isGCManagedPointer. The
-``statepoint-example`` and ``coreclr`` strategies (the only two default
+that the `statepoint-example` GC strategy uses to distinguish references from
+non references. This is controlled via GCStrategy::isGCManagedPointer. The
+`statepoint-example` and `coreclr` strategies (the only two default
strategies that support statepoints) both use addrspace(1) to determine which
pointers are references, however custom strategies don't have to follow this
convention.
This pass can be used an utility function by a language frontend that doesn't
want to manually reason about liveness, base pointers, or relocation when
-constructing IR. As currently implemented, RewriteStatepointsForGC must be
+constructing IR. As currently implemented, RewriteStatepointsForGC must be
run after SSA construction (i.e. mem2ref).
RewriteStatepointsForGC will ensure that appropriate base pointers are listed
-for every relocation created. It will do so by duplicating code as needed to
+for every relocation created. It will do so by duplicating code as needed to
propagate the base pointer associated with each pointer being relocated to
-the appropriate safepoints. The implementation assumes that the following
+the appropriate safepoints. The implementation assumes that the following
IR constructs produce base pointers: loads from the heap, addresses of global
variables, function arguments, function return values. Constant pointers (such
-as null) are also assumed to be base pointers. In practice, this constraint
+as null) are also assumed to be base pointers. In practice, this constraint
can be relaxed to producing interior derived pointers provided the target
collector can find the associated allocation from an arbitrary interior
derived pointer.
-By default RewriteStatepointsForGC passes in ``0xABCDEF00`` as the statepoint
-ID and ``0`` as the number of patchable bytes to the newly constructed
-``gc.statepoint``. These values can be configured on a per-callsite
-basis using the attributes ``"statepoint-id"`` and
-``"statepoint-num-patch-bytes"``. If a call site is marked with a
-``"statepoint-id"`` function attribute and its value is a positive
+By default RewriteStatepointsForGC passes in `0xABCDEF00` as the statepoint
+ID and `0` as the number of patchable bytes to the newly constructed
+`gc.statepoint`. These values can be configured on a per-callsite
+basis using the attributes `"statepoint-id"` and
+`"statepoint-num-patch-bytes"`. If a call site is marked with a
+`"statepoint-id"` function attribute and its value is a positive
integer (represented as a string), then that value is used as the ID
-of the newly constructed ``gc.statepoint``. If a call site is marked
-with a ``"statepoint-num-patch-bytes"`` function attribute and its
+of the newly constructed `gc.statepoint`. If a call site is marked
+with a `"statepoint-num-patch-bytes"` function attribute and its
value is a positive integer, then that value is used as the 'num patch
-bytes' parameter of the newly constructed ``gc.statepoint``. The
-``"statepoint-id"`` and ``"statepoint-num-patch-bytes"`` attributes
-are not propagated to the ``gc.statepoint`` call or invoke if they
+bytes' parameter of the newly constructed `gc.statepoint`. The
+`"statepoint-id"` and `"statepoint-num-patch-bytes"` attributes
+are not propagated to the `gc.statepoint` call or invoke if they
could be successfully parsed.
In practice, RewriteStatepointsForGC should be run much later in the pass
-pipeline, after most optimization is already done. This helps to improve
+pipeline, after most optimization is already done. This helps to improve
the quality of the generated code when compiled with garbage collection support.
-.. _RewriteStatepointsForGC_intrinsic_lowering:
+(rewritestatepointsforgc-intrinsic-lowering)=
-RewriteStatepointsForGC intrinsic lowering
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### RewriteStatepointsForGC intrinsic lowering
As a part of lowering to the explicit model of relocations
RewriteStatepointsForGC performs GC specific lowering for the following
intrinsics:
-* ``gc.get.pointer.base``
-* ``gc.get.pointer.offset``
-* ``llvm.memcpy.element.unordered.atomic.*``
-* ``llvm.memmove.element.unordered.atomic.*``
+- `gc.get.pointer.base`
+- `gc.get.pointer.offset`
+- `llvm.memcpy.element.unordered.atomic.*`
+- `llvm.memmove.element.unordered.atomic.*`
There are two possible lowerings for the memcpy and memmove operations:
GC leaf lowering and GC parseable lowering. If a call is explicitly marked with
"gc-leaf-function" attribute the call is lowered to a GC leaf call to
-'``__llvm_memcpy_element_unordered_atomic_*``' or
-'``__llvm_memmove_element_unordered_atomic_*``' symbol. Such a call can not
+'`__llvm_memcpy_element_unordered_atomic_*`' or
+'`__llvm_memmove_element_unordered_atomic_*`' symbol. Such a call can not
take a safepoint. Otherwise, the call is made GC parseable by wrapping the
call into a statepoint. This makes it possible to take a safepoint during
copy operation. Note that a GC parseable copy operation is not required to
take a safepoint. For example, a short copy operation may be performed without
taking a safepoint.
-GC parseable calls to '``llvm.memcpy.element.unordered.atomic.*``',
-'``llvm.memmove.element.unordered.atomic.*``' intrinsics are lowered to calls
-to '``__llvm_memcpy_element_unordered_atomic_safepoint_*``',
-'``__llvm_memmove_element_unordered_atomic_safepoint_*``' symbols respectively.
+GC parseable calls to '`llvm.memcpy.element.unordered.atomic.*`',
+'`llvm.memmove.element.unordered.atomic.*`' intrinsics are lowered to calls
+to '`__llvm_memcpy_element_unordered_atomic_safepoint_*`',
+'`__llvm_memmove_element_unordered_atomic_safepoint_*`' symbols respectively.
This way the runtime can provide implementations of copy operations with and
without safepoints.
@@ -645,18 +626,16 @@ pointers to be available in the copy operation. In order to make the base
pointers available RewriteStatepointsForGC replaces derived pointers with base
pointer and offset pairs. For example:
-.. code-block:: llvm
+```llvm
+declare void @__llvm_memcpy_element_unordered_atomic_safepoint_1(
+ i8 addrspace(1)* %dest_base, i64 %dest_offset,
+ i8 addrspace(1)* %src_base, i64 %src_offset,
+ i64 %length)
+```
- declare void @__llvm_memcpy_element_unordered_atomic_safepoint_1(
- i8 addrspace(1)* %dest_base, i64 %dest_offset,
- i8 addrspace(1)* %src_base, i64 %src_offset,
- i64 %length)
+(placesafepoints)=
-
-.. _PlaceSafepoints:
-
-PlaceSafepoints
-^^^^^^^^^^^^^^^^
+### PlaceSafepoints
The pass PlaceSafepoints inserts safepoint polls sufficient to ensure running
code checks for a safepoint request on a timely manner. This pass is expected
@@ -665,128 +644,117 @@ relocation sequences.
As an example, given input IR of the following:
-.. code-block:: llvm
-
- define void @test() gc "statepoint-example" {
- call void @foo()
- ret void
- }
-
- declare void @do_safepoint()
- define void @gc.safepoint_poll() {
- call void @do_safepoint()
- ret void
- }
+```llvm
+define void @test() gc "statepoint-example" {
+ call void @foo()
+ ret void
+}
+declare void @do_safepoint()
+define void @gc.safepoint_poll() {
+ call void @do_safepoint()
+ ret void
+}
+```
This pass would produce the following IR:
-.. code-block:: llvm
-
- define void @test() gc "statepoint-example" {
- call void @do_safepoint()
- call void @foo()
- ret void
- }
-
-In this case, we've added an (unconditional) entry safepoint poll. Note that
-despite appearances, the entry poll is not necessarily redundant. We'd have to
-know that ``foo`` and ``test`` were not mutually recursive for the poll to be
-redundant. In practice, you'd probably want to your poll definition to contain
+```llvm
+define void @test() gc "statepoint-example" {
+ call void @do_safepoint()
+ call void @foo()
+ ret void
+}
+```
+
+In this case, we've added an (unconditional) entry safepoint poll. Note that
+despite appearances, the entry poll is not necessarily redundant. We'd have to
+know that `foo` and `test` were not mutually recursive for the poll to be
+redundant. In practice, you'd probably want to your poll definition to contain
a conditional branch of some form.
At the moment, PlaceSafepoints can insert safepoint polls at method entry and
-loop backedges locations. Extending this to work with return polls would be
+loop backedges locations. Extending this to work with return polls would be
straight forward if desired.
PlaceSafepoints includes a number of optimizations to avoid placing safepoint
polls at particular sites unless needed to ensure timely execution of a poll
-under normal conditions. PlaceSafepoints does not attempt to ensure timely
+under normal conditions. PlaceSafepoints does not attempt to ensure timely
execution of a poll under worst case conditions such as heavy system paging.
The implementation of a safepoint poll action is specified by looking up a
-function of the name ``gc.safepoint_poll`` in the containing Module. The body
-of this function is inserted at each poll site desired. While calls or invokes
-inside this method are transformed to a ``gc.statepoints``, recursive poll
+function of the name `gc.safepoint_poll` in the containing Module. The body
+of this function is inserted at each poll site desired. While calls or invokes
+inside this method are transformed to a `gc.statepoints`, recursive poll
insertion is not performed.
This pass is useful for any language frontend which only has to support
-garbage collection semantics at safepoints. If you need other abstract
+garbage collection semantics at safepoints. If you need other abstract
frame information at safepoints (e.g. for deoptimization or introspection),
-you can insert safepoint polls in the frontend. If you have the later case,
-please ask on llvm-dev for suggestions. There's been a good amount of work
+you can insert safepoint polls in the frontend. If you have the later case,
+please ask on llvm-dev for suggestions. There's been a good amount of work
done on making such a scheme work well in practice which is not yet documented
here.
-
-Supported Architectures
-=======================
+## Supported Architectures
Support for statepoint generation requires some code for each backend.
Today, only Aarch64 and X86_64 are supported.
-.. _OpenWork:
+(openwork)=
-Limitations and Half Baked Ideas
-================================
+## Limitations and Half Baked Ideas
-Mixing References and Raw Pointers
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Mixing References and Raw Pointers
Support for languages which allow unmanaged pointers to garbage collected
objects (i.e. pass a pointer to an object to a C routine) in the abstract
-machine model. At the moment, the best idea on how to approach this
+machine model. At the moment, the best idea on how to approach this
involves an intrinsic or opaque function which hides the connection between
-the reference value and the raw pointer. The problem is that having a
+the reference value and the raw pointer. The problem is that having a
ptrtoint or inttoptr cast (which is common for such use cases) breaks the
rules used for inferring base pointers for arbitrary references when
-lowering out of the abstract model to the explicit physical model. Note
+lowering out of the abstract model to the explicit physical model. Note
that a frontend which lowers directly to the physical model doesn't have
any problems here.
-Objects on the Stack
-^^^^^^^^^^^^^^^^^^^^
+### Objects on the Stack
As noted above, the explicit lowering supports objects allocated on the
stack provided the collector can find a heap map given the stack address.
The missing pieces are a) integration with rewriting (RS4GC) from the
abstract machine model and b) support for optionally decomposing on stack
-objects so as not to require heap maps for them. The later is required
+objects so as not to require heap maps for them. The later is required
for ease of integration with some collectors.
-Lowering Quality and Representation Overhead
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Lowering Quality and Representation Overhead
-The current statepoint lowering is known to be somewhat poor. In the very
+The current statepoint lowering is known to be somewhat poor. In the very
long term, we'd like to integrate statepoints with the register allocator;
-in the near term this is unlikely to happen. We've found the quality of
+in the near term this is unlikely to happen. We've found the quality of
lowering to be relatively unimportant as hot-statepoints are almost always
inliner bugs.
Concerns have been raised that the statepoint representation results in a
large amount of IR being produced for some examples and that this
-contributes to higher than expected memory usage and compile times. There's
+contributes to higher than expected memory usage and compile times. There's
no immediate plans to make changes due to this, but alternate models may be
explored in the future.
-Relocations Along Exceptional Edges
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Relocations Along Exceptional Edges
-Relocations along exceptional paths are currently broken in ToT. In
+Relocations along exceptional paths are currently broken in ToT. In
particular, there is current no way to represent a rethrow on a path which
-also has relocations. See `this llvm-dev discussion
-<https://groups.google.com/forum/#!topic/llvm-dev/AE417XjgxvI>`_ for more
+also has relocations. See [this llvm-dev discussion](https://groups.google.com/forum/#!topic/llvm-dev/AE417XjgxvI) for more
detail.
-Bugs and Enhancements
-=====================
+## Bugs and Enhancements
Currently known bugs and enhancements under consideration can be
-tracked by performing a `bugzilla search
-<https://bugs.llvm.org/buglist.cgi?cmdtype=runnamed&namedcmd=Statepoint%20Bugs&list_id=64342>`_
+tracked by performing a [bugzilla search](https://bugs.llvm.org/buglist.cgi?cmdtype=runnamed&namedcmd=Statepoint%20Bugs&list_id=64342)
for [Statepoint] in the summary field. When filing new bugs, please
-use this tag so that interested parties see the newly filed bug. As
-with most LLVM features, design discussions take place on the `Discourse forums <https://discourse.llvm.org>`_ and patches
-should be sent to `llvm-commits
-<http://lists.llvm.org/mailman/listinfo/llvm-commits>`_ for review.
+use this tag so that interested parties see the newly filed bug. As
+with most LLVM features, design discussions take place on the [Discourse forums](https://discourse.llvm.org) and patches
+should be sent to [llvm-commits](http://lists.llvm.org/mailman/listinfo/llvm-commits) for review.
+
diff --git a/llvm/docs/SupportPolicy.md b/llvm/docs/SupportPolicy.md
index 0766522a9c578..3f22b36ea15db 100644
--- a/llvm/docs/SupportPolicy.md
+++ b/llvm/docs/SupportPolicy.md
@@ -1,6 +1,4 @@
-=============================
-LLVM Community Support Policy
-=============================
+# LLVM Community Support Policy
As a compilation infrastructure, LLVM has multiple types of users, both
downstream and upstream, of many combinations of its projects, tools and
@@ -27,14 +25,13 @@ the external repositories that need them.
But the maintenance costs of such diverse ecosystem is non trivial, so we divide
the level of support in two tiers: core and peripheral, with two
different levels of impact and responsibilities. Those tiers refer only to the
-main repository (``llvm-project``) and not the other repositories in our git
+main repository (`llvm-project`) and not the other repositories in our git
project, unless explicitly stated.
Regardless of the tier, all code must follow the existing policies on quality,
reviews, style, etc.
-Core Tier
-=========
+## Core Tier
The core tier encompasses all of the code in the main repository that is
in production, is actively tested and released in a regular schedule, including
@@ -44,31 +41,28 @@ tools, etc.
It is the responsibility of **every** LLVM developer to care for the core tier
regardless of where their work is applied to.
-What is covered
----------------
+### What is covered
The core tier is composed of:
- * Core code (``llvm-project``) present in official releases and buildbots:
- compiler, debugger, linker, libraries, etc, including infrastructure code
- (table-gen, lit, file-check, unit-tests, etc).
- * Build infrastructure that creates releases and buildbots (CMake, scripts).
- * `Phabricator <https://github.com/llvm/phabricator>`_ and
- `buildbot <https://github.com/llvm/llvm-zorg>`_ infrastructure.
- * The `test-suite <https://github.com/llvm/llvm-test-suite>`_.
+: - Core code (`llvm-project`) present in official releases and buildbots:
+ compiler, debugger, linker, libraries, etc, including infrastructure code
+ (table-gen, lit, file-check, unit-tests, etc).
+ - Build infrastructure that creates releases and buildbots (CMake, scripts).
+ - [Phabricator](https://github.com/llvm/phabricator) and
+ [buildbot](https://github.com/llvm/llvm-zorg) infrastructure.
+ - The [test-suite](https://github.com/llvm/llvm-test-suite).
-Requirements
-------------
+### Requirements
Code in this tier must:
- * Keep official buildbots green, with warnings on breakages being emailed to
- all affected developers. Those must be fixed as soon as possible or patches
- must be reverted, as per review policy.
- * Bit-rot of a component in the core tier will result in that component being
- downgraded to the peripheral tier or being removed. Sub-communities can
- avoid this by fixing all raised issues in a timely manner.
+: - Keep official buildbots green, with warnings on breakages being emailed to
+ all affected developers. Those must be fixed as soon as possible or patches
+ must be reverted, as per review policy.
+ - Bit-rot of a component in the core tier will result in that component being
+ downgraded to the peripheral tier or being removed. Sub-communities can
+ avoid this by fixing all raised issues in a timely manner.
-Peripheral Tier
-===============
+## Peripheral Tier
The peripheral tier encompass the parts of LLVM that cater to a specific
sub-community and which don't usually affect the core components directly.
@@ -81,65 +75,62 @@ It is the responsibility of each sub-community to care about their own parts
and the intersection of that with the core tier and other peripheral parts.
There are three main groups of code that fit in this category:
- * Code that is making its way into LLVM, via the `experimental <https://llvm.org/docs/DeveloperPolicy.html#introducing-new-components-into-llvm>`_
- roadmap or similar efforts.
- * Code that is making its way out of LLVM, via deprecation, replacement or
- bit-rot, and will be removed if the sub-community that cares about it
- cannot maintain it.
- * Code that isn't meant to be in LLVM core and can coexist with the code in
- the core tier (and others in the peripheral tier) long term, without causing
- breakages or disturbances.
-
-What is covered
----------------
+: - Code that is making its way into LLVM, via the [experimental](https://llvm.org/docs/DeveloperPolicy.html#introducing-new-components-into-llvm)
+ roadmap or similar efforts.
+ - Code that is making its way out of LLVM, via deprecation, replacement or
+ bit-rot, and will be removed if the sub-community that cares about it
+ cannot maintain it.
+ - Code that isn't meant to be in LLVM core and can coexist with the code in
+ the core tier (and others in the peripheral tier) long term, without causing
+ breakages or disturbances.
+
+### What is covered
The peripheral tier is composed of:
- * Experimental targets and options that haven't been enable by default yet.
- * Main repository projects that don't get released or regularly tested.
- * Legacy tools and scripts that aren't used in upstream validation.
- * Alternative build systems (ex. GN, Bazel) and related infrastructure.
- * Tools support (ex. gdb scripts, editor configuration, helper scripts).
+: - Experimental targets and options that haven't been enable by default yet.
+ - Main repository projects that don't get released or regularly tested.
+ - Legacy tools and scripts that aren't used in upstream validation.
+ - Alternative build systems (ex. GN, Bazel) and related infrastructure.
+ - Tools support (ex. gdb scripts, editor configuration, helper scripts).
-Requirements
-------------
+### Requirements
Code in this tier must:
- * Have a clear benefit for residing in the main repository, catering to an
- active sub-community (upstream or downstream).
- * Be actively maintained by such sub-community and have its problems addressed
- in a timely manner.
+: - Have a clear benefit for residing in the main repository, catering to an
+ active sub-community (upstream or downstream).
+ - Be actively maintained by such sub-community and have its problems addressed
+ in a timely manner.
Code in this tier must **not**:
- * Break or invalidate core tier code or infrastructure. If that happens
- accidentally, reverting functionality and working on the issues offline
- is the only acceptable course of action.
- * Negatively affect development of core tier code, with the sub-community
- involved responsible for making changes to address specific concerns.
- * Negatively affect other peripheral tier code, with the sub-communities
- involved tasked to resolve the issues, still making sure the solution doesn't
- break or invalidate the core tier.
- * Impose sub-optimal implementation strategies on core tier components as a
- result of idiosyncrasies in the peripheral component.
- * Have build infrastructure that spams all developers about their breakages.
- * Fall into disrepair. This is a reflection of lack of an active sub-community
- and will result in removal.
+: - Break or invalidate core tier code or infrastructure. If that happens
+ accidentally, reverting functionality and working on the issues offline
+ is the only acceptable course of action.
+ - Negatively affect development of core tier code, with the sub-community
+ involved responsible for making changes to address specific concerns.
+ - Negatively affect other peripheral tier code, with the sub-communities
+ involved tasked to resolve the issues, still making sure the solution doesn't
+ break or invalidate the core tier.
+ - Impose sub-optimal implementation strategies on core tier components as a
+ result of idiosyncrasies in the peripheral component.
+ - Have build infrastructure that spams all developers about their breakages.
+ - Fall into disrepair. This is a reflection of lack of an active sub-community
+ and will result in removal.
Code in this tier should:
- * Have infrastructure to test, whenever meaningful, with either no warnings or
- notification contained within the sub-community.
- * Have support and testing that scales with the complexity and resilience of
- the component, with the bar for simple and gracefully-degrading components
- (such as editor bindings) much lower than for complex components that must
- remain fresh with HEAD (such as experimental back-ends or alternative build
- systems).
- * Have a document making clear the status of implementation, level of support
- available, who the sub-community is and, if applicable, roadmap for inclusion
- into the core tier.
- * Be restricted to a specific directory or have a consistent pattern (ex.
- unique file suffix), making it easy to remove when necessary.
-
-Inclusion Policy
-================
+: - Have infrastructure to test, whenever meaningful, with either no warnings or
+ notification contained within the sub-community.
+ - Have support and testing that scales with the complexity and resilience of
+ the component, with the bar for simple and gracefully-degrading components
+ (such as editor bindings) much lower than for complex components that must
+ remain fresh with HEAD (such as experimental back-ends or alternative build
+ systems).
+ - Have a document making clear the status of implementation, level of support
+ available, who the sub-community is and, if applicable, roadmap for inclusion
+ into the core tier.
+ - Be restricted to a specific directory or have a consistent pattern (ex.
+ unique file suffix), making it easy to remove when necessary.
+
+## Inclusion Policy
To add a new peripheral component, send an RFC to the appropriate dev list
proposing its addition and explaining how it will meet the support requirements
@@ -163,8 +154,7 @@ are not added too close to a release branch. The time will depend on the size
and complexity of the component, so adding release and testing managers on the
RFC and review is strongly advisable.
-Deprecation Policy
-==================
+## Deprecation Policy
The LLVM code base has a number of files that aren't being actively maintained.
But not all of those files are obstructing the development of the project and
@@ -174,17 +164,16 @@ useful for downstream users.
For code to remain in the repository, its presence must not impose an undue
burden on maintaining other components (core or peripheral).
-Warnings
---------
+### Warnings
There are multiple types of issues that might trigger a request for deprecation,
including (but not limited to):
- * Changes in a component consistently break other areas of the project.
- * Components go broken for long periods of time (weeks or more).
- * Clearly superior alternatives are in use and maintenance is painful.
- * Builds and tests are harder / take longer, increasing the cost of
- maintenance, overtaking the perceived benefits.
+> - Changes in a component consistently break other areas of the project.
+> - Components go broken for long periods of time (weeks or more).
+> - Clearly superior alternatives are in use and maintenance is painful.
+> - Builds and tests are harder / take longer, increasing the cost of
+> maintenance, overtaking the perceived benefits.
If the maintenance cost is higher than it is acceptable by the majority of
developers, it means that either the sub-community is too small (and the extra
@@ -192,8 +181,7 @@ cost should be paid locally), or not active enough (and the problems won't be
fixed any time soon). In either case, removal of such problematic component is
justified.
-Steps for removal
------------------
+### Steps for removal
However clear the needs for removal are, we should take an incremental approach
to deprecating code, especially when there's still a sub-community that cares
@@ -201,25 +189,28 @@ about it. In that sense, code will never be removed outright without a series
of steps are taken.
A minimum set of steps should be:
- #. A proposal for removal / deactivation should be made to the Discourse forums
- (under the appropriate category), with a clear
- statement of the maintenance costs imposed and the alternatives, if
- applicable.
- #. There must be enough consensus on the list that removal is warranted, and no
- pending proposals to fix the situation from a sub-community.
- #. An announcement for removal must be made on the same lists, with ample time
- for downstream users to take action on their local infrastructure. The time
- will depend on what is being removed.
-
- #. If a script or documents are to be removed, they can always be pulled
- from previous revision, and can be removed within days.
- #. if a whole target is removed, we need to first announce publicly, and
- potentially mark as deprecated in one release, only to remove on the
- next release.
- #. Everything else will fall in between those two extremes.
- #. The removal is made by either the proposer or the sub-community that used to
- maintain it, with replacements and arrangements made atomically on the same
- commit.
+: 1. A proposal for removal / deactivation should be made to the Discourse forums
+ (under the appropriate category), with a clear
+ statement of the maintenance costs imposed and the alternatives, if
+ applicable.
+
+ 2. There must be enough consensus on the list that removal is warranted, and no
+ pending proposals to fix the situation from a sub-community.
+
+ 3. An announcement for removal must be made on the same lists, with ample time
+ for downstream users to take action on their local infrastructure. The time
+ will depend on what is being removed.
+
+ 1. If a script or documents are to be removed, they can always be pulled
+ from previous revision, and can be removed within days.
+ 2. if a whole target is removed, we need to first announce publicly, and
+ potentially mark as deprecated in one release, only to remove on the
+ next release.
+ 3. Everything else will fall in between those two extremes.
+
+ 4. The removal is made by either the proposer or the sub-community that used to
+ maintain it, with replacements and arrangements made atomically on the same
+ commit.
If a proposal for removal is delayed by the promise a sub-community will take
care of the code affected, the sub-community will have a time to fix all the
@@ -227,8 +218,7 @@ issues (depending on each case, as above), and if those are not fixed in time, a
subsequent request for removal should be made and the community may elect to
eject the component without further attempts to fix.
-Reinstatement
--------------
+### Reinstatement
If a component is removed from LLVM, it may, at a later date, request inclusion
of a modified version, with evidence that all of the issues were fixed and that
diff --git a/llvm/docs/SystemLibrary.md b/llvm/docs/SystemLibrary.md
index 4409532153a68..044ececb6503f 100644
--- a/llvm/docs/SystemLibrary.md
+++ b/llvm/docs/SystemLibrary.md
@@ -1,9 +1,7 @@
-==============
-System Library
-==============
+# System Library
-Moved
-=====
+## Moved
The System Library has been renamed to Support Library with documentation
-available at :doc:`SupportLibrary`. Please, change your links to that page.
+available at {doc}`SupportLibrary`. Please, change your links to that page.
+
diff --git a/llvm/docs/TableGen/BackEnds.md b/llvm/docs/TableGen/BackEnds.md
index dead1ba129178..47b7be492332f 100644
--- a/llvm/docs/TableGen/BackEnds.md
+++ b/llvm/docs/TableGen/BackEnds.md
@@ -1,10 +1,6 @@
-=================
-TableGen BackEnds
-=================
+# TableGen BackEnds
-
-Introduction
-============
+## Introduction
TableGen backends are at the core of TableGen's functionality. The source
files provide the classes and records that are parsed and end up as a
@@ -26,18 +22,18 @@ warnings, tips) and attributes, so more on the textual end of the scale.
MLIR uses TableGen to define operations, operation dialects, and operation
traits.
-See the :doc:`TableGen Programmer's Reference <./ProgRef>` for an in-depth
-description of TableGen, and the :doc:`TableGen Backend Developer's Guide
+See the {doc}`TableGen Programmer's Reference <./ProgRef>` for an in-depth
+description of TableGen, and the {doc}`TableGen Backend Developer's Guide
<./BackGuide>` for a guide to writing a new backend.
-LLVM BackEnds
-=============
+## LLVM BackEnds
-.. warning::
- This portion is incomplete. Each section below needs three subsections:
- description of its purpose with a list of users, output generated from
- generic input, and finally why it needed a new backend (in case there's
- something similar).
+:::{warning}
+This portion is incomplete. Each section below needs three subsections:
+description of its purpose with a list of users, output generated from
+generic input, and finally why it needed a new backend (in case there's
+something similar).
+:::
Overall, each backend will take the same TableGen file type and transform into
similar output for different targets/uses. There is an implicit contract between
@@ -48,10 +44,10 @@ sections. Based on whether the file is included by a header or a source file,
or even in which context of each file the include is being used, you have
to define a macro just before including it, to get the right output:
-.. code-block:: c++
-
- #define GET_REGINFO_TARGET_DESC
- #include "ARMGenRegisterInfo.inc"
+```c++
+#define GET_REGINFO_TARGET_DESC
+#include "ARMGenRegisterInfo.inc"
+```
And just part of the generated file would be included. This is useful if
you need the same information in multiple formats (instantiation, initialization,
@@ -61,48 +57,45 @@ to re-compile the TableGen file multiple times.
Sometimes, multiple macros might be defined before the same include file to
output multiple blocks:
-.. code-block:: c++
-
- #define GET_REGISTER_MATCHER
- #define GET_SUBTARGET_FEATURE_NAME
- #define GET_MATCHER_IMPLEMENTATION
- #include "ARMGenAsmMatcher.inc"
+```c++
+#define GET_REGISTER_MATCHER
+#define GET_SUBTARGET_FEATURE_NAME
+#define GET_MATCHER_IMPLEMENTATION
+#include "ARMGenAsmMatcher.inc"
+```
The macros will be undef'd automatically as they're used, in the include file.
-On all LLVM back-ends, the ``llvm-tblgen`` binary will be executed on the root
-TableGen file ``<Target>.td``, which should include all others. This guarantees
+On all LLVM back-ends, the `llvm-tblgen` binary will be executed on the root
+TableGen file `<Target>.td`, which should include all others. This guarantees
that all information needed is accessible, and that no duplication is needed
in the TableGen files.
-CodeEmitter
------------
+### CodeEmitter
-**Purpose**: ``CodeEmitterGen`` uses the descriptions of instructions and their fields to
-construct an automated code emitter: a function that, given a ``MachineInstr``,
+**Purpose**: `CodeEmitterGen` uses the descriptions of instructions and their fields to
+construct an automated code emitter: a function that, given a `MachineInstr`,
returns the (currently, 32-bit unsigned) value of the instruction.
**Output**: C++ code, implementing the target's CodeEmitter
-class by overriding the virtual functions as ``<Target>CodeEmitter::function()``.
+class by overriding the virtual functions as `<Target>CodeEmitter::function()`.
-**Usage**: Used to include directly at the end of ``<Target>MCCodeEmitter.cpp``.
+**Usage**: Used to include directly at the end of `<Target>MCCodeEmitter.cpp`.
-RegisterInfo
-------------
+### RegisterInfo
**Purpose**: This tablegen backend is responsible for emitting a description of a target
-register file for a code generator. It uses instances of the Register,
+register file for a code generator. It uses instances of the Register,
RegisterAliases, and RegisterClass classes to gather this information.
**Output**: C++ code with enums and structures representing the register mappings,
properties, masks, etc.
-**Usage**: Both on ``<Target>BaseRegisterInfo`` and ``<Target>MCTargetDesc`` (headers
+**Usage**: Both on `<Target>BaseRegisterInfo` and `<Target>MCTargetDesc` (headers
and source files) with macros defining in which they are for declaration vs.
initialization issues.
-InstrInfo
----------
+### InstrInfo
**Purpose**: This tablegen backend is responsible for emitting a description of the target
instruction set for the code generator. (what are the differences from CodeEmitter?)
@@ -110,78 +103,71 @@ instruction set for the code generator. (what are the differences from CodeEmitt
**Output**: C++ code with enums and structures representing the instruction mappings,
properties, masks, etc.
-**Usage**: Both on ``<Target>BaseInstrInfo`` and ``<Target>MCTargetDesc`` (headers
+**Usage**: Both on `<Target>BaseInstrInfo` and `<Target>MCTargetDesc` (headers
and source files) with macros defining in which they are for declaration vs.
initialization issues.
-AsmWriter
----------
+### AsmWriter
**Purpose**: Emits an assembly printer for the current target.
-**Output**: Implementation of ``<Target>InstPrinter::printInstruction()``, among
+**Output**: Implementation of `<Target>InstPrinter::printInstruction()`, among
other things.
-**Usage**: Included directly into ``InstPrinter/<Target>InstPrinter.cpp``.
+**Usage**: Included directly into `InstPrinter/<Target>InstPrinter.cpp`.
-AsmMatcher
-----------
+### AsmMatcher
**Purpose**: Emits a target specifier matcher for
-converting parsed assembly operands in the ``MCInst`` structures. It also
+converting parsed assembly operands in the `MCInst` structures. It also
emits a matcher for custom operand parsing. Extensive documentation is
-written on the ``AsmMatcherEmitter.cpp`` file.
+written on the `AsmMatcherEmitter.cpp` file.
**Output**: Assembler parsers' matcher functions, declarations, etc.
-**Usage**: Used in back-ends' ``AsmParser/<Target>AsmParser.cpp`` for
+**Usage**: Used in back-ends' `AsmParser/<Target>AsmParser.cpp` for
building the AsmParser class.
-Disassembler
-------------
+### Disassembler
**Purpose**: Contains disassembler table emitters for various
architectures. Extensive documentation is written on the
-``DisassemblerEmitter.cpp`` file.
+`DisassemblerEmitter.cpp` file.
**Output**: Decoding tables, static decoding functions, etc.
-**Usage**: Directly included in ``Disassembler/<Target>Disassembler.cpp``
+**Usage**: Directly included in `Disassembler/<Target>Disassembler.cpp`
to cater for all default decodings, after all hand-made ones.
-PseudoLowering
---------------
+### PseudoLowering
**Purpose**: Generate pseudo instruction lowering.
-**Output**: Implements ``<Target>AsmPrinter::emitPseudoExpansionLowering()``.
+**Output**: Implements `<Target>AsmPrinter::emitPseudoExpansionLowering()`.
-**Usage**: Included directly into ``<Target>AsmPrinter.cpp``.
+**Usage**: Included directly into `<Target>AsmPrinter.cpp`.
-CallingConv
------------
+### CallingConv
**Purpose**: Responsible for emitting descriptions of the calling
conventions supported by this target.
**Output**: Implement static functions to deal with calling conventions
-chained by matching styles, returning ``false`` on no match.
+chained by matching styles, returning `false` on no match.
**Usage**: Used in ISelLowering and FastIsel as function pointers to
implementation returned by a CC selection function.
-DAGISel
--------
+### DAGISel
**Purpose**: Generate a DAG instruction selector.
**Output**: Creates huge functions for automating DAG selection.
-**Usage**: Included in ``<Target>ISelDAGToDAG.cpp`` inside the target's
-implementation of ``SelectionDAGISel``.
+**Usage**: Included in `<Target>ISelDAGToDAG.cpp` inside the target's
+implementation of `SelectionDAGISel`.
-DFAPacketizer
--------------
+### DFAPacketizer
**Purpose**: This class parses the Schedule.td file and produces an API that
can be used to reason about whether an instruction can be added to a packet
@@ -191,45 +177,40 @@ to functional units as instructions are added to a packet.
**Output**: Scheduling tables for GPU back-ends (Hexagon, AMD).
-**Usage**: Included directly on ``<Target>InstrInfo.cpp``.
+**Usage**: Included directly on `<Target>InstrInfo.cpp`.
-FastISel
---------
+### FastISel
**Purpose**: This tablegen backend emits code for use by the "fast"
instruction selection algorithm. See the comments at the top of
-``lib/CodeGen/SelectionDAG/FastISel.cpp`` for background. This file
+`lib/CodeGen/SelectionDAG/FastISel.cpp` for background. This file
scans through the target's tablegen instruction-info files
and extracts instructions with obvious-looking patterns, and it emits
code to look up these instructions by type and operator.
-**Output**: Generates ``Predicate`` and ``FastEmit`` methods.
+**Output**: Generates `Predicate` and `FastEmit` methods.
**Usage**: Implements private methods of the targets' implementation
-of ``FastISel`` class.
+of `FastISel` class.
-Subtarget
----------
+### Subtarget
**Purpose**: Generate subtarget enumerations.
**Output**: Enums, globals, local tables for sub-target information.
-**Usage**: Populates ``<Target>Subtarget`` and
-``MCTargetDesc/<Target>MCTargetDesc`` files (both headers and source).
+**Usage**: Populates `<Target>Subtarget` and
+`MCTargetDesc/<Target>MCTargetDesc` files (both headers and source).
-Intrinsic
----------
+### Intrinsic
**Purpose**: Generate (target) intrinsic information.
-OptParserDefs
--------------
+### OptParserDefs
**Purpose**: Print enum values for a class.
-SearchableTables
-----------------
+### SearchableTables
**Purpose**: Generate custom searchable tables.
@@ -240,237 +221,199 @@ from TableGen records. The ARM and AArch64 targets use this backend to generate
tables of system registers; the AMDGPU target uses it to generate meta-data
about complex image and memory buffer instructions.
-See `SearchableTables Reference`_ for a detailed description.
+See [SearchableTables Reference] for a detailed description.
-CTags
------
+### CTags
**Purpose**: This tablegen backend emits an index of definitions in ctags(1)
format. A helper script, utils/TableGen/tdtags, provides an easier-to-use
interface; run 'tdtags -H' for documentation.
-X86EVEX2VEX
------------
+### X86EVEX2VEX
**Purpose**: This X86 specific tablegen backend emits tables that map EVEX
encoded instructions to their VEX encoded identical instruction.
-Clang BackEnds
-==============
+## Clang BackEnds
-ClangAttrClasses
-----------------
+### ClangAttrClasses
**Purpose**: Creates Attrs.inc, which contains semantic attribute class
-declarations for any attribute in ``Attr.td`` that has not set ``ASTNode = 0``.
-This file is included as part of ``Attr.h``.
+declarations for any attribute in `Attr.td` that has not set `ASTNode = 0`.
+This file is included as part of `Attr.h`.
-ClangAttrParserStringSwitches
------------------------------
+### ClangAttrParserStringSwitches
-**Purpose**: Creates ``AttrParserStringSwitches.inc``, which contains
-``StringSwitch::Case`` statements for parser-related string switches. Each switch
-is given its own macro (such as ``CLANG_ATTR_ARG_CONTEXT_LIST``, or
-``CLANG_ATTR_IDENTIFIER_ARG_LIST``), which is expected to be defined before
-including ``AttrParserStringSwitches.inc``, and undefined after.
+**Purpose**: Creates `AttrParserStringSwitches.inc`, which contains
+`StringSwitch::Case` statements for parser-related string switches. Each switch
+is given its own macro (such as `CLANG_ATTR_ARG_CONTEXT_LIST`, or
+`CLANG_ATTR_IDENTIFIER_ARG_LIST`), which is expected to be defined before
+including `AttrParserStringSwitches.inc`, and undefined after.
-ClangAttrImpl
--------------
+### ClangAttrImpl
-**Purpose**: Creates ``AttrImpl.inc``, which contains semantic attribute class
-definitions for any attribute in ``Attr.td`` that has not set ``ASTNode = 0``.
-This file is included as part of ``AttrImpl.cpp``.
+**Purpose**: Creates `AttrImpl.inc`, which contains semantic attribute class
+definitions for any attribute in `Attr.td` that has not set `ASTNode = 0`.
+This file is included as part of `AttrImpl.cpp`.
-ClangAttrList
--------------
+### ClangAttrList
-**Purpose**: Creates ``AttrList.inc``, which is used when a list of semantic
-attribute identifiers is required. For instance, ``AttrKinds.h`` includes this
-file to generate the list of ``attr::Kind`` enumeration values. This list is
+**Purpose**: Creates `AttrList.inc`, which is used when a list of semantic
+attribute identifiers is required. For instance, `AttrKinds.h` includes this
+file to generate the list of `attr::Kind` enumeration values. This list is
separated out into multiple categories: attributes, inheritable attributes, and
inheritable parameter attributes. This categorization happens automatically
-based on information in ``Attr.td`` and is used to implement the ``classof``
-functionality required for ``dyn_cast`` and similar APIs.
+based on information in `Attr.td` and is used to implement the `classof`
+functionality required for `dyn_cast` and similar APIs.
-ClangAttrPCHRead
-----------------
+### ClangAttrPCHRead
-**Purpose**: Creates ``AttrPCHRead.inc``, which is used to deserialize attributes
-in the ``ASTReader::ReadAttributes`` function.
+**Purpose**: Creates `AttrPCHRead.inc`, which is used to deserialize attributes
+in the `ASTReader::ReadAttributes` function.
-ClangAttrPCHWrite
------------------
+### ClangAttrPCHWrite
-**Purpose**: Creates ``AttrPCHWrite.inc``, which is used to serialize attributes in
-the ``ASTWriter::WriteAttributes`` function.
+**Purpose**: Creates `AttrPCHWrite.inc`, which is used to serialize attributes in
+the `ASTWriter::WriteAttributes` function.
-ClangAttrSpellings
----------------------
+### ClangAttrSpellings
-**Purpose**: Creates ``AttrSpellings.inc``, which is used to implement the
-``__has_attribute`` feature test macro.
+**Purpose**: Creates `AttrSpellings.inc`, which is used to implement the
+`__has_attribute` feature test macro.
-ClangAttrSpellingListIndex
---------------------------
+### ClangAttrSpellingListIndex
-**Purpose**: Creates ``AttrSpellingListIndex.inc``, which is used to map parsed
+**Purpose**: Creates `AttrSpellingListIndex.inc`, which is used to map parsed
attribute spellings (including which syntax or scope was used) to an attribute
spelling list index. These spelling list index values are internal
implementation details exposed via
-``AttributeList::getAttributeSpellingListIndex``.
+`AttributeList::getAttributeSpellingListIndex`.
-ClangAttrVisitor
--------------------
+### ClangAttrVisitor
-**Purpose**: Creates ``AttrVisitor.inc``, which is used when implementing
+**Purpose**: Creates `AttrVisitor.inc`, which is used when implementing
recursive AST visitors.
-ClangAttrTemplateInstantiate
-----------------------------
+### ClangAttrTemplateInstantiate
-**Purpose**: Creates ``AttrTemplateInstantiate.inc``, which implements the
-``instantiateTemplateAttribute`` function, used when instantiating a template
+**Purpose**: Creates `AttrTemplateInstantiate.inc`, which implements the
+`instantiateTemplateAttribute` function, used when instantiating a template
that requires an attribute to be cloned.
-ClangAttrParsedAttrList
------------------------
+### ClangAttrParsedAttrList
-**Purpose**: Creates ``AttrParsedAttrList.inc``, which is used to generate the
-``AttributeList::Kind`` parsed attribute enumeration.
+**Purpose**: Creates `AttrParsedAttrList.inc`, which is used to generate the
+`AttributeList::Kind` parsed attribute enumeration.
-ClangAttrParsedAttrImpl
------------------------
+### ClangAttrParsedAttrImpl
-**Purpose**: Creates ``AttrParsedAttrImpl.inc``, which is used by
-``AttributeList.cpp`` to implement several functions on the ``AttributeList``
-class. This functionality is implemented via the ``AttrInfoMap ParsedAttrInfo``
+**Purpose**: Creates `AttrParsedAttrImpl.inc`, which is used by
+`AttributeList.cpp` to implement several functions on the `AttributeList`
+class. This functionality is implemented via the `AttrInfoMap ParsedAttrInfo`
array, which contains one element per parsed attribute object.
-ClangAttrParsedAttrKinds
-------------------------
+### ClangAttrParsedAttrKinds
-**Purpose**: Creates ``AttrParsedAttrKinds.inc``, which is used to implement the
-``AttributeList::getKind`` function, mapping a string (and syntax) to a parsed
-attribute ``AttributeList::Kind`` enumeration.
+**Purpose**: Creates `AttrParsedAttrKinds.inc`, which is used to implement the
+`AttributeList::getKind` function, mapping a string (and syntax) to a parsed
+attribute `AttributeList::Kind` enumeration.
-ClangAttrIsTypeDependent
-------------------------
+### ClangAttrIsTypeDependent
-**Purpose**: Creates ``AttrIsTypeDependent.inc``, which is used to implement the
-``Sema::CheckAttributesOnDeducedType`` function, mapping an attribute kind to a
+**Purpose**: Creates `AttrIsTypeDependent.inc`, which is used to implement the
+`Sema::CheckAttributesOnDeducedType` function, mapping an attribute kind to a
Sema function if it exists.
-ClangAttrDump
--------------
+### ClangAttrDump
-**Purpose**: Creates ``AttrDump.inc``, which dumps information about an attribute.
-It is used to implement ``ASTDumper::dumpAttr``.
+**Purpose**: Creates `AttrDump.inc`, which dumps information about an attribute.
+It is used to implement `ASTDumper::dumpAttr`.
-ClangDiagsDefs
---------------
+### ClangDiagsDefs
Generate Clang diagnostics definitions.
-ClangDiagGroups
----------------
+### ClangDiagGroups
Generate Clang diagnostic groups.
-ClangDiagsIndexName
--------------------
+### ClangDiagsIndexName
Generate Clang diagnostic name index.
-ClangCommentNodes
------------------
+### ClangCommentNodes
Generate Clang AST comment nodes.
-ClangDeclNodes
---------------
+### ClangDeclNodes
Generate Clang AST declaration nodes.
-ClangStmtNodes
---------------
+### ClangStmtNodes
Generate Clang AST statement nodes.
-ClangSACheckers
----------------
+### ClangSACheckers
Generate Clang Static Analyzer checkers.
-ClangCommentHTMLTags
---------------------
+### ClangCommentHTMLTags
Generate efficient matchers for HTML tag names that are used in documentation comments.
-ClangCommentHTMLTagsProperties
-------------------------------
+### ClangCommentHTMLTagsProperties
Generate efficient matchers for HTML tag properties.
-ClangCommentHTMLNamedCharacterReferences
-----------------------------------------
+### ClangCommentHTMLNamedCharacterReferences
Generate function to translate named character references to UTF-8 sequences.
-ClangCommentCommandInfo
------------------------
+### ClangCommentCommandInfo
Generate command properties for commands that are used in documentation comments.
-ClangCommentCommandList
------------------------
+### ClangCommentCommandList
Generate list of commands that are used in documentation comments.
-ArmNeon
--------
+### ArmNeon
-Generate ``arm_neon.h`` for clang.
+Generate `arm_neon.h` for clang.
-ArmNeonSema
------------
+### ArmNeonSema
Generate ARM NEON sema support for clang.
-ArmNeonTest
------------
+### ArmNeonTest
Generate ARM NEON tests for clang.
-AttrDocs
---------
+### AttrDocs
-**Purpose**: Creates ``AttributeReference.md`` from ``AttrDocs.td``, and is
+**Purpose**: Creates `AttributeReference.md` from `AttrDocs.td`, and is
used for documenting user-facing attributes.
-General BackEnds
-================
+## General BackEnds
-Print Records
--------------
+### Print Records
-The TableGen command option ``--print-records`` invokes a simple backend
+The TableGen command option `--print-records` invokes a simple backend
that prints all the classes and records defined in the source files. This is
-the default backend option. See the :doc:`TableGen Backend Developer's Guide
+the default backend option. See the {doc}`TableGen Backend Developer's Guide
<./BackGuide>` for more information.
-Print Detailed Records
-----------------------
+### Print Detailed Records
-The TableGen command option ``--print-detailed-records`` invokes a backend
+The TableGen command option `--print-detailed-records` invokes a backend
that prints all the global variables, classes, and records defined in the
source files, with more detail than the default record printer. See the
-:doc:`TableGen Backend Developer's Guide <./BackGuide>` for more
+{doc}`TableGen Backend Developer's Guide <./BackGuide>` for more
information.
-JSON Reference
---------------
+### JSON Reference
-**Purpose**: Output all the values in every ``def``, as a JSON data
+**Purpose**: Output all the values in every `def`, as a JSON data
structure that can be easily parsed by a variety of languages. Useful
for writing custom backends without having to modify TableGen itself,
or for performing auxiliary analysis on the same TableGen data passed
@@ -481,43 +424,38 @@ to a built-in backend.
The root of the output file is a JSON object (i.e., dictionary),
containing the following fixed keys:
-* ``!tablegen_json_version``: a numeric version field that will
+- `!tablegen_json_version`: a numeric version field that will
increase if an incompatible change is ever made to the structure of
this data. The format described here corresponds to version 1.
-
-* ``!instanceof``: a dictionary whose keys are the class names defined
+- `!instanceof`: a dictionary whose keys are the class names defined
in the TableGen input. For each key, the corresponding value is an
- array of strings giving the names of ``def`` records that derive
- from that class. So ``root["!instanceof"]["Instruction"]``, for
+ array of strings giving the names of `def` records that derive
+ from that class. So `root["!instanceof"]["Instruction"]`, for
example, would list the names of all the records deriving from the
- class ``Instruction``.
+ class `Instruction`.
-For each ``def`` record, the root object also has a key for the record
+For each `def` record, the root object also has a key for the record
name. The corresponding value is a subsidiary object containing the
following fixed keys:
-* ``!superclasses``: an array of strings giving the names of all the
+- `!superclasses`: an array of strings giving the names of all the
classes that this record derives from.
-
-* ``!fields``: an array of strings giving the names of all the variables
- in this record that were defined with the ``field`` keyword.
-
-* ``!name``: a string giving the name of the record. This is always
+- `!fields`: an array of strings giving the names of all the variables
+ in this record that were defined with the `field` keyword.
+- `!name`: a string giving the name of the record. This is always
identical to the key in the JSON root object corresponding to this
record's dictionary. (If the record is anonymous, the name is
arbitrary.)
-
-* ``!anonymous``: a boolean indicating whether the record's name was
- specified by the TableGen input (if it is ``false``), or invented by
- TableGen itself (if ``true``).
-
-* ``!locs``: an array of strings giving the source locations associated with
- this record. For records instantiated from a ``multiclass``, this gives the
- location of each ``def`` or ``defm``, starting with the inner-most
- ``multiclass``, and ending with the top-level ``defm``. Each string contains
+- `!anonymous`: a boolean indicating whether the record's name was
+ specified by the TableGen input (if it is `false`), or invented by
+ TableGen itself (if `true`).
+- `!locs`: an array of strings giving the source locations associated with
+ this record. For records instantiated from a `multiclass`, this gives the
+ location of each `def` or `defm`, starting with the inner-most
+ `multiclass`, and ending with the top-level `defm`. Each string contains
the file name and line number, separated by a colon.
-For each variable defined in a record, the ``def`` object for that
+For each variable defined in a record, the `def` object for that
record also has a key for the variable name. The corresponding value
is a translation into JSON of the variable's value, using the
conventions described below.
@@ -525,479 +463,457 @@ conventions described below.
Some TableGen data types are translated directly into the
corresponding JSON type:
-* A completely undefined value (e.g., for a variable declared without
+- A completely undefined value (e.g., for a variable declared without
initializer in some superclass of this record, and never initialized
by the record itself or any other superclass) is emitted as the JSON
- ``null`` value.
-
-* ``int`` and ``bit`` values are emitted as numbers. Note that
- TableGen ``int`` values are capable of holding integers too large to
+ `null` value.
+- `int` and `bit` values are emitted as numbers. Note that
+ TableGen `int` values are capable of holding integers too large to
be exactly representable in IEEE double precision. The integer
literal in the JSON output will show the full exact integer value.
So if you need to retrieve large integers with full precision, you
should use a JSON reader capable of translating such literals back
into 64-bit integers without losing precision, such as Python's
- standard ``json`` module.
-
-* ``string`` and ``code`` values are emitted as JSON strings.
-
-* ``list<T>`` values, for any element type ``T``, are emitted as JSON
+ standard `json` module.
+- `string` and `code` values are emitted as JSON strings.
+- `list<T>` values, for any element type `T`, are emitted as JSON
arrays. Each element of the array is represented in turn using these
same conventions.
-
-* ``bits`` values are also emitted as arrays. A ``bits`` array is
+- `bits` values are also emitted as arrays. A `bits` array is
ordered from least-significant bit to most-significant. So the
- element with index ``i`` corresponds to the bit described as
- ``x{i}`` in TableGen source. However, note that this means that
+ element with index `i` corresponds to the bit described as
+ `x{i}` in TableGen source. However, note that this means that
scripting languages are likely to *display* the array in the
opposite order from the way it appears in the TableGen source or in
- the diagnostic ``-print-records`` output.
+ the diagnostic `-print-records` output.
All other TableGen value types are emitted as a JSON object,
-containing two standard fields: ``kind`` is a discriminator describing
-which kind of value the object represents, and ``printable`` is a
+containing two standard fields: `kind` is a discriminator describing
+which kind of value the object represents, and `printable` is a
string giving the same representation of the value that would appear
-in ``-print-records``.
+in `-print-records`.
-* A reference to a ``def`` object has ``kind=="def"``, and has an
- extra field ``def`` giving the name of the object referred to.
+- A reference to a `def` object has `kind=="def"`, and has an
+ extra field `def` giving the name of the object referred to.
-* A reference to another variable in the same record has
- ``kind=="var"``, and has an extra field ``var`` giving the name of
+- A reference to another variable in the same record has
+ `kind=="var"`, and has an extra field `var` giving the name of
the variable referred to.
-* A reference to a specific bit of a ``bits``-typed variable in the
- same record has ``kind=="varbit"``, and has two extra fields:
- ``var`` gives the name of the variable referred to, and ``index``
+- A reference to a specific bit of a `bits`-typed variable in the
+ same record has `kind=="varbit"`, and has two extra fields:
+ `var` gives the name of the variable referred to, and `index`
gives the index of the bit.
-* A value of type ``dag`` has ``kind=="dag"``, and has two extra
- fields. ``operator`` gives the initial value after the opening
- parenthesis of the dag initializer; ``args`` is an array giving the
- following arguments. The elements of ``args`` are arrays of length
+- A value of type `dag` has `kind=="dag"`, and has two extra
+ fields. `operator` gives the initial value after the opening
+ parenthesis of the dag initializer; `args` is an array giving the
+ following arguments. The elements of `args` are arrays of length
2, giving the value of each argument followed by its colon-suffixed
name (if any). For example, in the JSON representation of the dag
- value ``(Op 22, "hello":$foo)`` (assuming that ``Op`` is the name of
- a record defined elsewhere with a ``def`` statement):
-
- * ``operator`` will be an object in which ``kind=="def"`` and
- ``def=="Op"``
+ value `(Op 22, "hello":$foo)` (assuming that `Op` is the name of
+ a record defined elsewhere with a `def` statement):
- * ``args`` will be the array ``[[22, null], ["hello", "foo"]]``.
+ - `operator` will be an object in which `kind=="def"` and
+ `def=="Op"`
+ - `args` will be the array `[[22, null], ["hello", "foo"]]`.
-* If any other kind of value or complicated expression appears in the
- output, it will have ``kind=="complex"``, and no additional fields.
+- If any other kind of value or complicated expression appears in the
+ output, it will have `kind=="complex"`, and no additional fields.
These values are not expected to be needed by backends. The standard
- ``printable`` field can be used to extract a representation of them
+ `printable` field can be used to extract a representation of them
in TableGen source syntax if necessary.
-SearchableTables Reference
---------------------------
+### SearchableTables Reference
-A TableGen include file, ``SearchableTable.td``, provides classes for
+A TableGen include file, `SearchableTable.td`, provides classes for
generating C++ searchable tables. These tables are described in the
-following sections. To generate the C++ code, run ``llvm-tblgen`` with the
-``--gen-searchable-tables`` option, which invokes the backend that generates
+following sections. To generate the C++ code, run `llvm-tblgen` with the
+`--gen-searchable-tables` option, which invokes the backend that generates
the tables from the records you provide.
Each of the data structures generated for searchable tables is guarded by an
-``#ifdef``. This allows you to include the generated ``.inc`` file and select only
+`#ifdef`. This allows you to include the generated `.inc` file and select only
certain data structures for inclusion. The examples below show the macro
names used in these guards.
-Generic Enumerated Types
-~~~~~~~~~~~~~~~~~~~~~~~~
+#### Generic Enumerated Types
-The ``GenericEnum`` class makes it easy to define a C++ enumerated type and
+The `GenericEnum` class makes it easy to define a C++ enumerated type and
the enumerated *elements* of that type. To define the type, define a record
-whose parent class is ``GenericEnum`` and whose name is the desired enum
+whose parent class is `GenericEnum` and whose name is the desired enum
type. This class provides three fields, which you can set in the record
-using the ``let`` statement.
+using the `let` statement.
-* ``string FilterClass``. The enum type will have one element for each record
+- `string FilterClass`. The enum type will have one element for each record
that derives from this class. These records are collected to assemble the
complete set of elements.
-
-* ``string NameField``. The name of a field *in the collected records* that specifies
+- `string NameField`. The name of a field *in the collected records* that specifies
the name of the element. If a record has no such field, the record's
name will be used.
-
-* ``string ValueField``. The name of a field *in the collected records* that
+- `string ValueField`. The name of a field *in the collected records* that
specifies the numerical value of the element. If a record has no such
field, it will be assigned an integer value. Values are assigned in
alphabetical order starting with 0.
-
-* ``string UnderlyingType``. The name of the underlying C++ data type
+- `string UnderlyingType`. The name of the underlying C++ data type
of the enum. If a record has no such field, there will be no specification
in the generated enum.
Here is an example where the values of the elements are specified
-explicitly, as a template argument to the ``BEntry`` class. The resulting
+explicitly, as a template argument to the `BEntry` class. The resulting
C++ code is shown.
-.. code-block:: text
-
- def BValues : GenericEnum {
- let FilterClass = "BEntry";
- let NameField = "Name";
- let ValueField = "Encoding";
- }
-
- class BEntry<bits<16> enc> {
- string Name = NAME;
- bits<16> Encoding = enc;
- }
-
- def BFoo : BEntry<0xac>;
- def BBar : BEntry<0x14>;
- def BZoo : BEntry<0x80>;
- def BSnork : BEntry<0x4c>;
-
-.. code-block:: text
-
- #ifdef GET_BValues_DECL
- enum BValues {
- BBar = 20,
- BFoo = 172,
- BSnork = 76,
- BZoo = 128,
- };
- #endif
+```text
+def BValues : GenericEnum {
+ let FilterClass = "BEntry";
+ let NameField = "Name";
+ let ValueField = "Encoding";
+}
+
+class BEntry<bits<16> enc> {
+ string Name = NAME;
+ bits<16> Encoding = enc;
+}
+
+def BFoo : BEntry<0xac>;
+def BBar : BEntry<0x14>;
+def BZoo : BEntry<0x80>;
+def BSnork : BEntry<0x4c>;
+```
+
+```text
+#ifdef GET_BValues_DECL
+enum BValues {
+ BBar = 20,
+ BFoo = 172,
+ BSnork = 76,
+ BZoo = 128,
+};
+#endif
+```
In the following example, the values of the elements are assigned
automatically. Note that values are assigned from 0, in alphabetical order
by element name.
-.. code-block:: text
-
- def CEnum : GenericEnum {
- let FilterClass = "CEnum";
- let UnderlyingType = "uint32_t";
- }
-
- class CEnum;
+```text
+def CEnum : GenericEnum {
+ let FilterClass = "CEnum";
+ let UnderlyingType = "uint32_t";
+}
- def CFoo : CEnum;
- def CBar : CEnum;
- def CBaz : CEnum;
+class CEnum;
-.. code-block:: text
-
- #ifdef GET_CEnum_DECL
- enum CEnum : uint32_t {
- CBar = 0,
- CBaz = 1,
- CFoo = 2,
- };
- #endif
+def CFoo : CEnum;
+def CBar : CEnum;
+def CBaz : CEnum;
+```
+```text
+#ifdef GET_CEnum_DECL
+enum CEnum : uint32_t {
+ CBar = 0,
+ CBaz = 1,
+ CFoo = 2,
+};
+#endif
+```
-Generic Tables
-~~~~~~~~~~~~~~
+#### Generic Tables
-The ``GenericTable`` class is used to define a searchable generic table.
+The `GenericTable` class is used to define a searchable generic table.
TableGen produces C++ code to define the table entries and also produces
the declaration and definition of a function to search the table based on a
primary key. To define the table, define a record whose parent class is
-``GenericTable`` and whose name is the name of the global table of entries.
+`GenericTable` and whose name is the name of the global table of entries.
This class provides the following fields.
-* ``string FilterClass``. The table will have one entry for each record
+- `string FilterClass`. The table will have one entry for each record
that derives from this class.
-
-* ``string FilterClassField``. This is an optional field of ``FilterClass``
+- `string FilterClassField`. This is an optional field of `FilterClass`
which should be `bit` type. If specified, only those records with this field
being true will have corresponding entries in the table. This field won't be
- included in generated C++ fields if it isn't included in ``Fields`` list.
-
-* ``string CppTypeName``. The name of the C++ struct/class type of the
- table that holds the entries. If unspecified, the ``FilterClass`` name is
+ included in generated C++ fields if it isn't included in `Fields` list.
+- `string CppTypeName`. The name of the C++ struct/class type of the
+ table that holds the entries. If unspecified, the `FilterClass` name is
used.
-
-* ``list<string> Fields``. A list of the names of the fields *in the
+- `list<string> Fields`. A list of the names of the fields *in the
collected records* that contain the data for the table entries. The order of
this list determines the order of the values in the C++ initializers. See
below for information about the types of these fields.
-
-* ``list<string> PrimaryKey``. The list of fields that make up the
+- `list<string> PrimaryKey`. The list of fields that make up the
primary key.
-
-* ``string PrimaryKeyName``. The name of the generated C++ function
+- `string PrimaryKeyName`. The name of the generated C++ function
that performs a lookup on the primary key.
-
-* ``bit PrimaryKeyEarlyOut``. See the third example below.
-
-* ``bit PrimaryKeyReturnRange``. when set to 1, modifies the lookup function’s
+- `bit PrimaryKeyEarlyOut`. See the third example below.
+- `bit PrimaryKeyReturnRange`. when set to 1, modifies the lookup function’s
definition to return a range of results rather than a single pointer to the
object. This feature proves useful when multiple objects meet the criteria
specified by the lookup function. Currently, it is supported only for primary
lookup functions. Refer to the second example below for further details.
-
-* ``bit DisallowSparseTable``. When set to 1 (the default), prevents the
+- `bit DisallowSparseTable`. When set to 1 (the default), prevents the
emitter from generating a sparse direct-lookup array for this table. Set to
0 to allow the emitter to emit a sparse directly-indexed array when the
primary key qualifies (see below).
TableGen attempts to deduce the type of each of the table fields so that it
-can format the C++ initializers in the emitted table. It can deduce ``bit``,
-``bits<n>``, ``string``, ``Intrinsic``, and ``Instruction``. These can be
+can format the C++ initializers in the emitted table. It can deduce `bit`,
+`bits<n>`, `string`, `Intrinsic`, and `Instruction`. These can be
used in the primary key. Any other field types must be specified
explicitly; this is done as shown in the second example below. Such fields
cannot be used in the primary key.
One special case of the field type has to do with code. Arbitrary code is
represented by a string, but has to be emitted as a C++ initializer without
-quotes. If the code field was defined using a code literal (``[{...}]``),
+quotes. If the code field was defined using a code literal (`[{...}]`),
then TableGen will know to emit it without quotes. However, if it was
defined using a string literal or complex string expression, then TableGen
will not know. In this case, you can force TableGen to treat the field as
-code by including the following line in the ``GenericTable`` record, where
+code by including the following line in the `GenericTable` record, where
*xxx* is the code field name.
-.. code-block:: text
-
- string TypeOf_xxx = "code";
+```text
+string TypeOf_xxx = "code";
+```
Here is an example where TableGen can deduce the field types. Note that the
table entry records are anonymous; the names of entry records are
irrelevant.
-.. code-block:: text
-
- def ATable : GenericTable {
- let FilterClass = "AEntry";
- let FilterClassField = "IsNeeded";
- let Fields = ["Str", "Val1", "Val2"];
- let PrimaryKey = ["Val1", "Val2"];
- let PrimaryKeyName = "lookupATableByValues";
- }
-
- class AEntry<string str, int val1, int val2, bit isNeeded> {
- string Str = str;
- bits<8> Val1 = val1;
- bits<10> Val2 = val2;
- bit IsNeeded = isNeeded;
- }
-
- def : AEntry<"Bob", 5, 3, 1>;
- def : AEntry<"Carol", 2, 6, 1>;
- def : AEntry<"Ted", 4, 4, 1>;
- def : AEntry<"Alice", 4, 5, 1>;
- def : AEntry<"Costa", 2, 1, 1>;
- def : AEntry<"Dale", 2, 1, 0>;
-
-Here is the generated C++ code. The declaration of ``lookupATableByValues``
-is guarded by ``GET_ATable_DECL``, while the definitions are guarded by
-``GET_ATable_IMPL``.
-
-.. code-block:: text
-
- #ifdef GET_ATable_DECL
- const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2);
- #endif
-
- #ifdef GET_ATable_IMPL
- constexpr AEntry ATable[] = {
- { "Costa", 0x2, 0x1 }, // 0
- { "Carol", 0x2, 0x6 }, // 1
- { "Ted", 0x4, 0x4 }, // 2
- { "Alice", 0x4, 0x5 }, // 3
- { "Bob", 0x5, 0x3 }, // 4
- /* { "Dale", 0x2, 0x1 }, // 5 */ // We don't generate this line as `IsNeeded` is 0.
+```text
+def ATable : GenericTable {
+ let FilterClass = "AEntry";
+ let FilterClassField = "IsNeeded";
+ let Fields = ["Str", "Val1", "Val2"];
+ let PrimaryKey = ["Val1", "Val2"];
+ let PrimaryKeyName = "lookupATableByValues";
+}
+
+class AEntry<string str, int val1, int val2, bit isNeeded> {
+ string Str = str;
+ bits<8> Val1 = val1;
+ bits<10> Val2 = val2;
+ bit IsNeeded = isNeeded;
+}
+
+def : AEntry<"Bob", 5, 3, 1>;
+def : AEntry<"Carol", 2, 6, 1>;
+def : AEntry<"Ted", 4, 4, 1>;
+def : AEntry<"Alice", 4, 5, 1>;
+def : AEntry<"Costa", 2, 1, 1>;
+def : AEntry<"Dale", 2, 1, 0>;
+```
+
+Here is the generated C++ code. The declaration of `lookupATableByValues`
+is guarded by `GET_ATable_DECL`, while the definitions are guarded by
+`GET_ATable_IMPL`.
+
+```text
+#ifdef GET_ATable_DECL
+const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2);
+#endif
+
+#ifdef GET_ATable_IMPL
+constexpr AEntry ATable[] = {
+ { "Costa", 0x2, 0x1 }, // 0
+ { "Carol", 0x2, 0x6 }, // 1
+ { "Ted", 0x4, 0x4 }, // 2
+ { "Alice", 0x4, 0x5 }, // 3
+ { "Bob", 0x5, 0x3 }, // 4
+ /* { "Dale", 0x2, 0x1 }, // 5 */ // We don't generate this line as `IsNeeded` is 0.
+};
+
+const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
+ struct KeyType {
+ uint8_t Val1;
+ uint16_t Val2;
};
-
- const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
- struct KeyType {
- uint8_t Val1;
- uint16_t Val2;
- };
- KeyType Key = { Val1, Val2 };
- auto Table = ArrayRef(ATable);
- auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
- [](const AEntry &LHS, const KeyType &RHS) {
- if (LHS.Val1 < RHS.Val1)
- return true;
- if (LHS.Val1 > RHS.Val1)
- return false;
- if (LHS.Val2 < RHS.Val2)
- return true;
- if (LHS.Val2 > RHS.Val2)
- return false;
+ KeyType Key = { Val1, Val2 };
+ auto Table = ArrayRef(ATable);
+ auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
+ [](const AEntry &LHS, const KeyType &RHS) {
+ if (LHS.Val1 < RHS.Val1)
+ return true;
+ if (LHS.Val1 > RHS.Val1)
return false;
- });
-
- if (Idx == Table.end() ||
- Key.Val1 != Idx->Val1 ||
- Key.Val2 != Idx->Val2)
- return nullptr;
- return &*Idx;
- }
- #endif
-
-The table entries in ``ATable`` are sorted in order by ``Val1``, and within
-each of those values, by ``Val2``. This allows a binary search of the table,
-which is performed in the lookup function by ``std::lower_bound``. The
+ if (LHS.Val2 < RHS.Val2)
+ return true;
+ if (LHS.Val2 > RHS.Val2)
+ return false;
+ return false;
+ });
+
+ if (Idx == Table.end() ||
+ Key.Val1 != Idx->Val1 ||
+ Key.Val2 != Idx->Val2)
+ return nullptr;
+ return &*Idx;
+}
+#endif
+```
+
+The table entries in `ATable` are sorted in order by `Val1`, and within
+each of those values, by `Val2`. This allows a binary search of the table,
+which is performed in the lookup function by `std::lower_bound`. The
lookup function returns a reference to the found table entry, or the null
pointer if no entry is found.
The emitter selects the lookup strategy automatically based on the primary key:
-* **Dense direct lookup**: used when the primary key is a single integral field
+- **Dense direct lookup**: used when the primary key is a single integral field
whose values form a contiguous range. A compact array is emitted and the
lookup function indexes into it directly.
-
-* **Sparse direct lookup**: used when ``DisallowSparseTable = 0``, the primary
- key is a single ``bits<N>`` field with N ≤ 12, ``PrimaryKeyReturnRange`` is
+- **Sparse direct lookup**: used when `DisallowSparseTable = 0`, the primary
+ key is a single `bits<N>` field with N ≤ 12, `PrimaryKeyReturnRange` is
false, and the table has no secondary search indexes. The emitter allocates a
- directly-indexed array of ``2^N`` entries. Empty slots are filled with a
+ directly-indexed array of `2^N` entries. Empty slots are filled with a
sentinel value in the key field such that the in-place key comparison in the
- lookup function returns ``nullptr`` for them. This trades memory for
+ lookup function returns `nullptr` for them. This trades memory for
O(1) lookup.
+- **Binary search**: the default for all other cases. Entries are sorted by the
+ primary key and `std::lower_bound` is used in the lookup function.
-* **Binary search**: the default for all other cases. Entries are sorted by the
- primary key and ``std::lower_bound`` is used in the lookup function.
-
-This example includes a field whose type TableGen cannot deduce. The ``Kind``
-field uses the enumerated type ``CEnum`` defined above. To inform TableGen
-of the type, the record derived from ``GenericTable`` must include a string field
-named ``TypeOf_``\ *field*, where *field* is the name of the field whose type
+This example includes a field whose type TableGen cannot deduce. The `Kind`
+field uses the enumerated type `CEnum` defined above. To inform TableGen
+of the type, the record derived from `GenericTable` must include a string field
+named `TypeOf_`*field*, where *field* is the name of the field whose type
is required.
-.. code-block:: text
-
- def CTable : GenericTable {
- let FilterClass = "CEntry";
- let Fields = ["Name", "Kind", "Encoding"];
- string TypeOf_Kind = "CEnum";
- let PrimaryKey = ["Encoding"];
- let PrimaryKeyName = "lookupCEntryByEncoding";
- }
-
- class CEntry<string name, CEnum kind, int enc> {
- string Name = name;
- CEnum Kind = kind;
- bits<16> Encoding = enc;
- }
-
- def : CEntry<"Apple", CFoo, 10>;
- def : CEntry<"Pear", CBaz, 15>;
- def : CEntry<"Apple", CBar, 13>;
+```text
+def CTable : GenericTable {
+ let FilterClass = "CEntry";
+ let Fields = ["Name", "Kind", "Encoding"];
+ string TypeOf_Kind = "CEnum";
+ let PrimaryKey = ["Encoding"];
+ let PrimaryKeyName = "lookupCEntryByEncoding";
+}
+
+class CEntry<string name, CEnum kind, int enc> {
+ string Name = name;
+ CEnum Kind = kind;
+ bits<16> Encoding = enc;
+}
+
+def : CEntry<"Apple", CFoo, 10>;
+def : CEntry<"Pear", CBaz, 15>;
+def : CEntry<"Apple", CBar, 13>;
+```
Here is the generated C++ code.
-.. code-block:: text
-
- #ifdef GET_CTable_DECL
- const CEntry *lookupCEntryByEncoding(uint16_t Encoding);
- #endif
-
- #ifdef GET_CTable_IMPL
- constexpr CEntry CTable[] = {
- { "Apple", CFoo, 0xA }, // 0
- { "Apple", CBar, 0xD }, // 1
- { "Pear", CBaz, 0xF }, // 2
+```text
+#ifdef GET_CTable_DECL
+const CEntry *lookupCEntryByEncoding(uint16_t Encoding);
+#endif
+
+#ifdef GET_CTable_IMPL
+constexpr CEntry CTable[] = {
+ { "Apple", CFoo, 0xA }, // 0
+ { "Apple", CBar, 0xD }, // 1
+ { "Pear", CBaz, 0xF }, // 2
+};
+
+const CEntry *lookupCEntryByEncoding(uint16_t Encoding) {
+ struct KeyType {
+ uint16_t Encoding;
};
-
- const CEntry *lookupCEntryByEncoding(uint16_t Encoding) {
- struct KeyType {
- uint16_t Encoding;
- };
- KeyType Key = { Encoding };
- auto Table = ArrayRef(CTable);
- auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
- [](const CEntry &LHS, const KeyType &RHS) {
- if (LHS.Encoding < RHS.Encoding)
- return true;
- if (LHS.Encoding > RHS.Encoding)
- return false;
+ KeyType Key = { Encoding };
+ auto Table = ArrayRef(CTable);
+ auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
+ [](const CEntry &LHS, const KeyType &RHS) {
+ if (LHS.Encoding < RHS.Encoding)
+ return true;
+ if (LHS.Encoding > RHS.Encoding)
return false;
- });
+ return false;
+ });
- if (Idx == Table.end() ||
- Key.Encoding != Idx->Encoding)
- return nullptr;
- return &*Idx;
- }
+ if (Idx == Table.end() ||
+ Key.Encoding != Idx->Encoding)
+ return nullptr;
+ return &*Idx;
+}
+```
In the above example, lets add one more record with encoding same as that of
-record ``CEntry<"Pear", CBaz, 15>``.
-
-.. code-block:: text
-
- def CFoobar : CEnum;
- def : CEntry<"Banana", CFoobar, 15>;
-
-Below is the new generated ``CTable``
-
-.. code-block:: text
-
- #ifdef GET_Table_IMPL
- constexpr CEntry Table[] = {
- { "Apple", CFoo, 0xA }, // 0
- { "Apple", CBar, 0xD }, // 1
- { "Banana", CFoobar, 0xF }, // 2
- { "Pear", CBaz, 0xF }, // 3
- };
-
-Since ``Banana`` lexicographically appears first, therefore in the ``CEntry``
-table, record with name ``Banana`` will come before the record with name
-``Pear``. Because of this, the ``lookupCEntryByEncoding`` function will always
-return a pointer to the record with name ``Banana`` even though in some cases
-the correct result can be the record with name ``Pear``. Such kind of scenario
+record `CEntry<"Pear", CBaz, 15>`.
+
+```text
+def CFoobar : CEnum;
+def : CEntry<"Banana", CFoobar, 15>;
+```
+
+Below is the new generated `CTable`
+
+```text
+#ifdef GET_Table_IMPL
+constexpr CEntry Table[] = {
+ { "Apple", CFoo, 0xA }, // 0
+ { "Apple", CBar, 0xD }, // 1
+ { "Banana", CFoobar, 0xF }, // 2
+ { "Pear", CBaz, 0xF }, // 3
+};
+```
+
+Since `Banana` lexicographically appears first, therefore in the `CEntry`
+table, record with name `Banana` will come before the record with name
+`Pear`. Because of this, the `lookupCEntryByEncoding` function will always
+return a pointer to the record with name `Banana` even though in some cases
+the correct result can be the record with name `Pear`. Such kind of scenario
makes the existing lookup function insufficient because they always return a
pointer to a single entry from the table, but instead it should return a range
of results because multiple entries match the criteria sought by the lookup
function. In this case, the definition of the lookup function needs to be
modified to return a range of results which can be done by setting
-``PrimaryKeyReturnRange``.
-
-.. code-block:: text
-
- def CTable : GenericTable {
- let FilterClass = "CEntry";
- let Fields = ["Name", "Kind", "Encoding"];
- string TypeOf_Kind = "CEnum";
- let PrimaryKey = ["Encoding"];
- let PrimaryKeyName = "lookupCEntryByEncoding";
- let PrimaryKeyReturnRange = true;
- }
+`PrimaryKeyReturnRange`.
+
+```text
+def CTable : GenericTable {
+ let FilterClass = "CEntry";
+ let Fields = ["Name", "Kind", "Encoding"];
+ string TypeOf_Kind = "CEnum";
+ let PrimaryKey = ["Encoding"];
+ let PrimaryKeyName = "lookupCEntryByEncoding";
+ let PrimaryKeyReturnRange = true;
+}
+```
Here is the modified lookup function.
-.. code-block:: text
-
- llvm::iterator_range<const CEntry *> lookupCEntryByEncoding(uint16_t Encoding) {
- struct KeyType {
- uint16_t Encoding;
- };
- KeyType Key = {Encoding};
- struct Comp {
- bool operator()(const CEntry &LHS, const KeyType &RHS) const {
- if (LHS.Encoding < RHS.Encoding)
- return true;
- if (LHS.Encoding > RHS.Encoding)
- return false;
+```text
+llvm::iterator_range<const CEntry *> lookupCEntryByEncoding(uint16_t Encoding) {
+ struct KeyType {
+ uint16_t Encoding;
+ };
+ KeyType Key = {Encoding};
+ struct Comp {
+ bool operator()(const CEntry &LHS, const KeyType &RHS) const {
+ if (LHS.Encoding < RHS.Encoding)
+ return true;
+ if (LHS.Encoding > RHS.Encoding)
return false;
- }
- bool operator()(const KeyType &LHS, const CEntry &RHS) const {
- if (LHS.Encoding < RHS.Encoding)
- return true;
- if (LHS.Encoding > RHS.Encoding)
- return false;
+ return false;
+ }
+ bool operator()(const KeyType &LHS, const CEntry &RHS) const {
+ if (LHS.Encoding < RHS.Encoding)
+ return true;
+ if (LHS.Encoding > RHS.Encoding)
return false;
- }
- };
- auto Table = ArrayRef(Table);
- auto It = std::equal_range(Table.begin(), Table.end(), Key, Comp());
- return llvm::make_range(It.first, It.second);
- }
+ return false;
+ }
+ };
+ auto Table = ArrayRef(Table);
+ auto It = std::equal_range(Table.begin(), Table.end(), Key, Comp());
+ return llvm::make_range(It.first, It.second);
+}
+```
The new lookup function will return an iterator range with first pointer to the
first result and the last pointer to the last matching result from the table.
However, please note that the support for emitting a modified definition exists
-for ``PrimaryKeyName`` only.
+for `PrimaryKeyName` only.
-The ``PrimaryKeyEarlyOut`` field, when set to 1, modifies the lookup
+The `PrimaryKeyEarlyOut` field, when set to 1, modifies the lookup
function so that it tests the first field of the primary key to determine
whether it is within the range of the collected records' primary keys. If
not, the function returns the null pointer without performing the binary
@@ -1005,209 +921,207 @@ search. This is useful for tables that provide data for only some of the
elements of a larger enum-based space. The first field of the primary key
must be an integral type; it cannot be a string.
-Adding ``let PrimaryKeyEarlyOut = 1`` to the ``ATable`` above:
-
-.. code-block:: text
+Adding `let PrimaryKeyEarlyOut = 1` to the `ATable` above:
- def ATable : GenericTable {
- let FilterClass = "AEntry";
- let Fields = ["Str", "Val1", "Val2"];
- let PrimaryKey = ["Val1", "Val2"];
- let PrimaryKeyName = "lookupATableByValues";
- let PrimaryKeyEarlyOut = 1;
- }
+```text
+def ATable : GenericTable {
+ let FilterClass = "AEntry";
+ let Fields = ["Str", "Val1", "Val2"];
+ let PrimaryKey = ["Val1", "Val2"];
+ let PrimaryKeyName = "lookupATableByValues";
+ let PrimaryKeyEarlyOut = 1;
+}
+```
causes the lookup function to change as follows:
-.. code-block:: text
+```text
+const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
+ if ((Val1 < 0x2) ||
+ (Val1 > 0x5))
+ return nullptr;
- const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
- if ((Val1 < 0x2) ||
- (Val1 > 0x5))
- return nullptr;
-
- struct KeyType {
- ...
+ struct KeyType {
+ ...
+```
-We can construct two GenericTables with the same ``FilterClass``, so that they
+We can construct two GenericTables with the same `FilterClass`, so that they
select from the same overall set of records, but assign them with different
-``FilterClassField`` values so that they include different subsets of the
+`FilterClassField` values so that they include different subsets of the
records of that class.
For example, we can create two tables that contain only even or odd records.
-Fields ``IsEven`` and ``IsOdd`` won't be included in generated C++ fields
-because they aren't included in ``Fields`` list.
-
-.. code-block:: text
-
- class EEntry<bits<8> value> {
- bits<8> Value = value;
- bit IsEven = !eq(!and(value, 1), 0);
- bit IsOdd = !not(IsEven);
- }
-
- foreach i = {1-10} in {
- def : EEntry<i>;
- }
-
- def EEntryEvenTable : GenericTable {
- let FilterClass = "EEntry";
- let FilterClassField = "IsEven";
- let Fields = ["Value"];
- let PrimaryKey = ["Value"];
- let PrimaryKeyName = "lookupEEntryEvenTableByValue";
- }
-
- def EEntryOddTable : GenericTable {
- let FilterClass = "EEntry";
- let FilterClassField = "IsOdd";
- let Fields = ["Value"];
- let PrimaryKey = ["Value"];
- let PrimaryKeyName = "lookupEEntryOddTableByValue";
- }
+Fields `IsEven` and `IsOdd` won't be included in generated C++ fields
+because they aren't included in `Fields` list.
+
+```text
+class EEntry<bits<8> value> {
+ bits<8> Value = value;
+ bit IsEven = !eq(!and(value, 1), 0);
+ bit IsOdd = !not(IsEven);
+}
+
+foreach i = {1-10} in {
+ def : EEntry<i>;
+}
+
+def EEntryEvenTable : GenericTable {
+ let FilterClass = "EEntry";
+ let FilterClassField = "IsEven";
+ let Fields = ["Value"];
+ let PrimaryKey = ["Value"];
+ let PrimaryKeyName = "lookupEEntryEvenTableByValue";
+}
+
+def EEntryOddTable : GenericTable {
+ let FilterClass = "EEntry";
+ let FilterClassField = "IsOdd";
+ let Fields = ["Value"];
+ let PrimaryKey = ["Value"];
+ let PrimaryKeyName = "lookupEEntryOddTableByValue";
+}
+```
The generated tables are:
-.. code-block:: text
-
- constexpr EEntry EEntryEvenTable[] = {
- { 0x2 }, // 0
- { 0x4 }, // 1
- { 0x6 }, // 2
- { 0x8 }, // 3
- { 0xA }, // 4
- };
-
- constexpr EEntry EEntryOddTable[] = {
- { 0x1 }, // 0
- { 0x3 }, // 1
- { 0x5 }, // 2
- { 0x7 }, // 3
- { 0x9 }, // 4
- };
-
-Here is an example of a sparse direct-lookup table. ``FTable`` uses a 4-bit
-primary key (``bits<4>``), so the emitter allocates an array of
-``2^4 = 16`` entries.
-
-.. code-block:: text
-
- def FTable : GenericTable {
- let FilterClass = "FEntry";
- let Fields = ["Key", "Val"];
- let PrimaryKey = ["Key"];
- let PrimaryKeyName = "lookupFTableByKey";
- let DisallowSparseTable = false;
- }
-
-Here is the generated C++ code. The declaration of ``lookupFTableByKey`` is
-guarded by ``GET_FTable_DECL``, while the definitions are guarded by
-``GET_FTable_IMPL``.
-
-.. code-block:: text
-
- #ifdef GET_FTable_DECL
- const FEntry *lookupFTableByKey(uint8_t Key);
- #endif
-
- #ifdef GET_FTable_IMPL
- constexpr FEntry FTable[] = {
- { 0xF, 0x0 }, // 0
- { 0xE, 0x0 }, // 1
- { 0x2, 0xA }, // 2
- { 0xC, 0x0 }, // 3
- { 0xB, 0x0 }, // 4
- { 0x5, 0x14 }, // 5
- { 0x9, 0x0 }, // 6
- { 0x8, 0x0 }, // 7
- { 0x7, 0x0 }, // 8
- { 0x6, 0x0 }, // 9
- { 0x5, 0x0 }, // 10
- { 0x4, 0x0 }, // 11
- { 0x3, 0x0 }, // 12
- { 0xD, 0x1E }, // 13
- { 0x1, 0x0 }, // 14
- { 0x0, 0x0 }, // 15
- };
-
- const FEntry *lookupFTableByKey(uint8_t Key) {
- if (Key >= 16)
- return nullptr;
- const auto *Entry = &FTable[Key];
- return Entry->Key == Key ? Entry : nullptr;
- }
- #endif
-
-Empty slots are filled with a sentinel value in the ``Key`` field
-(``(15 ^ Idx)``) so that the in-place comparison ``Entry->Key == Key``
-returns ``nullptr`` for them without a separate presence array.
-
-Search Indexes
-~~~~~~~~~~~~~~
-
-The ``SearchIndex`` class is used to define additional lookup functions for
+```text
+constexpr EEntry EEntryEvenTable[] = {
+ { 0x2 }, // 0
+ { 0x4 }, // 1
+ { 0x6 }, // 2
+ { 0x8 }, // 3
+ { 0xA }, // 4
+};
+
+constexpr EEntry EEntryOddTable[] = {
+ { 0x1 }, // 0
+ { 0x3 }, // 1
+ { 0x5 }, // 2
+ { 0x7 }, // 3
+ { 0x9 }, // 4
+};
+```
+
+Here is an example of a sparse direct-lookup table. `FTable` uses a 4-bit
+primary key (`bits<4>`), so the emitter allocates an array of
+`2^4 = 16` entries.
+
+```text
+def FTable : GenericTable {
+ let FilterClass = "FEntry";
+ let Fields = ["Key", "Val"];
+ let PrimaryKey = ["Key"];
+ let PrimaryKeyName = "lookupFTableByKey";
+ let DisallowSparseTable = false;
+}
+```
+
+Here is the generated C++ code. The declaration of `lookupFTableByKey` is
+guarded by `GET_FTable_DECL`, while the definitions are guarded by
+`GET_FTable_IMPL`.
+
+```text
+#ifdef GET_FTable_DECL
+const FEntry *lookupFTableByKey(uint8_t Key);
+#endif
+
+#ifdef GET_FTable_IMPL
+constexpr FEntry FTable[] = {
+ { 0xF, 0x0 }, // 0
+ { 0xE, 0x0 }, // 1
+ { 0x2, 0xA }, // 2
+ { 0xC, 0x0 }, // 3
+ { 0xB, 0x0 }, // 4
+ { 0x5, 0x14 }, // 5
+ { 0x9, 0x0 }, // 6
+ { 0x8, 0x0 }, // 7
+ { 0x7, 0x0 }, // 8
+ { 0x6, 0x0 }, // 9
+ { 0x5, 0x0 }, // 10
+ { 0x4, 0x0 }, // 11
+ { 0x3, 0x0 }, // 12
+ { 0xD, 0x1E }, // 13
+ { 0x1, 0x0 }, // 14
+ { 0x0, 0x0 }, // 15
+};
+
+const FEntry *lookupFTableByKey(uint8_t Key) {
+ if (Key >= 16)
+ return nullptr;
+ const auto *Entry = &FTable[Key];
+ return Entry->Key == Key ? Entry : nullptr;
+}
+#endif
+```
+
+Empty slots are filled with a sentinel value in the `Key` field
+(`(15 ^ Idx)`) so that the in-place comparison `Entry->Key == Key`
+returns `nullptr` for them without a separate presence array.
+
+#### Search Indexes
+
+The `SearchIndex` class is used to define additional lookup functions for
generic tables. To define an additional function, define a record whose parent
-class is ``SearchIndex`` and whose name is the name of the desired lookup
+class is `SearchIndex` and whose name is the name of the desired lookup
function. This class provides three fields.
-* ``GenericTable Table``. The name of the table that is to receive another
+- `GenericTable Table`. The name of the table that is to receive another
lookup function.
+- `list<string> Key`. The list of fields that make up the secondary key.
+- `bit EarlyOut`. See the third example in [Generic Tables].
-* ``list<string> Key``. The list of fields that make up the secondary key.
-
-* ``bit EarlyOut``. See the third example in `Generic Tables`_.
+Here is an example of a secondary key added to the `CTable` above. The
+generated function looks up entries based on the `Name` and `Kind` fields.
-Here is an example of a secondary key added to the ``CTable`` above. The
-generated function looks up entries based on the ``Name`` and ``Kind`` fields.
+```text
+def lookupCEntry : SearchIndex {
+ let Table = CTable;
+ let Key = ["Name", "Kind"];
+}
+```
-.. code-block:: text
+This use of `SearchIndex` generates the following additional C++ code.
- def lookupCEntry : SearchIndex {
- let Table = CTable;
- let Key = ["Name", "Kind"];
- }
+```text
+const CEntry *lookupCEntry(StringRef Name, unsigned Kind);
-This use of ``SearchIndex`` generates the following additional C++ code.
+...
-.. code-block:: text
+const CEntry *lookupCEntryByName(StringRef Name, unsigned Kind) {
+ struct IndexType {
+ const char * Name;
+ unsigned Kind;
+ unsigned _index;
+ };
+ static const struct IndexType Index[] = {
+ { "APPLE", CBar, 1 },
+ { "APPLE", CFoo, 0 },
+ { "PEAR", CBaz, 2 },
+ };
- const CEntry *lookupCEntry(StringRef Name, unsigned Kind);
+ struct KeyType {
+ std::string Name;
+ unsigned Kind;
+ };
+ KeyType Key = { Name.upper(), Kind };
+ auto Table = ArrayRef(Index);
+ auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
+ [](const IndexType &LHS, const KeyType &RHS) {
+ int CmpName = StringRef(LHS.Name).compare(RHS.Name);
+ if (CmpName < 0) return true;
+ if (CmpName > 0) return false;
+ if ((unsigned)LHS.Kind < (unsigned)RHS.Kind)
+ return true;
+ if ((unsigned)LHS.Kind > (unsigned)RHS.Kind)
+ return false;
+ return false;
+ });
- ...
+ if (Idx == Table.end() ||
+ Key.Name != Idx->Name ||
+ Key.Kind != Idx->Kind)
+ return nullptr;
+ return &CTable[Idx->_index];
+}
+```
- const CEntry *lookupCEntryByName(StringRef Name, unsigned Kind) {
- struct IndexType {
- const char * Name;
- unsigned Kind;
- unsigned _index;
- };
- static const struct IndexType Index[] = {
- { "APPLE", CBar, 1 },
- { "APPLE", CFoo, 0 },
- { "PEAR", CBaz, 2 },
- };
-
- struct KeyType {
- std::string Name;
- unsigned Kind;
- };
- KeyType Key = { Name.upper(), Kind };
- auto Table = ArrayRef(Index);
- auto Idx = std::lower_bound(Table.begin(), Table.end(), Key,
- [](const IndexType &LHS, const KeyType &RHS) {
- int CmpName = StringRef(LHS.Name).compare(RHS.Name);
- if (CmpName < 0) return true;
- if (CmpName > 0) return false;
- if ((unsigned)LHS.Kind < (unsigned)RHS.Kind)
- return true;
- if ((unsigned)LHS.Kind > (unsigned)RHS.Kind)
- return false;
- return false;
- });
-
- if (Idx == Table.end() ||
- Key.Name != Idx->Name ||
- Key.Kind != Idx->Kind)
- return nullptr;
- return &CTable[Idx->_index];
- }
diff --git a/llvm/docs/TableGen/BackGuide.md b/llvm/docs/TableGen/BackGuide.md
index 6cc6f04afe901..1e232c1cbeb28 100644
--- a/llvm/docs/TableGen/BackGuide.md
+++ b/llvm/docs/TableGen/BackGuide.md
@@ -1,12 +1,11 @@
-===================================
-TableGen Backend Developer's Guide
-===================================
+# TableGen Backend Developer's Guide
+```{eval-rst}
.. sectnum::
+```
-Introduction
-============
+## Introduction
The purpose of TableGen is to generate complex output files based on
information from source files that are significantly easier to code than the
@@ -14,22 +13,21 @@ output files would be, and also easier to maintain and modify over time. The
information is coded in a declarative style involving classes and records,
which are then processed by TableGen. The internalized records are passed on
to various backends, which extract information from a subset of the records
-and generate an output file. These output files are typically ``.inc`` files
+and generate an output file. These output files are typically `.inc` files
for C++, but they may be any type of file that the backend developer needs.
This document is a guide to writing a backend for TableGen. It is not a
complete reference manual, but rather a guide to using the facilities
provided by TableGen for the backends. For a complete reference to the
various data structures and functions involved, see the primary TableGen
-header file (``record.h``) and/or the Doxygen documentation.
+header file (`record.h`) and/or the Doxygen documentation.
-This document assumes that you have read the :doc:`TableGen Programmer's
+This document assumes that you have read the {doc}`TableGen Programmer's
Reference <./ProgRef>`, which provides a detailed reference for coding
TableGen source files. For a description of the existing backends, see
-:doc:`TableGen BackEnds <./BackEnds>`.
+{doc}`TableGen BackEnds <./BackEnds>`.
-Data Structures
-===============
+## Data Structures
The following sections describe the data structures that contain the classes
and records that are collected from the TableGen source files by the
@@ -39,811 +37,727 @@ class, while the term *record* refers to a concrete record.
Unless otherwise noted, functions associated with classes are instance
functions.
-``RecordKeeper``
-----------------
+### `RecordKeeper`
-An instance of the ``RecordKeeper`` class acts as the container for all the
-classes and records parsed and collected by TableGen. The ``RecordKeeper``
+An instance of the `RecordKeeper` class acts as the container for all the
+classes and records parsed and collected by TableGen. The `RecordKeeper`
instance is passed to the backend when it is invoked by TableGen. This class
-is usually abbreviated ``RK``.
+is usually abbreviated `RK`.
There are two maps in the recordkeeper, one for classes and one for records
(the latter often referred to as *defs*). Each map maps the class or record
-name to an instance of the ``Record`` class (see `Record`_), which contains
+name to an instance of the `Record` class (see [Record]), which contains
all the information about that class or record.
-In addition to the two maps, the ``RecordKeeper`` instance contains:
+In addition to the two maps, the `RecordKeeper` instance contains:
-* A map that maps the names of global variables to their values.
+- A map that maps the names of global variables to their values.
Global variables are defined in TableGen files with outer
- ``defvar`` statements.
+ `defvar` statements.
+- A counter for naming anonymous records.
-* A counter for naming anonymous records.
+The `RecordKeeper` class provides a few useful functions.
-The ``RecordKeeper`` class provides a few useful functions.
+- Functions to get the complete class and record maps.
+- Functions to get a subset of the records based on their parent classes.
+- Functions to get individual classes, records, and globals, by name.
-* Functions to get the complete class and record maps.
-
-* Functions to get a subset of the records based on their parent classes.
-
-* Functions to get individual classes, records, and globals, by name.
-
-A ``RecordKeeper`` instance can be printed to an output stream with the ``<<``
+A `RecordKeeper` instance can be printed to an output stream with the `<<`
operator.
-``Record``
-----------
+### `Record`
Each class or record built by TableGen is represented by an instance of
-the ``Record`` class. The ``RecordKeeper`` instance contains one map for the
+the `Record` class. The `RecordKeeper` instance contains one map for the
classes and one for the records. The primary data members of a record are
the record name, the vector of field names and their values, and the vector of
superclasses of the record.
-The record name is stored as a pointer to an ``Init`` (see `Init`_), which
+The record name is stored as a pointer to an `Init` (see [Init]), which
is a class whose instances hold TableGen values (sometimes referred to as
*initializers*). The field names and values are stored in a vector of
-``RecordVal`` instances (see `RecordVal`_), each of which contains both the
+`RecordVal` instances (see [RecordVal]), each of which contains both the
field name and its value. The superclass vector contains a sequence of
pairs, with each pair including the superclass record and its source
file location.
-In addition to those members, a ``Record`` instance contains:
+In addition to those members, a `Record` instance contains:
-* A vector of source file locations that includes the record definition
+- A vector of source file locations that includes the record definition
itself, plus the locations of any multiclasses involved in its definition.
+- For a class record, a vector of the class's template arguments.
+- An instance of `DefInit` (see [DefInit]) corresponding to this record.
+- A unique record ID.
+- A boolean that specifies whether this is a class definition.
+- A boolean that specifies whether this is an anonymous record.
-* For a class record, a vector of the class's template arguments.
-
-* An instance of ``DefInit`` (see `DefInit`_) corresponding to this record.
-
-* A unique record ID.
-
-* A boolean that specifies whether this is a class definition.
+The `Record` class provides many useful functions.
-* A boolean that specifies whether this is an anonymous record.
-
-The ``Record`` class provides many useful functions.
-
-* Functions to get the record name, fields, source file locations,
+- Functions to get the record name, fields, source file locations,
template arguments, and unique ID.
-
-* Functions to get all the record's superclasses or just its direct
+- Functions to get all the record's superclasses or just its direct
superclasses.
-
-* Functions to get a particular field value by specifying its name in various
+- Functions to get a particular field value by specifying its name in various
forms and returning its value in various forms
- (see `Getting Record Names and Fields`_).
-
-* Boolean functions to check the various attributes of the record.
+ (see [Getting Record Names and Fields]).
+- Boolean functions to check the various attributes of the record.
-A ``Record`` instance can be printed to an output stream with the ``<<``
+A `Record` instance can be printed to an output stream with the `<<`
operator.
+### `RecordVal`
-``RecordVal``
--------------
-
-Each field of a record is stored in an instance of the ``RecordVal`` class.
-The ``Record`` instance includes a vector of these value instances. A
-``RecordVal`` instance contains the name of the field, stored in an ``Init``
+Each field of a record is stored in an instance of the `RecordVal` class.
+The `Record` instance includes a vector of these value instances. A
+`RecordVal` instance contains the name of the field, stored in an `Init`
instance. It also contains the value of the field, likewise stored in an
-``Init``. (A better name for this class might be ``RecordField``.)
+`Init`. (A better name for this class might be `RecordField`.)
-In addition to those primary members, the ``RecordVal`` has other data members.
+In addition to those primary members, the `RecordVal` has other data members.
-* The source file location of the field definition.
+- The source file location of the field definition.
+- The type of the field, stored as an instance
+ of the `RecTy` class (see [RecTy]).
-* The type of the field, stored as an instance
- of the ``RecTy`` class (see `RecTy`_).
+The `RecordVal` class provides some useful functions.
-The ``RecordVal`` class provides some useful functions.
+- Functions to get the name of the field in various forms.
+- A function to get the type of the field.
+- A function to get the value of the field.
+- A function to get the source file location.
-* Functions to get the name of the field in various forms.
+Note that field values are more easily obtained directly from the `Record`
+instance (see [Record]).
-* A function to get the type of the field.
-
-* A function to get the value of the field.
-
-* A function to get the source file location.
-
-Note that field values are more easily obtained directly from the ``Record``
-instance (see `Record`_).
-
-A ``RecordVal`` instance can be printed to an output stream with the ``<<``
+A `RecordVal` instance can be printed to an output stream with the `<<`
operator.
-``RecTy``
----------
+### `RecTy`
-The ``RecTy`` class is used to represent the types of field values. It is
+The `RecTy` class is used to represent the types of field values. It is
the base class for a series of subclasses, one for each of the
-available field types. The ``RecTy`` class has one data member that is an
+available field types. The `RecTy` class has one data member that is an
enumerated type specifying the specific type of field value. (A better
-name for this class might be ``FieldTy``.)
-
-The ``RecTy`` class provides a few useful functions.
+name for this class might be `FieldTy`.)
-* A virtual function to get the type name as a string.
+The `RecTy` class provides a few useful functions.
-* A virtual function to check whether all the values of this type can
+- A virtual function to get the type name as a string.
+- A virtual function to check whether all the values of this type can
be converted to another given type.
-
-* A virtual function to check whether this type is a subtype of
+- A virtual function to check whether this type is a subtype of
another given type.
-
-* A function to get the corresponding ``list``
+- A function to get the corresponding `list`
type for lists with elements of this type. For example, the function
- returns the ``list<int>`` type when called with the ``int`` type.
-
-The subclasses that inherit from ``RecTy`` are
-``BitRecTy``,
-``BitsRecTy``,
-``CodeRecTy``,
-``DagRecTy``,
-``IntRecTy``,
-``ListRecTy``,
-``RecordRecTy``, and
-``StringRecTy``.
+ returns the `list<int>` type when called with the `int` type.
+
+The subclasses that inherit from `RecTy` are
+`BitRecTy`,
+`BitsRecTy`,
+`CodeRecTy`,
+`DagRecTy`,
+`IntRecTy`,
+`ListRecTy`,
+`RecordRecTy`, and
+`StringRecTy`.
Some of these classes have additional members that
are described in the following subsections.
-*All* of the classes derived from ``RecTy`` provide the ``get()`` function.
-It returns an instance of ``RecTy`` corresponding to the derived class.
-Some of the ``get()`` functions require an argument to
+*All* of the classes derived from `RecTy` provide the `get()` function.
+It returns an instance of `RecTy` corresponding to the derived class.
+Some of the `get()` functions require an argument to
specify which particular variant of the type is desired. These arguments are
described in the following subsections.
-A ``RecTy`` instance can be printed to an output stream with the ``<<``
+A `RecTy` instance can be printed to an output stream with the `<<`
operator.
-.. warning::
- It is not specified whether there is a single ``RecTy`` instance of a
- particular type or multiple instances.
-
+:::{warning}
+It is not specified whether there is a single `RecTy` instance of a
+particular type or multiple instances.
+:::
-``BitsRecTy``
-~~~~~~~~~~~~~
+#### `BitsRecTy`
-This class includes a data member with the size of the ``bits`` value and a
+This class includes a data member with the size of the `bits` value and a
function to get that size.
-The ``get()`` function takes the length of the sequence, *n*, and returns the
-``BitsRecTy`` type corresponding to ``bits<``\ *n*\ ``>``.
+The `get()` function takes the length of the sequence, *n*, and returns the
+`BitsRecTy` type corresponding to `bits<`*n*`>`.
-``ListRecTy``
-~~~~~~~~~~~~~
+#### `ListRecTy`
This class includes a data member that specifies the type of the list's
elements and a function to get that type.
-The ``get()`` function takes the ``RecTy`` *type* of the list members and
-returns the ``ListRecTy`` type corresponding to ``list<``\ *type*\ ``>``.
-
+The `get()` function takes the `RecTy` *type* of the list members and
+returns the `ListRecTy` type corresponding to `list<`*type*`>`.
-``RecordRecTy``
-~~~~~~~~~~~~~~~
+#### `RecordRecTy`
This class includes data members that contain the list of parent classes of
this record. It also provides a function to obtain the array of classes and
-two functions to get the iterator ``begin()`` and ``end()`` values. The
+two functions to get the iterator `begin()` and `end()` values. The
class defines a type for the return values of the latter two functions.
-.. code-block:: text
+```text
+using const_record_iterator = Record * const *;
+```
- using const_record_iterator = Record * const *;
-
-The ``get()`` function takes an ``ArrayRef`` of pointers to the ``Record``
-instances of the *direct* superclasses of the record and returns the ``RecordRecTy``
+The `get()` function takes an `ArrayRef` of pointers to the `Record`
+instances of the *direct* superclasses of the record and returns the `RecordRecTy`
corresponding to the record inheriting from those superclasses.
-``Init``
---------
+### `Init`
-The ``Init`` class is used to represent TableGen values. The name derives
+The `Init` class is used to represent TableGen values. The name derives
from *initialization value*. This class should not be confused with the
-``RecordVal`` class, which represents record fields, both their names and
-values. The ``Init`` class is the base class for a series of subclasses, one
-for each of the available value types. The primary data member of ``Init``
+`RecordVal` class, which represents record fields, both their names and
+values. The `Init` class is the base class for a series of subclasses, one
+for each of the available value types. The primary data member of `Init`
is an enumerated type that represents the specific type of the value.
-The ``Init`` class provides a few useful functions.
-
-* A function to get the type enumerator.
+The `Init` class provides a few useful functions.
-* A boolean virtual function to determine whether a value is completely
+- A function to get the type enumerator.
+- A boolean virtual function to determine whether a value is completely
specified; that is, has no uninitialized subvalues.
-
-* Virtual functions to get the value as a string.
-
-* Virtual functions to cast the value to other types, implement the bit
+- Virtual functions to get the value as a string.
+- Virtual functions to cast the value to other types, implement the bit
range feature of TableGen, and implement the list slice feature.
+- A virtual function to get a particular bit of the value.
-* A virtual function to get a particular bit of the value.
-
-The subclasses that inherit directly from ``Init`` are
-``UnsetInit`` and ``TypedInit``.
+The subclasses that inherit directly from `Init` are
+`UnsetInit` and `TypedInit`.
-An ``Init`` instance can be printed to an output stream with the ``<<``
+An `Init` instance can be printed to an output stream with the `<<`
operator.
-.. warning::
- It is not specified whether two separate initialization values with
- the same underlying type and value (e.g., two strings with the value
- "Hello") are represented by two ``Init``\ s or share the same ``Init``.
+:::{warning}
+It is not specified whether two separate initialization values with
+the same underlying type and value (e.g., two strings with the value
+"Hello") are represented by two `Init`s or share the same `Init`.
+:::
-``UnsetInit``
-~~~~~~~~~~~~~
+#### `UnsetInit`
-This class, a subclass of ``Init``, represents the unset (uninitialized)
-value. The static function ``get()`` can be used to obtain the singleton
-``Init`` of this type.
+This class, a subclass of `Init`, represents the unset (uninitialized)
+value. The static function `get()` can be used to obtain the singleton
+`Init` of this type.
+#### `TypedInit`
-``TypedInit``
-~~~~~~~~~~~~~
-
-This class, a subclass of ``Init``, acts as the parent class of the classes
+This class, a subclass of `Init`, acts as the parent class of the classes
that represent specific value types (except for the unset value). These
-classes include ``BitInit``, ``BitsInit``, ``DagInit``, ``DefInit``,
-``IntInit``, ``ListInit``, and ``StringInit``. (There are additional derived
+classes include `BitInit`, `BitsInit`, `DagInit`, `DefInit`,
+`IntInit`, `ListInit`, and `StringInit`. (There are additional derived
types used by the TableGen parser.)
-This class includes a data member that specifies the ``RecTy`` type of the
-value. It provides a function to get that ``RecTy`` type.
+This class includes a data member that specifies the `RecTy` type of the
+value. It provides a function to get that `RecTy` type.
-``BitInit``
-~~~~~~~~~~~
+#### `BitInit`
-The ``BitInit`` class is a subclass of ``TypedInit``. Its instances
+The `BitInit` class is a subclass of `TypedInit`. Its instances
represent the possible values of a bit: 0 or 1. It includes a data member
that contains the bit.
-*All* of the classes derived from ``TypedInit`` provide the following functions:
+*All* of the classes derived from `TypedInit` provide the following functions:
-* A static function named ``get()`` that returns an ``Init`` representing
- the specified value(s). In the case of ``BitInit``, ``get(true)`` returns
- an instance of ``BitInit`` representing true, while ``get(false)`` returns
+- A static function named `get()` that returns an `Init` representing
+ the specified value(s). In the case of `BitInit`, `get(true)` returns
+ an instance of `BitInit` representing true, while `get(false)` returns
an instance
representing false. As noted above, it is not specified whether there
- is exactly one or more than one ``BitInit`` representing true (or false).
-
-* A function named ``GetValue()`` that returns the value of the instance
- in a more direct form, in this case as a ``bool``.
+ is exactly one or more than one `BitInit` representing true (or false).
+- A function named `GetValue()` that returns the value of the instance
+ in a more direct form, in this case as a `bool`.
-``BitsInit``
-~~~~~~~~~~~~
+#### `BitsInit`
-The ``BitsInit`` class is a subclass of ``TypedInit``. Its instances
+The `BitsInit` class is a subclass of `TypedInit`. Its instances
represent sequences of bits, from high-order to low-order. It includes a
data member with the length of the sequence and a vector of pointers to
-``Init`` instances, one per bit.
+`Init` instances, one per bit.
-The class provides the usual ``get()`` function. It does not provide the
-``getValue()`` function.
+The class provides the usual `get()` function. It does not provide the
+`getValue()` function.
The class provides the following additional functions.
-* A function to get the number of bits in the sequence.
-
-* A function that gets a bit specified by an integer index.
+- A function to get the number of bits in the sequence.
+- A function that gets a bit specified by an integer index.
-``DagInit``
-~~~~~~~~~~~
+#### `DagInit`
-The ``DagInit`` class is a subclass of ``TypedInit``. Its instances
-represent the possible directed acyclic graphs (``dag``).
+The `DagInit` class is a subclass of `TypedInit`. Its instances
+represent the possible directed acyclic graphs (`dag`).
-The class includes a pointer to an ``Init`` for the DAG operator and a
-pointer to a ``StringInit`` for the operator name. It includes the count of
+The class includes a pointer to an `Init` for the DAG operator and a
+pointer to a `StringInit` for the operator name. It includes the count of
DAG operands and the count of operand names. Finally, it includes a vector of
-pointers to ``Init`` instances for the operands and another to
-``StringInit`` instances for the operand names.
+pointers to `Init` instances for the operands and another to
+`StringInit` instances for the operand names.
(The DAG operands are also referred to as *arguments*.)
-The class provides two forms of the usual ``get()`` function. It does not
-provide the usual ``getValue()`` function.
+The class provides two forms of the usual `get()` function. It does not
+provide the usual `getValue()` function.
The class provides many additional functions:
-* Functions to get the operator in various forms and to get the
+- Functions to get the operator in various forms and to get the
operator name in various forms.
-
-* Functions to determine whether there are any operands and to get the
+- Functions to determine whether there are any operands and to get the
number of operands.
-
-* Functions to get the operands, both individually and together.
-
-* Functions to determine whether there are any names and to
+- Functions to get the operands, both individually and together.
+- Functions to determine whether there are any names and to
get the number of names.
-
-* Functions to get the names, both individually and together.
-
-* Functions to get the operand iterator ``begin()`` and ``end()`` values.
-
-* Functions to get the name iterator ``begin()`` and ``end()`` values.
+- Functions to get the names, both individually and together.
+- Functions to get the operand iterator `begin()` and `end()` values.
+- Functions to get the name iterator `begin()` and `end()` values.
The class defines two types for the return values of the operand and name
iterators.
-.. code-block:: text
-
- using const_arg_iterator = SmallVectorImpl<Init*>::const_iterator;
- using const_name_iterator = SmallVectorImpl<StringInit*>::const_iterator;
-
+```text
+using const_arg_iterator = SmallVectorImpl<Init*>::const_iterator;
+using const_name_iterator = SmallVectorImpl<StringInit*>::const_iterator;
+```
-``DefInit``
-~~~~~~~~~~~
+#### `DefInit`
-The ``DefInit`` class is a subclass of ``TypedInit``. Its instances
+The `DefInit` class is a subclass of `TypedInit`. Its instances
represent the records that were collected by TableGen. It includes a data
-member that is a pointer to the record's ``Record`` instance.
+member that is a pointer to the record's `Record` instance.
-The class provides the usual ``get()`` function. It does not provide
-``getValue()``. Instead, it provides ``getDef()``, which returns the
-``Record`` instance.
+The class provides the usual `get()` function. It does not provide
+`getValue()`. Instead, it provides `getDef()`, which returns the
+`Record` instance.
-``IntInit``
-~~~~~~~~~~~
+#### `IntInit`
-The ``IntInit`` class is a subclass of ``TypedInit``. Its instances
+The `IntInit` class is a subclass of `TypedInit`. Its instances
represent the possible values of a 64-bit integer. It includes a data member
that contains the integer.
-The class provides the usual ``get()`` and ``getValue()`` functions. The
-latter function returns the integer as an ``int64_t``.
+The class provides the usual `get()` and `getValue()` functions. The
+latter function returns the integer as an `int64_t`.
-The class also provides a function, ``getBit()``, to obtain a specified bit
+The class also provides a function, `getBit()`, to obtain a specified bit
of the integer value.
-``ListInit``
-~~~~~~~~~~~~
+#### `ListInit`
-The ``ListInit`` class is a subclass of ``TypedInit``. Its instances
+The `ListInit` class is a subclass of `TypedInit`. Its instances
represent lists of elements of some type. It includes a data member with the
-length of the list and a vector of pointers to ``Init`` instances, one per
+length of the list and a vector of pointers to `Init` instances, one per
element.
-The class provides the usual ``get()`` and ``getValues()`` functions. The
-latter function returns an ``ArrayRef`` of the vector of pointers to ``Init``
+The class provides the usual `get()` and `getValues()` functions. The
+latter function returns an `ArrayRef` of the vector of pointers to `Init`
instances.
The class provides these additional functions:
-* A function to get the element type.
-
-* Functions to get the length of the vector and to determine whether
+- A function to get the element type.
+- Functions to get the length of the vector and to determine whether
it is empty.
-
-* Functions to get an element specified by an integer index and return
+- Functions to get an element specified by an integer index and return
it in various forms.
-
-* Functions to get the iterator ``begin()`` and ``end()`` values. The
+- Functions to get the iterator `begin()` and `end()` values. The
class defines a type for the return type of these two functions.
-.. code-block:: text
+```text
+using const_iterator = Init *const *;
+```
- using const_iterator = Init *const *;
+#### `StringInit`
-
-``StringInit``
-~~~~~~~~~~~~~~
-
-The ``StringInit`` class is a subclass of ``TypedInit``. Its instances
+The `StringInit` class is a subclass of `TypedInit`. Its instances
represent arbitrary-length strings. It includes a data member
-that contains a ``StringRef`` of the value.
+that contains a `StringRef` of the value.
-The class provides the usual ``get()`` and ``getValue()`` functions. The
-latter function returns the ``StringRef``.
+The class provides the usual `get()` and `getValue()` functions. The
+latter function returns the `StringRef`.
-Creating a New Backend
-======================
+## Creating a New Backend
The following steps are required to create a new backend for TableGen.
-#. Invent a name for your backend C++ file, say ``GenAddressModes``.
-
-#. Write the new backend, using the file ``TableGenBackendSkeleton.cpp``
+1. Invent a name for your backend C++ file, say `GenAddressModes`.
+2. Write the new backend, using the file `TableGenBackendSkeleton.cpp`
as a starting point.
-
-#. Determine which instance of TableGen requires the new backend. There is
+3. Determine which instance of TableGen requires the new backend. There is
one instance for Clang and another for LLVM. Or you may be building
your own instance.
-
-#. Add your backend C++ file to the appropriate ``CMakeLists.txt`` file so
+4. Add your backend C++ file to the appropriate `CMakeLists.txt` file so
that it will be built.
+5. Add your C++ file to the system.
-#. Add your C++ file to the system.
+## The Backend Skeleton
-The Backend Skeleton
-====================
-
-The file ``TableGenBackendSkeleton.cpp`` provides a skeleton C++ translation
+The file `TableGenBackendSkeleton.cpp` provides a skeleton C++ translation
unit for writing a new TableGen backend. Here are a few notes on the file:
-* The list of includes is the minimal list required by most backends.
+- The list of includes is the minimal list required by most backends.
-* As with all LLVM C++ files, it has a ``using namespace llvm;`` statement.
+- As with all LLVM C++ files, it has a `using namespace llvm;` statement.
It also has an anonymous namespace that contains all the file-specific
data structure definitions, along with the class embodying the emitter
- data members and functions. Continuing with the ``GenAddressModes`` example,
- this class is named ``AddressModesEmitter``.
+ data members and functions. Continuing with the `GenAddressModes` example,
+ this class is named `AddressModesEmitter`.
-* The constructor for the emitter class accepts a ``RecordKeeper`` reference,
- typically named ``RK``. The ``RecordKeeper`` reference is saved in a data
+- The constructor for the emitter class accepts a `RecordKeeper` reference,
+ typically named `RK`. The `RecordKeeper` reference is saved in a data
member so that records can be obtained from it. This data member is usually
- named ``Records``.
+ named `Records`.
-* One function is named ``run``. It is invoked by the backend's "main
+- One function is named `run`. It is invoked by the backend's "main
function" to collect records and emit the output file. It accepts an instance
- of the ``raw_ostream`` class, typically named ``OS``. The output file is
+ of the `raw_ostream` class, typically named `OS`. The output file is
emitted by writing to this stream.
-* The ``run`` function should use the ``emitSourceFileHeader`` helper function
+- The `run` function should use the `emitSourceFileHeader` helper function
to include a standard header in the emitted file.
-* Register the class or the function as the command-line option
- with ``llvm/TableGen/TableGenBackend.h``.
-
- * Use ``llvm::TableGen::Emitter::OptClass<AddressModesEmitter>``
- if the class has the constructor ``(RK)`` and
- the method ``run(OS)``.
+- Register the class or the function as the command-line option
+ with `llvm/TableGen/TableGenBackend.h`.
- * Otherwise, use ``llvm::TableGen::Emitter::Opt``.
+ - Use `llvm::TableGen::Emitter::OptClass<AddressModesEmitter>`
+ if the class has the constructor `(RK)` and
+ the method `run(OS)`.
+ - Otherwise, use `llvm::TableGen::Emitter::Opt`.
All the examples in the remainder of this document will assume the naming
conventions used in the skeleton file.
-Getting Classes
-===============
-
-The ``RecordKeeper`` class provides two functions for getting the
-``Record`` instances for classes defined in the TableGen files.
+## Getting Classes
-* ``getClasses()`` returns a ``RecordMap`` reference for all the classes.
+The `RecordKeeper` class provides two functions for getting the
+`Record` instances for classes defined in the TableGen files.
-* ``getClass(``\ *name*\ ``)`` returns a ``Record`` reference for the named
+- `getClasses()` returns a `RecordMap` reference for all the classes.
+- `getClass(`*name*`)` returns a `Record` reference for the named
class.
If you need to iterate over all the class records:
-.. code-block:: text
-
- for (auto ClassPair : Records.getClasses()) {
- Record *ClassRec = ClassPair.second.get();
- ...
- }
-
-``ClassPair.second`` gets the class's ``unique_ptr``, and then ``.get()`` gets the
-class ``Record`` itself.
+```text
+for (auto ClassPair : Records.getClasses()) {
+ Record *ClassRec = ClassPair.second.get();
+ ...
+}
+```
+`ClassPair.second` gets the class's `unique_ptr`, and then `.get()` gets the
+class `Record` itself.
-Getting Records
-===============
+## Getting Records
-The ``RecordKeeper`` class provides four functions for getting the
-``Record`` instances for concrete records defined in the TableGen files.
+The `RecordKeeper` class provides four functions for getting the
+`Record` instances for concrete records defined in the TableGen files.
-* ``getDefs()`` returns a ``RecordMap`` reference for all the concrete
+- `getDefs()` returns a `RecordMap` reference for all the concrete
records.
-
-* ``getDef(``\ *name*\ ``)`` returns a ``Record`` reference for the named
+- `getDef(`*name*`)` returns a `Record` reference for the named
concrete record.
-
-* ``getAllDerivedDefinitions(``\ *classname*\ ``)`` returns a vector of
- ``Record`` references for the concrete records that derive from the
+- `getAllDerivedDefinitions(`*classname*`)` returns a vector of
+ `Record` references for the concrete records that derive from the
given class.
-
-* ``getAllDerivedDefinitions(``\ *classnames*\ ``)`` returns
- a vector of ``Record`` references for the concrete records that derive from
+- `getAllDerivedDefinitions(`*classnames*`)` returns
+ a vector of `Record` references for the concrete records that derive from
*all* of the given classes.
-This statement obtains all the records that derive from the ``Attribute``
+This statement obtains all the records that derive from the `Attribute`
class and iterates over them.
-.. code-block:: text
-
- auto AttrRecords = Records.getAllDerivedDefinitions("Attribute");
- for (Record *AttrRec : AttrRecords) {
- ...
- }
+```text
+auto AttrRecords = Records.getAllDerivedDefinitions("Attribute");
+for (Record *AttrRec : AttrRecords) {
+ ...
+}
+```
-Getting Record Names and Fields
-===============================
+## Getting Record Names and Fields
-As described above (see `Record`_), there are multiple functions that
+As described above (see [Record]), there are multiple functions that
return the name of a record. One particularly useful one is
-``getNameInitAsString()``, which returns the name as a ``std::string``.
+`getNameInitAsString()`, which returns the name as a `std::string`.
There are also multiple functions that return the fields of a record. To
obtain and iterate over all the fields:
-.. code-block:: text
-
- for (const RecordVal &Field : SomeRec->getValues()) {
- ...
- }
+```text
+for (const RecordVal &Field : SomeRec->getValues()) {
+ ...
+}
+```
-You will recall that ``RecordVal`` is the class whose instances contain
+You will recall that `RecordVal` is the class whose instances contain
information about the fields in records.
-The ``getValue()`` function returns the ``RecordVal`` instance for a field
+The `getValue()` function returns the `RecordVal` instance for a field
specified by name. There are multiple overloaded functions, some taking a
-``StringRef`` and others taking a ``const Init *``. Some functions return a
-``RecordVal *`` and others return a ``const RecordVal *``. If the field does
+`StringRef` and others taking a `const Init *`. Some functions return a
+`RecordVal *` and others return a `const RecordVal *`. If the field does
not exist, a fatal error message is printed.
More often than not, you are interested in the value of the field, not all
-the information in the ``RecordVal``. There is a large set of functions that
+the information in the `RecordVal`. There is a large set of functions that
take a field name in some form and return its value. One function,
-``getValueInit``, returns the value as an ``Init *``. Another function,
-``isValueUnset``, returns a boolean specifying whether the value is unset
+`getValueInit`, returns the value as an `Init *`. Another function,
+`isValueUnset`, returns a boolean specifying whether the value is unset
(uninitialized).
Most of the functions return the value in some more useful form. For
example:
-.. code-block:: text
-
- std::vector<int64_t> RegCosts =
- SomeRec->getValueAsListOfInts("RegCosts");
+```text
+std::vector<int64_t> RegCosts =
+ SomeRec->getValueAsListOfInts("RegCosts");
+```
-The field ``RegCosts`` is assumed to be a list of integers. That list is
-returned as a ``std::vector`` of 64-bit integers. If the field is not a list
+The field `RegCosts` is assumed to be a list of integers. That list is
+returned as a `std::vector` of 64-bit integers. If the field is not a list
of integers, a fatal error message is printed.
-Here is a function that returns a field value as a ``Record``, but returns
+Here is a function that returns a field value as a `Record`, but returns
null if the field does not exist.
-.. code-block:: text
-
- if (Record *BaseRec = SomeRec->getValueAsOptionalDef(BaseFieldName)) {
- ...
- }
+```text
+if (Record *BaseRec = SomeRec->getValueAsOptionalDef(BaseFieldName)) {
+ ...
+}
+```
The field is assumed to have another record as its value. That record is returned
-as a pointer to a ``Record``. If the field does not exist or is unset, the
+as a pointer to a `Record`. If the field does not exist or is unset, the
function returns null.
-Getting Record Superclasses
-===========================
+## Getting Record Superclasses
-The ``Record`` class provides a function to obtain the direct superclasses
-of a record. It is named ``getDirectSuperClasses`` and returns an
-``ArrayRef`` of an array of ``std::pair`` instances. Each pair consists of a
-pointer to the ``Record`` instance for a superclass record and an instance
-of the ``SMRange`` class. The range indicates the source file locations of
+The `Record` class provides a function to obtain the direct superclasses
+of a record. It is named `getDirectSuperClasses` and returns an
+`ArrayRef` of an array of `std::pair` instances. Each pair consists of a
+pointer to the `Record` instance for a superclass record and an instance
+of the `SMRange` class. The range indicates the source file locations of
the beginning and end of the class definition.
-This example obtains the direct superclasses of the ``Prototype`` record and
+This example obtains the direct superclasses of the `Prototype` record and
then iterates over the pairs in the returned array.
-.. code-block:: text
-
- ArrayRef<std::pair<const Record *, SMRange>>
- Superclasses = Prototype->getDirectSuperClasses();
- for (const auto &[Super, Range] : Superclasses) {
- ...
- }
+```text
+ArrayRef<std::pair<const Record *, SMRange>>
+ Superclasses = Prototype->getDirectSuperClasses();
+for (const auto &[Super, Range] : Superclasses) {
+ ...
+}
+```
-The ``Record`` class also provides a function, ``getSuperClasses``, to
+The `Record` class also provides a function, `getSuperClasses`, to
return a vector of *all* superclasses of a record. The superclasses are in
postorder: the order in which the superclasses were visited while copying
their fields into the record.
-Emitting Text to the Output Stream
-==================================
+## Emitting Text to the Output Stream
-The ``run`` function is passed a ``raw_ostream`` to which it prints the
+The `run` function is passed a `raw_ostream` to which it prints the
output file. By convention, this stream is saved in the emitter class member
-named ``OS``, although some ``run`` functions are simple and just use the
+named `OS`, although some `run` functions are simple and just use the
stream without saving it. The output can be produced by writing values
-directly to the output stream, or by using the ``std::format()`` or
-``llvm::formatv()`` functions.
-
-.. code-block:: text
+directly to the output stream, or by using the `std::format()` or
+`llvm::formatv()` functions.
- OS << "#ifndef " << NodeName << "\n";
+```text
+OS << "#ifndef " << NodeName << "\n";
- OS << format("0x%0*x, ", Digits, Value);
+OS << format("0x%0*x, ", Digits, Value);
+```
-Instances of the following classes can be printed using the ``<<`` operator:
-``RecordKeeper``,
-``Record``,
-``RecTy``,
-``RecordVal``, and
-``Init``.
+Instances of the following classes can be printed using the `<<` operator:
+`RecordKeeper`,
+`Record`,
+`RecTy`,
+`RecordVal`, and
+`Init`.
-The helper function ``emitSourceFileHeader()`` prints the header comment
+The helper function `emitSourceFileHeader()` prints the header comment
that should be included at the top of every output file. A call to it is
-included in the skeleton backend file ``TableGenBackendSkeleton.cpp``.
+included in the skeleton backend file `TableGenBackendSkeleton.cpp`.
-Printing Error Messages
-=======================
+## Printing Error Messages
TableGen records are often derived from multiple classes and also often
defined through a sequence of multiclasses. Because of this, it can be
difficult for backends to report clear error messages with accurate source
-file locations. To make error reporting easier, five error reporting
+file locations. To make error reporting easier, five error reporting
functions are provided, each with four overloads.
-* ``PrintWarning`` prints a message tagged as a warning.
-
-* ``PrintError`` prints a message tagged as an error.
-
-* ``PrintFatalError`` prints a message tagged as an error and then terminates.
-
-* ``PrintNote`` prints a note. It is often used after one of the previous
+- `PrintWarning` prints a message tagged as a warning.
+- `PrintError` prints a message tagged as an error.
+- `PrintFatalError` prints a message tagged as an error and then terminates.
+- `PrintNote` prints a note. It is often used after one of the previous
functions to provide more information.
-
-* ``PrintFatalNote`` prints a note and then terminates.
+- `PrintFatalNote` prints a note and then terminates.
Each of these five functions is overloaded four times.
-* ``PrintError(const Twine &Msg)``:
+- `PrintError(const Twine &Msg)`:
Prints the message with no source file location.
-
-* ``PrintError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg)``:
+- `PrintError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg)`:
Prints the message followed by the specified source line,
along with a pointer to the item in error. The array of
- source file locations is typically taken from a ``Record`` instance.
-
-* ``PrintError(const Record *Rec, const Twine &Msg)``:
+ source file locations is typically taken from a `Record` instance.
+- `PrintError(const Record *Rec, const Twine &Msg)`:
Prints the message followed by the source line associated with the
- specified record (see `Record`_).
-
-* ``PrintError(const RecordVal *RecVal, const Twine &Msg)``:
+ specified record (see [Record]).
+- `PrintError(const RecordVal *RecVal, const Twine &Msg)`:
Prints the message followed by the source line associated with the
- specified record field (see `RecordVal`_).
+ specified record field (see [RecordVal]).
Using these functions, the goal is to produce the most specific error report
possible.
-Debugging Tools
-===============
+## Debugging Tools
TableGen provides some tools to aid in debugging backends.
-The ``PrintRecords`` Backend
-----------------------------
+### The `PrintRecords` Backend
-The TableGen command option ``--print-records`` invokes a simple backend
+The TableGen command option `--print-records` invokes a simple backend
that prints all the classes and records defined in the source files. This is
the default backend option. The format of the output is guaranteed to be
constant over time, so that the output can be compared in tests. The output
looks like this:
-.. code-block:: text
-
- ------------- Classes -----------------
- ...
- class XEntry<string XEntry:str = ?, int XEntry:val1 = ?> { // XBase
- string Str = XEntry:str;
- bits<8> Val1 = { !cast<bits<8>>(XEntry:val1){7}, ... };
- bit Val3 = 1;
- }
- ...
- ------------- Defs -----------------
- def ATable { // GenericTable
- string FilterClass = "AEntry";
- string CppTypeName = "AEntry";
- list<string> Fields = ["Str", "Val1", "Val2"];
- list<string> PrimaryKey = ["Val1", "Val2"];
- string PrimaryKeyName = "lookupATableByValues";
- bit PrimaryKeyEarlyOut = 0;
- }
- ...
- def anonymous_0 { // AEntry
- string Str = "Bob";
- bits<8> Val1 = { 0, 0, 0, 0, 0, 1, 0, 1 };
- bits<10> Val2 = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
- }
+```text
+------------- Classes -----------------
+...
+class XEntry<string XEntry:str = ?, int XEntry:val1 = ?> { // XBase
+ string Str = XEntry:str;
+ bits<8> Val1 = { !cast<bits<8>>(XEntry:val1){7}, ... };
+ bit Val3 = 1;
+}
+...
+------------- Defs -----------------
+def ATable { // GenericTable
+ string FilterClass = "AEntry";
+ string CppTypeName = "AEntry";
+ list<string> Fields = ["Str", "Val1", "Val2"];
+ list<string> PrimaryKey = ["Val1", "Val2"];
+ string PrimaryKeyName = "lookupATableByValues";
+ bit PrimaryKeyEarlyOut = 0;
+}
+...
+def anonymous_0 { // AEntry
+ string Str = "Bob";
+ bits<8> Val1 = { 0, 0, 0, 0, 0, 1, 0, 1 };
+ bits<10> Val2 = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+}
+```
Classes are shown with their template arguments, parent classes (following
-``//``), and fields. Records are shown with their parent classes and
-fields. Note that anonymous records are named ``anonymous_0``,
-``anonymous_1``, etc.
+`//`), and fields. Records are shown with their parent classes and
+fields. Note that anonymous records are named `anonymous_0`,
+`anonymous_1`, etc.
-The ``PrintDetailedRecords`` Backend
-------------------------------------
+### The `PrintDetailedRecords` Backend
-The TableGen command option ``--print-detailed-records`` invokes a backend
+The TableGen command option `--print-detailed-records` invokes a backend
that prints all the global variables, classes, and records defined in the
source files. The format of the output is *not* guaranteed to be constant
over time. The output looks like this:
-.. code-block:: text
-
- DETAILED RECORDS for file llvm-project\llvm\lib\target\arc\arc.td
-
- -------------------- Global Variables (5) --------------------
-
- AMDGPUBufferIntrinsics = [int_amdgcn_s_buffer_load, ...
- AMDGPUImageDimAtomicIntrinsics = [int_amdgcn_image_atomic_swap_1d, ...
- ...
- -------------------- Classes (758) --------------------
-
- AMDGPUBufferLoad |IntrinsicsAMDGPU.td:879|
- Template args:
- LLVMType AMDGPUBufferLoad:data_ty = llvm_any_ty |IntrinsicsAMDGPU.td:879|
- Superclasses: (SDPatternOperator) Intrinsic AMDGPURsrcIntrinsic
- Fields:
- list<SDNodeProperty> Properties = [SDNPMemOperand] |Intrinsics.td:348|
- string LLVMName = "" |Intrinsics.td:343|
- ...
- -------------------- Records (12303) --------------------
-
- AMDGPUSample_lz_o |IntrinsicsAMDGPU.td:560|
- Defm sequence: |IntrinsicsAMDGPU.td:584| |IntrinsicsAMDGPU.td:566|
- Superclasses: AMDGPUSampleVariant
- Fields:
- string UpperCaseMod = "_LZ_O" |IntrinsicsAMDGPU.td:542|
- string LowerCaseMod = "_lz_o" |IntrinsicsAMDGPU.td:543|
- ...
-
-* Global variables defined with outer ``defvar`` statements are shown with
+```text
+DETAILED RECORDS for file llvm-project\llvm\lib\target\arc\arc.td
+
+-------------------- Global Variables (5) --------------------
+
+AMDGPUBufferIntrinsics = [int_amdgcn_s_buffer_load, ...
+AMDGPUImageDimAtomicIntrinsics = [int_amdgcn_image_atomic_swap_1d, ...
+...
+-------------------- Classes (758) --------------------
+
+AMDGPUBufferLoad |IntrinsicsAMDGPU.td:879|
+ Template args:
+ LLVMType AMDGPUBufferLoad:data_ty = llvm_any_ty |IntrinsicsAMDGPU.td:879|
+ Superclasses: (SDPatternOperator) Intrinsic AMDGPURsrcIntrinsic
+ Fields:
+ list<SDNodeProperty> Properties = [SDNPMemOperand] |Intrinsics.td:348|
+ string LLVMName = "" |Intrinsics.td:343|
+...
+-------------------- Records (12303) --------------------
+
+AMDGPUSample_lz_o |IntrinsicsAMDGPU.td:560|
+ Defm sequence: |IntrinsicsAMDGPU.td:584| |IntrinsicsAMDGPU.td:566|
+ Superclasses: AMDGPUSampleVariant
+ Fields:
+ string UpperCaseMod = "_LZ_O" |IntrinsicsAMDGPU.td:542|
+ string LowerCaseMod = "_lz_o" |IntrinsicsAMDGPU.td:543|
+...
+```
+
+- Global variables defined with outer `defvar` statements are shown with
their values.
-
-* The classes are shown with their source location, template arguments,
+- The classes are shown with their source location, template arguments,
superclasses, and fields.
-
-* The records are shown with their source location, ``defm`` sequence,
+- The records are shown with their source location, `defm` sequence,
superclasses, and fields.
Superclasses are shown in the order processed, with indirect superclasses in
parentheses. Each field is shown with its value and the source location at
which it was set.
-The ``defm`` sequence gives the locations of the ``defm`` statements that
+The `defm` sequence gives the locations of the `defm` statements that
were involved in generating the record, in the order they were invoked.
-Timing TableGen Phases
-----------------------
+### Timing TableGen Phases
TableGen provides a phase timing feature that produces a report of the time
used by the various phases of parsing the source files and running the
-selected backend. This feature is enabled with the ``--time-phases`` option
+selected backend. This feature is enabled with the `--time-phases` option
of the TableGen command.
If the backend is *not* instrumented for timing, then a report such as the
following is produced. This is the timing for the
-``--print-detailed-records`` backend run on the AMDGPU target.
+`--print-detailed-records` backend run on the AMDGPU target.
-.. code-block:: text
+```text
+===-------------------------------------------------------------------------===
+ TableGen Phase Timing
+===-------------------------------------------------------------------------===
+ Total Execution Time: 101.0106 seconds (102.4819 wall clock)
- ===-------------------------------------------------------------------------===
- TableGen Phase Timing
- ===-------------------------------------------------------------------------===
- Total Execution Time: 101.0106 seconds (102.4819 wall clock)
-
- ---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
- 85.5197 ( 84.9%) 0.1560 ( 50.0%) 85.6757 ( 84.8%) 85.7009 ( 83.6%) Backend overall
- 15.1789 ( 15.1%) 0.0000 ( 0.0%) 15.1789 ( 15.0%) 15.1829 ( 14.8%) Parse, build records
- 0.0000 ( 0.0%) 0.1560 ( 50.0%) 0.1560 ( 0.2%) 1.5981 ( 1.6%) Write output
- 100.6986 (100.0%) 0.3120 (100.0%) 101.0106 (100.0%) 102.4819 (100.0%) Total
+ ---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
+ 85.5197 ( 84.9%) 0.1560 ( 50.0%) 85.6757 ( 84.8%) 85.7009 ( 83.6%) Backend overall
+ 15.1789 ( 15.1%) 0.0000 ( 0.0%) 15.1789 ( 15.0%) 15.1829 ( 14.8%) Parse, build records
+ 0.0000 ( 0.0%) 0.1560 ( 50.0%) 0.1560 ( 0.2%) 1.5981 ( 1.6%) Write output
+ 100.6986 (100.0%) 0.3120 (100.0%) 101.0106 (100.0%) 102.4819 (100.0%) Total
+```
Note that all the time for the backend is lumped under "Backend overall".
If the backend is instrumented for timing, then its processing is
divided into phases and each one timed separately. This is the timing for
-the ``--emit-dag-isel`` backend run on the AMDGPU target.
-
-.. code-block:: text
-
- ===-------------------------------------------------------------------------===
- TableGen Phase Timing
- ===-------------------------------------------------------------------------===
- Total Execution Time: 746.3868 seconds (747.1447 wall clock)
-
- ---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
- 657.7938 ( 88.1%) 0.1404 ( 90.0%) 657.9342 ( 88.1%) 658.6497 ( 88.2%) Emit matcher table
- 70.2317 ( 9.4%) 0.0000 ( 0.0%) 70.2317 ( 9.4%) 70.2700 ( 9.4%) Convert to matchers
- 14.8825 ( 2.0%) 0.0156 ( 10.0%) 14.8981 ( 2.0%) 14.9009 ( 2.0%) Parse, build records
- 2.1840 ( 0.3%) 0.0000 ( 0.0%) 2.1840 ( 0.3%) 2.1791 ( 0.3%) Sort patterns
- 1.1388 ( 0.2%) 0.0000 ( 0.0%) 1.1388 ( 0.2%) 1.1401 ( 0.2%) Optimize matchers
- 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0050 ( 0.0%) Write output
- 746.2308 (100.0%) 0.1560 (100.0%) 746.3868 (100.0%) 747.1447 (100.0%) Total
+the `--emit-dag-isel` backend run on the AMDGPU target.
+
+```text
+===-------------------------------------------------------------------------===
+ TableGen Phase Timing
+===-------------------------------------------------------------------------===
+ Total Execution Time: 746.3868 seconds (747.1447 wall clock)
+
+ ---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
+ 657.7938 ( 88.1%) 0.1404 ( 90.0%) 657.9342 ( 88.1%) 658.6497 ( 88.2%) Emit matcher table
+ 70.2317 ( 9.4%) 0.0000 ( 0.0%) 70.2317 ( 9.4%) 70.2700 ( 9.4%) Convert to matchers
+ 14.8825 ( 2.0%) 0.0156 ( 10.0%) 14.8981 ( 2.0%) 14.9009 ( 2.0%) Parse, build records
+ 2.1840 ( 0.3%) 0.0000 ( 0.0%) 2.1840 ( 0.3%) 2.1791 ( 0.3%) Sort patterns
+ 1.1388 ( 0.2%) 0.0000 ( 0.0%) 1.1388 ( 0.2%) 1.1401 ( 0.2%) Optimize matchers
+ 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0050 ( 0.0%) Write output
+ 746.2308 (100.0%) 0.1560 (100.0%) 746.3868 (100.0%) 747.1447 (100.0%) Total
+```
The backend has been divided into four phases and timed separately.
-If you want to instrument a backend, refer to the backend ``DAGISelEmitter.cpp``
-and search for ``Records.startTimer``.
+If you want to instrument a backend, refer to the backend `DAGISelEmitter.cpp`
+and search for `Records.startTimer`.
+
diff --git a/llvm/docs/TableGen/ProgRef.md b/llvm/docs/TableGen/ProgRef.md
index d5d0e28da665e..4c2c802fc9fe5 100644
--- a/llvm/docs/TableGen/ProgRef.md
+++ b/llvm/docs/TableGen/ProgRef.md
@@ -1,12 +1,11 @@
-===============================
-TableGen Programmer's Reference
-===============================
+# TableGen Programmer's Reference
+```{eval-rst}
.. sectnum::
+```
-Introduction
-============
+## Introduction
The purpose of TableGen is to generate complex output files based on
information from source files that are significantly easier to code than the
@@ -15,41 +14,34 @@ information is coded in a declarative style involving classes and records,
which are then processed by TableGen. The internalized records are passed on
to various *backends*, which extract information from a subset of the records
and generate one or more output files. These output files are typically
-``.inc`` files for C++, but may be any type of file that the backend
+`.inc` files for C++, but may be any type of file that the backend
developer needs.
This document describes the LLVM TableGen facility in detail. It is intended
for the programmer who is using TableGen to produce code for a project. If
-you are looking for a simple overview, check out the :doc:`TableGen Overview
-<./index>`. The various ``*-tblgen`` commands used to invoke TableGen are
-described in :doc:`tblgen Family - Description to C++
+you are looking for a simple overview, check out the {doc}`TableGen Overview
+<./index>`. The various `*-tblgen` commands used to invoke TableGen are
+described in {doc}`tblgen Family - Description to C++
Code<../CommandGuide/tblgen>`.
-An example of a backend is ``RegisterInfo``, which generates the register
+An example of a backend is `RegisterInfo`, which generates the register
file information for a particular target machine, for use by the LLVM
-target-independent code generator. See :doc:`TableGen Backends <./BackEnds>`
-for a description of the LLVM TableGen backends, and :doc:`TableGen
+target-independent code generator. See {doc}`TableGen Backends <./BackEnds>`
+for a description of the LLVM TableGen backends, and {doc}`TableGen
Backend Developer's Guide <./BackGuide>` for a guide to writing a new
backend.
Here are a few of the things backends can do.
-* Generate the register file information for a particular target machine.
-
-* Generate the instruction definitions for a target.
-
-* Generate the patterns that the code generator uses to match instructions
+- Generate the register file information for a particular target machine.
+- Generate the instruction definitions for a target.
+- Generate the patterns that the code generator uses to match instructions
to intermediate representation (IR) nodes.
+- Generate semantic attribute identifiers for Clang.
+- Generate abstract syntax tree (AST) declaration node definitions for Clang.
+- Generate AST statement node definitions for Clang.
-* Generate semantic attribute identifiers for Clang.
-
-* Generate abstract syntax tree (AST) declaration node definitions for Clang.
-
-* Generate AST statement node definitions for Clang.
-
-
-Concepts
---------
+### Concepts
TableGen source files contain two primary items: *abstract records* and
*concrete records*. In this and other TableGen documents, abstract records
@@ -66,16 +58,16 @@ backends will process. Note that TableGen assigns no meaning to fields; the
meanings are entirely up to the backends and the programs that incorporate
the output of those backends.
-.. note::
-
- The term "parent class" can refer to a class that is a parent of another
- class, and also to a class from which a concrete record inherits. This
- nonstandard use of the term arises because TableGen treats classes and
- concrete records similarly.
+:::{note}
+The term "parent class" can refer to a class that is a parent of another
+class, and also to a class from which a concrete record inherits. This
+nonstandard use of the term arises because TableGen treats classes and
+concrete records similarly.
+:::
A backend processes some subset of the concrete records built by the
TableGen parser and emits the output files. These files are usually C++
-``.inc`` files that are included by the programs that require the data in
+`.inc` files that are included by the programs that require the data in
those records. However, a backend can produce any type of output files. For
example, it could produce a data file containing messages tagged with
identifiers and substitution parameters. In a complex use case such as the
@@ -93,14 +85,14 @@ abstracts common "sub-concepts" from the two original concepts.
In order to make classes more useful, a concrete record (or another class)
can request a class as a parent class and pass *template arguments* to it.
These template arguments can be used in the fields of the parent class to
-initialize them in a custom manner. That is, record or class ``A`` can
-request parent class ``S`` with one set of template arguments, while record or class
-``B`` can request ``S`` with a different set of arguments. Without template
+initialize them in a custom manner. That is, record or class `A` can
+request parent class `S` with one set of template arguments, while record or class
+`B` can request `S` with a different set of arguments. Without template
arguments, many more classes would be required, one for each combination of
the template arguments.
Both classes and concrete records can include fields that are uninitialized.
-The uninitialized "value" is represented by a question mark (``?``). Classes
+The uninitialized "value" is represented by a question mark (`?`). Classes
often have uninitialized fields that are expected to be filled in when those
classes are inherited by concrete records. Even so, some fields of concrete
records may remain uninitialized.
@@ -111,110 +103,117 @@ multiple concrete records all at once. A multiclass can inherit from other
multiclasses, which means that the multiclass inherits all the definitions
from its parent multiclasses.
-`Appendix C: Sample Record`_ illustrates a complex record in the Intel X86
+[Appendix C: Sample Record] illustrates a complex record in the Intel X86
target and the simple way in which it is defined.
-Source Files
-============
+## Source Files
TableGen source files are plain ASCII text files. The files can contain
-statements, comments, and blank lines (see `Lexical Analysis`_). The standard file
-extension for TableGen files is ``.td``.
+statements, comments, and blank lines (see [Lexical Analysis]). The standard file
+extension for TableGen files is `.td`.
TableGen files can grow quite large, so there is an include mechanism that
-allows one file to include the content of another file (see `Include
-Files`_). This allows large files to be broken up into smaller ones, and
+allows one file to include the content of another file (see [Include
+Files][include files]). This allows large files to be broken up into smaller ones, and
also provides a simple library mechanism where multiple source files can
include the same library file.
TableGen supports a simple preprocessor that can be used to conditionalize
-portions of ``.td`` files. See `Preprocessing Facilities`_ for more
+portions of `.td` files. See [Preprocessing Facilities] for more
information.
-Lexical Analysis
-================
+## Lexical Analysis
The lexical and syntax notation used here is intended to imitate
-`Python's`_ notation. In particular, for lexical definitions, the productions
+[Python's][python's] notation. In particular, for lexical definitions, the productions
operate at the character level and there is no implied whitespace between
elements. The syntax definitions operate at the token level, so there is
implied whitespace between tokens.
-.. _`Python's`: http://docs.python.org/py3k/reference/introduction.html#notation
-
-TableGen supports BCPL-style comments (``// ...``) and nestable C-style
-comments (``/* ... */``).
-TableGen also provides simple `Preprocessing Facilities`_.
+TableGen supports BCPL-style comments (`// ...`) and nestable C-style
+comments (`/* ... */`).
+TableGen also provides simple [Preprocessing Facilities].
Formfeed characters may be used freely in files to produce page breaks when
the file is printed for review.
-The following are the basic punctuation tokens::
+The following are the basic punctuation tokens:
- - + [ ] { } ( ) < > : ; . ... = ? #
+```
+- + [ ] { } ( ) < > : ; . ... = ? #
+```
-Literals
---------
+### Literals
Numeric literals take one of the following forms:
+```{eval-rst}
.. productionlist::
TokInteger: `DecimalInteger` | `HexInteger` | `BinInteger`
DecimalInteger: ["+" | "-"] ("0"..."9")+
HexInteger: "0x" ("0"..."9" | "a"..."f" | "A"..."F")+
BinInteger: "0b" ("0" | "1")+
+```
-Observe that the :token:`DecimalInteger` token includes the optional ``+``
-or ``-`` sign, unlike most languages where the sign would be treated as a
+Observe that the {token}`DecimalInteger` token includes the optional `+`
+or `-` sign, unlike most languages where the sign would be treated as a
unary operator.
TableGen has two kinds of string literals:
+```{eval-rst}
.. productionlist::
TokString: '"' (non-'"' characters and escapes) '"'
TokCode: "[{" (text not containing "}]") "}]"
+```
-A :token:`TokCode` is nothing more than a multi-line string literal
-delimited by ``[{`` and ``}]``. It can break across lines and the
+A {token}`TokCode` is nothing more than a multi-line string literal
+delimited by `[{` and `}]`. It can break across lines and the
line breaks are retained in the string.
-The current implementation accepts the following escape sequences::
+The current implementation accepts the following escape sequences:
- \\ \' \" \t \n
+```
+\\ \' \" \t \n
+```
-Identifiers
------------
+### Identifiers
TableGen has name- and identifier-like tokens, which are case-sensitive.
+```{eval-rst}
.. productionlist::
ualpha: "a"..."z" | "A"..."Z" | "_"
TokIdentifier: ("0"..."9")* `ualpha` (`ualpha` | "0"..."9")*
TokVarName: "$" `ualpha` (`ualpha` | "0"..."9")*
+```
-Note that, unlike most languages, TableGen allows :token:`TokIdentifier` to
+Note that, unlike most languages, TableGen allows {token}`TokIdentifier` to
begin with an integer. In case of ambiguity, a token is interpreted as a
numeric literal rather than an identifier.
TableGen has the following reserved keywords, which cannot be used as
-identifiers::
+identifiers:
- assert bit bits class code
- dag def dump else false
- foreach defm defset defvar field
- if in include int let
- list multiclass string then true
+```
+assert bit bits class code
+dag def dump else false
+foreach defm defset defvar field
+if in include int let
+list multiclass string then true
+```
-.. warning::
- The ``field`` reserved word is deprecated, except when used with the
- CodeEmitterGen backend where it's used to distinguish normal record
- fields from encoding fields.
+:::{warning}
+The `field` reserved word is deprecated, except when used with the
+CodeEmitterGen backend where it's used to distinguish normal record
+fields from encoding fields.
+:::
-Bang operators
---------------
+### Bang operators
TableGen provides "bang operators" that have a wide variety of uses:
+```{eval-rst}
.. productionlist::
BangOperator: one of
: !add !and !cast !con !dag
@@ -228,101 +227,114 @@ TableGen provides "bang operators" that have a wide variety of uses:
: !setdagname !setdagop !setdagopname !shl !size
: !sra !srl !strconcat !sub !subst
: !substr !tail !tolower !toupper !xor
+```
-The ``!cond`` operator has a slightly different
+The `!cond` operator has a slightly different
syntax compared to other bang operators, so it is defined separately:
+```{eval-rst}
.. productionlist::
CondOperator: !cond
+```
-See `Appendix A: Bang Operators`_ for a description of each bang operator.
+See [Appendix A: Bang Operators] for a description of each bang operator.
-Include files
--------------
+### Include files
TableGen has an include mechanism. The content of the included file
-lexically replaces the ``include`` directive and is then parsed as if it were
+lexically replaces the `include` directive and is then parsed as if it were
originally in the main file.
+```{eval-rst}
.. productionlist::
IncludeDirective: "include" `TokString`
+```
Portions of the main file and included files can be conditionalized using
preprocessor directives.
+```{eval-rst}
.. productionlist::
PreprocessorDirective: "#define" | "#ifdef" | "#ifndef"
+```
-Types
-=====
+## Types
The TableGen language is statically typed, using a simple but complete type
system. Types are used to check for errors, to perform implicit conversions,
and to help interface designers constrain the allowed input. Every value is
required to have an associated type.
-TableGen supports a mixture of low-level types (e.g., ``bit``) and
-high-level types (e.g., ``dag``). This flexibility allows you to describe a
+TableGen supports a mixture of low-level types (e.g., `bit`) and
+high-level types (e.g., `dag`). This flexibility allows you to describe a
wide range of records conveniently and compactly.
+```{eval-rst}
.. productionlist::
Type: "bit" | "int" | "string" | "dag" | "code"
:| "bits" "<" `TokInteger` ">"
:| "list" "<" `Type` ">"
:| `ClassID`
ClassID: `TokIdentifier`
+```
+
+`bit`
+
+: A `bit` is a boolean value that can be 0 or 1.
+
+`int`
+
+: The `int` type represents a simple 64-bit integer value, such as 5 or
+ -42.
+
+`string`
+
+: The `string` type represents an ordered sequence of characters of arbitrary
+ length.
+
+`code`
+
+: The keyword `code` is an alias for `string` which may be used to
+ indicate string values that are code.
+
+`bits<`*n*`>`
+
+: The `bits` type is a fixed-sized integer of arbitrary length *n* that
+ is treated as separate bits. These bits can be accessed individually.
+ A field of this type is useful for representing an instruction operation
+ code, register number, or address mode/register/displacement. The bits of
+ the field can be set individually or as subfields. For example, in an
+ instruction address, the addressing mode, base register number, and
+ displacement can be set separately.
+
+`list<`*type*`>`
+
+: This type represents a list whose elements are of the *type* specified in
+ angle brackets. The element type is arbitrary; it can even be another
+ list type. List elements are indexed from 0.
-``bit``
- A ``bit`` is a boolean value that can be 0 or 1.
-
-``int``
- The ``int`` type represents a simple 64-bit integer value, such as 5 or
- -42.
-
-``string``
- The ``string`` type represents an ordered sequence of characters of arbitrary
- length.
-
-``code``
- The keyword ``code`` is an alias for ``string`` which may be used to
- indicate string values that are code.
-
-``bits<``\ *n*\ ``>``
- The ``bits`` type is a fixed-sized integer of arbitrary length *n* that
- is treated as separate bits. These bits can be accessed individually.
- A field of this type is useful for representing an instruction operation
- code, register number, or address mode/register/displacement. The bits of
- the field can be set individually or as subfields. For example, in an
- instruction address, the addressing mode, base register number, and
- displacement can be set separately.
-
-``list<``\ *type*\ ``>``
- This type represents a list whose elements are of the *type* specified in
- angle brackets. The element type is arbitrary; it can even be another
- list type. List elements are indexed from 0.
-
-``dag``
- This type represents a nestable directed acyclic graph (DAG) of nodes.
- Each node has an *operator* and zero or more *arguments* (or *operands*).
- An argument can be
- another ``dag`` object, allowing an arbitrary tree of nodes and edges.
- As an example, DAGs are used to represent code patterns for use by
- the code generator instruction selection algorithms. See `Directed
- acyclic graphs (DAGs)`_ for more details;
-
-:token:`ClassID`
- Specifying a class name in a type context indicates
- that the type of the defined value must
- be a subclass of the specified class. This is useful in conjunction with
- the ``list`` type; for example, to constrain the elements of the list to a
- common base class (e.g., a ``list<Register>`` can only contain definitions
- derived from the ``Register`` class).
- The :token:`ClassID` must name a class that has been previously
- declared or defined.
-
-
-Values and Expressions
-======================
+`dag`
+
+: This type represents a nestable directed acyclic graph (DAG) of nodes.
+ Each node has an *operator* and zero or more *arguments* (or *operands*).
+ An argument can be
+ another `dag` object, allowing an arbitrary tree of nodes and edges.
+ As an example, DAGs are used to represent code patterns for use by
+ the code generator instruction selection algorithms. See [Directed
+ acyclic graphs (DAGs)][directed acyclic graphs (dags)] for more details;
+
+{token}`ClassID`
+
+: Specifying a class name in a type context indicates
+ that the type of the defined value must
+ be a subclass of the specified class. This is useful in conjunction with
+ the `list` type; for example, to constrain the elements of the list to a
+ common base class (e.g., a `list<Register>` can only contain definitions
+ derived from the `Register` class).
+ The {token}`ClassID` must name a class that has been previously
+ declared or defined.
+
+## Values and Expressions
There are many contexts in TableGen statements where a value is required. A
common example is in the definition of a record, where each field is
@@ -332,9 +344,10 @@ allow the TableGen file to be written in a syntax that is natural for the
application.
Note that all of the values have rules for converting them from one type to
-another. For example, these rules allow you to assign a value like ``7``
-to an entity of type ``bits<4>``.
+another. For example, these rules allow you to assign a value like `7`
+to an entity of type `bits<4>`.
+```{eval-rst}
.. productionlist::
Value: `SimpleValue` `ValueSuffix`*
:| `Value` "#" [`Value`]
@@ -351,19 +364,21 @@ to an entity of type ``bits<4>``.
:| `Value` "..." `Value`
:| `Value` "-" `Value`
:| `Value` `TokInteger`
+```
-.. warning::
- The peculiar last form of :token:`RangePiece` and :token:`SliceElement` is
- due to the fact that the "``-``" is included in the :token:`TokInteger`,
- hence ``1-5`` gets lexed as two consecutive tokens, with values ``1`` and
- ``-5``, instead of "1", "-", and "5".
- The use of hyphen as the range punctuation is deprecated.
+:::{warning}
+The peculiar last form of {token}`RangePiece` and {token}`SliceElement` is
+due to the fact that the "`-`" is included in the {token}`TokInteger`,
+hence `1-5` gets lexed as two consecutive tokens, with values `1` and
+`-5`, instead of "1", "-", and "5".
+The use of hyphen as the range punctuation is deprecated.
+:::
-Simple values
--------------
+### Simple values
-The :token:`SimpleValue` has a number of forms.
+The {token}`SimpleValue` has a number of forms.
+```{eval-rst}
.. productionlist::
SimpleValue: `SimpleValue1`
:| `SimpleValue2`
@@ -375,192 +390,226 @@ The :token:`SimpleValue` has a number of forms.
:| `SimpleValue8`
:| `SimpleValue9`
SimpleValue1: `TokInteger` | `TokString`+ | `TokCode`
+```
A value can be an integer literal, a string literal, or a code literal.
Multiple adjacent string literals are concatenated as in C/C++; the simple
value is the concatenation of the strings. Code literals become strings and
are then indistinguishable from them.
+```{eval-rst}
.. productionlist::
SimpleValue2: "true" | "false"
+```
-The ``true`` and ``false`` literals are essentially syntactic sugar for the
+The `true` and `false` literals are essentially syntactic sugar for the
integer values 1 and 0. They improve the readability of TableGen files when
-boolean values are used in field initializations, bit sequences, ``if``
+boolean values are used in field initializations, bit sequences, `if`
statements, etc. When parsed, these literals are converted to integers.
-.. note::
-
- Although ``true`` and ``false`` are literal names for 1 and 0, we
- recommend as a stylistic rule that you use them for boolean
- values only.
+:::{note}
+Although `true` and `false` are literal names for 1 and 0, we
+recommend as a stylistic rule that you use them for boolean
+values only.
+:::
+```{eval-rst}
.. productionlist::
SimpleValue3: "?"
+```
A question mark represents an uninitialized value.
+```{eval-rst}
.. productionlist::
SimpleValue4: "{" [`ValueList`] "}"
ValueList: `ValueListNE`
ValueListNE: `Value` ("," `Value`)*
+```
This value represents a sequence of bits, which can be used to initialize a
-``bits<``\ *n*\ ``>`` field (note the braces). When doing so, the values
+`bits<`*n*`>` field (note the braces). When doing so, the values
must represent a total of *n* bits.
+```{eval-rst}
.. productionlist::
SimpleValue5: "[" `ValueList` "]" ["<" `Type` ">"]
+```
This value is a list initializer (note the brackets). The values in brackets
-are the elements of the list. The optional :token:`Type` can be used to
+are the elements of the list. The optional {token}`Type` can be used to
indicate a specific element type; otherwise the element type is inferred
from the given values. TableGen can usually infer the type, although
-sometimes not when the value is the empty list (``[]``).
+sometimes not when the value is the empty list (`[]`).
+```{eval-rst}
.. productionlist::
SimpleValue6: "(" `DagArg` [`DagArgList`] ")"
DagArgList: `DagArg` ("," `DagArg`)*
DagArg: `Value` [":" `TokVarName`] | `TokVarName`
+```
-This represents a DAG initializer (note the parentheses). The first
-:token:`DagArg` is called the "operator" of the DAG and must be a record.
-See `Directed acyclic graphs (DAGs)`_ for more details.
+This represents a DAG initializer (note the parentheses). The first
+{token}`DagArg` is called the "operator" of the DAG and must be a record.
+See [Directed acyclic graphs (DAGs)] for more details.
+```{eval-rst}
.. productionlist::
SimpleValue7: `TokIdentifier`
+```
The resulting value is the value of the entity named by the identifier. The
possible identifiers are described here, but the descriptions will make more
sense after reading the remainder of this guide.
-.. The code for this is exceptionally abstruse. These examples are a
- best-effort attempt.
+% The code for this is exceptionally abstruse. These examples are a
+% best-effort attempt.
-* A template argument of a ``class``, such as the use of ``Bar`` in::
+- A template argument of a `class`, such as the use of `Bar` in:
- class Foo <int Bar> {
- int Baz = Bar;
- }
+ ```
+ class Foo <int Bar> {
+ int Baz = Bar;
+ }
+ ```
-* The implicit template argument ``NAME`` in a ``class`` or ``multiclass``
- definition (see `NAME`_).
+- The implicit template argument `NAME` in a `class` or `multiclass`
+ definition (see [NAME]).
-* A field local to a ``class``, such as the use of ``Bar`` in::
+- A field local to a `class`, such as the use of `Bar` in:
- class Foo {
- int Bar = 5;
- int Baz = Bar;
- }
+ ```
+ class Foo {
+ int Bar = 5;
+ int Baz = Bar;
+ }
+ ```
-* The name of a record definition, such as the use of ``Bar`` in the
- definition of ``Foo``::
+- The name of a record definition, such as the use of `Bar` in the
+ definition of `Foo`:
- def Bar : SomeClass {
- int X = 5;
- }
+ ```
+ def Bar : SomeClass {
+ int X = 5;
+ }
- def Foo {
- SomeClass Baz = Bar;
- }
+ def Foo {
+ SomeClass Baz = Bar;
+ }
+ ```
-* A field local to a record definition, such as the use of ``Bar`` in::
+- A field local to a record definition, such as the use of `Bar` in:
- def Foo {
- int Bar = 5;
- int Baz = Bar;
- }
+ ```
+ def Foo {
+ int Bar = 5;
+ int Baz = Bar;
+ }
+ ```
Fields inherited from the record's parent classes can be accessed the same way.
-* A template argument of a ``multiclass``, such as the use of ``Bar`` in::
+- A template argument of a `multiclass`, such as the use of `Bar` in:
- multiclass Foo <int Bar> {
- def : SomeClass<Bar>;
- }
+ ```
+ multiclass Foo <int Bar> {
+ def : SomeClass<Bar>;
+ }
+ ```
-* A variable defined with the ``defvar`` or ``defset`` statements.
+- A variable defined with the `defvar` or `defset` statements.
-* The iteration variable of a ``foreach``, such as the use of ``i`` in::
+- The iteration variable of a `foreach`, such as the use of `i` in:
- foreach i = 0...5 in
- def Foo#i;
+ ```
+ foreach i = 0...5 in
+ def Foo#i;
+ ```
+```{eval-rst}
.. productionlist::
SimpleValue8: `ClassID` "<" `ArgValueList` ">"
+```
This form creates a new anonymous record definition (as would be created by an
-unnamed ``def`` inheriting from the given class with the given template
-arguments; see `def`_) and the value is that record. A field of the record can be
-obtained using a suffix; see `Suffixed Values`_.
+unnamed `def` inheriting from the given class with the given template
+arguments; see [def]) and the value is that record. A field of the record can be
+obtained using a suffix; see [Suffixed Values].
Invoking a class in this manner can provide a simple subroutine facility.
-See `Using Classes as Subroutines`_ for more information.
+See [Using Classes as Subroutines] for more information.
+```{eval-rst}
.. productionlist::
SimpleValue9: `BangOperator` ["<" `Type` ">"] "(" `ValueListNE` ")"
:| `CondOperator` "(" `CondClause` ("," `CondClause`)* ")"
CondClause: `Value` ":" `Value`
+```
The bang operators provide functions that are not available with the other
-simple values. Except in the case of ``!cond``, a bang operator takes a list
+simple values. Except in the case of `!cond`, a bang operator takes a list
of arguments enclosed in parentheses and performs some function on those
-arguments, producing a value for that bang operator. The ``!cond`` operator
-takes a list of pairs of arguments separated by colons. See `Appendix A:
-Bang Operators`_ for a description of each bang operator.
+arguments, producing a value for that bang operator. The `!cond` operator
+takes a list of pairs of arguments separated by colons. See [Appendix A:
+Bang Operators][appendix a: bang operators] for a description of each bang operator.
The `Type` is only accepted for certain bang operators, and must not be
-``code``.
+`code`.
-Suffixed values
----------------
+### Suffixed values
-The :token:`SimpleValue` values described above can be specified with
+The {token}`SimpleValue` values described above can be specified with
certain suffixes. The purpose of a suffix is to obtain a subvalue of the
primary value. Here are the possible suffixes for some primary *value*.
-*value*\ ``{17}``
- The final value is bit 17 of the integer *value* (note the braces).
+*value*`{17}`
+
+: The final value is bit 17 of the integer *value* (note the braces).
+
+*value*`{8...15}`
+
+: The final value is bits 8--15 of the integer *value*. The order of the
+ bits can be reversed by specifying `{15...8}`.
+
+*value*`[i]`
-*value*\ ``{8...15}``
- The final value is bits 8--15 of the integer *value*. The order of the
- bits can be reversed by specifying ``{15...8}``.
+: The final value is element `i` of the list *value* (note the brackets).
+ In other words, the brackets act as a subscripting operator on the list.
+ This is the case only when a single element is specified.
-*value*\ ``[i]``
- The final value is element `i` of the list *value* (note the brackets).
- In other words, the brackets act as a subscripting operator on the list.
- This is the case only when a single element is specified.
+*value*`[i,]`
-*value*\ ``[i,]``
- The final value is a list that contains a single element `i` of the list.
- In short, a list slice with a single element.
+: The final value is a list that contains a single element `i` of the list.
+ In short, a list slice with a single element.
-*value*\ ``[4...7,17,2...3,4]``
- The final value is a new list that is a slice of the list *value*.
- The new list contains elements 4, 5, 6, 7, 17, 2, 3, and 4.
- Elements may be included multiple times and in any order. This is the result
- only when more than one element is specified.
+*value*`[4...7,17,2...3,4]`
- *value*\ ``[i,m...n,j,ls]``
- Each element may be an expression (variables, bang operators).
- The type of `m` and `n` should be `int`.
- The type of `i`, `j`, and `ls` should be either `int` or `list<int>`.
+: The final value is a new list that is a slice of the list *value*.
+ The new list contains elements 4, 5, 6, 7, 17, 2, 3, and 4.
+ Elements may be included multiple times and in any order. This is the result
+ only when more than one element is specified.
-*value*\ ``.``\ *field*
- The final value is the value of the specified *field* in the specified
- record *value*.
+ *value*`[i,m...n,j,ls]`
-The paste operator
-------------------
+ : Each element may be an expression (variables, bang operators).
+ The type of `m` and `n` should be `int`.
+ The type of `i`, `j`, and `ls` should be either `int` or `list<int>`.
-The paste operator (``#``) is the only infix operator available in TableGen
+*value*`.`*field*
+
+: The final value is the value of the specified *field* in the specified
+ record *value*.
+
+### The paste operator
+
+The paste operator (`#`) is the only infix operator available in TableGen
expressions. It allows you to concatenate strings or lists, but has a few
unusual features.
The paste operator can be used when specifying the record name in a
-:token:`Def` or :token:`Defm` statement, in which case it must construct a
-string. If an operand is an undefined name (:token:`TokIdentifier`) or the
-name of a global :token:`Defvar` or :token:`Defset`, it is treated as a
+{token}`Def` or {token}`Defm` statement, in which case it must construct a
+string. If an operand is an undefined name ({token}`TokIdentifier`) or the
+name of a global {token}`Defvar` or {token}`Defset`, it is treated as a
verbatim string of characters. The value of a global name is not used.
The paste operator can be used in all other value expressions, in which case
@@ -572,78 +621,78 @@ left-hand-side operand is treated normally.
Values can have a trailing paste operator, in which case the left-hand-side
operand is concatenated to an empty string.
-`Appendix B: Paste Operator Examples`_ presents examples of the behavior of
+[Appendix B: Paste Operator Examples] presents examples of the behavior of
the paste operator.
-Statements
-==========
+## Statements
The following statements may appear at the top level of TableGen source
files.
+```{eval-rst}
.. productionlist::
TableGenFile: (`Statement` | `IncludeDirective`
:| `PreprocessorDirective`)*
Statement: `Assert` | `Class` | `Def` | `Defm` | `Defset` | `Deftype`
:| `Defvar` | `Dump` | `Foreach` | `If` | `Let` | `MultiClass`
+```
The following sections describe each of these top-level statements.
+### `class` --- define an abstract record class
-``class`` --- define an abstract record class
----------------------------------------------
-
-A ``class`` statement defines an abstract record class from which other
+A `class` statement defines an abstract record class from which other
classes and records can inherit.
+```{eval-rst}
.. productionlist::
Class: "class" `ClassID` [`TemplateArgList`] `RecordBody`
TemplateArgList: "<" `TemplateArgDecl` ("," `TemplateArgDecl`)* ">"
TemplateArgDecl: `Type` `TokIdentifier` ["=" `Value`]
+```
A class can be parameterized by a list of "template arguments," whose values
can be used in the class's record body. These template arguments are
specified each time the class is inherited by another class or record.
-If a template argument is not assigned a default value with ``=``, it is
-uninitialized (has the "value" ``?``) and must be specified in the template
+If a template argument is not assigned a default value with `=`, it is
+uninitialized (has the "value" `?`) and must be specified in the template
argument list when the class is inherited (required argument). If an
argument is assigned a default value, then it need not be specified in the
argument list (optional argument). In the declaration, all required template
arguments must precede any optional arguments. The template argument default
values are evaluated from left to right.
-The :token:`RecordBody` is defined below. It can include a list of
+The {token}`RecordBody` is defined below. It can include a list of
parent classes from which the current class inherits, along with field
-definitions and other statements. When a class ``C`` inherits from another
-class ``D``, the fields of ``D`` are effectively merged into the fields of
-``C``.
+definitions and other statements. When a class `C` inherits from another
+class `D`, the fields of `D` are effectively merged into the fields of
+`C`.
-A given class can only be defined once. A ``class`` statement is
+A given class can only be defined once. A `class` statement is
considered to define the class if *any* of the following are true (the
-:token:`RecordBody` elements are described below).
+{token}`RecordBody` elements are described below).
-* The :token:`TemplateArgList` is present, or
-* The :token:`ParentClassList` in the :token:`RecordBody` is present, or
-* The :token:`Body` in the :token:`RecordBody` is present and not empty.
+- The {token}`TemplateArgList` is present, or
+- The {token}`ParentClassList` in the {token}`RecordBody` is present, or
+- The {token}`Body` in the {token}`RecordBody` is present and not empty.
-You can declare an empty class by specifying an empty :token:`TemplateArgList`
-and an empty :token:`RecordBody`. This can serve as a restricted form of
+You can declare an empty class by specifying an empty {token}`TemplateArgList`
+and an empty {token}`RecordBody`. This can serve as a restricted form of
forward declaration. Note that records derived from a forward-declared
class will inherit no fields from it, because those records are built when
their declarations are parsed, and thus before the class is finally defined.
-.. _NAME:
+(name)=
-Every class has an implicit template argument named ``NAME`` (uppercase),
-which is bound to the name of the :token:`Def` or :token:`Defm` inheriting
+Every class has an implicit template argument named `NAME` (uppercase),
+which is bound to the name of the {token}`Def` or {token}`Defm` inheriting
from the class. If the class is inherited by an anonymous record, the name
is unspecified but globally unique.
-See `Examples: classes and records`_ for examples.
+See [Examples: classes and records] for examples.
-Record Bodies
-`````````````
+#### Record Bodies
Record bodies appear in both class and record definitions. A record body can
include a parent class list, which specifies the classes from which the
@@ -652,6 +701,7 @@ parent classes of the class or record. The record body also
includes the main body of the definition, which contains the specification
of the fields of the class or record.
+```{eval-rst}
.. productionlist::
RecordBody: `ParentClassList` `Body`
ParentClassList: [":" `ParentClassListNE`]
@@ -660,20 +710,21 @@ of the fields of the class or record.
ArgValueList: `PostionalArgValueList` [","] `NamedArgValueList`
PostionalArgValueList: [`Value` {"," `Value`}*]
NamedArgValueList: [`NameValue` "=" `Value` {"," `NameValue` "=" `Value`}*]
+```
-A :token:`ParentClassList` containing a :token:`MultiClassID` is valid only
-in the class list of a ``defm`` statement. In that case, the ID must be the
+A {token}`ParentClassList` containing a {token}`MultiClassID` is valid only
+in the class list of a `defm` statement. In that case, the ID must be the
name of a multiclass.
The argument values can be specified in two forms:
-* Positional argument (``value``). The value is assigned to the argument in the
- corresponding position. For ``Foo<a0, a1>``, ``a0`` will be assigned to the first
- argument and ``a1`` will be assigned to the second argument.
-* Named argument (``name=value``). The value is assigned to the argument with
- the specified name. For ``Foo<a=a0, b=a1>``, ``a0`` will be assigned to the
- argument with name ``a`` and ``a1`` will be assigned to the argument with
- name ``b``.
+- Positional argument (`value`). The value is assigned to the argument in the
+ corresponding position. For `Foo<a0, a1>`, `a0` will be assigned to the first
+ argument and `a1` will be assigned to the second argument.
+- Named argument (`name=value`). The value is assigned to the argument with
+ the specified name. For `Foo<a=a0, b=a1>`, `a0` will be assigned to the
+ argument with name `a` and `a1` will be assigned to the argument with
+ name `b`.
Required arguments can also be specified as a named argument.
@@ -681,6 +732,7 @@ Note that the argument can only be specified once regardless of the way (named
or positional) to specify and positional arguments should precede named
arguments.
+```{eval-rst}
.. productionlist::
Body: ";" | "{" `BodyItem`* "}"
BodyItem: `Type` `TokIdentifier` ["=" `Value`] ";"
@@ -688,9 +740,10 @@ arguments.
:| "defvar" `TokIdentifier` "=" `Value` ";"
:| `Assert`
LetMode: "append" | "prepend"
+```
-Note that ``append`` and ``prepend`` are context-sensitive keywords: they are
-only recognized as modifiers immediately after ``let``. In all other positions,
+Note that `append` and `prepend` are context-sensitive keywords: they are
+only recognized as modifiers immediately after `let`. In all other positions,
they remain valid identifiers (e.g., usable as field names).
A field definition in the body specifies a field to be included in the class
@@ -698,77 +751,77 @@ or record. If no initial value is specified, then the field's value is
uninitialized. The type must be specified; TableGen will not infer it from
the value.
-The ``let`` form is used to reset a field to a new value. This can be done
+The `let` form is used to reset a field to a new value. This can be done
for fields defined directly in the body or fields inherited from parent
-classes. A :token:`RangeList` can be specified to reset certain bits in a
-``bit<n>`` field.
+classes. A {token}`RangeList` can be specified to reset certain bits in a
+`bit<n>` field.
-The ``let append`` and ``let prepend`` forms concatenate a value with the
-field's current value instead of replacing it. For ``append``, the new value
-is added after the current value; for ``prepend``, it is added before. The
+The `let append` and `let prepend` forms concatenate a value with the
+field's current value instead of replacing it. For `append`, the new value
+is added after the current value; for `prepend`, it is added before. The
supported types and concatenation operators are:
-* ``list<T>``: uses ``!listconcat``
-* ``string`` / ``code``: uses ``!strconcat``
-* ``dag``: uses ``!con``
+- `list<T>`: uses `!listconcat`
+- `string` / `code`: uses `!strconcat`
+- `dag`: uses `!con`
-If the field is currently unset (``?``), ``let append`` and ``let prepend``
+If the field is currently unset (`?`), `let append` and `let prepend`
simply set the value directly. This is useful for accumulating values across
a class hierarchy:
-.. code-block:: text
-
- class Base {
- list<int> items = [2, 3];
- }
- class Middle : Base {
- let append items = [4]; // items = [2, 3, 4]
- }
- def Concrete : Middle {
- let prepend items = [1]; // items = [1, 2, 3, 4]
- }
-
-A plain ``let`` (without ``append``/``prepend``) always replaces the current
+```text
+class Base {
+ list<int> items = [2, 3];
+}
+class Middle : Base {
+ let append items = [4]; // items = [2, 3, 4]
+}
+def Concrete : Middle {
+ let prepend items = [1]; // items = [1, 2, 3, 4]
+}
+```
+
+A plain `let` (without `append`/`prepend`) always replaces the current
value, which can be used to opt out of accumulated values.
-The ``defvar`` form defines a variable whose value can be used in other
+The `defvar` form defines a variable whose value can be used in other
value expressions within the body. The variable is not a field: it does not
become a field of the class or record being defined. Variables are provided
-to hold temporary values while processing the body. See `Defvar in a Record
-Body`_ for more details.
-
-When class ``C2`` inherits from class ``C1``, it acquires all the field
-definitions of ``C1``. As those definitions are merged into class ``C2``, any
-template arguments passed to ``C1`` by ``C2`` are substituted into the
-definitions. In other words, the abstract record fields defined by ``C1`` are
-expanded with the template arguments before being merged into ``C2``.
+to hold temporary values while processing the body. See [Defvar in a Record
+Body][defvar in a record body] for more details.
+When class `C2` inherits from class `C1`, it acquires all the field
+definitions of `C1`. As those definitions are merged into class `C2`, any
+template arguments passed to `C1` by `C2` are substituted into the
+definitions. In other words, the abstract record fields defined by `C1` are
+expanded with the template arguments before being merged into `C2`.
-.. _def:
+(def)=
-``def`` --- define a concrete record
-------------------------------------
+### `def` --- define a concrete record
-A ``def`` statement defines a new concrete record.
+A `def` statement defines a new concrete record.
+```{eval-rst}
.. productionlist::
Def: "def" [`NameValue`] `RecordBody`
NameValue: `Value` (parsed in a special mode)
+```
The name value is optional. If specified, it is parsed in a special mode
where undefined (unrecognized) identifiers are interpreted as literal
strings. In particular, global identifiers are considered unrecognized.
-These include global variables defined by ``defvar`` and ``defset``. A
+These include global variables defined by `defvar` and `defset`. A
record name can be the null string.
If no name value is given, the record is *anonymous*. The final name of an
anonymous record is unspecified but globally unique.
-Special handling occurs if a ``def`` appears inside a ``multiclass``
-statement. See the ``multiclass`` section below for details.
+Special handling occurs if a `def` appears inside a `multiclass`
+statement. See the `multiclass` section below for details.
A record can inherit from one or more classes by specifying the
-:token:`ParentClassList` clause at the beginning of its record body. All of
+{token}`ParentClassList` clause at the beginning of its record body. All of
the fields in the parent classes are added to the record. If two or more
parent classes provide the same field, the record ends up with the field value
of the last parent class.
@@ -776,47 +829,45 @@ of the last parent class.
As a special case, the name of a record can be passed as a template argument
to that record's parent classes. For example:
-.. code-block:: text
+```text
+class A <dag d> {
+ dag the_dag = d;
+}
- class A <dag d> {
- dag the_dag = d;
- }
-
- def rec1 : A<(ops rec1)>;
-
-The DAG ``(ops rec1)`` is passed as a template argument to class ``A``. Notice
-that the DAG includes ``rec1``, the record being defined.
+def rec1 : A<(ops rec1)>;
+```
-The steps taken to create a new record are somewhat complex. See `How
-records are built`_.
+The DAG `(ops rec1)` is passed as a template argument to class `A`. Notice
+that the DAG includes `rec1`, the record being defined.
-See `Examples: classes and records`_ for examples.
+The steps taken to create a new record are somewhat complex. See [How
+records are built][how records are built].
+See [Examples: classes and records] for examples.
-Examples: classes and records
------------------------------
+### Examples: classes and records
Here is a simple TableGen file with one class and two record definitions.
-.. code-block:: text
-
- class C {
- bit V = true;
- }
+```text
+class C {
+ bit V = true;
+}
- def X : C;
- def Y : C {
- let V = false;
- string Greeting = "Hello!";
- }
+def X : C;
+def Y : C {
+ let V = false;
+ string Greeting = "Hello!";
+}
+```
-First, the abstract class ``C`` is defined. It has one field named ``V``
+First, the abstract class `C` is defined. It has one field named `V`
that is a bit initialized to true.
-Next, two records are defined, derived from class ``C``; that is, with ``C``
-as their parent class. Thus they both inherit the ``V`` field. Record ``Y``
-also defines another string field, ``Greeting``, which is initialized to
-``"Hello!"``. In addition, ``Y`` overrides the inherited ``V`` field,
+Next, two records are defined, derived from class `C`; that is, with `C`
+as their parent class. Thus they both inherit the `V` field. Record `Y`
+also defines another string field, `Greeting`, which is initialized to
+`"Hello!"`. In addition, `Y` overrides the inherited `V` field,
setting it to false.
A class is useful for isolating the common features of multiple records in
@@ -828,766 +879,767 @@ nonparameterized ones. Parameterized classes specify a list of variable
declarations, which may optionally have defaults, that are bound when the
class is specified as a parent class of another class or record.
-.. code-block:: text
-
- class FPFormat <bits<3> val> {
- bits<3> Value = val;
- }
-
- def NotFP : FPFormat<0>;
- def ZeroArgFP : FPFormat<1>;
- def OneArgFP : FPFormat<2>;
- def OneArgFPRW : FPFormat<3>;
- def TwoArgFP : FPFormat<4>;
- def CompareFP : FPFormat<5>;
- def CondMovFP : FPFormat<6>;
- def SpecialFP : FPFormat<7>;
-
-The purpose of the ``FPFormat`` class is to act as a sort of enumerated
-type. It provides a single field, ``Value``, which holds a 3-bit number. Its
-template argument, ``val``, is used to set the ``Value`` field. Each of the
-eight records is defined with ``FPFormat`` as its parent class. The
+```text
+class FPFormat <bits<3> val> {
+ bits<3> Value = val;
+}
+
+def NotFP : FPFormat<0>;
+def ZeroArgFP : FPFormat<1>;
+def OneArgFP : FPFormat<2>;
+def OneArgFPRW : FPFormat<3>;
+def TwoArgFP : FPFormat<4>;
+def CompareFP : FPFormat<5>;
+def CondMovFP : FPFormat<6>;
+def SpecialFP : FPFormat<7>;
+```
+
+The purpose of the `FPFormat` class is to act as a sort of enumerated
+type. It provides a single field, `Value`, which holds a 3-bit number. Its
+template argument, `val`, is used to set the `Value` field. Each of the
+eight records is defined with `FPFormat` as its parent class. The
enumeration value is passed in angle brackets as the template argument. Each
-record will inherit the ``Value`` field with the appropriate enumeration
+record will inherit the `Value` field with the appropriate enumeration
value.
Here is a more complex example of classes with template arguments. First, we
-define a class similar to the ``FPFormat`` class above. It takes a template
-argument and uses it to initialize a field named ``Value``. Then we define
-four records that inherit the ``Value`` field with its four different
+define a class similar to the `FPFormat` class above. It takes a template
+argument and uses it to initialize a field named `Value`. Then we define
+four records that inherit the `Value` field with its four different
integer values.
-.. code-block:: text
-
- class ModRefVal <bits<2> val> {
- bits<2> Value = val;
- }
+```text
+class ModRefVal <bits<2> val> {
+ bits<2> Value = val;
+}
- def None : ModRefVal<0>;
- def Mod : ModRefVal<1>;
- def Ref : ModRefVal<2>;
- def ModRef : ModRefVal<3>;
+def None : ModRefVal<0>;
+def Mod : ModRefVal<1>;
+def Ref : ModRefVal<2>;
+def ModRef : ModRefVal<3>;
+```
This is somewhat contrived, but let's say we would like to examine the two
-bits of the ``Value`` field independently. We can define a class that
-accepts a ``ModRefVal`` record as a template argument and splits up its
+bits of the `Value` field independently. We can define a class that
+accepts a `ModRefVal` record as a template argument and splits up its
value into two fields, one bit each. Then we can define records that inherit from
-``ModRefBits`` and so acquire two fields from it, one for each bit in the
-``ModRefVal`` record passed as the template argument.
-
-.. code-block:: text
-
- class ModRefBits <ModRefVal mrv> {
- // Break the value up into its bits, which can provide a nice
- // interface to the ModRefVal values.
- bit isMod = mrv.Value{0};
- bit isRef = mrv.Value{1};
- }
-
- // Example uses.
- def foo : ModRefBits<Mod>;
- def bar : ModRefBits<Ref>;
- def snork : ModRefBits<ModRef>;
+`ModRefBits` and so acquire two fields from it, one for each bit in the
+`ModRefVal` record passed as the template argument.
+
+```text
+class ModRefBits <ModRefVal mrv> {
+ // Break the value up into its bits, which can provide a nice
+ // interface to the ModRefVal values.
+ bit isMod = mrv.Value{0};
+ bit isRef = mrv.Value{1};
+}
+
+// Example uses.
+def foo : ModRefBits<Mod>;
+def bar : ModRefBits<Ref>;
+def snork : ModRefBits<ModRef>;
+```
This illustrates how one class can be defined to reorganize the
fields in another class, thus hiding the internal representation of that
other class.
-Running ``llvm-tblgen`` on the example prints the following definitions:
-
-.. code-block:: text
-
- def bar { // Value
- bit isMod = 0;
- bit isRef = 1;
- }
- def foo { // Value
- bit isMod = 1;
- bit isRef = 0;
- }
- def snork { // Value
- bit isMod = 1;
- bit isRef = 1;
- }
-
-``let`` --- override fields in classes or records
--------------------------------------------------
-
-A ``let`` statement collects a set of field values (sometimes called
+Running `llvm-tblgen` on the example prints the following definitions:
+
+```text
+def bar { // Value
+ bit isMod = 0;
+ bit isRef = 1;
+}
+def foo { // Value
+ bit isMod = 1;
+ bit isRef = 0;
+}
+def snork { // Value
+ bit isMod = 1;
+ bit isRef = 1;
+}
+```
+
+### `let` --- override fields in classes or records
+
+A `let` statement collects a set of field values (sometimes called
*bindings*) and applies them to all the classes and records defined by
-statements within the scope of the ``let``.
+statements within the scope of the `let`.
+```{eval-rst}
.. productionlist::
Let: "let" `LetList` "in" "{" `Statement`* "}"
:| "let" `LetList` "in" `Statement`
LetList: `LetItem` ("," `LetItem`)*
LetItem: [`LetMode`] `TokIdentifier` [`RangeList`] "=" `Value`
+```
-The ``let`` statement establishes a scope, which is a sequence of statements
+The `let` statement establishes a scope, which is a sequence of statements
in braces or a single statement with no braces. The bindings in the
-:token:`LetList` apply to the statements in that scope.
+{token}`LetList` apply to the statements in that scope.
-The field names in the :token:`LetList` must name fields in classes inherited by
+The field names in the {token}`LetList` must name fields in classes inherited by
the classes and records defined in the statements. The field values are
applied to the classes and records *after* the records inherit all the fields from
-their parent classes. So the ``let`` acts to override inherited field
-values. A ``let`` cannot override the value of a template argument.
+their parent classes. So the `let` acts to override inherited field
+values. A `let` cannot override the value of a template argument.
-Top-level ``let`` statements are often useful when a few fields need to be
-overridden in several records. Here are two examples. Note that ``let``
+Top-level `let` statements are often useful when a few fields need to be
+overridden in several records. Here are two examples. Note that `let`
statements can be nested.
-.. code-block:: text
-
- let isTerminator = true, isReturn = true, isBarrier = true, hasCtrlDep = true in
- def RET : I<0xC3, RawFrm, (outs), (ins), "ret", [(X86retflag 0)]>;
-
- let isCall = true in
- // All calls clobber the non-callee saved registers...
- let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0,
- MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, XMM0, XMM1, XMM2,
- XMM3, XMM4, XMM5, XMM6, XMM7, EFLAGS] in {
- def CALLpcrel32 : Ii32<0xE8, RawFrm, (outs), (ins i32imm:$dst, variable_ops),
- "call\t${dst:call}", []>;
- def CALL32r : I<0xFF, MRM2r, (outs), (ins GR32:$dst, variable_ops),
- "call\t{*}$dst", [(X86call GR32:$dst)]>;
- def CALL32m : I<0xFF, MRM2m, (outs), (ins i32mem:$dst, variable_ops),
- "call\t{*}$dst", []>;
- }
-
-Note that a top-level ``let`` will not override fields defined in the classes or records
+```text
+let isTerminator = true, isReturn = true, isBarrier = true, hasCtrlDep = true in
+ def RET : I<0xC3, RawFrm, (outs), (ins), "ret", [(X86retflag 0)]>;
+
+let isCall = true in
+ // All calls clobber the non-callee saved registers...
+ let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0,
+ MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, XMM0, XMM1, XMM2,
+ XMM3, XMM4, XMM5, XMM6, XMM7, EFLAGS] in {
+ def CALLpcrel32 : Ii32<0xE8, RawFrm, (outs), (ins i32imm:$dst, variable_ops),
+ "call\t${dst:call}", []>;
+ def CALL32r : I<0xFF, MRM2r, (outs), (ins GR32:$dst, variable_ops),
+ "call\t{*}$dst", [(X86call GR32:$dst)]>;
+ def CALL32m : I<0xFF, MRM2m, (outs), (ins i32mem:$dst, variable_ops),
+ "call\t{*}$dst", []>;
+ }
+```
+
+Note that a top-level `let` will not override fields defined in the classes or records
themselves.
-Top-level ``let`` also supports ``append`` and ``prepend`` modes, which
+Top-level `let` also supports `append` and `prepend` modes, which
concatenate the value with the field's current value instead of replacing it.
-See the :token:`BodyItem` production for the supported types and semantics.
-
-.. code-block:: text
-
- let append traits = [NewTrait] in {
- def MyRecord : Base;
- }
+See the {token}`BodyItem` production for the supported types and semantics.
+```text
+let append traits = [NewTrait] in {
+ def MyRecord : Base;
+}
+```
-``multiclass`` --- define multiple records
-------------------------------------------
+### `multiclass` --- define multiple records
While classes with template arguments are a good way to factor out commonality
between multiple records, multiclasses allow a convenient method for
defining many records at once. For example, consider a 3-address
-instruction architecture whose instructions come in two formats: ``reg = reg
-op reg`` and ``reg = reg op imm`` (e.g., SPARC). We would like to specify in
+instruction architecture whose instructions come in two formats: `reg = reg
+op reg` and `reg = reg op imm` (e.g., SPARC). We would like to specify in
one place that these two common formats exist, then in a separate place
-specify what all the operations are. The ``multiclass`` and ``defm``
+specify what all the operations are. The `multiclass` and `defm`
statements accomplish this goal. You can think of a multiclass as a macro or
template that expands into multiple records.
+```{eval-rst}
.. productionlist::
MultiClass: "multiclass" `TokIdentifier` [`TemplateArgList`]
: `ParentClassList`
: "{" `MultiClassStatement`+ "}"
MultiClassID: `TokIdentifier`
MultiClassStatement: `Assert` | `Def` | `Defm` | `Defvar` | `Foreach` | `If` | `Let`
+```
As with regular classes, the multiclass has a name and can accept template
arguments. A multiclass can inherit from other multiclasses, which causes
the other multiclasses to be expanded and contribute to the record
definitions in the inheriting multiclass. The body of the multiclass
-contains a series of statements that define records, using :token:`Def` and
-:token:`Defm`. In addition, :token:`Defvar`, :token:`Foreach`, and
-:token:`Let` statements can be used to factor out even more common elements.
-The :token:`If` and :token:`Assert` statements can also be used.
+contains a series of statements that define records, using {token}`Def` and
+{token}`Defm`. In addition, {token}`Defvar`, {token}`Foreach`, and
+{token}`Let` statements can be used to factor out even more common elements.
+The {token}`If` and {token}`Assert` statements can also be used.
Also as with regular classes, the multiclass has the implicit template
-argument ``NAME`` (see NAME_). When a named (non-anonymous) record is
+argument `NAME` (see [NAME]). When a named (non-anonymous) record is
defined in a multiclass and the record's name does not include a use of the
-template argument ``NAME``, such a use is automatically *prepended*
-to the name. That is, the following are equivalent inside a multiclass::
+template argument `NAME`, such a use is automatically *prepended*
+to the name. That is, the following are equivalent inside a multiclass:
- def Foo ...
- def NAME # Foo ...
+```
+def Foo ...
+def NAME # Foo ...
+```
The records defined in a multiclass are created when the multiclass is
-"instantiated" or "invoked" by a ``defm`` statement outside the multiclass
-definition. Each ``def`` statement in the multiclass produces a record. As
-with top-level ``def`` statements, these definitions can inherit from
+"instantiated" or "invoked" by a `defm` statement outside the multiclass
+definition. Each `def` statement in the multiclass produces a record. As
+with top-level `def` statements, these definitions can inherit from
multiple parent classes.
-See `Examples: multiclasses and defms`_ for examples.
-
+See [Examples: multiclasses and defms] for examples.
-``defm`` --- invoke multiclasses to define multiple records
------------------------------------------------------------
+### `defm` --- invoke multiclasses to define multiple records
-Once multiclasses have been defined, you use the ``defm`` statement to
+Once multiclasses have been defined, you use the `defm` statement to
"invoke" them and process the multiple record definitions in those
-multiclasses. Those record definitions are specified by ``def``
-statements in the multiclasses, and indirectly by ``defm`` statements.
+multiclasses. Those record definitions are specified by `def`
+statements in the multiclasses, and indirectly by `defm` statements.
+```{eval-rst}
.. productionlist::
Defm: "defm" [`NameValue`] `ParentClassList` ";"
+```
-The optional :token:`NameValue` is formed in the same way as the name of a
-``def``. The :token:`ParentClassList` is a colon followed by a list of at
+The optional {token}`NameValue` is formed in the same way as the name of a
+`def`. The {token}`ParentClassList` is a colon followed by a list of at
least one multiclass and any number of regular classes. The multiclasses
-must precede the regular classes. Note that the ``defm`` does not have a
+must precede the regular classes. Note that the `defm` does not have a
body.
This statement instantiates all the records defined in all the specified
-multiclasses, either directly by ``def`` statements or indirectly by
-``defm`` statements. These records also receive the fields defined in any
+multiclasses, either directly by `def` statements or indirectly by
+`defm` statements. These records also receive the fields defined in any
regular classes included in the parent class list. This is useful for adding
-a common set of fields to all the records created by the ``defm``.
+a common set of fields to all the records created by the `defm`.
-The name is parsed in the same special mode used by ``def``. If the name is
+The name is parsed in the same special mode used by `def`. If the name is
not included, an unspecified but globally unique name is provided. That is,
-the following examples end up with different names::
+the following examples end up with different names:
- defm : SomeMultiClass<...>; // A globally unique name.
- defm "" : SomeMultiClass<...>; // An empty name.
+```
+defm : SomeMultiClass<...>; // A globally unique name.
+defm "" : SomeMultiClass<...>; // An empty name.
+```
-The ``defm`` statement can be used in a multiclass body. When this occurs,
-the second variant is equivalent to::
+The `defm` statement can be used in a multiclass body. When this occurs,
+the second variant is equivalent to:
- defm NAME : SomeMultiClass<...>;
+```
+defm NAME : SomeMultiClass<...>;
+```
-More generally, when ``defm`` occurs in a multiclass and its name does not
-include a use of the implicit template argument ``NAME``, then ``NAME`` will
+More generally, when `defm` occurs in a multiclass and its name does not
+include a use of the implicit template argument `NAME`, then `NAME` will
be prepended automatically. That is, the following are equivalent inside a
-multiclass::
+multiclass:
- defm Foo : SomeMultiClass<...>;
- defm NAME # Foo : SomeMultiClass<...>;
+```
+defm Foo : SomeMultiClass<...>;
+defm NAME # Foo : SomeMultiClass<...>;
+```
-See `Examples: multiclasses and defms`_ for examples.
+See [Examples: multiclasses and defms] for examples.
-Examples: multiclasses and defms
---------------------------------
+### Examples: multiclasses and defms
-Here is a simple example using ``multiclass`` and ``defm``. Consider a
+Here is a simple example using `multiclass` and `defm`. Consider a
3-address instruction architecture whose instructions come in two formats:
-``reg = reg op reg`` and ``reg = reg op imm`` (immediate). The SPARC is an
+`reg = reg op reg` and `reg = reg op imm` (immediate). The SPARC is an
example of such an architecture.
-.. code-block:: text
-
- def ops;
- def GPR;
- def Imm;
- class inst <int opc, string asmstr, dag operandlist>;
-
- multiclass ri_inst <int opc, string asmstr> {
- def _rr : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
- (ops GPR:$dst, GPR:$src1, GPR:$src2)>;
- def _ri : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
- (ops GPR:$dst, GPR:$src1, Imm:$src2)>;
- }
-
- // Define records for each instruction in the RR and RI formats.
- defm ADD : ri_inst<0b111, "add">;
- defm SUB : ri_inst<0b101, "sub">;
- defm MUL : ri_inst<0b100, "mul">;
-
-Each use of the ``ri_inst`` multiclass defines two records, one with the
-``_rr`` suffix and one with ``_ri``. Recall that the name of the ``defm``
+```text
+def ops;
+def GPR;
+def Imm;
+class inst <int opc, string asmstr, dag operandlist>;
+
+multiclass ri_inst <int opc, string asmstr> {
+ def _rr : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
+ (ops GPR:$dst, GPR:$src1, GPR:$src2)>;
+ def _ri : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
+ (ops GPR:$dst, GPR:$src1, Imm:$src2)>;
+}
+
+// Define records for each instruction in the RR and RI formats.
+defm ADD : ri_inst<0b111, "add">;
+defm SUB : ri_inst<0b101, "sub">;
+defm MUL : ri_inst<0b100, "mul">;
+```
+
+Each use of the `ri_inst` multiclass defines two records, one with the
+`_rr` suffix and one with `_ri`. Recall that the name of the `defm`
that uses a multiclass is prepended to the names of the records defined in
-that multiclass. So the resulting definitions are named::
+that multiclass. So the resulting definitions are named:
- ADD_rr, ADD_ri
- SUB_rr, SUB_ri
- MUL_rr, MUL_ri
+```
+ADD_rr, ADD_ri
+SUB_rr, SUB_ri
+MUL_rr, MUL_ri
+```
-Without the ``multiclass`` feature, the instructions would have to be
+Without the `multiclass` feature, the instructions would have to be
defined as follows.
-.. code-block:: text
-
- def ops;
- def GPR;
- def Imm;
- class inst <int opc, string asmstr, dag operandlist>;
-
- class rrinst <int opc, string asmstr>
- : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
- (ops GPR:$dst, GPR:$src1, GPR:$src2)>;
-
- class riinst <int opc, string asmstr>
- : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
- (ops GPR:$dst, GPR:$src1, Imm:$src2)>;
-
- // Define records for each instruction in the RR and RI formats.
- def ADD_rr : rrinst<0b111, "add">;
- def ADD_ri : riinst<0b111, "add">;
- def SUB_rr : rrinst<0b101, "sub">;
- def SUB_ri : riinst<0b101, "sub">;
- def MUL_rr : rrinst<0b100, "mul">;
- def MUL_ri : riinst<0b100, "mul">;
-
-A ``defm`` can be used in a multiclass to "invoke" other multiclasses and
+```text
+def ops;
+def GPR;
+def Imm;
+class inst <int opc, string asmstr, dag operandlist>;
+
+class rrinst <int opc, string asmstr>
+ : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
+ (ops GPR:$dst, GPR:$src1, GPR:$src2)>;
+
+class riinst <int opc, string asmstr>
+ : inst<opc, !strconcat(asmstr, " $dst, $src1, $src2"),
+ (ops GPR:$dst, GPR:$src1, Imm:$src2)>;
+
+// Define records for each instruction in the RR and RI formats.
+def ADD_rr : rrinst<0b111, "add">;
+def ADD_ri : riinst<0b111, "add">;
+def SUB_rr : rrinst<0b101, "sub">;
+def SUB_ri : riinst<0b101, "sub">;
+def MUL_rr : rrinst<0b100, "mul">;
+def MUL_ri : riinst<0b100, "mul">;
+```
+
+A `defm` can be used in a multiclass to "invoke" other multiclasses and
create the records defined in those multiclasses in addition to the records
-defined in the current multiclass. In the following example, the ``basic_s``
-and ``basic_p`` multiclasses contain ``defm`` statements that refer to the
-``basic_r`` multiclass. The ``basic_r`` multiclass contains only ``def``
+defined in the current multiclass. In the following example, the `basic_s`
+and `basic_p` multiclasses contain `defm` statements that refer to the
+`basic_r` multiclass. The `basic_r` multiclass contains only `def`
statements.
-.. code-block:: text
-
- class Instruction <bits<4> opc, string Name> {
- bits<4> opcode = opc;
- string name = Name;
- }
-
- multiclass basic_r <bits<4> opc> {
- def rr : Instruction<opc, "rr">;
- def rm : Instruction<opc, "rm">;
- }
-
- multiclass basic_s <bits<4> opc> {
- defm SS : basic_r<opc>;
- defm SD : basic_r<opc>;
- def X : Instruction<opc, "x">;
- }
-
- multiclass basic_p <bits<4> opc> {
- defm PS : basic_r<opc>;
- defm PD : basic_r<opc>;
- def Y : Instruction<opc, "y">;
- }
-
- defm ADD : basic_s<0xf>, basic_p<0xf>;
-
-The final ``defm`` creates the following records, five from the ``basic_s``
-multiclass and five from the ``basic_p`` multiclass::
-
- ADDSSrr, ADDSSrm
- ADDSDrr, ADDSDrm
- ADDX
- ADDPSrr, ADDPSrm
- ADDPDrr, ADDPDrm
- ADDY
-
-A ``defm`` statement, both at top level and in a multiclass, can inherit
+```text
+class Instruction <bits<4> opc, string Name> {
+ bits<4> opcode = opc;
+ string name = Name;
+}
+
+multiclass basic_r <bits<4> opc> {
+ def rr : Instruction<opc, "rr">;
+ def rm : Instruction<opc, "rm">;
+}
+
+multiclass basic_s <bits<4> opc> {
+ defm SS : basic_r<opc>;
+ defm SD : basic_r<opc>;
+ def X : Instruction<opc, "x">;
+}
+
+multiclass basic_p <bits<4> opc> {
+ defm PS : basic_r<opc>;
+ defm PD : basic_r<opc>;
+ def Y : Instruction<opc, "y">;
+}
+
+defm ADD : basic_s<0xf>, basic_p<0xf>;
+```
+
+The final `defm` creates the following records, five from the `basic_s`
+multiclass and five from the `basic_p` multiclass:
+
+```
+ADDSSrr, ADDSSrm
+ADDSDrr, ADDSDrm
+ADDX
+ADDPSrr, ADDPSrm
+ADDPDrr, ADDPDrm
+ADDY
+```
+
+A `defm` statement, both at top level and in a multiclass, can inherit
from regular classes in addition to multiclasses. The rule is that the
regular classes must be listed after the multiclasses, and there must be at least
one multiclass.
-.. code-block:: text
-
- class XD {
- bits<4> Prefix = 11;
- }
- class XS {
- bits<4> Prefix = 12;
- }
- class I <bits<4> op> {
- bits<4> opcode = op;
- }
-
- multiclass R {
- def rr : I<4>;
- def rm : I<2>;
- }
-
- multiclass Y {
- defm SS : R, XD; // First multiclass R, then regular class XD.
- defm SD : R, XS;
- }
-
- defm Instr : Y;
+```text
+class XD {
+ bits<4> Prefix = 11;
+}
+class XS {
+ bits<4> Prefix = 12;
+}
+class I <bits<4> op> {
+ bits<4> opcode = op;
+}
+
+multiclass R {
+ def rr : I<4>;
+ def rm : I<2>;
+}
+
+multiclass Y {
+ defm SS : R, XD; // First multiclass R, then regular class XD.
+ defm SD : R, XS;
+}
+
+defm Instr : Y;
+```
This example will create four records, shown here in alphabetical order with
their fields.
-.. code-block:: text
-
- def InstrSDrm {
- bits<4> opcode = { 0, 0, 1, 0 };
- bits<4> Prefix = { 1, 1, 0, 0 };
- }
-
- def InstrSDrr {
- bits<4> opcode = { 0, 1, 0, 0 };
- bits<4> Prefix = { 1, 1, 0, 0 };
- }
-
- def InstrSSrm {
- bits<4> opcode = { 0, 0, 1, 0 };
- bits<4> Prefix = { 1, 0, 1, 1 };
- }
-
- def InstrSSrr {
- bits<4> opcode = { 0, 1, 0, 0 };
- bits<4> Prefix = { 1, 0, 1, 1 };
- }
-
-It's also possible to use ``let`` statements inside multiclasses, providing
+```text
+def InstrSDrm {
+ bits<4> opcode = { 0, 0, 1, 0 };
+ bits<4> Prefix = { 1, 1, 0, 0 };
+}
+
+def InstrSDrr {
+ bits<4> opcode = { 0, 1, 0, 0 };
+ bits<4> Prefix = { 1, 1, 0, 0 };
+}
+
+def InstrSSrm {
+ bits<4> opcode = { 0, 0, 1, 0 };
+ bits<4> Prefix = { 1, 0, 1, 1 };
+}
+
+def InstrSSrr {
+ bits<4> opcode = { 0, 1, 0, 0 };
+ bits<4> Prefix = { 1, 0, 1, 1 };
+}
+```
+
+It's also possible to use `let` statements inside multiclasses, providing
another way to factor out commonality from the records, especially when
using several levels of multiclass instantiations.
-.. code-block:: text
-
- multiclass basic_r <bits<4> opc> {
- let Predicates = [HasSSE2] in {
- def rr : Instruction<opc, "rr">;
- def rm : Instruction<opc, "rm">;
- }
- let Predicates = [HasSSE3] in
- def rx : Instruction<opc, "rx">;
+```text
+multiclass basic_r <bits<4> opc> {
+ let Predicates = [HasSSE2] in {
+ def rr : Instruction<opc, "rr">;
+ def rm : Instruction<opc, "rm">;
}
+ let Predicates = [HasSSE3] in
+ def rx : Instruction<opc, "rx">;
+}
- multiclass basic_ss <bits<4> opc> {
- let IsDouble = false in
- defm SS : basic_r<opc>;
-
- let IsDouble = true in
- defm SD : basic_r<opc>;
- }
+multiclass basic_ss <bits<4> opc> {
+ let IsDouble = false in
+ defm SS : basic_r<opc>;
- defm ADD : basic_ss<0xf>;
+ let IsDouble = true in
+ defm SD : basic_r<opc>;
+}
+defm ADD : basic_ss<0xf>;
+```
-``defset`` --- create a definition set
---------------------------------------
+### `defset` --- create a definition set
-The ``defset`` statement is used to collect a set of records into a global
+The `defset` statement is used to collect a set of records into a global
list of records.
+```{eval-rst}
.. productionlist::
Defset: "defset" `Type` `TokIdentifier` "=" "{" `Statement`* "}"
+```
-All records defined inside the braces via ``def`` and ``defm`` are defined
+All records defined inside the braces via `def` and `defm` are defined
as usual, and they are also collected in a global list of the given name
-(:token:`TokIdentifier`).
+({token}`TokIdentifier`).
-The specified type must be ``list<``\ *class*\ ``>``, where *class* is some
-record class. The ``defset`` statement establishes a scope for its
+The specified type must be `list<`*class*`>`, where *class* is some
+record class. The `defset` statement establishes a scope for its
statements. It is an error to define a record in the scope of the
-``defset`` that is not of type *class*.
+`defset` that is not of type *class*.
-The ``defset`` statement can be nested. The inner ``defset`` adds the
+The `defset` statement can be nested. The inner `defset` adds the
records to its own set, and all those records are also added to the outer
set.
Anonymous records created inside initialization expressions using the
-``ClassID<...>`` syntax are not collected in the set.
+`ClassID<...>` syntax are not collected in the set.
-``deftype`` --- define a type
---------------------------------
+### `deftype` --- define a type
-A ``deftype`` statement defines a type. The type can be used throughout the
+A `deftype` statement defines a type. The type can be used throughout the
statements that follow the definition.
+```{eval-rst}
.. productionlist::
Deftype: "deftype" `TokIdentifier` "=" `Type` ";"
+```
-The identifier on the left of the ``=`` is defined to be a type name
-whose actual type is given by the type expression on the right of the ``=``.
+The identifier on the left of the `=` is defined to be a type name
+whose actual type is given by the type expression on the right of the `=`.
Currently, only primitive types and type aliases are supported to be the source
type and `deftype` statements can only appear at the top level.
-``defvar`` --- define a variable
---------------------------------
+### `defvar` --- define a variable
-A ``defvar`` statement defines a global variable. Its value can be used
+A `defvar` statement defines a global variable. Its value can be used
throughout the statements that follow the definition.
+```{eval-rst}
.. productionlist::
Defvar: "defvar" `TokIdentifier` "=" `Value` ";"
+```
-The identifier on the left of the ``=`` is defined to be a global variable
-whose value is given by the value expression on the right of the ``=``. The
+The identifier on the left of the `=` is defined to be a global variable
+whose value is given by the value expression on the right of the `=`. The
type of the variable is automatically inferred.
Once a variable has been defined, it cannot be set to another value.
-Variables defined in a top-level ``foreach`` go out of scope at the end of
+Variables defined in a top-level `foreach` go out of scope at the end of
each loop iteration, so their value in one iteration is not available in
-the next iteration. The following ``defvar`` will not work::
+the next iteration. The following `defvar` will not work:
- defvar i = !add(i, 1);
+```
+defvar i = !add(i, 1);
+```
-Variables can also be defined with ``defvar`` in a record body. See
-`Defvar in a Record Body`_ for more details.
+Variables can also be defined with `defvar` in a record body. See
+[Defvar in a Record Body] for more details.
-``foreach`` --- iterate over a sequence of statements
------------------------------------------------------
+### `foreach` --- iterate over a sequence of statements
-The ``foreach`` statement iterates over a series of statements, varying a
+The `foreach` statement iterates over a series of statements, varying a
variable over a sequence of values.
+```{eval-rst}
.. productionlist::
Foreach: "foreach" `ForeachIterator` "in" "{" `Statement`* "}"
:| "foreach" `ForeachIterator` "in" `Statement`
ForeachIterator: `TokIdentifier` "=" (`RangeList` | `RangePiece` | `Value`)
+```
-The body of the ``foreach`` is a series of statements in braces or a
+The body of the `foreach` is a series of statements in braces or a
single statement with no braces. The statements are re-evaluated once for
each value in the range list, range piece, or single value. On each
-iteration, the :token:`TokIdentifier` variable is set to the value and can
+iteration, the {token}`TokIdentifier` variable is set to the value and can
be used in the statements.
The statement list establishes an inner scope. Variables local to a
-``foreach`` go out of scope at the end of each loop iteration, so their
+`foreach` go out of scope at the end of each loop iteration, so their
values do not carry over from one iteration to the next. Foreach loops may
be nested.
-.. Note that the productions involving RangeList and RangePiece have precedence
- over the more generic value parsing based on the first token.
-
-.. code-block:: text
+% Note that the productions involving RangeList and RangePiece have precedence
+% over the more generic value parsing based on the first token.
- foreach i = [0, 1, 2, 3] in {
- def R#i : Register<...>;
- def F#i : Register<...>;
- }
+```text
+foreach i = [0, 1, 2, 3] in {
+ def R#i : Register<...>;
+ def F#i : Register<...>;
+}
+```
-This loop defines records named ``R0``, ``R1``, ``R2``, and ``R3``, along
-with ``F0``, ``F1``, ``F2``, and ``F3``.
+This loop defines records named `R0`, `R1`, `R2`, and `R3`, along
+with `F0`, `F1`, `F2`, and `F3`.
-``dump`` --- print messages to stderr
--------------------------------------
+### `dump` --- print messages to stderr
-A ``dump`` statement prints the input string to standard error
+A `dump` statement prints the input string to standard error
output. It is intended for debugging purposes.
-* At top level, the message is printed immediately.
-
-* Within a record/class/multiclass, `dump` gets evaluated at each
+- At top level, the message is printed immediately.
+- Within a record/class/multiclass, `dump` gets evaluated at each
instantiation point of the containing record.
+```{eval-rst}
.. productionlist::
Dump: "dump" `Value` ";"
+```
-The :token:`Value` is an arbitrary string expression.
+The {token}`Value` is an arbitrary string expression.
For example, it can be used in combination with `!repr` to investigate
the values passed to a multiclass:
-.. code-block:: text
-
- multiclass MC<dag s> {
- dump "s = " # !repr(s);
- }
-
+```text
+multiclass MC<dag s> {
+ dump "s = " # !repr(s);
+}
+```
-``if`` --- select statements based on a test
---------------------------------------------
+### `if` --- select statements based on a test
-The ``if`` statement allows one of two statement groups to be selected based
+The `if` statement allows one of two statement groups to be selected based
on the value of an expression.
+```{eval-rst}
.. productionlist::
If: "if" `Value` "then" `IfBody`
:| "if" `Value` "then" `IfBody` "else" `IfBody`
IfBody: "{" `Statement`* "}" | `Statement`
+```
The value expression is evaluated. If it evaluates to true (in the same
sense used by the bang operators), then the statements following the
-``then`` reserved word are processed. Otherwise, if there is an ``else``
-reserved word, the statements following the ``else`` are processed. If the
-value is false and there is no ``else`` arm, no statements are processed.
+`then` reserved word are processed. Otherwise, if there is an `else`
+reserved word, the statements following the `else` are processed. If the
+value is false and there is no `else` arm, no statements are processed.
-Because the braces around the ``then`` statements are optional, this grammar rule
+Because the braces around the `then` statements are optional, this grammar rule
has the usual ambiguity with "dangling else" clauses, and it is resolved in
-the usual way: in a case like ``if v1 then if v2 then {...} else {...}``, the
-``else`` associates with the inner ``if`` rather than the outer one.
+the usual way: in a case like `if v1 then if v2 then {...} else {...}`, the
+`else` associates with the inner `if` rather than the outer one.
-The :token:`IfBody` of the then and else arms of the ``if`` establish an
-inner scope. Any ``defvar`` variables defined in the bodies go out of scope
-when the bodies are finished (see `Defvar in a Record Body`_ for more details).
+The {token}`IfBody` of the then and else arms of the `if` establish an
+inner scope. Any `defvar` variables defined in the bodies go out of scope
+when the bodies are finished (see [Defvar in a Record Body] for more details).
-The ``if`` statement can also be used in a record :token:`Body`.
+The `if` statement can also be used in a record {token}`Body`.
+### `assert` --- check that a condition is true
-``assert`` --- check that a condition is true
----------------------------------------------
-
-The ``assert`` statement checks a boolean condition to be sure that it is true
+The `assert` statement checks a boolean condition to be sure that it is true
and prints an error message if it is not.
+```{eval-rst}
.. productionlist::
Assert: "assert" `Value` "," `Value` ";"
+```
-The first :token:`Value` is a boolean condition. If it is true, the
+The first {token}`Value` is a boolean condition. If it is true, the
statement does nothing. If the condition is false, it prints a nonfatal
-error message. The second :token:`Value` is a message, which can be an
+error message. The second {token}`Value` is a message, which can be an
arbitrary string expression. It is included in the error message as a
-note. The exact behavior of the ``assert`` statement depends on its
+note. The exact behavior of the `assert` statement depends on its
placement.
-* At top level, the assertion is checked immediately.
-
-* In a record definition, the statement is saved and all assertions are
+- At top level, the assertion is checked immediately.
+- In a record definition, the statement is saved and all assertions are
checked after the record is completely built.
-
-* In a class definition, the assertions are saved and inherited by all
+- In a class definition, the assertions are saved and inherited by all
the subclasses and records that inherit from the class. The assertions are
then checked when the records are completely built.
-
-* In a multiclass definition, the assertions are saved with the other
+- In a multiclass definition, the assertions are saved with the other
components of the multiclass and then checked each time the multiclass
- is instantiated with ``defm``.
+ is instantiated with `defm`.
Using assertions in TableGen files can simplify record checking in TableGen
-backends. Here is an example of an ``assert`` in two class definitions.
-
-.. code-block:: text
+backends. Here is an example of an `assert` in two class definitions.
- class PersonName<string name> {
- assert !le(!size(name), 32), "person name is too long: " # name;
- string Name = name;
- }
+```text
+class PersonName<string name> {
+ assert !le(!size(name), 32), "person name is too long: " # name;
+ string Name = name;
+}
- class Person<string name, int age> : PersonName<name> {
- assert !and(!ge(age, 1), !le(age, 120)), "person age is invalid: " # age;
- int Age = age;
- }
+class Person<string name, int age> : PersonName<name> {
+ assert !and(!ge(age, 1), !le(age, 120)), "person age is invalid: " # age;
+ int Age = age;
+}
- def Rec20 : Person<"Donald Knuth", 60> {
- ...
- }
+def Rec20 : Person<"Donald Knuth", 60> {
+ ...
+}
+```
+## Additional Details
-Additional Details
-==================
-
-Directed acyclic graphs (DAGs)
-------------------------------
+### Directed acyclic graphs (DAGs)
A directed acyclic graph can be represented directly in TableGen using the
-``dag`` datatype. A DAG node consists of an operator and zero or more
+`dag` datatype. A DAG node consists of an operator and zero or more
arguments (or operands). Each argument can be of any desired type. By using
another DAG node as an argument, an arbitrary graph of DAG nodes can be
built.
-The syntax of a ``dag`` instance is:
+The syntax of a `dag` instance is:
- ``(`` *operator* *argument1*\ ``,`` *argument2*\ ``,`` ... ``)``
+> `(` *operator* *argument1*`,` *argument2*`,` ... `)`
The operator must be present and must be a record. There can be zero or more
arguments, separated by commas. The operator and arguments can have three
formats.
-====================== =============================================
-Format Meaning
-====================== =============================================
-*value* argument value
-*value*\ ``:``\ *name* argument value and associated name
-*name* argument name with unset (uninitialized) value
-====================== =============================================
+| Format | Meaning |
+| ---------------- | ---------------------------------------------- |
+| *value* | argument value |
+| *value*`:`*name* | argument value and associated name |
+| *name* | argument name with unset (uninitialized) value |
The *value* can be any TableGen value. The *name*, if present, must be a
-:token:`TokVarName`, which starts with a dollar sign (``$``). The purpose of
+{token}`TokVarName`, which starts with a dollar sign (`$`). The purpose of
a name is to tag an operator or argument in a DAG with a particular meaning,
or to associate an argument in one DAG with a like-named argument in another
DAG.
The following bang operators are useful for working with DAGs:
-``!con``, ``!dag``, ``!empty``, ``!foreach``, ``!getdagarg``, ``!getdagname``,
-``!getdagop``, ``!getdagopname``, ``!setdagarg``, ``!setdagname``, ``!setdagop``,
-``!setdagopname``, ``!size``.
+`!con`, `!dag`, `!empty`, `!foreach`, `!getdagarg`, `!getdagname`,
+`!getdagop`, `!getdagopname`, `!setdagarg`, `!setdagname`, `!setdagop`,
+`!setdagopname`, `!size`.
-Defvar in a record body
------------------------
+### Defvar in a record body
-In addition to defining global variables, the ``defvar`` statement can
-be used inside the :token:`Body` of a class or record definition to define
-local variables. Template arguments of ``class`` or ``multiclass`` can be
+In addition to defining global variables, the `defvar` statement can
+be used inside the {token}`Body` of a class or record definition to define
+local variables. Template arguments of `class` or `multiclass` can be
used in the value expression. The scope of the variable extends from the
-``defvar`` statement to the end of the body. It cannot be set to a different
-value within its scope. The ``defvar`` statement can also be used in the statement
-list of a ``foreach``, which establishes a scope.
+`defvar` statement to the end of the body. It cannot be set to a different
+value within its scope. The `defvar` statement can also be used in the statement
+list of a `foreach`, which establishes a scope.
-A variable named ``V`` in an inner scope shadows (hides) any variables ``V``
+A variable named `V` in an inner scope shadows (hides) any variables `V`
in outer scopes. In particular, there are several cases:
-* ``V`` in a record body shadows a global ``V``.
-
-* ``V`` in a record body shadows template argument ``V``.
-
-* ``V`` in template arguments shadows a global ``V``.
-
-* ``V`` in a ``foreach`` statement list shadows any ``V`` in surrounding record or
+- `V` in a record body shadows a global `V`.
+- `V` in a record body shadows template argument `V`.
+- `V` in template arguments shadows a global `V`.
+- `V` in a `foreach` statement list shadows any `V` in surrounding record or
global scopes.
-Variables defined in a ``foreach`` go out of scope at the end of
+Variables defined in a `foreach` go out of scope at the end of
each loop iteration, so their value in one iteration is not available in
-the next iteration. The following ``defvar`` will not work::
+the next iteration. The following `defvar` will not work:
- defvar i = !add(i, 1)
+```
+defvar i = !add(i, 1)
+```
-How records are built
----------------------
+### How records are built
The following steps are taken by TableGen when a record is built. Classes are simply
abstract records and so go through the same steps.
-1. Build the record name (:token:`NameValue`) and create an empty record.
-
-2. Parse the parent classes in the :token:`ParentClassList` from left to
+1. Build the record name ({token}`NameValue`) and create an empty record.
+2. Parse the parent classes in the {token}`ParentClassList` from left to
right, visiting each parent class's ancestor classes from top to bottom.
- a. Add the fields from the parent class to the record.
- b. Substitute the template arguments into those fields.
- c. Add the parent class to the record's list of inherited classes.
+> 1. Add the fields from the parent class to the record.
+> 2. Substitute the template arguments into those fields.
+> 3. Add the parent class to the record's list of inherited classes.
-3. Apply any top-level ``let`` bindings to the record. Recall that top-level
+3. Apply any top-level `let` bindings to the record. Recall that top-level
bindings only apply to inherited fields.
-
4. Parse the body of the record.
- * Add any fields to the record.
- * Modify the values of fields according to local ``let`` statements.
- * Define any ``defvar`` variables.
+> - Add any fields to the record.
+> - Modify the values of fields according to local `let` statements.
+> - Define any `defvar` variables.
5. Make a pass over all the fields to resolve any inter-field references.
-
6. Add the record to the final record list.
-Because references between fields are resolved (step 5) after ``let`` bindings are
-applied (step 3), the ``let`` statement has unusual power. For example:
+Because references between fields are resolved (step 5) after `let` bindings are
+applied (step 3), the `let` statement has unusual power. For example:
-.. code-block:: text
+```text
+class C <int x> {
+ int Y = x;
+ int Yplus1 = !add(Y, 1);
+ int xplus1 = !add(x, 1);
+}
- class C <int x> {
- int Y = x;
- int Yplus1 = !add(Y, 1);
- int xplus1 = !add(x, 1);
+let Y = 10 in {
+ def rec1 : C<5> {
}
-
- let Y = 10 in {
- def rec1 : C<5> {
- }
- }
-
- def rec2 : C<5> {
- let Y = 10;
- }
-
-In both cases, one where a top-level ``let`` is used to bind ``Y`` and one
-where a local ``let`` does the same thing, the results are:
-
-.. code-block:: text
-
- def rec1 { // C
- int Y = 10;
- int Yplus1 = 11;
- int xplus1 = 6;
- }
- def rec2 { // C
- int Y = 10;
- int Yplus1 = 11;
- int xplus1 = 6;
- }
-
-``Yplus1`` is 11 because the ``let Y`` is performed before the ``!add(Y,
-1)`` is resolved. Use this power wisely.
-
-
-Using Classes as Subroutines
-============================
-
-As described in `Simple values`_, a class can be invoked in an expression
+}
+
+def rec2 : C<5> {
+ let Y = 10;
+}
+```
+
+In both cases, one where a top-level `let` is used to bind `Y` and one
+where a local `let` does the same thing, the results are:
+
+```text
+def rec1 { // C
+ int Y = 10;
+ int Yplus1 = 11;
+ int xplus1 = 6;
+}
+def rec2 { // C
+ int Y = 10;
+ int Yplus1 = 11;
+ int xplus1 = 6;
+}
+```
+
+`Yplus1` is 11 because the `let Y` is performed before the `!add(Y,
+1)` is resolved. Use this power wisely.
+
+## Using Classes as Subroutines
+
+As described in [Simple values], a class can be invoked in an expression
and passed template arguments. This causes TableGen to create a new anonymous
record inheriting from that class. As usual, the record receives all the
fields defined in the class.
@@ -1595,48 +1647,48 @@ fields defined in the class.
This feature can be employed as a simple subroutine facility. The class can
use the template arguments to define various variables and fields, which end
up in the anonymous record. Those fields can then be retrieved in the
-expression invoking the class as follows. Assume that the field ``ret``
+expression invoking the class as follows. Assume that the field `ret`
contains the final value of the subroutine.
-.. code-block:: text
-
- int Result = ... CalcValue<arg>.ret ...;
+```text
+int Result = ... CalcValue<arg>.ret ...;
+```
-The ``CalcValue`` class is invoked with the template argument ``arg``. It
-calculates a value for the ``ret`` field, which is then retrieved at the
+The `CalcValue` class is invoked with the template argument `arg`. It
+calculates a value for the `ret` field, which is then retrieved at the
"point of call" in the initialization for the Result field. The anonymous
record created in this example serves no other purpose than to carry the
result value.
-Here is a practical example. The class ``isValidSize`` determines whether a
-specified number of bytes represents a valid data size. The bit ``ret`` is
-set appropriately. The field ``ValidSize`` obtains its initial value by
-invoking ``isValidSize`` with the data size and retrieving the ``ret`` field
+Here is a practical example. The class `isValidSize` determines whether a
+specified number of bytes represents a valid data size. The bit `ret` is
+set appropriately. The field `ValidSize` obtains its initial value by
+invoking `isValidSize` with the data size and retrieving the `ret` field
from the resulting anonymous record.
-.. code-block:: text
+```text
+class isValidSize<int size> {
+ bit ret = !cond(!eq(size, 1): 1,
+ !eq(size, 2): 1,
+ !eq(size, 4): 1,
+ !eq(size, 8): 1,
+ !eq(size, 16): 1,
+ true: 0);
+}
- class isValidSize<int size> {
- bit ret = !cond(!eq(size, 1): 1,
- !eq(size, 2): 1,
- !eq(size, 4): 1,
- !eq(size, 8): 1,
- !eq(size, 16): 1,
- true: 0);
- }
-
- def Data1 {
- int Size = ...;
- bit ValidSize = isValidSize<Size>.ret;
- }
+def Data1 {
+ int Size = ...;
+ bit ValidSize = isValidSize<Size>.ret;
+}
+```
-Preprocessing Facilities
-========================
+## Preprocessing Facilities
The preprocessor embedded in TableGen is intended only for simple
conditional compilation. It supports the following directives, which are
specified somewhat informally.
+```{eval-rst}
.. productionlist::
LineBegin: beginning of line
LineEnd: newline | return | EOF
@@ -1656,38 +1708,39 @@ specified somewhat informally.
: "#else" (`WhiteSpaceOrAnyComment`)* `LineEnd`
PreEndif: `LineBegin` (`WhiteSpaceOrCComment`)*
: "#endif" (`WhiteSpaceOrAnyComment`)* `LineEnd`
+```
-..
- PreRegContentException: `PreIfdef` | `PreElse` | `PreEndif` | EOF
- PreRegion: .* - `PreRegContentException`
- :| `PreIfdef`
- : (`PreRegion`)*
- : [`PreElse`]
- : (`PreRegion`)*
- : `PreEndif`
+% PreRegContentException: `PreIfdef` | `PreElse` | `PreEndif` | EOF
+% PreRegion: .* - `PreRegContentException`
+% :| `PreIfdef`
+% : (`PreRegion`)*
+% : [`PreElse`]
+% : (`PreRegion`)*
+% : `PreEndif`
-A :token:`MacroName` can be defined anywhere in a TableGen file. The name has
+A {token}`MacroName` can be defined anywhere in a TableGen file. The name has
no value; it can only be tested to see whether it is defined.
-A macro test region begins with an ``#ifdef`` or ``#ifndef`` directive. If
-the macro name is defined (``#ifdef``) or undefined (``#ifndef``), then the
-source code between the directive and the corresponding ``#else`` or
-``#endif`` is processed. If the test fails but there is an ``#else``
-clause, the source code between the ``#else`` and the ``#endif`` is
-processed. If the test fails and there is no ``#else`` clause, then no
+A macro test region begins with an `#ifdef` or `#ifndef` directive. If
+the macro name is defined (`#ifdef`) or undefined (`#ifndef`), then the
+source code between the directive and the corresponding `#else` or
+`#endif` is processed. If the test fails but there is an `#else`
+clause, the source code between the `#else` and the `#endif` is
+processed. If the test fails and there is no `#else` clause, then no
source code in the test region is processed.
Test regions may be nested, but they must be properly nested. A region
started in a file must end in that file; that is, must have its
-``#endif`` in the same file.
+`#endif` in the same file.
-A :token:`MacroName` may be defined externally using the ``-D`` option on the
-``*-tblgen`` command line::
+A {token}`MacroName` may be defined externally using the `-D` option on the
+`*-tblgen` command line:
- llvm-tblgen self-reference.td -Dmacro1 -Dmacro3
+```
+llvm-tblgen self-reference.td -Dmacro1 -Dmacro3
+```
-Appendix A: Bang Operators
-==========================
+## Appendix A: Bang Operators
Bang operators act as functions in value expressions. A bang operator takes
one or more arguments, operates on them, and produces a result. If the
@@ -1695,593 +1748,663 @@ operator produces a boolean result, the result value will be 1 for true or 0
for false. When an operator tests a boolean argument, it interprets 0 as false
and non-0 as true.
-``!add(``\ *a*\ ``,`` *b*\ ``, ...)``
- This operator adds *a*, *b*, etc., and produces the sum.
-
-``!and(``\ *a*\ ``,`` *b*\ ``, ...)``
- This operator does a bitwise AND on *a*, *b*, etc., and produces the
- result. A logical AND can be performed if all the arguments are either
- 0 or 1. This operator is short-circuit to 0 when the left-most operand
- is 0.
-
-``!cast<``\ *type*\ ``>(``\ *a*\ ``)``
- This operator performs a cast on *a* and produces the result.
- If *a* is not a string, then a straightforward cast is performed, say
- between an ``int`` and a ``bit``, or between record types. This allows
- casting a record to a class. If a record is cast to ``string``, the
- record's name is produced.
-
- If *a* is a string, then it is treated as a record name and looked up in
- the list of all defined records. The resulting record is expected to be of
- the specified *type*.
-
- For example, if ``!cast<``\ *type*\ ``>(``\ *name*\ ``)``
- appears in a multiclass definition, or in a
- class instantiated inside a multiclass definition, and the *name* does not
- reference any template arguments of the multiclass, then a record by
- that name must have been instantiated earlier
- in the source file. If *name* does reference
- a template argument, then the lookup is delayed until ``defm`` statements
- instantiating the multiclass (or later, if the defm occurs in another
- multiclass and template arguments of the inner multiclass that are
- referenced by *name* are substituted by values that themselves contain
- references to template arguments of the outer multiclass).
-
- If the type of *a* does not match *type*, TableGen raises an error.
-
-``!con(``\ *a*\ ``,`` *b*\ ``, ...)``
- This operator concatenates the DAG nodes *a*, *b*, etc. Their operations
- must equal.
-
- ``!con((op:$lhs a1:$name1, a2:$name2), (op:$rhs b1:$name3))``
-
- results in the DAG node ``(op:$lhs a1:$name1, a2:$name2, b1:$name3)``.
- The name of the dag operator is derived from the LHS DAG node if it is
- set, otherwise from the RHS DAG node.
-
-``!cond(``\ *cond1* ``:`` *val1*\ ``,`` *cond2* ``:`` *val2*\ ``, ...,`` *condn* ``:`` *valn*\ ``)``
- This operator tests *cond1* and returns *val1* if the result is true.
- If false, the operator tests *cond2* and returns *val2* if the result is
- true. And so forth. An error is reported if no conditions are true.
-
- !cond short-circuits at the first true condition, resolving to that
- condition's corresponding value. Subsequent conditions and values are left
- unresolved.
-
- This example produces the sign word for an integer::
-
- !cond(!lt(x, 0) : "negative", !eq(x, 0) : "zero", true : "positive")
-
-``!dag(``\ *op*\ ``,`` *arguments*\ ``,`` *names*\ ``)``
- This operator creates a DAG node with the given operator and
- arguments. The *arguments* and *names* arguments must be lists
- of equal length or uninitialized (``?``). The *names* argument
- must be of type ``list<string>``.
-
- Due to limitations of the type system, *arguments* must be a list of items
- of a common type. In practice, this means that they should either have the
- same type or be records with a common parent class. Mixing ``dag`` and
- non-``dag`` items is not possible. However, ``?`` can be used.
-
- Example: ``!dag(op, [a1, a2, ?], ["name1", "name2", "name3"])`` results in
- ``(op a1-value:$name1, a2-value:$name2, ?:$name3)``.
-
-``!div(``\ *a*\ ``,`` *b*\ ``)``
- This operator performs signed division of *a* by *b*, and produces the quotient.
- Division by 0 produces an error. Division of ``INT64_MIN`` by -1 produces an error.
-
-``!empty(``\ *a*\ ``)``
- This operator produces 1 if the string, list, or DAG *a* is empty; 0 otherwise.
- A dag is empty if it has no arguments; the operator does not count.
-
-``!eq(`` *a*\ `,` *b*\ ``)``
- This operator produces 1 if *a* is equal to *b*; 0 otherwise.
- The arguments must be ``bit``, ``bits``, ``int``, ``string``, or
- record values. Use ``!cast<string>`` to compare other types of objects.
-
-``!exists<``\ *type*\ ``>(``\ *name*\ ``)``
- This operator produces 1 if a record of the given *type* whose name is *name*
- exists; 0 otherwise. *name* should be of type *string*.
-
-``!filter(``\ *var*\ ``,`` *list*\ ``,`` *predicate*\ ``)``
-
- This operator creates a new ``list`` by filtering the elements in
- *list*. To perform the filtering, TableGen binds the variable *var* to each
- element and then evaluates the *predicate* expression, which presumably
- refers to *var*. The predicate must
- produce a boolean value (``bit``, ``bits``, or ``int``). The value is
- interpreted as with ``!if``:
- if the value is 0, the element is not included in the new list. If the value
- is anything else, the element is included.
-
-``!find(``\ *string1*\ ``,`` *string2*\ [``,`` *start*]\ ``)``
- This operator searches for *string2* in *string1* and produces its
- position. The starting position of the search may be specified by *start*,
- which can range between 0 and the length of *string1*; the default is 0.
- If the string is not found, the result is -1.
-
-``!foldl(``\ *init*\ ``,`` *list*\ ``,`` *acc*\ ``,`` *var*\ ``,`` *expr*\ ``)``
- This operator performs a left-fold over the items in *list*. The
- variable *acc* acts as the accumulator and is initialized to *init*.
- The variable *var* is bound to each element in the *list*. The
- expression is evaluated for each element and presumably uses *acc* and
- *var* to calculate the accumulated value, which ``!foldl`` stores back in
- *acc*. The type of *acc* is the same as *init*; the type of *var* is the
- same as the elements of *list*; *expr* must have the same type as *init*.
-
- The following example computes the total of the ``Number`` field in the
- list of records in ``RecList``::
-
- int x = !foldl(0, RecList, total, rec, !add(total, rec.Number));
-
- If your goal is to filter the list and produce a new list that includes only
- some of the elements, see ``!filter``.
-
-``!foreach(``\ *var*\ ``,`` *sequence*\ ``,`` *expr*\ ``)``
- This operator creates a new ``list``/``dag`` in which each element is a
- function of the corresponding element in the *sequence* ``list``/``dag``.
- To perform the function, TableGen binds the variable *var* to an element
- and then evaluates the expression. The expression presumably refers
- to the variable *var* and calculates the result value.
-
- If you simply want to create a list of a certain length containing
- the same value repeated multiple times, see ``!listsplat``.
-
-``!ge(``\ *a*\ `,` *b*\ ``)``
- This operator produces 1 if *a* is greater than or equal to *b*; 0 otherwise.
- The arguments must be ``bit``, ``bits``, ``int``, or ``string`` values.
-
-``!getdagarg<``\ *type*\ ``>(``\ *dag*\ ``,``\ *key*\ ``)``
- This operator retrieves the argument from the given *dag* node by the
- specified *key*, which is either an integer index or a string name. If that
- argument is not convertible to the specified *type*, ``?`` is returned.
-
-``!getdagname(``\ *dag*\ ``,``\ *index*\ ``)``
- This operator retrieves the argument name from the given *dag* node by the
- specified *index*. If that argument has no name associated, ``?`` is
- returned.
-
-``!getdagop(``\ *dag*\ ``)`` --or-- ``!getdagop<``\ *type*\ ``>(``\ *dag*\ ``)``
- This operator produces the operator of the given *dag* node.
- Example: ``!getdagop((foo 1, 2))`` results in ``foo``. Recall that
- DAG operators are always records.
-
- The result of ``!getdagop`` can be used directly in a context where
- any record class at all is acceptable (typically placing it into
- another dag value). But in other contexts, it must be explicitly
- cast to a particular class. The ``<``\ *type*\ ``>`` syntax is
- provided to make this easy.
-
- For example, to assign the result to a value of type ``BaseClass``, you
- could write either of these::
-
- BaseClass b = !getdagop<BaseClass>(someDag);
- BaseClass b = !cast<BaseClass>(!getdagop(someDag));
-
- But to create a new DAG node that reuses the operator from another, no
- cast is necessary::
-
- dag d = !dag(!getdagop(someDag), args, names);
-
-``!getdagopname(``\ *dag*\ ``)``
- This operator retrieves the name of the given *dag* operator. If the operator
- has no name associated, ``?`` is returned.
-
-``!gt(``\ *a*\ `,` *b*\ ``)``
- This operator produces 1 if *a* is greater than *b*; 0 otherwise.
- The arguments must be ``bit``, ``bits``, ``int``, or ``string`` values.
-
-``!head(``\ *a*\ ``)``
- This operator produces the zeroth element of the list *a*.
- (See also ``!tail``.)
-
-``!if(``\ *test*\ ``,`` *then*\ ``,`` *else*\ ``)``
- This operator evaluates the *test*, which must produce a ``bit`` or
- ``int``. If the result is not 0, the *then* expression is produced; otherwise
+`!add(`*a*`,` *b*`, ...)`
+
+: This operator adds *a*, *b*, etc., and produces the sum.
+
+`!and(`*a*`,` *b*`, ...)`
+
+: This operator does a bitwise AND on *a*, *b*, etc., and produces the
+ result. A logical AND can be performed if all the arguments are either
+ 0 or 1. This operator is short-circuit to 0 when the left-most operand
+ is 0.
+
+`!cast<`*type*`>(`*a*`)`
+
+: This operator performs a cast on *a* and produces the result.
+ If *a* is not a string, then a straightforward cast is performed, say
+ between an `int` and a `bit`, or between record types. This allows
+ casting a record to a class. If a record is cast to `string`, the
+ record's name is produced.
+
+ If *a* is a string, then it is treated as a record name and looked up in
+ the list of all defined records. The resulting record is expected to be of
+ the specified *type*.
+
+ For example, if `!cast<`*type*`>(`*name*`)`
+ appears in a multiclass definition, or in a
+ class instantiated inside a multiclass definition, and the *name* does not
+ reference any template arguments of the multiclass, then a record by
+ that name must have been instantiated earlier
+ in the source file. If *name* does reference
+ a template argument, then the lookup is delayed until `defm` statements
+ instantiating the multiclass (or later, if the defm occurs in another
+ multiclass and template arguments of the inner multiclass that are
+ referenced by *name* are substituted by values that themselves contain
+ references to template arguments of the outer multiclass).
+
+ If the type of *a* does not match *type*, TableGen raises an error.
+
+`!con(`*a*`,` *b*`, ...)`
+
+: This operator concatenates the DAG nodes *a*, *b*, etc. Their operations
+ must equal.
+
+ `!con((op:$lhs a1:$name1, a2:$name2), (op:$rhs b1:$name3))`
+
+ results in the DAG node `(op:$lhs a1:$name1, a2:$name2, b1:$name3)`.
+ The name of the dag operator is derived from the LHS DAG node if it is
+ set, otherwise from the RHS DAG node.
+
+`!cond(`*cond1* `:` *val1*`,` *cond2* `:` *val2*`, ...,` *condn* `:` *valn*`)`
+
+: This operator tests *cond1* and returns *val1* if the result is true.
+ If false, the operator tests *cond2* and returns *val2* if the result is
+ true. And so forth. An error is reported if no conditions are true.
+
+ !cond short-circuits at the first true condition, resolving to that
+ condition's corresponding value. Subsequent conditions and values are left
+ unresolved.
+
+ This example produces the sign word for an integer:
+
+ ```
+ !cond(!lt(x, 0) : "negative", !eq(x, 0) : "zero", true : "positive")
+ ```
+
+`!dag(`*op*`,` *arguments*`,` *names*`)`
+
+: This operator creates a DAG node with the given operator and
+ arguments. The *arguments* and *names* arguments must be lists
+ of equal length or uninitialized (`?`). The *names* argument
+ must be of type `list<string>`.
+
+ Due to limitations of the type system, *arguments* must be a list of items
+ of a common type. In practice, this means that they should either have the
+ same type or be records with a common parent class. Mixing `dag` and
+ non-`dag` items is not possible. However, `?` can be used.
+
+ Example: `!dag(op, [a1, a2, ?], ["name1", "name2", "name3"])` results in
+ `(op a1-value:$name1, a2-value:$name2, ?:$name3)`.
+
+`!div(`*a*`,` *b*`)`
+
+: This operator performs signed division of *a* by *b*, and produces the quotient.
+ Division by 0 produces an error. Division of `INT64_MIN` by -1 produces an error.
+
+`!empty(`*a*`)`
+
+: This operator produces 1 if the string, list, or DAG *a* is empty; 0 otherwise.
+ A dag is empty if it has no arguments; the operator does not count.
+
+`!eq(` *a*`,` *b*`)`
+
+: This operator produces 1 if *a* is equal to *b*; 0 otherwise.
+ The arguments must be `bit`, `bits`, `int`, `string`, or
+ record values. Use `!cast<string>` to compare other types of objects.
+
+`!exists<`*type*`>(`*name*`)`
+
+: This operator produces 1 if a record of the given *type* whose name is *name*
+ exists; 0 otherwise. *name* should be of type *string*.
+
+`!filter(`*var*`,` *list*`,` *predicate*`)`
+
+> This operator creates a new `list` by filtering the elements in
+> *list*. To perform the filtering, TableGen binds the variable *var* to each
+> element and then evaluates the *predicate* expression, which presumably
+> refers to *var*. The predicate must
+> produce a boolean value (`bit`, `bits`, or `int`). The value is
+> interpreted as with `!if`:
+> if the value is 0, the element is not included in the new list. If the value
+> is anything else, the element is included.
+
+`!find(`*string1*`,` *string2*\[`,` *start*\]`)`
+
+: This operator searches for *string2* in *string1* and produces its
+ position. The starting position of the search may be specified by *start*,
+ which can range between 0 and the length of *string1*; the default is 0.
+ If the string is not found, the result is -1.
+
+`!foldl(`*init*`,` *list*`,` *acc*`,` *var*`,` *expr*`)`
+
+: This operator performs a left-fold over the items in *list*. The
+ variable *acc* acts as the accumulator and is initialized to *init*.
+ The variable *var* is bound to each element in the *list*. The
+ expression is evaluated for each element and presumably uses *acc* and
+ *var* to calculate the accumulated value, which `!foldl` stores back in
+ *acc*. The type of *acc* is the same as *init*; the type of *var* is the
+ same as the elements of *list*; *expr* must have the same type as *init*.
+
+ The following example computes the total of the `Number` field in the
+ list of records in `RecList`:
+
+ ```
+ int x = !foldl(0, RecList, total, rec, !add(total, rec.Number));
+ ```
+
+ If your goal is to filter the list and produce a new list that includes only
+ some of the elements, see `!filter`.
+
+`!foreach(`*var*`,` *sequence*`,` *expr*`)`
+
+: This operator creates a new `list`/`dag` in which each element is a
+ function of the corresponding element in the *sequence* `list`/`dag`.
+ To perform the function, TableGen binds the variable *var* to an element
+ and then evaluates the expression. The expression presumably refers
+ to the variable *var* and calculates the result value.
+
+ If you simply want to create a list of a certain length containing
+ the same value repeated multiple times, see `!listsplat`.
+
+`!ge(`*a*`,` *b*`)`
+
+: This operator produces 1 if *a* is greater than or equal to *b*; 0 otherwise.
+ The arguments must be `bit`, `bits`, `int`, or `string` values.
+
+`!getdagarg<`*type*`>(`*dag*`,`*key*`)`
+
+: This operator retrieves the argument from the given *dag* node by the
+ specified *key*, which is either an integer index or a string name. If that
+ argument is not convertible to the specified *type*, `?` is returned.
+
+`!getdagname(`*dag*`,`*index*`)`
+
+: This operator retrieves the argument name from the given *dag* node by the
+ specified *index*. If that argument has no name associated, `?` is
+ returned.
+
+`!getdagop(`*dag*`)` --or-- `!getdagop<`*type*`>(`*dag*`)`
+
+: This operator produces the operator of the given *dag* node.
+ Example: `!getdagop((foo 1, 2))` results in `foo`. Recall that
+ DAG operators are always records.
+
+ The result of `!getdagop` can be used directly in a context where
+ any record class at all is acceptable (typically placing it into
+ another dag value). But in other contexts, it must be explicitly
+ cast to a particular class. The `<`*type*`>` syntax is
+ provided to make this easy.
+
+ For example, to assign the result to a value of type `BaseClass`, you
+ could write either of these:
+
+ ```
+ BaseClass b = !getdagop<BaseClass>(someDag);
+ BaseClass b = !cast<BaseClass>(!getdagop(someDag));
+ ```
+
+ But to create a new DAG node that reuses the operator from another, no
+ cast is necessary:
+
+ ```
+ dag d = !dag(!getdagop(someDag), args, names);
+ ```
+
+`!getdagopname(`*dag*`)`
+
+: This operator retrieves the name of the given *dag* operator. If the operator
+ has no name associated, `?` is returned.
+
+`!gt(`*a*`,` *b*`)`
+
+: This operator produces 1 if *a* is greater than *b*; 0 otherwise.
+ The arguments must be `bit`, `bits`, `int`, or `string` values.
+
+`!head(`*a*`)`
+
+: This operator produces the zeroth element of the list *a*.
+ (See also `!tail`.)
+
+`!if(`*test*`,` *then*`,` *else*`)`
+
+: This operator evaluates the *test*, which must produce a `bit` or
+ `int`. If the result is not 0, the *then* expression is produced; otherwise
the *else* expression is produced.
-``!initialized(``\ *a*\ ``)``
- This operator produces 1 if *a* is not the uninitialized value (``?``) and 0
+`!initialized(`*a*`)`
+
+: This operator produces 1 if *a* is not the uninitialized value (`?`) and 0
otherwise.
-``!instances<``\ *type*\ ``>([``\ *regex*\ ``])``
- This operator produces a list of records whose type is *type*. If *regex*
- is provided, only records whose name matches the regular expression *regex*
- will be included. The format of *regex* is ERE (Extended POSIX Regular
- Expressions).
-
- If ``!instances`` is in a class/multiclass/foreach, only these records of
- *type* that have been instantiated will be considered.
-
-``!interleave(``\ *list*\ ``,`` *delim*\ ``)``
- This operator concatenates the items in the *list*, interleaving the
- *delim* string between each pair, and produces the resulting string.
- The list can be a list of string, int, bits, or bit. An empty list
- results in an empty string. The delimiter can be the empty string.
-
-``!isa<``\ *type*\ ``>(``\ *a*\ ``)``
- This operator produces 1 if the type of *a* is a subtype of the given *type*; 0
- otherwise.
-
-``!le(``\ *a*\ ``,`` *b*\ ``)``
- This operator produces 1 if *a* is less than or equal to *b*; 0 otherwise.
- The arguments must be ``bit``, ``bits``, ``int``, or ``string`` values.
-
-``!listconcat(``\ *list1*\ ``,`` *list2*\ ``, ...)``
- This operator concatenates the list arguments *list1*, *list2*, etc., and
- produces the resulting list. The lists must have the same element type.
-
-``!listflatten(``\ *list*\ ``)``
- This operator flattens a list of lists *list* and produces a list with all
- elements of the constituent lists concatenated. If *list* is of type
- ``list<list<X>>`` the resulting list is of type ``list<X>``. If *list*'s
- element type is not a list, the result is *list* itself.
-
-``!listremove(``\ *list1*\ ``,`` *list2*\ ``)``
- This operator returns a copy of *list1* removing all elements that also occur in
- *list2*. The lists must have the same element type.
-
-``!listsplat(``\ *value*\ ``,`` *count*\ ``)``
- This operator produces a list of length *count* whose elements are all
- equal to the *value*. For example, ``!listsplat(42, 3)`` results in
- ``[42, 42, 42]``.
-
-``!logtwo(``\ *a*\ ``)``
- This operator produces the base 2 log of *a* and produces the integer
- result. The log of 0 or a negative number produces an error. This
- is a flooring operation.
-
-``!lt(``\ *a*\ `,` *b*\ ``)``
- This operator produces 1 if *a* is less than *b*; 0 otherwise.
- The arguments must be ``bit``, ``bits``, ``int``, or ``string`` values.
-
-``!match(``\ *str*\ `,` *regex*\ ``)``
- This operator produces 1 if the *str* matches the regular expression
- *regex*. The format of *regex* is ERE (Extended POSIX Regular Expressions).
-
-``!mul(``\ *a*\ ``,`` *b*\ ``, ...)``
- This operator multiplies *a*, *b*, etc., and produces the product.
-
-``!ne(``\ *a*\ `,` *b*\ ``)``
- This operator produces 1 if *a* is not equal to *b*; 0 otherwise.
- The arguments must be ``bit``, ``bits``, ``int``, ``string``,
- or record values. Use ``!cast<string>`` to compare other types of objects.
-
-``!not(``\ *a*\ ``)``
- This operator performs a logical NOT on *a*, which must be
- an integer. The argument 0 results in 1 (true); any other
- argument results in 0 (false).
-
-``!or(``\ *a*\ ``,`` *b*\ ``, ...)``
- This operator does a bitwise OR on *a*, *b*, etc., and produces the
- result. A logical OR can be performed if all the arguments are either
- 0 or 1. This operator is short-circuit to -1 (all ones) when the left-most
- operand is -1.
-
-``!range([``\ *start*\ ``,]`` *end*\ ``[,``\ *step*\ ``])``
- This operator produces half-open range sequence ``[start : end : step)`` as
- ``list<int>``. *start* is ``0`` and *step* is ``1`` by default. *step* can
- be negative and cannot be 0. If *start* ``<`` *end* and *step* is negative,
- or *start* ``>`` *end* and *step* is positive, the result is an empty list
- ``[]<int>``.
-
- For example:
-
- * ``!range(4)`` is equivalent to ``!range(0, 4, 1)`` and the result is
- `[0, 1, 2, 3]`.
- * ``!range(1, 4)`` is equivalent to ``!range(1, 4, 1)`` and the result is
- `[1, 2, 3]`.
- * The result of ``!range(0, 4, 2)`` is `[0, 2]`.
- * The results of ``!range(0, 4, -1)`` and ``!range(4, 0, 1)`` are empty.
-
-``!range(``\ *list*\ ``)``
- Equivalent to ``!range(0, !size(list))``.
-
-``!repr(``\ *value*\ ``)``
- Represents *value* as a string. The string format for the value is not
- guaranteed to be stable. Intended for debugging purposes only.
-
-``!setdagarg(``\ *dag*\ ``,``\ *key*\ ``,``\ *arg*\ ``)``
- This operator produces a DAG node with the same operator and arguments as
- *dag*, but replacing the value of the argument specified by the *key* with
- *arg*. That *key* could be either an integer index or a string name.
-
-``!setdagname(``\ *dag*\ ``,``\ *key*\ ``,``\ *name*\ ``)``
- This operator produces a DAG node with the same operator and arguments as
- *dag*, but replacing the name of the argument specified by the *key* with
- *name*. That *key* could be either an integer index or a string name.
-
-``!setdagop(``\ *dag*\ ``,`` *op*\ ``)``
- This operator produces a DAG node with the same arguments as *dag*, but with its
- operator replaced with *op*.
-
- Example: ``!setdagop((foo 1, 2), bar)`` results in ``(bar 1, 2)``.
-
-``!setdagopname(``\ *dag*\ ``,``\ *name*\ ``)``
- This operator produces a DAG node with the same operator and arguments as
- *dag*, but replacing the name of the operator with *name*.
-
-``!shl(``\ *a*\ ``,`` *count*\ ``)``
- This operator shifts *a* left logically by *count* bits and produces the resulting
- value. The operation is performed on a 64-bit integer; the result
- is undefined for shift counts outside 0...63.
-
-``!size(``\ *a*\ ``)``
- This operator produces the size of the string, list, or dag *a*.
- The size of a DAG is the number of arguments; the operator does not count.
-
-``!sort(``\ *var*\ ``,`` *list*\ ``,`` *key*\ ``)``
- This operator creates a new ``list`` containing the same elements as *list*
- but in sorted order. To determine the order, TableGen binds the variable
- *var* to each element and evaluates the *key* expression, which presumably
- refers to *var*. The key must produce a ``string`` or integer value
- (``bit``, ``bits``, or ``int``); all keys must be of the same type. Elements
- with equal keys preserve their original relative order, resulting in a
- stable sort.
-
- For example, to sort a list of records by their ``Name`` field::
-
- .. code-block:: text
-
- list<Thing> sorted = !sort(t, Things, t.Name);
-
-``!sra(``\ *a*\ ``,`` *count*\ ``)``
- This operator shifts *a* right arithmetically by *count* bits and produces the resulting
- value. The operation is performed on a 64-bit integer; the result
- is undefined for shift counts outside 0...63.
-
-``!srl(``\ *a*\ ``,`` *count*\ ``)``
- This operator shifts *a* right logically by *count* bits and produces the resulting
- value. The operation is performed on a 64-bit integer; the result
- is undefined for shift counts outside 0...63.
-
-``!strconcat(``\ *str1*\ ``,`` *str2*\ ``, ...)``
- This operator concatenates the string arguments *str1*, *str2*, etc., and
- produces the resulting string.
-
-``!sub(``\ *a*\ ``,`` *b*\ ``)``
- This operator subtracts *b* from *a* and produces the arithmetic difference.
-
-``!subst(``\ *target*\ ``,`` *repl*\ ``,`` *value*\ ``)``
- This operator replaces all occurrences of the *target* in the *value* with
- the *repl* and produces the resulting value. The *value* can
- be a string, in which case substring substitution is performed.
-
- The *value* can be a record name, in which case the operator produces the *repl*
- record if the *target* record name equals the *value* record name; otherwise it
- produces the *value*.
-
-``!substr(``\ *string*\ ``,`` *start*\ [``,`` *length*]\ ``)``
- This operator extracts a substring of the given *string*. The starting
- position of the substring is specified by *start*, which can range
- between 0 and the length of the string. The length of the substring
- is specified by *length*; if not specified, the rest of the string is
- extracted. The *start* and *length* arguments must be integers.
+`!instances<`*type*`>([`*regex*`])`
-``!switch(``\ *key*\ ``,`` *case1* ``:`` *val1*\ ``, ...,`` *casen* ``:`` *valn*\ ``,`` *default*\ ``)``
- This operator compares *key* to each *casei* in turn using ``!eq``.
- If *key* equals *casei*, the operator returns *vali*. If no case
- matches, the operator returns *default* --- the trailing argument
- with no ``:`` is the default value, identified by position. Both
- the trailing default and at least one *casei* : *vali* pair are
- mandatory.
+: This operator produces a list of records whose type is *type*. If *regex*
+ is provided, only records whose name matches the regular expression *regex*
+ will be included. The format of *regex* is ERE (Extended POSIX Regular
+ Expressions).
- ``!switch`` is a compact form of ``!cond`` using ``!eq`` comparisons.
- The expression ``!switch(key, c1: v1, c2: v2, vd)`` is equivalent to
- ``!cond(!eq(key, c1): v1, !eq(key, c2): v2, true: vd)``.
+ If `!instances` is in a class/multiclass/foreach, only these records of
+ *type* that have been instantiated will be considered.
- This example maps an integer size to a register-class name::
+`!interleave(`*list*`,` *delim*`)`
- !switch(size, 1: "byte", 2: "halfword", 4: "word", "unknown")
+: This operator concatenates the items in the *list*, interleaving the
+ *delim* string between each pair, and produces the resulting string.
+ The list can be a list of string, int, bits, or bit. An empty list
+ results in an empty string. The delimiter can be the empty string.
- (See also ``!cond``.)
+`!isa<`*type*`>(`*a*`)`
-``!tail(``\ *a*\ ``)``
- This operator produces a new list with all the elements
- of the list *a* except for the zeroth one. (See also ``!head``.)
+: This operator produces 1 if the type of *a* is a subtype of the given *type*; 0
+ otherwise.
-``!tolower(``\ *a*\ ``)``
- This operator converts a string input *a* to lower case.
+`!le(`*a*`,` *b*`)`
-``!toupper(``\ *a*\ ``)``
- This operator converts a string input *a* to upper case.
+: This operator produces 1 if *a* is less than or equal to *b*; 0 otherwise.
+ The arguments must be `bit`, `bits`, `int`, or `string` values.
-``!xor(``\ *a*\ ``,`` *b*\ ``, ...)``
- This operator does a bitwise EXCLUSIVE OR on *a*, *b*, etc., and produces
- the result. A logical XOR can be performed if all the arguments are either
- 0 or 1.
+`!listconcat(`*list1*`,` *list2*`, ...)`
-Appendix B: Paste Operator Examples
-===================================
+: This operator concatenates the list arguments *list1*, *list2*, etc., and
+ produces the resulting list. The lists must have the same element type.
-Here is an example illustrating the use of the paste operator in record names.
+`!listflatten(`*list*`)`
-.. code-block:: text
+: This operator flattens a list of lists *list* and produces a list with all
+ elements of the constituent lists concatenated. If *list* is of type
+ `list<list<X>>` the resulting list is of type `list<X>`. If *list*'s
+ element type is not a list, the result is *list* itself.
- defvar suffix = "_suffstring";
- defvar some_ints = [0, 1, 2, 3];
+`!listremove(`*list1*`,` *list2*`)`
- def name # suffix {
- }
+: This operator returns a copy of *list1* removing all elements that also occur in
+ *list2*. The lists must have the same element type.
- foreach i = [1, 2] in {
- def rec # i {
- }
- }
+`!listsplat(`*value*`,` *count*`)`
-The first ``def`` does not use the value of the ``suffix`` variable. The
-second def does use the value of the ``i`` iterator variable, because it is not a
-global name. The following records are produced.
+: This operator produces a list of length *count* whose elements are all
+ equal to the *value*. For example, `!listsplat(42, 3)` results in
+ `[42, 42, 42]`.
-.. code-block:: text
+`!logtwo(`*a*`)`
- def namesuffix {
- }
- def rec1 {
- }
- def rec2 {
- }
+: This operator produces the base 2 log of *a* and produces the integer
+ result. The log of 0 or a negative number produces an error. This
+ is a flooring operation.
-Here is a second example illustrating the paste operator in field value expressions.
+`!lt(`*a*`,` *b*`)`
-.. code-block:: text
+: This operator produces 1 if *a* is less than *b*; 0 otherwise.
+ The arguments must be `bit`, `bits`, `int`, or `string` values.
- def test {
- string strings = suffix # suffix;
- list<int> integers = some_ints # [4, 5, 6];
- }
+`!match(`*str*`,` *regex*`)`
-The ``strings`` field expression uses ``suffix`` on both sides of the paste
-operator. It is evaluated normally on the left hand side, but taken verbatim
-on the right hand side. The ``integers`` field expression uses the value of
-the ``some_ints`` variable and a literal list. The following record is
-produced.
+: This operator produces 1 if the *str* matches the regular expression
+ *regex*. The format of *regex* is ERE (Extended POSIX Regular Expressions).
-.. code-block:: text
+`!mul(`*a*`,` *b*`, ...)`
- def test {
- string strings = "_suffstringsuffix";
- list<int> ints = [0, 1, 2, 3, 4, 5, 6];
- }
+: This operator multiplies *a*, *b*, etc., and produces the product.
+`!ne(`*a*`,` *b*`)`
-Appendix C: Sample Record
-=========================
+: This operator produces 1 if *a* is not equal to *b*; 0 otherwise.
+ The arguments must be `bit`, `bits`, `int`, `string`,
+ or record values. Use `!cast<string>` to compare other types of objects.
+
+`!not(`*a*`)`
+
+: This operator performs a logical NOT on *a*, which must be
+ an integer. The argument 0 results in 1 (true); any other
+ argument results in 0 (false).
+
+`!or(`*a*`,` *b*`, ...)`
+
+: This operator does a bitwise OR on *a*, *b*, etc., and produces the
+ result. A logical OR can be performed if all the arguments are either
+ 0 or 1. This operator is short-circuit to -1 (all ones) when the left-most
+ operand is -1.
+
+`!range([`*start*`,]` *end*`[,`*step*`])`
+
+: This operator produces half-open range sequence `[start : end : step)` as
+ `list<int>`. *start* is `0` and *step* is `1` by default. *step* can
+ be negative and cannot be 0. If *start* `<` *end* and *step* is negative,
+ or *start* `>` *end* and *step* is positive, the result is an empty list
+ `[]<int>`.
+
+ For example:
+
+ - `!range(4)` is equivalent to `!range(0, 4, 1)` and the result is
+ `[0, 1, 2, 3]`.
+ - `!range(1, 4)` is equivalent to `!range(1, 4, 1)` and the result is
+ `[1, 2, 3]`.
+ - The result of `!range(0, 4, 2)` is `[0, 2]`.
+ - The results of `!range(0, 4, -1)` and `!range(4, 0, 1)` are empty.
+
+`!range(`*list*`)`
+
+: Equivalent to `!range(0, !size(list))`.
+
+`!repr(`*value*`)`
+
+: Represents *value* as a string. The string format for the value is not
+ guaranteed to be stable. Intended for debugging purposes only.
+
+`!setdagarg(`*dag*`,`*key*`,`*arg*`)`
+
+: This operator produces a DAG node with the same operator and arguments as
+ *dag*, but replacing the value of the argument specified by the *key* with
+ *arg*. That *key* could be either an integer index or a string name.
+
+`!setdagname(`*dag*`,`*key*`,`*name*`)`
+
+: This operator produces a DAG node with the same operator and arguments as
+ *dag*, but replacing the name of the argument specified by the *key* with
+ *name*. That *key* could be either an integer index or a string name.
+
+`!setdagop(`*dag*`,` *op*`)`
+
+: This operator produces a DAG node with the same arguments as *dag*, but with its
+ operator replaced with *op*.
+
+ Example: `!setdagop((foo 1, 2), bar)` results in `(bar 1, 2)`.
+
+`!setdagopname(`*dag*`,`*name*`)`
+
+: This operator produces a DAG node with the same operator and arguments as
+ *dag*, but replacing the name of the operator with *name*.
+
+`!shl(`*a*`,` *count*`)`
+
+: This operator shifts *a* left logically by *count* bits and produces the resulting
+ value. The operation is performed on a 64-bit integer; the result
+ is undefined for shift counts outside 0...63.
+
+`!size(`*a*`)`
+
+: This operator produces the size of the string, list, or dag *a*.
+ The size of a DAG is the number of arguments; the operator does not count.
+
+`!sort(`*var*`,` *list*`,` *key*`)`
+
+: This operator creates a new `list` containing the same elements as *list*
+ but in sorted order. To determine the order, TableGen binds the variable
+ *var* to each element and evaluates the *key* expression, which presumably
+ refers to *var*. The key must produce a `string` or integer value
+ (`bit`, `bits`, or `int`); all keys must be of the same type. Elements
+ with equal keys preserve their original relative order, resulting in a
+ stable sort.
+
+ For example, to sort a list of records by their `Name` field:
+
+ ```
+ .. code-block:: text
+ ```
+
+ > list\<Thing> sorted = !sort(t, Things, t.Name);
+
+`!sra(`*a*`,` *count*`)`
+
+: This operator shifts *a* right arithmetically by *count* bits and produces the resulting
+ value. The operation is performed on a 64-bit integer; the result
+ is undefined for shift counts outside 0...63.
+
+`!srl(`*a*`,` *count*`)`
+
+: This operator shifts *a* right logically by *count* bits and produces the resulting
+ value. The operation is performed on a 64-bit integer; the result
+ is undefined for shift counts outside 0...63.
+
+`!strconcat(`*str1*`,` *str2*`, ...)`
+
+: This operator concatenates the string arguments *str1*, *str2*, etc., and
+ produces the resulting string.
+
+`!sub(`*a*`,` *b*`)`
+
+: This operator subtracts *b* from *a* and produces the arithmetic difference.
+
+`!subst(`*target*`,` *repl*`,` *value*`)`
+
+: This operator replaces all occurrences of the *target* in the *value* with
+ the *repl* and produces the resulting value. The *value* can
+ be a string, in which case substring substitution is performed.
+
+ The *value* can be a record name, in which case the operator produces the *repl*
+ record if the *target* record name equals the *value* record name; otherwise it
+ produces the *value*.
+
+`!substr(`*string*`,` *start*\[`,` *length*\]`)`
+
+: This operator extracts a substring of the given *string*. The starting
+ position of the substring is specified by *start*, which can range
+ between 0 and the length of the string. The length of the substring
+ is specified by *length*; if not specified, the rest of the string is
+ extracted. The *start* and *length* arguments must be integers.
+
+`!switch(`*key*`,` *case1* `:` *val1*`, ...,` *casen* `:` *valn*`,` *default*`)`
+
+: This operator compares *key* to each *casei* in turn using `!eq`.
+ If *key* equals *casei*, the operator returns *vali*. If no case
+ matches, the operator returns *default* --- the trailing argument
+ with no `:` is the default value, identified by position. Both
+ the trailing default and at least one *casei* : *vali* pair are
+ mandatory.
+
+ `!switch` is a compact form of `!cond` using `!eq` comparisons.
+ The expression `!switch(key, c1: v1, c2: v2, vd)` is equivalent to
+ `!cond(!eq(key, c1): v1, !eq(key, c2): v2, true: vd)`.
+
+ This example maps an integer size to a register-class name:
+
+ ```
+ !switch(size, 1: "byte", 2: "halfword", 4: "word", "unknown")
+ ```
+
+ (See also `!cond`.)
+
+`!tail(`*a*`)`
+
+: This operator produces a new list with all the elements
+ of the list *a* except for the zeroth one. (See also `!head`.)
+
+`!tolower(`*a*`)`
+
+: This operator converts a string input *a* to lower case.
+
+`!toupper(`*a*`)`
+
+: This operator converts a string input *a* to upper case.
+
+`!xor(`*a*`,` *b*`, ...)`
+
+: This operator does a bitwise EXCLUSIVE OR on *a*, *b*, etc., and produces
+ the result. A logical XOR can be performed if all the arguments are either
+ 0 or 1.
+
+## Appendix B: Paste Operator Examples
+
+Here is an example illustrating the use of the paste operator in record names.
+
+```text
+defvar suffix = "_suffstring";
+defvar some_ints = [0, 1, 2, 3];
+
+def name # suffix {
+}
+
+foreach i = [1, 2] in {
+def rec # i {
+}
+}
+```
+
+The first `def` does not use the value of the `suffix` variable. The
+second def does use the value of the `i` iterator variable, because it is not a
+global name. The following records are produced.
+
+```text
+def namesuffix {
+}
+def rec1 {
+}
+def rec2 {
+}
+```
+
+Here is a second example illustrating the paste operator in field value expressions.
+
+```text
+def test {
+ string strings = suffix # suffix;
+ list<int> integers = some_ints # [4, 5, 6];
+}
+```
+
+The `strings` field expression uses `suffix` on both sides of the paste
+operator. It is evaluated normally on the left hand side, but taken verbatim
+on the right hand side. The `integers` field expression uses the value of
+the `some_ints` variable and a literal list. The following record is
+produced.
+
+```text
+def test {
+ string strings = "_suffstringsuffix";
+ list<int> ints = [0, 1, 2, 3, 4, 5, 6];
+}
+```
+
+## Appendix C: Sample Record
One target machine supported by LLVM is the Intel x86. The following output
from TableGen shows the record that is created to represent the 32-bit
register-to-register ADD instruction.
-.. code-block:: text
-
- def ADD32rr { // InstructionEncoding Instruction X86Inst I ITy Sched BinOpRR BinOpRR_RF
- int Size = 0;
- string DecoderNamespace = "";
- list<Predicate> Predicates = [];
- string DecoderMethod = "";
- bit hasCompleteDecoder = 1;
- string Namespace = "X86";
- dag OutOperandList = (outs GR32:$dst);
- dag InOperandList = (ins GR32:$src1, GR32:$src2);
- string AsmString = "add{l} {$src2, $src1|$src1, $src2}";
- EncodingByHwMode EncodingInfos = ?;
- list<dag> Pattern = [(set GR32:$dst, EFLAGS, (X86add_flag GR32:$src1, GR32:$src2))];
- list<Register> Uses = [];
- list<Register> Defs = [EFLAGS];
- int CodeSize = 3;
- int AddedComplexity = 0;
- bit isPreISelOpcode = 0;
- bit isReturn = 0;
- bit isBranch = 0;
- bit isEHScopeReturn = 0;
- bit isIndirectBranch = 0;
- bit isCompare = 0;
- bit isMoveImm = 0;
- bit isMoveReg = 0;
- bit isBitcast = 0;
- bit isSelect = 0;
- bit isBarrier = 0;
- bit isCall = 0;
- bit isAdd = 0;
- bit isTrap = 0;
- bit canFoldAsLoad = 0;
- bit mayLoad = ?;
- bit mayStore = ?;
- bit mayRaiseFPException = 0;
- bit isConvertibleToThreeAddress = 1;
- bit isCommutable = 1;
- bit isTerminator = 0;
- bit isReMaterializable = 0;
- bit isPredicable = 0;
- bit isUnpredicable = 0;
- bit hasDelaySlot = 0;
- bit usesCustomInserter = 0;
- bit hasPostISelHook = 0;
- bit hasCtrlDep = 0;
- bit isNotDuplicable = 0;
- bit isConvergent = 0;
- bit isAuthenticated = 0;
- bit isAsCheapAsAMove = 0;
- bit hasExtraSrcRegAllocReq = 0;
- bit hasExtraDefRegAllocReq = 0;
- bit isRegSequence = 0;
- bit isPseudo = 0;
- bit isExtractSubreg = 0;
- bit isInsertSubreg = 0;
- bit variadicOpsAreDefs = 0;
- bit hasSideEffects = ?;
- bit isCodeGenOnly = 0;
- bit isAsmParserOnly = 0;
- bit hasNoSchedulingInfo = 0;
- InstrItinClass Itinerary = NoItinerary;
- list<SchedReadWrite> SchedRW = [WriteALU];
- string Constraints = "$src1 = $dst";
- string DisableEncoding = "";
- string PostEncoderMethod = "";
- bits<64> TSFlags = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 };
- string AsmMatchConverter = "";
- string TwoOperandAliasConstraint = "";
- string AsmVariantName = "";
- bit UseNamedOperandTable = 0;
- bit FastISelShouldIgnore = 0;
- bits<8> Opcode = { 0, 0, 0, 0, 0, 0, 0, 1 };
- Format Form = MRMDestReg;
- bits<7> FormBits = { 0, 1, 0, 1, 0, 0, 0 };
- ImmType ImmT = NoImm;
- bit ForceDisassemble = 0;
- OperandSize OpSize = OpSize32;
- bits<2> OpSizeBits = { 1, 0 };
- AddressSize AdSize = AdSizeX;
- bits<2> AdSizeBits = { 0, 0 };
- Prefix OpPrefix = NoPrfx;
- bits<3> OpPrefixBits = { 0, 0, 0 };
- Map OpMap = OB;
- bits<3> OpMapBits = { 0, 0, 0 };
- bit hasREX_WPrefix = 0;
- FPFormat FPForm = NotFP;
- bit hasLockPrefix = 0;
- Domain ExeDomain = GenericDomain;
- bit hasREPPrefix = 0;
- Encoding OpEnc = EncNormal;
- bits<2> OpEncBits = { 0, 0 };
- bit HasVEX_W = 0;
- bit IgnoresVEX_W = 0;
- bit EVEX_W1_VEX_W0 = 0;
- bit hasVEX_4V = 0;
- bit hasVEX_L = 0;
- bit ignoresVEX_L = 0;
- bit hasEVEX_K = 0;
- bit hasEVEX_Z = 0;
- bit hasEVEX_L2 = 0;
- bit hasEVEX_B = 0;
- bits<3> CD8_Form = { 0, 0, 0 };
- int CD8_EltSize = 0;
- bit hasEVEX_RC = 0;
- bit hasNoTrackPrefix = 0;
- bits<7> VectSize = { 0, 0, 1, 0, 0, 0, 0 };
- bits<7> CD8_Scale = { 0, 0, 0, 0, 0, 0, 0 };
- string FoldGenRegForm = ?;
- string EVEX2VEXOverride = ?;
- bit isMemoryFoldable = 1;
- bit notEVEX2VEXConvertible = 0;
- }
-
-On the first line of the record, you can see that the ``ADD32rr`` record
+```text
+def ADD32rr { // InstructionEncoding Instruction X86Inst I ITy Sched BinOpRR BinOpRR_RF
+ int Size = 0;
+ string DecoderNamespace = "";
+ list<Predicate> Predicates = [];
+ string DecoderMethod = "";
+ bit hasCompleteDecoder = 1;
+ string Namespace = "X86";
+ dag OutOperandList = (outs GR32:$dst);
+ dag InOperandList = (ins GR32:$src1, GR32:$src2);
+ string AsmString = "add{l} {$src2, $src1|$src1, $src2}";
+ EncodingByHwMode EncodingInfos = ?;
+ list<dag> Pattern = [(set GR32:$dst, EFLAGS, (X86add_flag GR32:$src1, GR32:$src2))];
+ list<Register> Uses = [];
+ list<Register> Defs = [EFLAGS];
+ int CodeSize = 3;
+ int AddedComplexity = 0;
+ bit isPreISelOpcode = 0;
+ bit isReturn = 0;
+ bit isBranch = 0;
+ bit isEHScopeReturn = 0;
+ bit isIndirectBranch = 0;
+ bit isCompare = 0;
+ bit isMoveImm = 0;
+ bit isMoveReg = 0;
+ bit isBitcast = 0;
+ bit isSelect = 0;
+ bit isBarrier = 0;
+ bit isCall = 0;
+ bit isAdd = 0;
+ bit isTrap = 0;
+ bit canFoldAsLoad = 0;
+ bit mayLoad = ?;
+ bit mayStore = ?;
+ bit mayRaiseFPException = 0;
+ bit isConvertibleToThreeAddress = 1;
+ bit isCommutable = 1;
+ bit isTerminator = 0;
+ bit isReMaterializable = 0;
+ bit isPredicable = 0;
+ bit isUnpredicable = 0;
+ bit hasDelaySlot = 0;
+ bit usesCustomInserter = 0;
+ bit hasPostISelHook = 0;
+ bit hasCtrlDep = 0;
+ bit isNotDuplicable = 0;
+ bit isConvergent = 0;
+ bit isAuthenticated = 0;
+ bit isAsCheapAsAMove = 0;
+ bit hasExtraSrcRegAllocReq = 0;
+ bit hasExtraDefRegAllocReq = 0;
+ bit isRegSequence = 0;
+ bit isPseudo = 0;
+ bit isExtractSubreg = 0;
+ bit isInsertSubreg = 0;
+ bit variadicOpsAreDefs = 0;
+ bit hasSideEffects = ?;
+ bit isCodeGenOnly = 0;
+ bit isAsmParserOnly = 0;
+ bit hasNoSchedulingInfo = 0;
+ InstrItinClass Itinerary = NoItinerary;
+ list<SchedReadWrite> SchedRW = [WriteALU];
+ string Constraints = "$src1 = $dst";
+ string DisableEncoding = "";
+ string PostEncoderMethod = "";
+ bits<64> TSFlags = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 };
+ string AsmMatchConverter = "";
+ string TwoOperandAliasConstraint = "";
+ string AsmVariantName = "";
+ bit UseNamedOperandTable = 0;
+ bit FastISelShouldIgnore = 0;
+ bits<8> Opcode = { 0, 0, 0, 0, 0, 0, 0, 1 };
+ Format Form = MRMDestReg;
+ bits<7> FormBits = { 0, 1, 0, 1, 0, 0, 0 };
+ ImmType ImmT = NoImm;
+ bit ForceDisassemble = 0;
+ OperandSize OpSize = OpSize32;
+ bits<2> OpSizeBits = { 1, 0 };
+ AddressSize AdSize = AdSizeX;
+ bits<2> AdSizeBits = { 0, 0 };
+ Prefix OpPrefix = NoPrfx;
+ bits<3> OpPrefixBits = { 0, 0, 0 };
+ Map OpMap = OB;
+ bits<3> OpMapBits = { 0, 0, 0 };
+ bit hasREX_WPrefix = 0;
+ FPFormat FPForm = NotFP;
+ bit hasLockPrefix = 0;
+ Domain ExeDomain = GenericDomain;
+ bit hasREPPrefix = 0;
+ Encoding OpEnc = EncNormal;
+ bits<2> OpEncBits = { 0, 0 };
+ bit HasVEX_W = 0;
+ bit IgnoresVEX_W = 0;
+ bit EVEX_W1_VEX_W0 = 0;
+ bit hasVEX_4V = 0;
+ bit hasVEX_L = 0;
+ bit ignoresVEX_L = 0;
+ bit hasEVEX_K = 0;
+ bit hasEVEX_Z = 0;
+ bit hasEVEX_L2 = 0;
+ bit hasEVEX_B = 0;
+ bits<3> CD8_Form = { 0, 0, 0 };
+ int CD8_EltSize = 0;
+ bit hasEVEX_RC = 0;
+ bit hasNoTrackPrefix = 0;
+ bits<7> VectSize = { 0, 0, 1, 0, 0, 0, 0 };
+ bits<7> CD8_Scale = { 0, 0, 0, 0, 0, 0, 0 };
+ string FoldGenRegForm = ?;
+ string EVEX2VEXOverride = ?;
+ bit isMemoryFoldable = 1;
+ bit notEVEX2VEXConvertible = 0;
+}
+```
+
+On the first line of the record, you can see that the `ADD32rr` record
inherited from eight classes. Although the inheritance hierarchy is complex,
using parent classes is much simpler than specifying the 109 individual
fields for each instruction.
-Here is the code fragment used to define ``ADD32rr`` and multiple other
-``ADD`` instructions:
-
-.. code-block:: text
+Here is the code fragment used to define `ADD32rr` and multiple other
+`ADD` instructions:
- defm ADD : ArithBinOp_RF<0x00, 0x02, 0x04, "add", MRM0r, MRM0m,
- X86add_flag, add, 1, 1, 1>;
+```text
+defm ADD : ArithBinOp_RF<0x00, 0x02, 0x04, "add", MRM0r, MRM0m,
+ X86add_flag, add, 1, 1, 1>;
+```
-The ``defm`` statement tells TableGen that ``ArithBinOp_RF`` is a
+The `defm` statement tells TableGen that `ArithBinOp_RF` is a
multiclass, which contains multiple concrete record definitions that inherit
-from ``BinOpRR_RF``. That class, in turn, inherits from ``BinOpRR``, which
-inherits from ``ITy`` and ``Sched``, and so forth. The fields are inherited
-from all the parent classes; for example, ``IsIndirectBranch`` is inherited
-from the ``Instruction`` class.
+from `BinOpRR_RF`. That class, in turn, inherits from `BinOpRR`, which
+inherits from `ITy` and `Sched`, and so forth. The fields are inherited
+from all the parent classes; for example, `IsIndirectBranch` is inherited
+from the `Instruction` class.
+
+[python's]: http://docs.python.org/py3k/reference/introduction.html#notation
+
diff --git a/llvm/docs/TransformMetadata.md b/llvm/docs/TransformMetadata.md
index 42ba63981c468..302a35944db72 100644
--- a/llvm/docs/TransformMetadata.md
+++ b/llvm/docs/TransformMetadata.md
@@ -1,12 +1,8 @@
-.. _transformation-metadata:
+(transformation-metadata)=
-============================
-Code Transformation Metadata
-============================
+# Code Transformation Metadata
-
-Overview
-========
+## Overview
LLVM transformation passes can be controlled by attaching metadata to
the code to transform. By default, transformation passes use heuristics
@@ -26,38 +22,36 @@ user/programmer. OpenMP pragmas are an example of the latter.
If any such metadata is dropped from the program, the code's semantics
must not change.
-Metadata on Loops
-=================
+## Metadata on Loops
-Attributes can be attached to loops as described in :ref:`llvm.loop`.
+Attributes can be attached to loops as described in {ref}`llvm.loop`.
Attributes can describe properties of the loop, disable transformations,
force specific transformations and set transformation options.
Because metadata nodes are immutable (with the exception of
-``MDNode::replaceOperandWith`` which is dangerous to use on uniqued
-metadata), in order to add or remove a loop attributes, a new ``MDNode``
-must be created and assigned as the new ``llvm.loop`` metadata. Any
-connection between the old ``MDNode`` and the loop is lost. The
-``llvm.loop`` node is also used as LoopID (``Loop::getLoopID()``), i.e.
+`MDNode::replaceOperandWith` which is dangerous to use on uniqued
+metadata), in order to add or remove a loop attributes, a new `MDNode`
+must be created and assigned as the new `llvm.loop` metadata. Any
+connection between the old `MDNode` and the loop is lost. The
+`llvm.loop` node is also used as LoopID (`Loop::getLoopID()`), i.e.
the loop effectively gets a new identifier. For instance,
-``llvm.mem.parallel_loop_access`` references the LoopID. Therefore, if
+`llvm.mem.parallel_loop_access` references the LoopID. Therefore, if
the parallel access property is to be preserved after adding/removing
-loop attributes, any ``llvm.mem.parallel_loop_access`` reference must be
+loop attributes, any `llvm.mem.parallel_loop_access` reference must be
updated to the new LoopID.
-Transformation Metadata Structure
-=================================
+## Transformation Metadata Structure
Some attributes describe code transformations (unrolling, vectorizing,
loop distribution, etc.). They can either be a hint to the optimizer
that a transformation might be beneficial, instruction to use a specific
option, , or convey a specific request from the user (such as
-``#pragma clang loop`` or ``#pragma omp simd``).
+`#pragma clang loop` or `#pragma omp simd`).
If a transformation is forced but cannot be carried-out for any reason,
an optimization-missed warning must be emitted. Semantic information
such as a transformation being safe (e.g.
-``llvm.mem.parallel_loop_access``) can be unused by the optimizer
+`llvm.mem.parallel_loop_access`) can be unused by the optimizer
without generating a warning.
Unless explicitly disabled, any optimization pass may heuristically
@@ -66,47 +60,47 @@ metadata for another transformation was specified, applying a different
transformation before it might be inadvertent due to being applied on a
different loop or the loop not existing anymore. To avoid having to
explicitly disable an unknown number of passes, the attribute
-``llvm.loop.disable_nonforced`` disables all optional, high-level,
+`llvm.loop.disable_nonforced` disables all optional, high-level,
restructuring transformations.
The following example avoids the loop being altered before being
vectorized, for instance being unrolled.
-.. code-block:: llvm
-
- br i1 %exitcond, label %for.exit, label %for.header, !llvm.loop !0
- ...
- !0 = distinct !{!0, !1, !2}
- !1 = !{!"llvm.loop.vectorize.enable"}
- !2 = !{!"llvm.loop.disable_nonforced"}
+```llvm
+ br i1 %exitcond, label %for.exit, label %for.header, !llvm.loop !0
+...
+!0 = distinct !{!0, !1, !2}
+!1 = !{!"llvm.loop.vectorize.enable"}
+!2 = !{!"llvm.loop.disable_nonforced"}
+```
After a transformation is applied, follow-up attributes are set on the
transformed and/or new loop(s). This allows additional attributes
including followup-transformations to be specified. Specifying multiple
transformations in the same metadata node is possible for compatibility
reasons, but their execution order is undefined. For instance, when
-``llvm.loop.vectorize.enable`` and ``llvm.loop.unroll.enable`` are
+`llvm.loop.vectorize.enable` and `llvm.loop.unroll.enable` are
specified at the same time, unrolling may occur either before or after
vectorization.
As an example, the following instructs a loop to be vectorized and only
then unrolled.
-.. code-block:: llvm
-
- !0 = distinct !{!0, !1, !2, !3}
- !1 = !{!"llvm.loop.vectorize.enable"}
- !2 = !{!"llvm.loop.disable_nonforced"}
- !3 = !{!"llvm.loop.vectorize.followup_vectorized", !{"llvm.loop.unroll.enable"}}
+```llvm
+!0 = distinct !{!0, !1, !2, !3}
+!1 = !{!"llvm.loop.vectorize.enable"}
+!2 = !{!"llvm.loop.disable_nonforced"}
+!3 = !{!"llvm.loop.vectorize.followup_vectorized", !{"llvm.loop.unroll.enable"}}
+```
If, and only if, no followup is specified, the pass may add attributes itself.
-For instance, the vectorizer adds a ``llvm.loop.isvectorized`` attribute and
+For instance, the vectorizer adds a `llvm.loop.isvectorized` attribute and
all attributes from the original loop excluding its loop vectorizer
attributes. To avoid this, an empty followup attribute can be used, e.g.
-.. code-block:: llvm
-
- !3 = !{!"llvm.loop.vectorize.followup_vectorized"}
+```llvm
+!3 = !{!"llvm.loop.vectorize.followup_vectorized"}
+```
The followup attributes of a transformation that cannot be applied will
never be added to a loop and are therefore effectively ignored. This means
@@ -116,88 +110,85 @@ The user should receive a warning about the first transformation in the
transformation chain that could not be applied if it a forced
transformation. All following transformations are skipped.
-Pass-Specific Transformation Metadata
-=====================================
+## Pass-Specific Transformation Metadata
Transformation options are specific to each transformation. In the
following, we present the model for each LLVM loop optimization pass and
the metadata to influence them.
-Loop Vectorization and Interleaving
------------------------------------
+### Loop Vectorization and Interleaving
Loop vectorization and interleaving is interpreted as a single
transformation. It is interpreted as forced if
-``!{"llvm.loop.vectorize.enable"}`` is set.
+`!{"llvm.loop.vectorize.enable"}` is set.
Assuming the pre-vectorization loop is
-.. code-block:: c
-
- for (int i = 0; i < n; i+=1) // original loop
- Stmt(i);
+```c
+for (int i = 0; i < n; i+=1) // original loop
+ Stmt(i);
+```
then the code after vectorization will be approximately (assuming an
SIMD width of 4):
-.. code-block:: c
-
- int i = 0;
- if (rtc) {
- for (; i + 3 < n; i+=4) // vectorized/interleaved loop
- Stmt(i:i+3);
- }
- for (; i < n; i+=1) // epilogue loop
- Stmt(i);
+```c
+int i = 0;
+if (rtc) {
+ for (; i + 3 < n; i+=4) // vectorized/interleaved loop
+ Stmt(i:i+3);
+}
+for (; i < n; i+=1) // epilogue loop
+ Stmt(i);
+```
-where ``rtc`` is a generated runtime check.
+where `rtc` is a generated runtime check.
-``llvm.loop.vectorize.followup_vectorized`` will set the attributes for
-the vectorized loop. If not specified, ``llvm.loop.isvectorized`` is
+`llvm.loop.vectorize.followup_vectorized` will set the attributes for
+the vectorized loop. If not specified, `llvm.loop.isvectorized` is
combined with the original loop's attributes to avoid it being
vectorized multiple times.
-``llvm.loop.vectorize.followup_epilogue`` will set the attributes for
+`llvm.loop.vectorize.followup_epilogue` will set the attributes for
the remainder loop. If not specified, it will have the original loop's
-attributes combined with ``llvm.loop.isvectorized`` and
-``llvm.loop.unroll.runtime.disable`` (unless the original loop already
+attributes combined with `llvm.loop.isvectorized` and
+`llvm.loop.unroll.runtime.disable` (unless the original loop already
has unroll metadata).
-The attributes specified by ``llvm.loop.vectorize.followup_all`` are
+The attributes specified by `llvm.loop.vectorize.followup_all` are
added to both loops.
In addition to the above, the vectorizer automatically annotates the
generated loops with two metadata attributes for remark quality:
-- ``llvm.loop.vectorize.body`` is added to the vectorized loop.
-- ``llvm.loop.vectorize.epilogue`` is added to the scalar
+- `llvm.loop.vectorize.body` is added to the vectorized loop.
+- `llvm.loop.vectorize.epilogue` is added to the scalar
remainder (epilogue) loop.
Together these provide a four-way classification:
-- ``body`` only: main vectorized loop body
-- ``epilogue`` only: scalar epilogue loop after vectorization
+- `body` only: main vectorized loop body
+- `epilogue` only: scalar epilogue loop after vectorization
- Both: vectorized epilogue (a remainder that was itself
vectorized during epilogue vectorization)
- Neither: a plain loop not produced by the vectorizer
This is used by subsequent passes (e.g., the loop unroller and
-``WarnMissedTransforms``) to produce more precise optimization remarks.
+`WarnMissedTransforms`) to produce more precise optimization remarks.
For instance, instead of reporting both "loop unrolled" and "loop not
unrolled" for the same source line, the unroller can clarify that a
*vectorized* loop was unrolled while its *scalar epilogue* was not.
When using a follow-up attribute, it replaces any automatically deduced
attributes for the generated loop in question. Therefore it is
-recommended to add ``llvm.loop.isvectorized`` to
-``llvm.loop.vectorize.followup_all`` which avoids that the loop
+recommended to add `llvm.loop.isvectorized` to
+`llvm.loop.vectorize.followup_all` which avoids that the loop
vectorizer tries to optimize the loops again.
-Loop Unrolling
---------------
+### Loop Unrolling
-Unrolling is interpreted as forced any ``!{!"llvm.loop.unroll.enable"}``
-metadata or option (``llvm.loop.unroll.count``, ``llvm.loop.unroll.full``)
+Unrolling is interpreted as forced any `!{!"llvm.loop.unroll.enable"}`
+metadata or option (`llvm.loop.unroll.count`, `llvm.loop.unroll.full`)
is present. Unrolling can be full unrolling, partial unrolling of a loop
with constant trip count or runtime unrolling of a loop with a trip
count unknown at compile-time.
@@ -205,257 +196,251 @@ count unknown at compile-time.
If the loop has been unrolled fully, there is no followup-loop. For
partial/runtime unrolling, the original loop of
-.. code-block:: c
-
- for (int i = 0; i < n; i+=1) // original loop
- Stmt(i);
+```c
+for (int i = 0; i < n; i+=1) // original loop
+ Stmt(i);
+```
is transformed into (using an unroll factor of 4):
-.. code-block:: c
-
- int i = 0;
- for (; i + 3 < n; i+=4) { // unrolled loop
- Stmt(i);
- Stmt(i+1);
- Stmt(i+2);
- Stmt(i+3);
- }
- for (; i < n; i+=1) // remainder loop
- Stmt(i);
-
-``llvm.loop.unroll.followup_unrolled`` will set the loop attributes of
+```c
+int i = 0;
+for (; i + 3 < n; i+=4) { // unrolled loop
+ Stmt(i);
+ Stmt(i+1);
+ Stmt(i+2);
+ Stmt(i+3);
+}
+for (; i < n; i+=1) // remainder loop
+ Stmt(i);
+```
+
+`llvm.loop.unroll.followup_unrolled` will set the loop attributes of
the unrolled loop. If not specified, the attributes of the original loop
-without the ``llvm.loop.unroll.*`` attributes are copied and
-``llvm.loop.unroll.disable`` added to it.
+without the `llvm.loop.unroll.*` attributes are copied and
+`llvm.loop.unroll.disable` added to it.
-``llvm.loop.unroll.followup_remainder`` defines the attributes of the
+`llvm.loop.unroll.followup_remainder` defines the attributes of the
remainder loop. If not specified the remainder loop will have no
attributes. The remainder loop might not be present due to being fully
unrolled in which case this attribute has no effect.
-Attributes defined in ``llvm.loop.unroll.followup_all`` are added to the
+Attributes defined in `llvm.loop.unroll.followup_all` are added to the
unrolled and remainder loops.
To avoid that the partially unrolled loop is unrolled again, it is
-recommended to add ``llvm.loop.unroll.disable`` to
-``llvm.loop.unroll.followup_all``. If no follow-up attribute specified
+recommended to add `llvm.loop.unroll.disable` to
+`llvm.loop.unroll.followup_all`. If no follow-up attribute specified
for a generated loop, it is added automatically.
-Unroll-And-Jam
---------------
+### Unroll-And-Jam
Unroll-and-jam uses the following transformation model (here with an
unroll factor if 2). Currently, it does not support a fallback version
when the transformation is unsafe.
-.. code-block:: c
-
- for (int i = 0; i < n; i+=1) { // original outer loop
- Fore(i);
- for (int j = 0; j < m; j+=1) // original inner loop
- SubLoop(i, j);
- Aft(i);
- }
-
-.. code-block:: c
-
- int i = 0;
- for (; i + 1 < n; i+=2) { // unrolled outer loop
- Fore(i);
- Fore(i+1);
- for (int j = 0; j < m; j+=1) { // unrolled inner loop
- SubLoop(i, j);
- SubLoop(i+1, j);
- }
- Aft(i);
- Aft(i+1);
- }
- for (; i < n; i+=1) { // remainder outer loop
- Fore(i);
- for (int j = 0; j < m; j+=1) // remainder inner loop
- SubLoop(i, j);
- Aft(i);
- }
-
-``llvm.loop.unroll_and_jam.followup_outer`` will set the loop attributes
+```c
+for (int i = 0; i < n; i+=1) { // original outer loop
+ Fore(i);
+ for (int j = 0; j < m; j+=1) // original inner loop
+ SubLoop(i, j);
+ Aft(i);
+}
+```
+
+```c
+int i = 0;
+for (; i + 1 < n; i+=2) { // unrolled outer loop
+ Fore(i);
+ Fore(i+1);
+ for (int j = 0; j < m; j+=1) { // unrolled inner loop
+ SubLoop(i, j);
+ SubLoop(i+1, j);
+ }
+ Aft(i);
+ Aft(i+1);
+}
+for (; i < n; i+=1) { // remainder outer loop
+ Fore(i);
+ for (int j = 0; j < m; j+=1) // remainder inner loop
+ SubLoop(i, j);
+ Aft(i);
+}
+```
+
+`llvm.loop.unroll_and_jam.followup_outer` will set the loop attributes
of the unrolled outer loop. If not specified, the attributes of the
-original outer loop without the ``llvm.loop.unroll.*`` attributes are
-copied and ``llvm.loop.unroll.disable`` added to it.
+original outer loop without the `llvm.loop.unroll.*` attributes are
+copied and `llvm.loop.unroll.disable` added to it.
-``llvm.loop.unroll_and_jam.followup_inner`` will set the loop attributes
+`llvm.loop.unroll_and_jam.followup_inner` will set the loop attributes
of the unrolled inner loop. If not specified, the attributes of the
original inner loop are used unchanged.
-``llvm.loop.unroll_and_jam.followup_remainder_outer`` sets the loop
+`llvm.loop.unroll_and_jam.followup_remainder_outer` sets the loop
attributes of the outer remainder loop. If not specified it will not
have any attributes. The remainder loop might not be present due to
being fully unrolled.
-``llvm.loop.unroll_and_jam.followup_remainder_inner`` sets the loop
+`llvm.loop.unroll_and_jam.followup_remainder_inner` sets the loop
attributes of the inner remainder loop. If not specified it will have
the attributes of the original inner loop. It the outer remainder loop
is unrolled, the inner remainder loop might be present multiple times.
-Attributes defined in ``llvm.loop.unroll_and_jam.followup_all`` are
+Attributes defined in `llvm.loop.unroll_and_jam.followup_all` are
added to all of the aforementioned output loops.
To avoid that the unrolled loop is unrolled again, it is
-recommended to add ``llvm.loop.unroll.disable`` to
-``llvm.loop.unroll_and_jam.followup_all``. It suppresses unroll-and-jam
+recommended to add `llvm.loop.unroll.disable` to
+`llvm.loop.unroll_and_jam.followup_all`. It suppresses unroll-and-jam
as well as an additional inner loop unrolling. If no follow-up
attribute specified for a generated loop, it is added automatically.
-Loop Distribution
------------------
+### Loop Distribution
The LoopDistribution pass tries to separate vectorizable parts of a loop
from the non-vectorizable part (which otherwise would make the entire
loop non-vectorizable). Conceptually, it transforms a loop such as
-.. code-block:: c
-
- for (int i = 1; i < n; i+=1) { // original loop
- A[i] = i;
- B[i] = 2 + B[i];
- C[i] = 3 + C[i - 1];
- }
+```c
+for (int i = 1; i < n; i+=1) { // original loop
+ A[i] = i;
+ B[i] = 2 + B[i];
+ C[i] = 3 + C[i - 1];
+}
+```
into the following code:
-.. code-block:: c
-
- if (rtc) {
- for (int i = 1; i < n; i+=1) // coincident loop
- A[i] = i;
- for (int i = 1; i < n; i+=1) // coincident loop
- B[i] = 2 + B[i];
- for (int i = 1; i < n; i+=1) // sequential loop
- C[i] = 3 + C[i - 1];
- } else {
- for (int i = 1; i < n; i+=1) { // fallback loop
- A[i] = i;
- B[i] = 2 + B[i];
- C[i] = 3 + C[i - 1];
- }
- }
-
-where ``rtc`` is a generated runtime check.
-
-``llvm.loop.distribute.followup_coincident`` sets the loop attributes of
+```c
+if (rtc) {
+ for (int i = 1; i < n; i+=1) // coincident loop
+ A[i] = i;
+ for (int i = 1; i < n; i+=1) // coincident loop
+ B[i] = 2 + B[i];
+ for (int i = 1; i < n; i+=1) // sequential loop
+ C[i] = 3 + C[i - 1];
+} else {
+ for (int i = 1; i < n; i+=1) { // fallback loop
+ A[i] = i;
+ B[i] = 2 + B[i];
+ C[i] = 3 + C[i - 1];
+ }
+}
+```
+
+where `rtc` is a generated runtime check.
+
+`llvm.loop.distribute.followup_coincident` sets the loop attributes of
all loops without loop-carried dependencies (i.e. vectorizable loops).
There might be more than one such loops. If not defined, the loops will
inherit the original loop's attributes.
-``llvm.loop.distribute.followup_sequential`` sets the loop attributes of the
+`llvm.loop.distribute.followup_sequential` sets the loop attributes of the
loop with potentially unsafe dependencies. There should be at most one
such loop. If not defined, the loop will inherit the original loop's
attributes.
-``llvm.loop.distribute.followup_fallback`` defines the loop attributes
+`llvm.loop.distribute.followup_fallback` defines the loop attributes
for the fallback loop, which is a copy of the original loop for when
loop versioning is required. If undefined, the fallback loop inherits
all attributes from the original loop.
-Attributes defined in ``llvm.loop.distribute.followup_all`` are added to
+Attributes defined in `llvm.loop.distribute.followup_all` are added to
all of the aforementioned output loops.
-It is recommended to add ``llvm.loop.disable_nonforced`` to
-``llvm.loop.distribute.followup_fallback``. This avoids that the
+It is recommended to add `llvm.loop.disable_nonforced` to
+`llvm.loop.distribute.followup_fallback`. This avoids that the
fallback version (which is likely never executed) is further optimized
which would increase the code size.
-Attributes defined in ``llvm.loop.isdistributed`` are added to successfully
+Attributes defined in `llvm.loop.isdistributed` are added to successfully
distributed loops to prevent subsequent reprocessing.
As an example, the following instructs a loop to be ignored during
loop distribution.
-.. code-block:: llvm
+```llvm
+!4 = distinct !{!4, !5, !6}
+!5 = !{!"llvm.loop.mustprogress"}
+!6 = !{!"llvm.loop.isdistributed", i32 1}
+```
- !4 = distinct !{!4, !5, !6}
- !5 = !{!"llvm.loop.mustprogress"}
- !6 = !{!"llvm.loop.isdistributed", i32 1}
-
-Versioning LICM
----------------
+### Versioning LICM
The pass hoists code out of loops that are only loop-invariant when
dynamic conditions apply. For instance, it transforms the loop
-.. code-block:: c
-
- for (int i = 0; i < n; i+=1) // original loop
- A[i] = B[0];
+```c
+for (int i = 0; i < n; i+=1) // original loop
+ A[i] = B[0];
+```
into:
-.. code-block:: c
-
- if (rtc) {
- auto b = B[0];
- for (int i = 0; i < n; i+=1) // versioned loop
- A[i] = b;
- } else {
- for (int i = 0; i < n; i+=1) // unversioned loop
- A[i] = B[0];
- }
-
-The runtime condition (``rtc``) checks that the array ``A`` and the
+```c
+if (rtc) {
+ auto b = B[0];
+ for (int i = 0; i < n; i+=1) // versioned loop
+ A[i] = b;
+} else {
+ for (int i = 0; i < n; i+=1) // unversioned loop
+ A[i] = B[0];
+}
+```
+
+The runtime condition (`rtc`) checks that the array `A` and the
element `B[0]` do not alias.
Currently, this transformation does not support followup-attributes.
-Loop Interchange
-----------------
+### Loop Interchange
-Currently, the ``LoopInterchange`` pass does not use any metadata.
+Currently, the `LoopInterchange` pass does not use any metadata.
-Ambiguous Transformation Order
-==============================
+## Ambiguous Transformation Order
If there multiple transformations defined, the order in which they are
executed depends on the order in LLVM's pass pipeline, which is subject
to change. The default optimization pipeline (anything higher than
-``-O0``) has the following order.
+`-O0`) has the following order.
When using the legacy pass manager:
- - LoopInterchange (if enabled)
- - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
- - VersioningLICM (if enabled)
- - LoopDistribute
- - LoopVectorizer
- - LoopUnrollAndJam (if enabled)
- - LoopUnroll (partial and runtime unrolling)
+> - LoopInterchange (if enabled)
+> - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
+> - VersioningLICM (if enabled)
+> - LoopDistribute
+> - LoopVectorizer
+> - LoopUnrollAndJam (if enabled)
+> - LoopUnroll (partial and runtime unrolling)
When using the legacy pass manager with LTO:
- - LoopInterchange (if enabled)
- - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
- - LoopVectorizer
- - LoopUnroll (partial and runtime unrolling)
+> - LoopInterchange (if enabled)
+> - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
+> - LoopVectorizer
+> - LoopUnroll (partial and runtime unrolling)
When using the new pass manager:
- - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
- - LoopDistribute
- - LoopVectorizer
- - LoopUnrollAndJam (if enabled)
- - LoopUnroll (partial and runtime unrolling)
+> - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
+> - LoopDistribute
+> - LoopVectorizer
+> - LoopUnrollAndJam (if enabled)
+> - LoopUnroll (partial and runtime unrolling)
-Leftover Transformations
-========================
+## Leftover Transformations
Forced transformations that have not been applied after the last
transformation pass should be reported to the user. The transformation
passes themselves cannot be responsible for this reporting because they
might not be in the pipeline, there might be multiple passes able to
-apply a transformation (e.g. ``LoopInterchange`` and Polly) or a
+apply a transformation (e.g. `LoopInterchange` and Polly) or a
transformation attribute may be 'hidden' inside another passes' followup
attribute.
-The pass ``-transform-warning`` (``WarnMissedTransformationsPass``)
+The pass `-transform-warning` (`WarnMissedTransformationsPass`)
emits such warnings. It should be placed after the last transformation
pass.
@@ -465,8 +450,9 @@ that is executed later and thus leftover. For instance, a loop nest
cannot be distributed and then interchanged with the current pass
pipeline. The loop distribution will execute, but there is no loop
interchange pass following such that any loop interchange metadata will
-be ignored. The ``-transform-warning`` should emit a warning in this
+be ignored. The `-transform-warning` should emit a warning in this
case.
Future versions of LLVM may fix this by executing transformations using
a dynamic ordering.
+
diff --git a/llvm/docs/TypeMetadata.md b/llvm/docs/TypeMetadata.md
index 5fa864dc8ab21..8626fd39598d0 100644
--- a/llvm/docs/TypeMetadata.md
+++ b/llvm/docs/TypeMetadata.md
@@ -1,10 +1,8 @@
-=============
-Type Metadata
-=============
+# Type Metadata
Type metadata is a mechanism that allows IR modules to co-operatively build
pointer sets corresponding to addresses within a given set of globals. LLVM's
-`control flow integrity`_ implementation uses this metadata to efficiently
+[control flow integrity][control flow integrity] implementation uses this metadata to efficiently
check (at each call site) that a given address corresponds to either a
valid vtable or function pointer for a given class or function type, and its
whole-program devirtualization pass uses the metadata to identify potential
@@ -16,51 +14,49 @@ To use the mechanism, a client creates metadata nodes with two elements:
2. a metadata object representing an identifier for the type
These metadata nodes are associated with globals by using global object
-metadata attachments with the ``!type`` metadata kind.
+metadata attachments with the `!type` metadata kind.
Each type identifier must exclusively identify either global variables
or functions.
-.. admonition:: Limitation
+:::{admonition} Limitation
+The current implementation only supports attaching metadata to functions on
+the x86-32 and x86-64 architectures.
+:::
- The current implementation only supports attaching metadata to functions on
- the x86-32 and x86-64 architectures.
-
-An intrinsic, :ref:`llvm.type.test <type.test>`, is used to test whether a
+An intrinsic, {ref}`llvm.type.test <type.test>`, is used to test whether a
given pointer is associated with a type identifier.
-.. _control flow integrity: https://clang.llvm.org/docs/ControlFlowIntegrity.html
-
-Representing Type Information using Type Metadata
-=================================================
+## Representing Type Information using Type Metadata
This section describes how Clang represents C++ type information associated with
virtual tables using type metadata.
Consider the following inheritance hierarchy:
-.. code-block:: c++
-
- struct A {
- virtual void f();
- };
+```c++
+struct A {
+ virtual void f();
+};
- struct B : A {
- virtual void f();
- virtual void g();
- };
+struct B : A {
+ virtual void f();
+ virtual void g();
+};
- struct C {
- virtual void h();
- };
+struct C {
+ virtual void h();
+};
- struct D : A, C {
- virtual void f();
- virtual void h();
- };
+struct D : A, C {
+ virtual void f();
+ virtual void h();
+};
+```
The virtual table objects for A, B, C and D look like this (under the Itanium ABI):
+```{eval-rst}
.. csv-table:: Virtual Table Layout for A, B, C, D
:header: Class, 0, 1, 2, 3, 4, 5, 6
@@ -68,11 +64,12 @@ The virtual table objects for A, B, C and D look like this (under the Itanium AB
B, B::offset-to-top, &B::rtti, &B::f, &B::g
C, C::offset-to-top, &C::rtti, &C::h
D, D::offset-to-top, &D::rtti, &D::f, &D::h, D::offset-to-top, &D::rtti, thunk for &D::h
+```
-When an object of type A is constructed, the address of ``&A::f`` in A's
-virtual table object is stored in the object's vtable pointer. In ABI parlance
-this address is known as an `address point`_. Similarly, when an object of type
-B is constructed, the address of ``&B::f`` is stored in the vtable pointer. In
+When an object of type A is constructed, the address of `&A::f` in A's
+virtual table object is stored in the object's vtable pointer. In ABI parlance
+this address is known as an [address point][address point]. Similarly, when an object of type
+B is constructed, the address of `&B::f` is stored in the vtable pointer. In
this way, the vtable in B's virtual table object is compatible with A's vtable.
D is a little more complicated, due to the use of multiple inheritance. Its
@@ -87,6 +84,7 @@ shown below. The following table shows the name of a class, the offset of an
address point within that class's vtable and the name of one of the classes
with which that address point is compatible.
+```{eval-rst}
.. csv-table:: Type Offsets for A, B, C, D
:header: VTable for, Offset, Compatible Class
@@ -97,6 +95,7 @@ with which that address point is compatible.
D, 16, A
, , D
, 48, C
+```
The next step is to encode this compatibility information into the IR. The way
this is done is to create type metadata named after each of the compatible
@@ -104,44 +103,41 @@ classes, with which we associate each of the compatible address points in
each vtable. For example, these type metadata entries encode the compatibility
information for the above hierarchy:
-::
+```
+ at _ZTV1A = constant [...], !type !0
+ at _ZTV1B = constant [...], !type !0, !type !1
+ at _ZTV1C = constant [...], !type !2
+ at _ZTV1D = constant [...], !type !0, !type !3, !type !4
- @_ZTV1A = constant [...], !type !0
- @_ZTV1B = constant [...], !type !0, !type !1
- @_ZTV1C = constant [...], !type !2
- @_ZTV1D = constant [...], !type !0, !type !3, !type !4
+!0 = !{i64 16, !"_ZTS1A"}
+!1 = !{i64 16, !"_ZTS1B"}
+!2 = !{i64 16, !"_ZTS1C"}
+!3 = !{i64 16, !"_ZTS1D"}
+!4 = !{i64 48, !"_ZTS1C"}
+```
- !0 = !{i64 16, !"_ZTS1A"}
- !1 = !{i64 16, !"_ZTS1B"}
- !2 = !{i64 16, !"_ZTS1C"}
- !3 = !{i64 16, !"_ZTS1D"}
- !4 = !{i64 48, !"_ZTS1C"}
-
-With this type metadata, we can now use the ``llvm.type.test`` intrinsic to
+With this type metadata, we can now use the `llvm.type.test` intrinsic to
test whether a given pointer is compatible with a type identifier. Working
-backwards, if ``llvm.type.test`` returns true for a particular pointer,
+backwards, if `llvm.type.test` returns true for a particular pointer,
we can also statically determine the identities of the virtual functions
that a particular virtual call may call. For example, if a program assumes
-a pointer to be a member of ``!"_ZST1A"``, we know that the address can
-be only be one of ``_ZTV1A+16``, ``_ZTV1B+16`` or ``_ZTV1D+16`` (i.e. the
+a pointer to be a member of `!"_ZST1A"`, we know that the address can
+be only be one of `_ZTV1A+16`, `_ZTV1B+16` or `_ZTV1D+16` (i.e. the
address points of the vtables of A, B and D respectively). If we then load
an address from that pointer, we know that the address can only be one of
-``&A::f``, ``&B::f`` or ``&D::f``.
-
-.. _address point: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-general
+`&A::f`, `&B::f` or `&D::f`.
-Testing Addresses For Type Membership
-=====================================
+## Testing Addresses For Type Membership
-If a program tests an address using ``llvm.type.test``, this will cause
-a link-time optimization pass, ``LowerTypeTests``, to replace calls to this
+If a program tests an address using `llvm.type.test`, this will cause
+a link-time optimization pass, `LowerTypeTests`, to replace calls to this
intrinsic with efficient code to perform type member tests. At a high level,
the pass will lay out referenced globals in a consecutive memory region in
the object file, construct bit vectors that map onto that memory region,
-and generate code at each of the ``llvm.type.test`` call sites to test
+and generate code at each of the `llvm.type.test` call sites to test
pointers against those bit vectors. Because of the layout manipulation, the
globals' definitions must be available at LTO time. For more information,
-see the `control flow integrity design document`_.
+see the [control flow integrity design document][control flow integrity design document].
A type identifier that identifies functions is transformed into a jump table,
which is a block of code consisting of one branch instruction for each
@@ -157,76 +153,69 @@ associated with a type identifier, there is no guarantee that its identity
within the module will be the same as its identity outside of the module,
as the former will be the jump table entry if a jump table is necessary.
-The `GlobalLayoutBuilder`_ class is responsible for laying out the globals
+The [GlobalLayoutBuilder][globallayoutbuilder] class is responsible for laying out the globals
efficiently to minimize the sizes of the underlying bitsets.
-.. _control flow integrity design document: https://clang.llvm.org/docs/ControlFlowIntegrityDesign.html
-
-:Example:
-
-::
-
- target datalayout = "e-p:32:32"
-
- @a = internal global i32 0, !type !0
- @b = internal global i32 0, !type !0, !type !1
- @c = internal global i32 0, !type !1
- @d = internal global [2 x i32] [i32 0, i32 0], !type !2
-
- define void @e() !type !3 {
- ret void
- }
-
- define void @f() {
- ret void
- }
-
- declare void @g() !type !3
-
- !0 = !{i32 0, !"typeid1"}
- !1 = !{i32 0, !"typeid2"}
- !2 = !{i32 4, !"typeid2"}
- !3 = !{i32 0, !"typeid3"}
-
- declare i1 @llvm.type.test(i8* %ptr, metadata %typeid) nounwind readnone
-
- define i1 @foo(i32* %p) {
- %pi8 = bitcast i32* %p to i8*
- %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1")
- ret i1 %x
- }
-
- define i1 @bar(i32* %p) {
- %pi8 = bitcast i32* %p to i8*
- %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid2")
- ret i1 %x
- }
-
- define i1 @baz(void ()* %p) {
- %pi8 = bitcast void ()* %p to i8*
- %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid3")
- ret i1 %x
- }
-
- define void @main() {
- %a1 = call i1 @foo(i32* @a) ; returns 1
- %b1 = call i1 @foo(i32* @b) ; returns 1
- %c1 = call i1 @foo(i32* @c) ; returns 0
- %a2 = call i1 @bar(i32* @a) ; returns 0
- %b2 = call i1 @bar(i32* @b) ; returns 1
- %c2 = call i1 @bar(i32* @c) ; returns 1
- %d02 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 0)) ; returns 0
- %d12 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 1)) ; returns 1
- %e = call i1 @baz(void ()* @e) ; returns 1
- %f = call i1 @baz(void ()* @f) ; returns 0
- %g = call i1 @baz(void ()* @g) ; returns 1
- ret void
- }
-
-.. _GlobalLayoutBuilder: https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h
-
-``!vcall_visibility`` Metadata
-==============================
+```
+target datalayout = "e-p:32:32"
+
+ at a = internal global i32 0, !type !0
+ at b = internal global i32 0, !type !0, !type !1
+ at c = internal global i32 0, !type !1
+ at d = internal global [2 x i32] [i32 0, i32 0], !type !2
+
+define void @e() !type !3 {
+ ret void
+}
+
+define void @f() {
+ ret void
+}
+
+declare void @g() !type !3
+
+!0 = !{i32 0, !"typeid1"}
+!1 = !{i32 0, !"typeid2"}
+!2 = !{i32 4, !"typeid2"}
+!3 = !{i32 0, !"typeid3"}
+
+declare i1 @llvm.type.test(i8* %ptr, metadata %typeid) nounwind readnone
+
+define i1 @foo(i32* %p) {
+ %pi8 = bitcast i32* %p to i8*
+ %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1")
+ ret i1 %x
+}
+
+define i1 @bar(i32* %p) {
+ %pi8 = bitcast i32* %p to i8*
+ %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid2")
+ ret i1 %x
+}
+
+define i1 @baz(void ()* %p) {
+ %pi8 = bitcast void ()* %p to i8*
+ %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid3")
+ ret i1 %x
+}
+
+define void @main() {
+ %a1 = call i1 @foo(i32* @a) ; returns 1
+ %b1 = call i1 @foo(i32* @b) ; returns 1
+ %c1 = call i1 @foo(i32* @c) ; returns 0
+ %a2 = call i1 @bar(i32* @a) ; returns 0
+ %b2 = call i1 @bar(i32* @b) ; returns 1
+ %c2 = call i1 @bar(i32* @c) ; returns 1
+ %d02 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 0)) ; returns 0
+ %d12 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 1)) ; returns 1
+ %e = call i1 @baz(void ()* @e) ; returns 1
+ %f = call i1 @baz(void ()* @f) ; returns 0
+ %g = call i1 @baz(void ()* @g) ; returns 1
+ ret void
+}
+```
+
+## `!vcall_visibility` Metadata
In order to allow removing unused function pointers from vtables, we need to
know whether every virtual call which could use it is known to the compiler, or
@@ -235,30 +224,31 @@ This is not the same as the linkage of the vtable, because call sites could be
using a pointer of a more widely-visible base class. For example, consider this
code:
-.. code-block:: c++
-
- __attribute__((visibility("default")))
- struct A {
- virtual void f();
- };
-
- __attribute__((visibility("hidden")))
- struct B : A {
- virtual void f();
- };
-
-With LTO, we know that all code which can see the declaration of ``B`` is
-visible to us. However, a pointer to a ``B`` could be cast to ``A*`` and passed
-to another linkage unit, which could then call ``f`` on it. This call would
-load from the vtable for ``B`` (using the object pointer), and then call
-``B::f``. This means we can't remove the function pointer from ``B``'s vtable,
-or the implementation of ``B::f``. However, if we can see all code which knows
-about any dynamic base class (which would be the case if ``B`` only inherited
+```c++
+__attribute__((visibility("default")))
+struct A {
+ virtual void f();
+};
+
+__attribute__((visibility("hidden")))
+struct B : A {
+ virtual void f();
+};
+```
+
+With LTO, we know that all code which can see the declaration of `B` is
+visible to us. However, a pointer to a `B` could be cast to `A*` and passed
+to another linkage unit, which could then call `f` on it. This call would
+load from the vtable for `B` (using the object pointer), and then call
+`B::f`. This means we can't remove the function pointer from `B`'s vtable,
+or the implementation of `B::f`. However, if we can see all code which knows
+about any dynamic base class (which would be the case if `B` only inherited
from classes with hidden visibility), then this optimisation would be valid.
-This concept is represented in IR by the ``!vcall_visibility`` metadata
+This concept is represented in IR by the `!vcall_visibility` metadata
attached to vtable objects, with the following values:
+```{eval-rst}
.. list-table::
:header-rows: 1
:widths: 10 90
@@ -281,10 +271,17 @@ attached to vtable objects, with the following values:
- **Translation Unit**
All virtual function calls which might use this vtable are in the
current module.
+```
In addition, all function pointer loads from a vtable marked with the
-``!vcall_visibility`` metadata (with a non-zero value) must be done using the
-:ref:`llvm.type.checked.load <type.checked.load>` intrinsic, so that virtual
+`!vcall_visibility` metadata (with a non-zero value) must be done using the
+{ref}`llvm.type.checked.load <type.checked.load>` intrinsic, so that virtual
calls sites can be correlated with the vtables which they might load from.
Other parts of the vtable (RTTI, offset-to-top, ...) can still be accessed with
normal loads.
+
+[address point]: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-general
+[control flow integrity]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
+[control flow integrity design document]: https://clang.llvm.org/docs/ControlFlowIntegrityDesign.html
+[globallayoutbuilder]: https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h
+
diff --git a/llvm/docs/UndefinedBehavior.md b/llvm/docs/UndefinedBehavior.md
index 2055244664511..e25d29ec22ed7 100644
--- a/llvm/docs/UndefinedBehavior.md
+++ b/llvm/docs/UndefinedBehavior.md
@@ -1,17 +1,13 @@
-======================================
-LLVM IR Undefined Behavior (UB) Manual
-======================================
+# LLVM IR Undefined Behavior (UB) Manual
+## Abstract
-Abstract
-========
This document describes the undefined behavior (UB) in LLVM's IR, including
-undef and poison values, as well as the ``freeze`` instruction.
+undef and poison values, as well as the `freeze` instruction.
We also provide guidelines on when to use each form of UB.
+## Introduction
-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
@@ -21,15 +17,14 @@ 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.
+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
-============
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
@@ -40,39 +35,39 @@ 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
+```llvm
+define i32 @f(i1 %c, i32 %v) {
+ br i1 %c, label %then, label %else
- define i32 @f(i1 %c, i32 %v) {
- br i1 %c, label %then, label %else
+then:
+ %div = udiv i32 3, %v
+ br label %ret
- then:
- %div = udiv i32 3, %v
- br label %ret
+else:
+ br label %ret
- else:
- br label %ret
-
- ret:
- %r = phi i32 [ %div, %then ], [ 0, %else ]
- ret i32 %r
- }
+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.
+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
- }
+```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
+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
@@ -80,34 +75,32 @@ 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
-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``:
+For example, the following function triggers UB after calling `printf`:
-.. code-block:: llvm
+```llvm
+define void @fn() {
+ call void @printf(...) willreturn
+ unreachable
+}
+```
- 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
+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
- }
+```llvm
+define void @fn() {
+ unreachable
+}
+```
+## Deferred UB
-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
@@ -118,59 +111,58 @@ 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``.
+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
+```llvm
+define i32 @x86_shift(i32 %a, i32 %b) {
+ %mask = and i32 %b, 31
+ %shift = shl i32 %a, %mask
+ ret i32 %shift
+}
+```
- 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
+There are two deferred UB values in LLVM: `undef` and `poison`, which we
describe next.
+### Undef Values
-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).
+:::{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
+```llvm
+define i32 @fn() {
+ %add = add i32 undef, 0
+ %ret = add i32 %add, %add
+ ret i32 %ret
+}
+```
- define i32 @fn() {
- %add = add i32 undef, 0
- %ret = add i32 %add, %add
- ret i32 %ret
- }
-
-Unsurprisingly, the first addition yields ``undef``.
+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``.
+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
- }
+```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).
@@ -179,211 +171,206 @@ 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
+```llvm
+define i32 @fn(i32 %v) {
+ %mul2 = mul i32 %v, 2
+ ret i32 %mul2
+}
+```
- 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
+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
- }
+```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
+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.
+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``),
+`udiv %x, undef` is UB since we replace undef with 0 (`udiv %x, 0`),
becoming obvious that it is UB.
+### Poison Values
-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
+```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
+}
+```
- 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
+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
+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).
+or a `freeze` instruction).
+### Propagation of Poison Through Select
-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
+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
+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
- }
+```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.
+
+```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``):
+the condition (notice the flipped operands in the `select`):
-.. code-block:: llvm
+```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
+}
+```
- 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
-
-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.
+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
+```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:
+ %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
+loop.cont:
+ br i1 %c, label %then, label %else
- then:
- ...
- br label %loop.end
+then:
+ ...
+ br label %loop.end
- else:
- ...
- br label %loop.end
+else:
+ ...
+ br label %loop.end
- loop.end:
- %i2 = add i32 %i, 1
- br label %loop
+loop.end:
+ %i2 = add i32 %i, 1
+ br label %loop
- exit:
- ...
- }
+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.
+```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.
+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
+`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
+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
+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
- ...
- }
-
+```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
-========================================
+## 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
@@ -393,12 +380,12 @@ 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
- ...
- }
+```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
@@ -406,28 +393,28 @@ 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
- ...
- }
+```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.
+:::{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
-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``
+This can be avoided in some cases through the use of the `freeze`
instruction.
The lattice of values in LLVM is:
@@ -437,3 +424,4 @@ 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.
+
diff --git a/llvm/docs/VectorizationPlan.md b/llvm/docs/VectorizationPlan.md
index c480ac86d2a59..6df336f3c28e6 100644
--- a/llvm/docs/VectorizationPlan.md
+++ b/llvm/docs/VectorizationPlan.md
@@ -1,12 +1,9 @@
-==================
-Vectorization Plan
-==================
+# Vectorization Plan
+## Abstract
-Abstract
-========
The vectorization transformation can be rather complicated, involving several
-potential alternatives, especially for outer-loops [1]_ but also possibly for
+potential alternatives, especially for outer-loops [^footnote-1] but also possibly for
innermost loops. These alternatives may have significant performance impact,
both positive and negative. A cost model is therefore employed to identify the
best alternative, including the alternative of avoiding any transformation
@@ -17,24 +14,22 @@ candidates. It serves for both optimizing candidates including estimating their
cost reliably, and for performing their final translation into IR. This
facilitates dealing with multiple vectorization candidates.
-Current Status
-==============
+## Current Status
+
VPlan is currently used to drive code-generation in LoopVectorize. VPlans are
constructed after all cost-based and most legality-related decisions have been
taken. As def-use chains between recipes are now fully modeled in VPlan,
VPlan-based analyses and transformations are used to simplify and modularize
-the vectorization process [10]_. Those include transformations to
+the vectorization process [^footnote-10]. Those include transformations to
1. Legalize the initial VPlan, e.g. by introducing specialized recipes for
reductions and interleave groups.
-
2. Optimize the legalized VPlan, e.g. by removing redundant recipes or
introducing active-lane-masks.
-
3. Apply unroll- and vectorization-factor specific optimizations, e.g. removing
the backedge to reiterate the vector loop based on VF & UF.
-Refer to :ref:`fig-vplan-transform-pipeline` for an overview of the current
+Refer to {ref}`fig-vplan-transform-pipeline` for an overview of the current
transformation pipeline.
Note that some legality checks are already done in VPlan, including checking if
@@ -42,45 +37,48 @@ all users of a fixed-order recurrence can be re-ordered. This is implemented as
a VPlan-to-VPlan transformation that either applies a valid re-ordering or
bails out marking the VPlan as invalid.
-.. _fig-vplan-transform-pipeline:
-.. figure:: ./vplan-transform-pipeline.png
- :width: 800 px
+(fig-vplan-transform-pipeline)=
- VPlan Transformation Pipeline in 2024
+:::{figure} ./vplan-transform-pipeline.png
+:width: 800 px
+VPlan Transformation Pipeline in 2024
+:::
VPlan currently models the complete vector loop, as well as additional parts of
-the vectorization skeleton. Refer to :ref:`fig-vplan-scope` for an overview
+the vectorization skeleton. Refer to {ref}`fig-vplan-scope` for an overview
of the scope covered by VPlan.
-.. _fig-vplan-scope:
-.. figure:: ./vplan-scope.png
- :width: 800 px
+(fig-vplan-scope)=
- Scope modeled in VPlan in 2024
+:::{figure} ./vplan-scope.png
+:width: 800 px
+Scope modeled in VPlan in 2024
+:::
-High-level Design
-=================
+## High-level Design
+
+### Vectorization Workflow
-Vectorization Workflow
-----------------------
VPlan-based vectorization involves three major steps, taking a "scenario-based
approach" to vectorization planning:
1. Legal Step: check if a loop can be legally vectorized; encode constraints and
artifacts if so.
+
2. Plan Step:
- a. Build initial VPlans following the constraints and decisions taken by
+ 1. Build initial VPlans following the constraints and decisions taken by
Legal Step 1, and compute their cost.
- b. Apply optimizations to the VPlans, possibly forking additional VPlans.
+ 2. Apply optimizations to the VPlans, possibly forking additional VPlans.
Prune sub-optimal VPlans having relatively high cost.
+
3. Execute Step: materialize the best VPlan. Note that this is the only step
that modifies the IR.
-Design Guidelines
------------------
+### Design Guidelines
+
In what follows, the term "input IR" refers to code that is fed into the
vectorizer whereas the term "output IR" refers to code that is generated by the
vectorizer. The output IR contains code that has been vectorized or "widened"
@@ -99,15 +97,15 @@ The design of VPlan follows several high-level guidelines:
3. Support vectorizing additional constructs:
- a. Outer-loop vectorization. In particular, VPlan must be able to model the
+ 1. Outer-loop vectorization. In particular, VPlan must be able to model the
control-flow of the output IR which may include multiple basic-blocks and
nested loops.
- b. SLP vectorization.
- c. Combinations of the above, including nested vectorization: vectorizing
+ 2. SLP vectorization.
+ 3. Combinations of the above, including nested vectorization: vectorizing
both an inner loop and an outer-loop at the same time (each with its own
VF and UF), mixed vectorization: vectorizing a loop with SLP patterns
- inside [4]_, (re)vectorizing input IR containing vector code.
- d. Function vectorization [2]_.
+ inside [^footnote-4], (re)vectorizing input IR containing vector code.
+ 4. Function vectorization [^footnote-2].
4. Support multiple candidates efficiently. In particular, similar candidates
related to a range of possible VF's and UF's must be represented efficiently.
@@ -120,7 +118,7 @@ The design of VPlan follows several high-level guidelines:
6. Encapsulate Single-Entry Single-Exit regions (SESE). During vectorization
such regions may need to be, for example, predicated and linearized, or
- replicated VF*UF times to handle scalarized and predicated instructions.
+ replicated VF\*UF times to handle scalarized and predicated instructions.
Innerloops are also modelled as SESE regions.
7. Support instruction-level analysis and transformation, as part of Planning
@@ -129,16 +127,11 @@ The design of VPlan follows several high-level guidelines:
detection and formation involves searching for and optimizing instruction
patterns.
-Definitions
-===========
+## Definitions
+
The low-level design of VPlan comprises of the following classes.
-:LoopVectorizationPlanner:
- A LoopVectorizationPlanner is designed to handle the vectorization of a loop
- or a loop nest. It can construct, optimize and discard one or more VPlans,
- each VPlan modelling a distinct way to vectorize the loop or the loop nest.
- Once the best VPlan is determined, including the best VF and UF, this VPlan
- drives the generation of output IR.
+```{eval-rst}
:VPlan:
A model of a vectorized candidate for a given input IR loop or loop nest. This
@@ -214,6 +207,12 @@ The low-level design of VPlan comprises of the following classes.
The Planning Process and VPlan Roadmap
======================================
+Transforming the Loop Vectorizer to use VPlan follows a staged approach. First,
+VPlan was only used to record the final vectorization decisions, and to execute
+```
+
+## The Planning Process and VPlan Roadmap
+
Transforming the Loop Vectorizer to use VPlan follows a staged approach. First,
VPlan was only used to record the final vectorization decisions, and to execute
them: the Hierarchical CFG models the planned control-flow, and Recipes capture
@@ -244,48 +243,46 @@ them as VPInstructions. Finally, only logic that applies to instructions as a
group will remain in Recipes, such as interleave groups and potentially other
idiom groups having synergistic cost.
-Related LLVM components
------------------------
-1. SLP Vectorizer: one can compare the VPlan model with LLVM's existing SLP
- tree, where TSLP [3]_ adds Plan Step 2.b.
+### Related LLVM components
+1. SLP Vectorizer: one can compare the VPlan model with LLVM's existing SLP
+ tree, where TSLP [^footnote-3] adds Plan Step 2.b.
2. RegionInfo: one can compare VPlan's H-CFG with the Region Analysis as used by
- Polly [7]_.
-
+ Polly [^footnote-7].
3. Loop Vectorizer: the Vectorization Plan aims to upgrade the infrastructure of
- the Loop Vectorizer and extend it to handle outer loops [8]_, [9]_.
+ the Loop Vectorizer and extend it to handle outer loops [^footnote-8], [^footnote-9].
-References
-----------
-.. [1] "Outer-loop vectorization: revisited for short SIMD architectures", Dorit
+### References
+
+[^footnote-1]: "Outer-loop vectorization: revisited for short SIMD architectures", Dorit
Nuzman and Ayal Zaks, PACT 2008.
-.. [2] "Proposal for function vectorization and loop vectorization with function
- calls", Xinmin Tian, [`cfe-dev
- <http://lists.llvm.org/pipermail/cfe-dev/2016-March/047732.html>`_].,
+[^footnote-2]: "Proposal for function vectorization and loop vectorization with function
+ calls", Xinmin Tian, \[[cfe-dev](http://lists.llvm.org/pipermail/cfe-dev/2016-March/047732.html)\].,
March 2, 2016.
- See also `review <https://reviews.llvm.org/D22792>`_.
+ See also [review](https://reviews.llvm.org/D22792).
-.. [3] "Throttling Automatic Vectorization: When Less is More", Vasileios
+[^footnote-3]: "Throttling Automatic Vectorization: When Less is More", Vasileios
Porpodas and Tim Jones, PACT 2015 and LLVM Developers' Meeting 2015.
-.. [4] "Exploiting mixed SIMD parallelism by reducing data reorganization
+[^footnote-4]: "Exploiting mixed SIMD parallelism by reducing data reorganization
overhead", Hao Zhou and Jingling Xue, CGO 2016.
-.. [5] "Register Allocation via Hierarchical Graph Coloring", David Callahan and
+[^footnote-5]: "Register Allocation via Hierarchical Graph Coloring", David Callahan and
Brian Koblenz, PLDI 1991
-.. [6] "Structural analysis: A new approach to flow analysis in optimizing
+[^footnote-6]: "Structural analysis: A new approach to flow analysis in optimizing
compilers", M. Sharir, Journal of Computer Languages, Jan. 1980
-.. [7] "Enabling Polyhedral Optimizations in LLVM", Tobias Grosser, Diploma
+[^footnote-7]: "Enabling Polyhedral Optimizations in LLVM", Tobias Grosser, Diploma
thesis, 2011.
-.. [8] "Introducing VPlan to the Loop Vectorizer", Gil Rapaport and Ayal Zaks,
+[^footnote-8]: "Introducing VPlan to the Loop Vectorizer", Gil Rapaport and Ayal Zaks,
European LLVM Developers' Meeting 2017.
-.. [9] "Extending LoopVectorizer: OpenMP4.5 SIMD and Outer Loop
+[^footnote-9]: "Extending LoopVectorizer: OpenMP4.5 SIMD and Outer Loop
Auto-Vectorization", Intel Vectorizer Team, LLVM Developers' Meeting 2016.
-.. [10] "VPlan: Status Update and Future Roadmap", Ayal Zaks and Florian Hahn,
- LLVM Developers' Meeting 2023, https://www.youtube.com/watch?v=SzGP4PgMuLE
+[^footnote-10]: "VPlan: Status Update and Future Roadmap", Ayal Zaks and Florian Hahn,
+ LLVM Developers' Meeting 2023, <https://www.youtube.com/watch?v=SzGP4PgMuLE>
+
diff --git a/llvm/docs/XRay.md b/llvm/docs/XRay.md
index 2a975de8ab9b7..6a306e067a891 100644
--- a/llvm/docs/XRay.md
+++ b/llvm/docs/XRay.md
@@ -1,29 +1,27 @@
-====================
-XRay Instrumentation
-====================
+---
+Version: 1 as of 2016-11-08
+---
-:Version: 1 as of 2016-11-08
+# XRay Instrumentation
-
-
-Introduction
-============
+## Introduction
XRay is a function call tracing system which combines compiler-inserted
instrumentation points and a runtime library that can dynamically enable and
disable the instrumentation.
-More high level information about XRay can be found in the `XRay whitepaper`_.
+More high level information about XRay can be found in the [XRay whitepaper][xray whitepaper].
This document describes how to use XRay as implemented in LLVM.
-XRay in LLVM
-============
+## XRay in LLVM
XRay consists of three main parts:
- Compiler-inserted instrumentation points.
+
- A runtime library for enabling/disabling tracing at runtime.
+
- A suite of tools for analysing the traces.
**NOTE:** As of July 25, 2018 , XRay is only available for the following
@@ -32,13 +30,12 @@ XRay consists of three main parts:
OpenBSD: x86_64.
The compiler-inserted instrumentation points come in the form of nop-sleds in
-the final generated binary, and an ELF section named ``xray_instr_map`` which
+the final generated binary, and an ELF section named `xray_instr_map` which
contains entries pointing to these instrumentation points. The runtime library
-relies on being able to access the entries of the ``xray_instr_map``, and
+relies on being able to access the entries of the `xray_instr_map`, and
overwrite the instrumentation points at runtime.
-Using XRay
-==========
+## Using XRay
You can use XRay in a couple of ways:
@@ -48,246 +45,228 @@ You can use XRay in a couple of ways:
The rest of this section covers these main ways and later on how to customize
what XRay does in an XRay-instrumented binary.
-Instrumenting your C/C++/Objective-C Application
-------------------------------------------------
+### Instrumenting your C/C++/Objective-C Application
The easiest way of getting XRay instrumentation for your application is by
-enabling the ``-fxray-instrument`` flag in your clang invocation.
+enabling the `-fxray-instrument` flag in your clang invocation.
For example:
-::
-
- clang -fxray-instrument ...
+```
+clang -fxray-instrument ...
+```
By default, functions that have at least 200 instructions (or contain a loop) will
get XRay instrumentation points. You can tweak that number through the
-``-fxray-instruction-threshold=`` flag:
+`-fxray-instruction-threshold=` flag:
-::
+```
+clang -fxray-instrument -fxray-instruction-threshold=1 ...
+```
- clang -fxray-instrument -fxray-instruction-threshold=1 ...
-
-The loop detection can be disabled with ``-fxray-ignore-loops`` to use only the
+The loop detection can be disabled with `-fxray-ignore-loops` to use only the
instruction threshold. You can also specifically instrument functions in your
binary to either always or never be instrumented using source-level attributes.
You can do it using the GCC-style attributes or C++11-style attributes.
-.. code-block:: c++
-
- [[clang::xray_always_instrument]] void always_instrumented();
+```c++
+[[clang::xray_always_instrument]] void always_instrumented();
- [[clang::xray_never_instrument]] void never_instrumented();
+[[clang::xray_never_instrument]] void never_instrumented();
- void alt_always_instrumented() __attribute__((xray_always_instrument));
+void alt_always_instrumented() __attribute__((xray_always_instrument));
- void alt_never_instrumented() __attribute__((xray_never_instrument));
+void alt_never_instrumented() __attribute__((xray_never_instrument));
+```
-When linking a binary, you can either manually link in the `XRay Runtime
-Library`_ or use ``clang`` to link it in automatically with the
-``-fxray-instrument`` flag. Alternatively, you can statically link-in the XRay
+When linking a binary, you can either manually link in the [XRay Runtime
+Library][xray runtime library] or use `clang` to link it in automatically with the
+`-fxray-instrument` flag. Alternatively, you can statically link-in the XRay
runtime library from compiler-rt -- those archive files will take the name of
`libclang_rt.xray-{arch}` where `{arch}` is the mnemonic supported by clang
(x86_64, arm7, etc.).
-LLVM Function Attribute
------------------------
+### LLVM Function Attribute
-If you're using LLVM IR directly, you can add the ``function-instrument``
+If you're using LLVM IR directly, you can add the `function-instrument`
string attribute to your functions, to get the similar effect that the
C/C++/Objective-C source-level attributes would get:
-.. code-block:: llvm
+```llvm
+define i32 @always_instrument() uwtable "function-instrument"="xray-always" {
+ ; ...
+}
- define i32 @always_instrument() uwtable "function-instrument"="xray-always" {
- ; ...
- }
+define i32 @never_instrument() uwtable "function-instrument"="xray-never" {
+ ; ...
+}
+```
- define i32 @never_instrument() uwtable "function-instrument"="xray-never" {
- ; ...
- }
-
-You can also set the ``xray-instruction-threshold`` attribute and provide a
+You can also set the `xray-instruction-threshold` attribute and provide a
numeric string value for how many instructions should be in the function before
it gets instrumented.
-.. code-block:: llvm
-
- define i32 @maybe_instrument() uwtable "xray-instruction-threshold"="2" {
- ; ...
- }
+```llvm
+define i32 @maybe_instrument() uwtable "xray-instruction-threshold"="2" {
+ ; ...
+}
+```
-Special Case File
------------------
+### Special Case File
Attributes can be imbued through the use of special case files instead of
adding them to the original source files. You can use this to mark certain
functions and classes to be never, always, or instrumented with first-argument
logging from a file. The file's format is described below:
-.. code-block:: bash
+```bash
+# Comments are supported
+[always]
+fun:always_instrument
+fun:log_arg1=arg1 # Log the first argument for the function
- # Comments are supported
- [always]
- fun:always_instrument
- fun:log_arg1=arg1 # Log the first argument for the function
+[never]
+fun:never_instrument
+```
- [never]
- fun:never_instrument
-
-These files can be provided through the ``-fxray-attr-list=`` flag to clang.
+These files can be provided through the `-fxray-attr-list=` flag to clang.
You may have multiple files loaded through multiple instances of the flag.
-XRay Runtime Library
---------------------
+### XRay Runtime Library
The XRay Runtime Library is part of the compiler-rt project, which implements
the runtime components that perform the patching and unpatching of inserted
-instrumentation points. When you use ``clang`` to link your binaries and the
-``-fxray-instrument`` flag, it will automatically link in the XRay runtime.
+instrumentation points. When you use `clang` to link your binaries and the
+`-fxray-instrument` flag, it will automatically link in the XRay runtime.
The default implementation of the XRay runtime will enable XRay instrumentation
-before ``main`` starts, which works for applications that have a short
+before `main` starts, which works for applications that have a short
lifetime. This implementation also records all function entry and exit events
which may result in a lot of records in the resulting trace.
-Also by default the filename of the XRay trace is ``xray-log.XXXXXX`` where the
-``XXXXXX`` part is randomly generated.
+Also by default the filename of the XRay trace is `xray-log.XXXXXX` where the
+`XXXXXX` part is randomly generated.
-These options can be controlled through the ``XRAY_OPTIONS`` environment
+These options can be controlled through the `XRAY_OPTIONS` environment
variable during program run-time, where we list down the options and their
defaults below.
-+-------------------+-----------------+---------------+------------------------+
-| Option | Type | Default | Description |
-+===================+=================+===============+========================+
-| patch_premain | ``bool`` | ``false`` | Whether to patch |
-| | | | instrumentation points |
-| | | | before main. |
-+-------------------+-----------------+---------------+------------------------+
-| xray_mode | ``const char*`` | ``""`` | Default mode to |
-| | | | install and initialize |
-| | | | before ``main``. |
-+-------------------+-----------------+---------------+------------------------+
-| xray_logfile_base | ``const char*`` | ``xray-log.`` | Filename base for the |
-| | | | XRay logfile. |
-+-------------------+-----------------+---------------+------------------------+
-| verbosity | ``int`` | ``0`` | Runtime verbosity |
-| | | | level. |
-+-------------------+-----------------+---------------+------------------------+
-
+| Option | Type | Default | Description |
+| ----------------- | ------------- | ----------- | ----------------------------------------------------- |
+| patch_premain | `bool` | `false` | Whether to patch instrumentation points before main. |
+| xray_mode | `const char*` | `""` | Default mode to install and initialize before `main`. |
+| xray_logfile_base | `const char*` | `xray-log.` | Filename base for the XRay logfile. |
+| verbosity | `int` | `0` | Runtime verbosity level. |
In addition to environment variable, you can also provide your own definition of
-``const char *__xray_default_options(void)`` function, which returns the option
+`const char *__xray_default_options(void)` function, which returns the option
strings. This method effectively provides default options during program build
-time. For example, you can create an additional source file (e.g. ``xray-opt.c``
-) with the following ``__xray_default_options`` definition:
+time. For example, you can create an additional source file (e.g. `xray-opt.c`
+) with the following `__xray_default_options` definition:
-.. code-block:: c
-
- __attribute__((xray_never_instrument))
- const char *__xray_default_options() {
- return "patch_premain=true,xray_mode=xray-basic";
- }
+```c
+__attribute__((xray_never_instrument))
+const char *__xray_default_options() {
+ return "patch_premain=true,xray_mode=xray-basic";
+}
+```
And link it with the program you want to instrument:
-::
-
- clang -fxray-instrument prog.c xray-opt.c ...
+```
+clang -fxray-instrument prog.c xray-opt.c ...
+```
The instrumented binary will use 'patch_premain=true,xray_mode=xray-basic' by
-default even without setting ``XRAY_OPTIONS``.
+default even without setting `XRAY_OPTIONS`.
-Note that you still can override options designated by ``__xray_default_options``
-using ``XRAY_OPTIONS`` during run-time.
+Note that you still can override options designated by `__xray_default_options`
+using `XRAY_OPTIONS` during run-time.
If you choose to not use the default logging implementation that comes with the
XRay runtime and/or control when/how the XRay instrumentation runs, you may use
the XRay APIs directly for doing so. To do this, you'll need to include the
-``xray_log_interface.h`` from the compiler-rt ``xray`` directory. The important API
+`xray_log_interface.h` from the compiler-rt `xray` directory. The important API
functions we list below:
-- ``__xray_log_register_mode(...)``: Register a logging implementation against
+- `__xray_log_register_mode(...)`: Register a logging implementation against
a string Mode identifier. The implementation is an instance of
- ``XRayLogImpl`` defined in ``xray/xray_log_interface.h``.
-- ``__xray_log_select_mode(...)``: Select the mode to install, associated with
+ `XRayLogImpl` defined in `xray/xray_log_interface.h`.
+- `__xray_log_select_mode(...)`: Select the mode to install, associated with
a string Mode identifier. Only implementations registered with
- ``__xray_log_register_mode(...)`` can be chosen with this function.
-- ``__xray_log_init_mode(...)``: This function allows for initializing and
+ `__xray_log_register_mode(...)` can be chosen with this function.
+- `__xray_log_init_mode(...)`: This function allows for initializing and
re-initializing an installed logging implementation. See
- ``xray/xray_log_interface.h`` for details, part of the XRay compiler-rt
+ `xray/xray_log_interface.h` for details, part of the XRay compiler-rt
installation.
Once a logging implementation has been initialized, it can be "stopped" by
-finalizing the implementation through the ``__xray_log_finalize()`` function.
+finalizing the implementation through the `__xray_log_finalize()` function.
The finalization routine is the opposite of the initialization. When finalized,
an implementation's data can be cleared out through the
-``__xray_log_flushLog()`` function. For implementations that support in-memory
+`__xray_log_flushLog()` function. For implementations that support in-memory
processing, these should register an iterator function to provide access to the
-data via the ``__xray_log_set_buffer_iterator(...)`` which allows code calling
-the ``__xray_log_process_buffers(...)`` function to deal with the data in
+data via the `__xray_log_set_buffer_iterator(...)` which allows code calling
+the `__xray_log_process_buffers(...)` function to deal with the data in
memory.
-All of this is better explained in the ``xray/xray_log_interface.h`` header.
+All of this is better explained in the `xray/xray_log_interface.h` header.
-Basic Mode
-----------
+### Basic Mode
XRay supports a basic logging mode which will trace the application's
execution, and periodically append to a single log. This mode can be
-installed/enabled by setting ``xray_mode=xray-basic`` in the ``XRAY_OPTIONS``
-environment variable. Combined with ``patch_premain=true`` this can allow for
+installed/enabled by setting `xray_mode=xray-basic` in the `XRAY_OPTIONS`
+environment variable. Combined with `patch_premain=true` this can allow for
tracing applications from start to end.
-Like all the other modes installed through ``__xray_log_select_mode(...)``, the
-implementation can be configured through the ``__xray_log_init_mode(...)``
+Like all the other modes installed through `__xray_log_select_mode(...)`, the
+implementation can be configured through the `__xray_log_init_mode(...)`
function, providing the mode string and the flag options. Basic-mode specific
-defaults can be provided in the ``XRAY_BASIC_OPTIONS`` environment variable.
+defaults can be provided in the `XRAY_BASIC_OPTIONS` environment variable.
-Flight Data Recorder Mode
--------------------------
+### Flight Data Recorder Mode
XRay supports a logging mode which allows the application to only capture a
fixed amount of memory's worth of events. Flight Data Recorder (FDR) mode works
very much like a plane's "black box" which keeps recording data to memory in a
fixed-size circular queue of buffers, and have the data available
programmatically until the buffers are finalized and flushed. To use FDR mode
-on your application, you may set the ``xray_mode`` variable to ``xray-fdr`` in
-the ``XRAY_OPTIONS`` environment variable. Additional options to the FDR mode
-implementation can be provided in the ``XRAY_FDR_OPTIONS`` environment
+on your application, you may set the `xray_mode` variable to `xray-fdr` in
+the `XRAY_OPTIONS` environment variable. Additional options to the FDR mode
+implementation can be provided in the `XRAY_FDR_OPTIONS` environment
variable. Programmatic configuration can be done by calling
-``__xray_log_init_mode("xray-fdr", <configuration string>)`` once it has been
+`__xray_log_init_mode("xray-fdr", <configuration string>)` once it has been
selected/installed.
When the buffers are flushed to disk, the result is a binary trace format
-described by `XRay FDR format <XRayFDRFormat.html>`_
+described by [XRay FDR format](XRayFDRFormat.html)
When FDR mode is on, it will keep writing and recycling memory buffers until
the logging implementation is finalized -- at which point it can be flushed and
re-initialised later. To do this programmatically, we follow the workflow
provided below:
-.. code-block:: c++
+```c++
+// Patch the sleds, if we haven't yet.
+auto patch_status = __xray_patch();
- // Patch the sleds, if we haven't yet.
- auto patch_status = __xray_patch();
+// Maybe handle the patch_status errors.
- // Maybe handle the patch_status errors.
+// When we want to flush the log, we need to finalize it first, to give
+// threads a chance to return buffers to the queue.
+auto finalize_status = __xray_log_finalize();
+if (finalize_status != XRAY_LOG_FINALIZED) {
+ // maybe retry, or bail out.
+}
- // When we want to flush the log, we need to finalize it first, to give
- // threads a chance to return buffers to the queue.
- auto finalize_status = __xray_log_finalize();
- if (finalize_status != XRAY_LOG_FINALIZED) {
- // maybe retry, or bail out.
- }
-
- // At this point, we are sure that the log is finalized, so we may try
- // flushing the log.
- auto flush_status = __xray_log_flushLog();
- if (flush_status != XRAY_LOG_FLUSHED) {
- // maybe retry, or bail out.
- }
+// At this point, we are sure that the log is finalized, so we may try
+// flushing the log.
+auto flush_status = __xray_log_flushLog();
+if (flush_status != XRAY_LOG_FLUSHED) {
+ // maybe retry, or bail out.
+}
+```
The default settings for the FDR mode implementation will create logs named
similarly to the basic log implementation, but will have a different log
@@ -295,85 +274,80 @@ format. All the trace analysis tools (and the trace reading library) will
support all versions of the FDR mode format as we add more functionality and
record types in the future.
- **NOTE:** We do not promise perpetual support for when we update the log
- versions we support going forward. Deprecation of the formats will be
- announced and discussed on the developers mailing list.
+> **NOTE:** We do not promise perpetual support for when we update the log
+> versions we support going forward. Deprecation of the formats will be
+> announced and discussed on the developers mailing list.
-Trace Analysis Tools
---------------------
+### Trace Analysis Tools
We currently have the beginnings of a trace analysis tool in LLVM, which can be
-found in the ``tools/llvm-xray`` directory. The ``llvm-xray`` tool currently
+found in the `tools/llvm-xray` directory. The `llvm-xray` tool currently
supports the following subcommands:
-- ``extract``: Extract the instrumentation map from a binary, and return it as
+- `extract`: Extract the instrumentation map from a binary, and return it as
YAML.
-- ``account``: Performs basic function call accounting statistics with various
+- `account`: Performs basic function call accounting statistics with various
options for sorting, and output formats (supports CSV, YAML, and
console-friendly TEXT).
-- ``convert``: Converts an XRay log file from one format to another. We can
+- `convert`: Converts an XRay log file from one format to another. We can
convert from binary XRay traces (both basic and FDR mode) to YAML,
- `flame-graph <https://github.com/brendangregg/FlameGraph>`_ friendly text
+ [flame-graph](https://github.com/brendangregg/FlameGraph) friendly text
formats, as well as `Chrome Trace Viewer (catapult)
<https://github.com/catapult-project/catapult>` formats.
-- ``graph``: Generates a DOT graph of the function call relationships between
+- `graph`: Generates a DOT graph of the function call relationships between
functions found in an XRay trace.
-- ``stack``: Reconstructs function call stacks from a timeline of function
+- `stack`: Reconstructs function call stacks from a timeline of function
calls in an XRay trace.
These subcommands use various library components found as part of the XRay
libraries, distributed with the LLVM distribution. These are:
-- ``llvm/XRay/Trace.h`` : A trace reading library for conveniently loading
+- `llvm/XRay/Trace.h` : A trace reading library for conveniently loading
an XRay trace of supported forms, into a convenient in-memory representation.
All the analysis tools that deal with traces use this implementation.
-- ``llvm/XRay/Graph.h`` : A semi-generic graph type used by the graph
+- `llvm/XRay/Graph.h` : A semi-generic graph type used by the graph
subcommand to conveniently represent a function call graph with statistics
associated with edges and vertices.
-- ``llvm/XRay/InstrumentationMap.h``: A convenient tool for analyzing the
+- `llvm/XRay/InstrumentationMap.h`: A convenient tool for analyzing the
instrumentation map in XRay-instrumented object files and binaries. The
- ``extract`` and ``stack`` subcommands uses this particular library.
-
+ `extract` and `stack` subcommands uses this particular library.
-Minimizing Binary Size
-----------------------
+### Minimizing Binary Size
-XRay supports several different instrumentation points including ``function-entry``,
-``function-exit``, ``custom``, and ``typed`` points. These can be enabled individually
-using the ``-fxray-instrumentation-bundle=`` flag. For example if you only wanted to
+XRay supports several different instrumentation points including `function-entry`,
+`function-exit`, `custom`, and `typed` points. These can be enabled individually
+using the `-fxray-instrumentation-bundle=` flag. For example if you only wanted to
instrument function entry and custom points you could specify:
-::
-
- clang -fxray-instrument -fxray-instrumentation-bundle=function-entry,custom ...
+```
+clang -fxray-instrument -fxray-instrumentation-bundle=function-entry,custom ...
+```
This will omit the other sled types entirely, reducing the binary size. You can also
instrument just a sampled subset of functions using instrumentation groups.
For example, to instrument only a quarter of available functions invoke:
-::
-
- clang -fxray-instrument -fxray-function-groups=4
+```
+clang -fxray-instrument -fxray-function-groups=4
+```
A subset will be chosen arbitrarily based on a hash of the function name. To sample a
-different subset you can specify ``-fxray-selected-function-group=`` with a group number
-in the range of 0 to ``xray-function-groups`` - 1. Together these options could be used
+different subset you can specify `-fxray-selected-function-group=` with a group number
+in the range of 0 to `xray-function-groups` - 1. Together these options could be used
to produce multiple binaries with different instrumented subsets. If all you need is
runtime control over which functions are being traced at any given time it is better
to selectively patch and unpatch the individual functions you need using the XRay
-Runtime Library's ``__xray_patch_function()`` method.
+Runtime Library's `__xray_patch_function()` method.
-Future Work
-===========
+## Future Work
There are a number of ongoing efforts for expanding the toolset building around
the XRay instrumentation system.
-Trace Analysis Tools
---------------------
+### Trace Analysis Tools
- Work is in progress to integrate with or develop tools to visualize findings
- from an XRay trace. Particularly, the ``stack`` tool is being expanded to
+ from an XRay trace. Particularly, the `stack` tool is being expanded to
output formats that allow graphing and exploring the duration of time in each
call stack.
- With a large instrumented binary, the size of generated XRay traces can
@@ -381,13 +355,12 @@ Trace Analysis Tools
heuristics for the analysis tools to sift through the traces and surface only
relevant information.
-More Platforms
---------------
+### More Platforms
We're looking forward to contributions to port XRay to more architectures and
operating systems.
-.. References...
+% References...
-.. _`XRay whitepaper`: http://research.google.com/pubs/pub45287.html
+[xray whitepaper]: http://research.google.com/pubs/pub45287.html
diff --git a/llvm/docs/XRayExample.md b/llvm/docs/XRayExample.md
index ccb02b359d7c3..dc2d591eda85e 100644
--- a/llvm/docs/XRayExample.md
+++ b/llvm/docs/XRayExample.md
@@ -1,171 +1,160 @@
-===================
-Debugging with XRay
-===================
+# Debugging with XRay
This document shows an example of how you would go about analyzing applications
-built with XRay instrumentation. Here we will attempt to debug ``llc``
+built with XRay instrumentation. Here we will attempt to debug `llc`
compiling some sample LLVM IR generated by Clang.
-
-Building with XRay
-------------------
+## Building with XRay
To debug an application with XRay instrumentation, we need to build it with a
-Clang that supports the ``-fxray-instrument`` option. See `XRay <XRay.html>`_
+Clang that supports the `-fxray-instrument` option. See [XRay](XRay.html)
for more technical details of how XRay works for background information.
-In our example, we need to add ``-fxray-instrument`` to the list of flags
+In our example, we need to add `-fxray-instrument` to the list of flags
passed to Clang when building a binary. Note that we need to link with Clang as
-well to get the XRay runtime linked in appropriately. For building ``llc`` with
+well to get the XRay runtime linked in appropriately. For building `llc` with
XRay, we do something similar below for our LLVM build:
-::
-
- $ mkdir -p llvm-build && cd llvm-build
- # Assume that the LLVM sources are at ../llvm
- $ cmake -GNinja ../llvm -DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_C_FLAGS_RELEASE="-fxray-instrument" -DCMAKE_CXX_FLAGS="-fxray-instrument" \
- # Once this finishes, we should build llc
- $ ninja llc
-
-
-To verify that we have an XRay instrumented binary, we can use ``objdump`` to
-look for the ``xray_instr_map`` section.
+```
+$ mkdir -p llvm-build && cd llvm-build
+# Assume that the LLVM sources are at ../llvm
+$ cmake -GNinja ../llvm -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_C_FLAGS_RELEASE="-fxray-instrument" -DCMAKE_CXX_FLAGS="-fxray-instrument" \
+# Once this finishes, we should build llc
+$ ninja llc
+```
-::
+To verify that we have an XRay instrumented binary, we can use `objdump` to
+look for the `xray_instr_map` section.
- $ objdump -h -j xray_instr_map ./bin/llc
- ./bin/llc: file format elf64-x86-64
+```
+$ objdump -h -j xray_instr_map ./bin/llc
+./bin/llc: file format elf64-x86-64
- Sections:
- Idx Name Size VMA LMA File off Algn
- 14 xray_instr_map 00002fc0 00000000041516c6 00000000041516c6 03d516c6 2**0
- CONTENTS, ALLOC, LOAD, READONLY, DATA
+Sections:
+Idx Name Size VMA LMA File off Algn
+ 14 xray_instr_map 00002fc0 00000000041516c6 00000000041516c6 03d516c6 2**0
+ CONTENTS, ALLOC, LOAD, READONLY, DATA
+```
-Getting Traces
---------------
+## Getting Traces
By default, XRay does not write out the trace files or patch the application
-before main starts. If we run ``llc`` it should work like a normally built
+before main starts. If we run `llc` it should work like a normally built
binary. If we want to get a full trace of the application's operations (of the
functions we do end up instrumenting with XRay) then we need to enable XRay
-at application start. To do this, XRay checks the ``XRAY_OPTIONS`` environment
+at application start. To do this, XRay checks the `XRAY_OPTIONS` environment
variable.
-::
+```
+# The following doesn't create an XRay trace by default.
+$ ./bin/llc input.ll
- # The following doesn't create an XRay trace by default.
- $ ./bin/llc input.ll
-
- # We need to set the XRAY_OPTIONS to enable some features.
- $ XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic verbosity=1" ./bin/llc input.ll
- ==69819==XRay: Log file in 'xray-log.llc.m35qPB'
+# We need to set the XRAY_OPTIONS to enable some features.
+$ XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic verbosity=1" ./bin/llc input.ll
+==69819==XRay: Log file in 'xray-log.llc.m35qPB'
+```
At this point we now have an XRay trace we can start analysing.
-The ``llvm-xray`` Tool
-----------------------
+## The `llvm-xray` Tool
Having a trace then allows us to do basic accounting of the functions that were
instrumented, and how much time we're spending in parts of the code. To make
-sense of this data, we use the ``llvm-xray`` tool which has a few subcommands
+sense of this data, we use the `llvm-xray` tool which has a few subcommands
to help us understand our trace.
One of the things we can do is to get an accounting of the functions that have
-been instrumented. We can see an example accounting with ``llvm-xray account``:
-
-::
-
- $ llvm-xray account xray-log.llc.m35qPB --top=10 --sort=sum --sortorder=dsc --instr_map=./bin/llc
- Functions with latencies: 29
- funcid count [ min, med, 90p, 99p, max] sum function
- 187 360 [ 0.000000, 0.000001, 0.000014, 0.000032, 0.000075] 0.001596 LLLexer.cpp:446:0: llvm::LLLexer::LexIdentifier()
- 85 130 [ 0.000000, 0.000000, 0.000018, 0.000023, 0.000156] 0.000799 X86ISelDAGToDAG.cpp:1984:0: (anonymous namespace)::X86DAGToDAGISel::Select(llvm::SDNode*)
- 138 130 [ 0.000000, 0.000000, 0.000017, 0.000155, 0.000155] 0.000774 SelectionDAGISel.cpp:2963:0: llvm::SelectionDAGISel::SelectCodeCommon(llvm::SDNode*, unsigned char const*, unsigned int)
- 188 103 [ 0.000000, 0.000000, 0.000003, 0.000123, 0.000214] 0.000737 LLParser.cpp:2692:0: llvm::LLParser::ParseValID(llvm::ValID&, llvm::LLParser::PerFunctionState*)
- 88 1 [ 0.000562, 0.000562, 0.000562, 0.000562, 0.000562] 0.000562 X86ISelLowering.cpp:83:0: llvm::X86TargetLowering::X86TargetLowering(llvm::X86TargetMachine const&, llvm::X86Subtarget const&)
- 125 102 [ 0.000001, 0.000003, 0.000010, 0.000017, 0.000049] 0.000471 Verifier.cpp:3714:0: (anonymous namespace)::Verifier::visitInstruction(llvm::Instruction&)
- 90 8 [ 0.000023, 0.000035, 0.000106, 0.000106, 0.000106] 0.000342 X86ISelLowering.cpp:3363:0: llvm::X86TargetLowering::LowerCall(llvm::TargetLowering::CallLoweringInfo&, llvm::SmallVectorImpl<llvm::SDValue>&) const
- 124 32 [ 0.000003, 0.000007, 0.000016, 0.000041, 0.000041] 0.000310 Verifier.cpp:1967:0: (anonymous namespace)::Verifier::visitFunction(llvm::Function const&)
- 123 1 [ 0.000302, 0.000302, 0.000302, 0.000302, 0.000302] 0.000302 LLVMContextImpl.cpp:54:0: llvm::LLVMContextImpl::~LLVMContextImpl()
- 139 46 [ 0.000000, 0.000002, 0.000006, 0.000008, 0.000019] 0.000138 TargetLowering.cpp:506:0: llvm::TargetLowering::SimplifyDemandedBits(llvm::SDValue, llvm::APInt const&, llvm::APInt&, llvm::APInt&, llvm::TargetLowering::TargetLoweringOpt&, unsigned int, bool) const
-
-This shows us that for our input file, ``llc`` spent the most cumulative time
+been instrumented. We can see an example accounting with `llvm-xray account`:
+
+```
+$ llvm-xray account xray-log.llc.m35qPB --top=10 --sort=sum --sortorder=dsc --instr_map=./bin/llc
+Functions with latencies: 29
+ funcid count [ min, med, 90p, 99p, max] sum function
+ 187 360 [ 0.000000, 0.000001, 0.000014, 0.000032, 0.000075] 0.001596 LLLexer.cpp:446:0: llvm::LLLexer::LexIdentifier()
+ 85 130 [ 0.000000, 0.000000, 0.000018, 0.000023, 0.000156] 0.000799 X86ISelDAGToDAG.cpp:1984:0: (anonymous namespace)::X86DAGToDAGISel::Select(llvm::SDNode*)
+ 138 130 [ 0.000000, 0.000000, 0.000017, 0.000155, 0.000155] 0.000774 SelectionDAGISel.cpp:2963:0: llvm::SelectionDAGISel::SelectCodeCommon(llvm::SDNode*, unsigned char const*, unsigned int)
+ 188 103 [ 0.000000, 0.000000, 0.000003, 0.000123, 0.000214] 0.000737 LLParser.cpp:2692:0: llvm::LLParser::ParseValID(llvm::ValID&, llvm::LLParser::PerFunctionState*)
+ 88 1 [ 0.000562, 0.000562, 0.000562, 0.000562, 0.000562] 0.000562 X86ISelLowering.cpp:83:0: llvm::X86TargetLowering::X86TargetLowering(llvm::X86TargetMachine const&, llvm::X86Subtarget const&)
+ 125 102 [ 0.000001, 0.000003, 0.000010, 0.000017, 0.000049] 0.000471 Verifier.cpp:3714:0: (anonymous namespace)::Verifier::visitInstruction(llvm::Instruction&)
+ 90 8 [ 0.000023, 0.000035, 0.000106, 0.000106, 0.000106] 0.000342 X86ISelLowering.cpp:3363:0: llvm::X86TargetLowering::LowerCall(llvm::TargetLowering::CallLoweringInfo&, llvm::SmallVectorImpl<llvm::SDValue>&) const
+ 124 32 [ 0.000003, 0.000007, 0.000016, 0.000041, 0.000041] 0.000310 Verifier.cpp:1967:0: (anonymous namespace)::Verifier::visitFunction(llvm::Function const&)
+ 123 1 [ 0.000302, 0.000302, 0.000302, 0.000302, 0.000302] 0.000302 LLVMContextImpl.cpp:54:0: llvm::LLVMContextImpl::~LLVMContextImpl()
+ 139 46 [ 0.000000, 0.000002, 0.000006, 0.000008, 0.000019] 0.000138 TargetLowering.cpp:506:0: llvm::TargetLowering::SimplifyDemandedBits(llvm::SDValue, llvm::APInt const&, llvm::APInt&, llvm::APInt&, llvm::TargetLowering::TargetLoweringOpt&, unsigned int, bool) const
+```
+
+This shows us that for our input file, `llc` spent the most cumulative time
in the lexer (a total of 1 millisecond). If we wanted for example to work with
this data in a spreadsheet, we can output the results as CSV using the
-``-format=csv`` option to the command for further analysis.
+`-format=csv` option to the command for further analysis.
If we want to get a textual representation of the raw trace we can use the
-``llvm-xray convert`` tool to get YAML output. The first few lines of that
+`llvm-xray convert` tool to get YAML output. The first few lines of that
output for an example trace would look like the following:
-::
-
- $ llvm-xray convert -f yaml --symbolize --instr_map=./bin/llc xray-log.llc.m35qPB
- ---
- header:
- version: 1
- type: 0
- constant-tsc: true
- nonstop-tsc: true
- cycle-frequency: 2601000000
- records:
- - { type: 0, func-id: 110, function: __cxx_global_var_init.8, cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426023268520 }
- - { type: 0, func-id: 110, function: __cxx_global_var_init.8, cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426023523052 }
- - { type: 0, func-id: 164, function: __cxx_global_var_init, cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426029925386 }
- - { type: 0, func-id: 164, function: __cxx_global_var_init, cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426030031128 }
- - { type: 0, func-id: 142, function: '(anonymous namespace)::CommandLineParser::ParseCommandLineOptions(int, char const* const*, llvm::StringRef, llvm::raw_ostream*)', cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426046951388 }
- - { type: 0, func-id: 142, function: '(anonymous namespace)::CommandLineParser::ParseCommandLineOptions(int, char const* const*, llvm::StringRef, llvm::raw_ostream*)', cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426047282020 }
- - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426047857332 }
- - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426047984152 }
- - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426048036584 }
- - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426048042292 }
- - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426048055056 }
- - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426048067316 }
-
-Controlling Fidelity
---------------------
+```
+$ llvm-xray convert -f yaml --symbolize --instr_map=./bin/llc xray-log.llc.m35qPB
+---
+header:
+ version: 1
+ type: 0
+ constant-tsc: true
+ nonstop-tsc: true
+ cycle-frequency: 2601000000
+records:
+ - { type: 0, func-id: 110, function: __cxx_global_var_init.8, cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426023268520 }
+ - { type: 0, func-id: 110, function: __cxx_global_var_init.8, cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426023523052 }
+ - { type: 0, func-id: 164, function: __cxx_global_var_init, cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426029925386 }
+ - { type: 0, func-id: 164, function: __cxx_global_var_init, cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426030031128 }
+ - { type: 0, func-id: 142, function: '(anonymous namespace)::CommandLineParser::ParseCommandLineOptions(int, char const* const*, llvm::StringRef, llvm::raw_ostream*)', cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426046951388 }
+ - { type: 0, func-id: 142, function: '(anonymous namespace)::CommandLineParser::ParseCommandLineOptions(int, char const* const*, llvm::StringRef, llvm::raw_ostream*)', cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426047282020 }
+ - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426047857332 }
+ - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426047984152 }
+ - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426048036584 }
+ - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426048042292 }
+ - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-enter, tsc: 5434426048055056 }
+ - { type: 0, func-id: 187, function: 'llvm::LLLexer::LexIdentifier()', cpu: 37, thread: 69819, kind: function-exit, tsc: 5434426048067316 }
+```
+
+## Controlling Fidelity
So far in our examples, we haven't been getting full coverage of the functions
we have in the binary. To get that, we need to modify the compiler flags so
that we can instrument more (if not all) the functions we have in the binary.
We have two options for doing that, and we explore both of these below.
-Instruction Threshold
-`````````````````````
+### Instruction Threshold
The first "blunt" way of doing this is by setting the minimum threshold for
function bodies to 1. We can do that with the
-``-fxray-instruction-threshold=N`` flag when building our binary. We rebuild
-``llc`` with this option and observe the results:
-
-::
-
- $ rm CMakeCache.txt
- $ cmake -GNinja ../llvm -DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_C_FLAGS_RELEASE="-fxray-instrument -fxray-instruction-threshold=1" \
- -DCMAKE_CXX_FLAGS="-fxray-instrument -fxray-instruction-threshold=1"
- $ ninja llc
- $ XRAY_OPTIONS="patch_premain=true" ./bin/llc input.ll
- ==69819==XRay: Log file in 'xray-log.llc.5rqxkU'
-
- $ llvm-xray account xray-log.llc.5rqxkU --top=10 --sort=sum --sortorder=dsc --instr_map=./bin/llc
- Functions with latencies: 36652
- funcid count [ min, med, 90p, 99p, max] sum function
- 75 1 [ 0.672368, 0.672368, 0.672368, 0.672368, 0.672368] 0.672368 llc.cpp:271:0: main
- 78 1 [ 0.626455, 0.626455, 0.626455, 0.626455, 0.626455] 0.626455 llc.cpp:381:0: compileModule(char**, llvm::LLVMContext&)
- 139617 1 [ 0.472618, 0.472618, 0.472618, 0.472618, 0.472618] 0.472618 LegacyPassManager.cpp:1723:0: llvm::legacy::PassManager::run(llvm::Module&)
- 139610 1 [ 0.472618, 0.472618, 0.472618, 0.472618, 0.472618] 0.472618 LegacyPassManager.cpp:1681:0: llvm::legacy::PassManagerImpl::run(llvm::Module&)
- 139612 1 [ 0.470948, 0.470948, 0.470948, 0.470948, 0.470948] 0.470948 LegacyPassManager.cpp:1564:0: (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&)
- 139607 2 [ 0.147345, 0.315994, 0.315994, 0.315994, 0.315994] 0.463340 LegacyPassManager.cpp:1530:0: llvm::FPPassManager::runOnModule(llvm::Module&)
- 139605 21 [ 0.000002, 0.000002, 0.102593, 0.213336, 0.213336] 0.463331 LegacyPassManager.cpp:1491:0: llvm::FPPassManager::runOnFunction(llvm::Function&)
- 139563 26096 [ 0.000002, 0.000002, 0.000037, 0.000063, 0.000215] 0.225708 LegacyPassManager.cpp:1083:0: llvm::PMDataManager::findAnalysisPass(void const*, bool)
- 108055 188 [ 0.000002, 0.000120, 0.001375, 0.004523, 0.062624] 0.159279 MachineFunctionPass.cpp:38:0: llvm::MachineFunctionPass::runOnFunction(llvm::Function&)
- 62635 22 [ 0.000041, 0.000046, 0.000050, 0.126744, 0.126744] 0.127715 X86TargetMachine.cpp:242:0: llvm::X86TargetMachine::getSubtargetImpl(llvm::Function const&) const
-
-
-Instrumentation Attributes
-``````````````````````````
+`-fxray-instruction-threshold=N` flag when building our binary. We rebuild
+`llc` with this option and observe the results:
+
+```
+$ rm CMakeCache.txt
+$ cmake -GNinja ../llvm -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_C_FLAGS_RELEASE="-fxray-instrument -fxray-instruction-threshold=1" \
+ -DCMAKE_CXX_FLAGS="-fxray-instrument -fxray-instruction-threshold=1"
+$ ninja llc
+$ XRAY_OPTIONS="patch_premain=true" ./bin/llc input.ll
+==69819==XRay: Log file in 'xray-log.llc.5rqxkU'
+
+$ llvm-xray account xray-log.llc.5rqxkU --top=10 --sort=sum --sortorder=dsc --instr_map=./bin/llc
+Functions with latencies: 36652
+ funcid count [ min, med, 90p, 99p, max] sum function
+ 75 1 [ 0.672368, 0.672368, 0.672368, 0.672368, 0.672368] 0.672368 llc.cpp:271:0: main
+ 78 1 [ 0.626455, 0.626455, 0.626455, 0.626455, 0.626455] 0.626455 llc.cpp:381:0: compileModule(char**, llvm::LLVMContext&)
+ 139617 1 [ 0.472618, 0.472618, 0.472618, 0.472618, 0.472618] 0.472618 LegacyPassManager.cpp:1723:0: llvm::legacy::PassManager::run(llvm::Module&)
+ 139610 1 [ 0.472618, 0.472618, 0.472618, 0.472618, 0.472618] 0.472618 LegacyPassManager.cpp:1681:0: llvm::legacy::PassManagerImpl::run(llvm::Module&)
+ 139612 1 [ 0.470948, 0.470948, 0.470948, 0.470948, 0.470948] 0.470948 LegacyPassManager.cpp:1564:0: (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&)
+ 139607 2 [ 0.147345, 0.315994, 0.315994, 0.315994, 0.315994] 0.463340 LegacyPassManager.cpp:1530:0: llvm::FPPassManager::runOnModule(llvm::Module&)
+ 139605 21 [ 0.000002, 0.000002, 0.102593, 0.213336, 0.213336] 0.463331 LegacyPassManager.cpp:1491:0: llvm::FPPassManager::runOnFunction(llvm::Function&)
+ 139563 26096 [ 0.000002, 0.000002, 0.000037, 0.000063, 0.000215] 0.225708 LegacyPassManager.cpp:1083:0: llvm::PMDataManager::findAnalysisPass(void const*, bool)
+ 108055 188 [ 0.000002, 0.000120, 0.001375, 0.004523, 0.062624] 0.159279 MachineFunctionPass.cpp:38:0: llvm::MachineFunctionPass::runOnFunction(llvm::Function&)
+ 62635 22 [ 0.000041, 0.000046, 0.000050, 0.126744, 0.126744] 0.127715 X86TargetMachine.cpp:242:0: llvm::X86TargetMachine::getSubtargetImpl(llvm::Function const&) const
+```
+
+### Instrumentation Attributes
The other way is to use configuration files for selecting which functions
should always be instrumented by the compiler. This gives us a way of ensuring
@@ -177,169 +166,163 @@ instrument, and another for functions to never instrument. The format of these
files are exactly the same as the SanitizerLists files that control similar
things for the sanitizer implementations. For example:
-::
+```
+# xray-attr-list.txt
+# always instrument functions that match the following filters:
+[always]
+fun:main
- # xray-attr-list.txt
- # always instrument functions that match the following filters:
- [always]
- fun:main
-
- # never instrument functions that match the following filters:
- [never]
- fun:__cxx_*
+# never instrument functions that match the following filters:
+[never]
+fun:__cxx_*
+```
Given the file above we can re-build by providing it to the
-``-fxray-attr-list=`` flag to clang. You can have multiple files, each defining
+`-fxray-attr-list=` flag to clang. You can have multiple files, each defining
different sets of attribute sets, to be combined into a single list by clang.
-The XRay stack tool
--------------------
+## The XRay stack tool
-Given a trace, and optionally an instrumentation map, the ``llvm-xray stack``
+Given a trace, and optionally an instrumentation map, the `llvm-xray stack`
command can be used to analyze a call stack graph constructed from the function
call timeline.
The way to use the command is to output the top stacks by call count and time spent.
-::
-
- $ llvm-xray stack xray-log.llc.5rqxkU --instr_map=./bin/llc
+```
+$ llvm-xray stack xray-log.llc.5rqxkU --instr_map=./bin/llc
- Unique Stacks: 3069
- Top 10 Stacks by leaf sum:
+Unique Stacks: 3069
+Top 10 Stacks by leaf sum:
- Sum: 9633790
- lvl function count sum
- #0 main 1 58421550
- #1 compileModule(char**, llvm::LLVMContext&) 1 51440360
- #2 llvm::legacy::PassManagerImpl::run(llvm::Module&) 1 40535375
- #3 llvm::FPPassManager::runOnModule(llvm::Module&) 2 39337525
- #4 llvm::FPPassManager::runOnFunction(llvm::Function&) 6 39331465
- #5 llvm::PMDataManager::verifyPreservedAnalysis(llvm::Pass*) 399 16628590
- #6 llvm::PMTopLevelManager::findAnalysisPass(void const*) 4584 15155600
- #7 llvm::PMDataManager::findAnalysisPass(void const*, bool) 32088 9633790
+Sum: 9633790
+lvl function count sum
+#0 main 1 58421550
+#1 compileModule(char**, llvm::LLVMContext&) 1 51440360
+#2 llvm::legacy::PassManagerImpl::run(llvm::Module&) 1 40535375
+#3 llvm::FPPassManager::runOnModule(llvm::Module&) 2 39337525
+#4 llvm::FPPassManager::runOnFunction(llvm::Function&) 6 39331465
+#5 llvm::PMDataManager::verifyPreservedAnalysis(llvm::Pass*) 399 16628590
+#6 llvm::PMTopLevelManager::findAnalysisPass(void const*) 4584 15155600
+#7 llvm::PMDataManager::findAnalysisPass(void const*, bool) 32088 9633790
- ..etc..
+..etc..
+```
In the default mode, identical stacks on different threads are independently
aggregated. In a multithreaded program, you may end up having identical call
stacks fill your list of top calls.
-To address this, you may specify the ``--aggregate-threads`` or
-``--per-thread-stacks`` flags. ``--per-thread-stacks`` treats the thread id as an
-implicit root in each call stack tree, while ``--aggregate-threads`` combines
+To address this, you may specify the `--aggregate-threads` or
+`--per-thread-stacks` flags. `--per-thread-stacks` treats the thread id as an
+implicit root in each call stack tree, while `--aggregate-threads` combines
identical stacks from all threads.
-Flame Graph Generation
-----------------------
+## Flame Graph Generation
-The ``llvm-xray stack`` tool may also be used to generate flamegraphs for
+The `llvm-xray stack` tool may also be used to generate flamegraphs for
visualizing your instrumented invocations. The tool does not generate the graphs
themselves, but instead generates a format that can be used with Brendan Gregg's
-FlameGraph tool, currently available on `github
-<https://github.com/brendangregg/FlameGraph>`_.
+FlameGraph tool, currently available on [github](https://github.com/brendangregg/FlameGraph).
To generate output for a flamegraph, a few more options are necessary.
-- ``--all-stacks`` - Emits all of the stacks.
-- ``--stack-format`` - Choose the flamegraph output format 'flame'.
-- ``--aggregation-type`` - Choose the metric to graph.
+- `--all-stacks` - Emits all of the stacks.
+- `--stack-format` - Choose the flamegraph output format 'flame'.
+- `--aggregation-type` - Choose the metric to graph.
You may pipe the command output directly to the flamegraph tool to obtain an
svg file.
-::
-
- $ llvm-xray stack xray-log.llc.5rqxkU --instr_map=./bin/llc --stack-format=flame --aggregation-type=time --all-stacks | \
- /path/to/FlameGraph/flamegraph.pl > flamegraph.svg
+```
+$ llvm-xray stack xray-log.llc.5rqxkU --instr_map=./bin/llc --stack-format=flame --aggregation-type=time --all-stacks | \
+/path/to/FlameGraph/flamegraph.pl > flamegraph.svg
+```
If you open the svg in a browser, mouse events allow exploring the call stacks.
-Chrome Trace Viewer Visualization
----------------------------------
+## Chrome Trace Viewer Visualization
We can also generate a trace which can be loaded by the Chrome Trace Viewer
from the same generated trace:
-::
+```
+$ llvm-xray convert --symbolize --instr_map=./bin/llc \
+ --output-format=trace_event xray-log.llc.5rqxkU \
+ | gzip > llc-trace.txt.gz
+```
- $ llvm-xray convert --symbolize --instr_map=./bin/llc \
- --output-format=trace_event xray-log.llc.5rqxkU \
- | gzip > llc-trace.txt.gz
+From a Chrome browser, navigating to `chrome:///tracing` allows us to load
+the `sample-trace.txt.gz` file to visualize the execution trace.
-From a Chrome browser, navigating to ``chrome:///tracing`` allows us to load
-the ``sample-trace.txt.gz`` file to visualize the execution trace.
+## Further Exploration
-Further Exploration
--------------------
-
-The ``llvm-xray`` tool has a few other subcommands that are in various stages
+The `llvm-xray` tool has a few other subcommands that are in various stages
of being developed. One interesting subcommand that can highlight a few
-interesting things is the ``graph`` subcommand. Given for example the following
+interesting things is the `graph` subcommand. Given for example the following
toy program that we build with XRay instrumentation, we can see how the
generated graph may be a helpful indicator of where time is being spent for the
application.
-.. code-block:: c++
-
- // sample.cc
- #include <iostream>
- #include <thread>
-
- [[clang::xray_always_instrument]] void f() {
- std::cerr << '.';
- }
+```c++
+// sample.cc
+#include <iostream>
+#include <thread>
- [[clang::xray_always_instrument]] void g() {
- for (int i = 0; i < 1 << 10; ++i) {
- std::cerr << '-';
- }
- }
+[[clang::xray_always_instrument]] void f() {
+ std::cerr << '.';
+}
- int main(int argc, char* argv[]) {
- std::thread t1([] {
- for (int i = 0; i < 1 << 10; ++i)
- f();
- });
- std::thread t2([] {
- g();
- });
- t1.join();
- t2.join();
- std::cerr << '\n';
+[[clang::xray_always_instrument]] void g() {
+ for (int i = 0; i < 1 << 10; ++i) {
+ std::cerr << '-';
}
+}
+
+int main(int argc, char* argv[]) {
+ std::thread t1([] {
+ for (int i = 0; i < 1 << 10; ++i)
+ f();
+ });
+ std::thread t2([] {
+ g();
+ });
+ t1.join();
+ t2.join();
+ std::cerr << '\n';
+}
+```
We then build the above with XRay instrumentation:
-::
-
- $ clang++ -o sample -O3 sample.cc -std=c++11 -fxray-instrument -fxray-instruction-threshold=1
- $ XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic" ./sample
+```
+$ clang++ -o sample -O3 sample.cc -std=c++11 -fxray-instrument -fxray-instruction-threshold=1
+$ XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic" ./sample
+```
We can then explore the graph rendering of the trace generated by this sample
application. We assume you have the graphviz tools available in your system,
-including both ``unflatten`` and ``dot``. If you prefer rendering or exploring
-the graph using another tool, then that should be feasible as well. ``llvm-xray
-graph`` will create DOT format graphs which should be usable in most graph
-rendering applications. One example invocation of the ``llvm-xray graph``
+including both `unflatten` and `dot`. If you prefer rendering or exploring
+the graph using another tool, then that should be feasible as well. `llvm-xray
+graph` will create DOT format graphs which should be usable in most graph
+rendering applications. One example invocation of the `llvm-xray graph`
command should yield some interesting insights to the workings of C++
applications:
-::
+```
+$ llvm-xray graph xray-log.sample.* -m sample --color-edges=sum --edge-label=sum \
+ | unflatten -f -l10 | dot -Tsvg -o sample.svg
+```
- $ llvm-xray graph xray-log.sample.* -m sample --color-edges=sum --edge-label=sum \
- | unflatten -f -l10 | dot -Tsvg -o sample.svg
-
-
-Next Steps
-----------
+## Next Steps
If you have some interesting analyses you'd like to implement as part of the
llvm-xray tool, please feel free to propose them on the llvm-dev@ mailing list.
The following are some ideas to inspire you in getting involved and potentially
making things better.
- - Implement a query/filtering library that allows for finding patterns in the
- XRay traces.
- - Collecting function call stacks and how often they're encountered in the
- XRay trace.
+> - Implement a query/filtering library that allows for finding patterns in the
+> XRay traces.
+> - Collecting function call stacks and how often they're encountered in the
+> XRay trace.
+
diff --git a/llvm/docs/XRayFDRFormat.md b/llvm/docs/XRayFDRFormat.md
index 86048b78096cf..19005b5a4aca7 100644
--- a/llvm/docs/XRayFDRFormat.md
+++ b/llvm/docs/XRayFDRFormat.md
@@ -1,13 +1,10 @@
-======================================
-XRay Flight Data Recorder Trace Format
-======================================
+---
+Version: 1 as of 2017-07-20
+---
-:Version: 1 as of 2017-07-20
+# XRay Flight Data Recorder Trace Format
-
-
-Introduction
-============
+## Introduction
When gathering XRay traces in Flight Data Recorder mode, each thread of an
application will claim buffers to fill with trace data, which at some point
@@ -18,9 +15,7 @@ corresponds to the buffer.
This document describes the format of a trace file.
-
-General
-=======
+## General
Each trace file corresponds to a sequence of events in a particular thread.
@@ -29,57 +24,28 @@ The file has a header followed by a sequence of discriminated record types.
The endianness of byte fields matches the endianness of the platform which
produced the trace file.
-
-Header Section
-==============
+## Header Section
A trace file begins with a 32-byte header.
-+-------------------+-----------------+----------------------------------------+
-| Field | Size (bytes) | Description |
-+===================+=================+========================================+
-| version | ``2`` | Anticipates versioned readers. This |
-| | | document describes the format when |
-| | | version == 1 |
-+-------------------+-----------------+----------------------------------------+
-| type | ``2`` | An enumeration encoding the type of |
-| | | trace. Flight Data Recorder mode |
-| | | traces have type == 1 |
-+-------------------+-----------------+----------------------------------------+
-| bitfield | ``4`` | Holds parameters that are not aligned |
-| | | to bytes. Further described below. |
-+-------------------+-----------------+----------------------------------------+
-| cycle_frequency | ``8`` | The frequency in hertz of the CPU |
-| | | oscillator used to measure duration of |
-| | | events in ticks. |
-+-------------------+-----------------+----------------------------------------+
-| buffer_size | ``8`` | The size in bytes of the data portion |
-| | | of the trace following the header. |
-+-------------------+-----------------+----------------------------------------+
-| reserved | ``8`` | Reserved for future use. |
-+-------------------+-----------------+----------------------------------------+
+| Field | Size (bytes) | Description |
+| --------------- | ------------ | ------------------------------------------------------------------------------------------ |
+| version | `2` | Anticipates versioned readers. This document describes the format when version == 1 |
+| type | `2` | An enumeration encoding the type of trace. Flight Data Recorder mode traces have type == 1 |
+| bitfield | `4` | Holds parameters that are not aligned to bytes. Further described below. |
+| cycle_frequency | `8` | The frequency in hertz of the CPU oscillator used to measure duration of events in ticks. |
+| buffer_size | `8` | The size in bytes of the data portion of the trace following the header. |
+| reserved | `8` | Reserved for future use. |
The bitfield parameter of the file header is composed of the following fields.
-+-------------------+----------------+-----------------------------------------+
-| Field | Size (bits) | Description |
-+===================+================+=========================================+
-| constant_tsc | ``1`` | Whether the platform's timestamp |
-| | | counter used to record ticks between |
-| | | events ticks at a constant frequency |
-| | | despite CPU frequency changes. |
-| | | 0 == non-constant. 1 == constant. |
-+-------------------+----------------+-----------------------------------------+
-| nonstop_tsc | ``1`` | Whether the tsc continues to count |
-| | | despite whether the CPU is in a low |
-| | | power state. 0 == stop. 1 == non-stop. |
-+-------------------+----------------+-----------------------------------------+
-| reserved | ``30`` | Not meaningful. |
-+-------------------+----------------+-----------------------------------------+
-
-
-Data Section
-============
+| Field | Size (bits) | Description |
+| ------------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| constant_tsc | `1` | Whether the platform's timestamp counter used to record ticks between events ticks at a constant frequency despite CPU frequency changes. 0 == non-constant. 1 == constant. |
+| nonstop_tsc | `1` | Whether the tsc continues to count despite whether the CPU is in a low power state. 0 == stop. 1 == non-stop. |
+| reserved | `30` | Not meaningful. |
+
+## Data Section
Following the header in a trace is a data section with size matching the
buffer_size field in the header.
@@ -88,20 +54,17 @@ The data section is a stream of elements of different types.
There are a few categories of data in the sequence.
-- ``Function Records``: Function Records contain the timing of entry into and
+- `Function Records`: Function Records contain the timing of entry into and
exit from function execution. Function Records have 8 bytes each.
-
-- ``Metadata Records``: Metadata records serve many purposes. Mostly, they
+- `Metadata Records`: Metadata records serve many purposes. Mostly, they
capture information that may be too costly to record for each function, but
that is required to contextualize the fine-grained timings. They also are used
as markers for user-defined Event Data payloads. Metadata records have 16
bytes each.
-
-- ``Event Data``: Free form data may be associated with events that are traced
+- `Event Data`: Free form data may be associated with events that are traced
by the binary and encode data defined by a handler function. Event data is
always preceded with a marker record which indicates how large it is.
-
-- ``Function Arguments``: The arguments to some functions are included in the
+- `Function Arguments`: The arguments to some functions are included in the
trace. These are either pointer addresses or primitives that are read and
logged independently of their types in a high level language. To the tracer,
they are all numbers. Function Records that have attached arguments will
@@ -113,68 +76,41 @@ There are a few categories of data in the sequence.
A reader of the memory format must maintain a state machine. The format makes no
attempt to pad for alignment, and it is not seekable.
-
-Function Records
-----------------
+### Function Records
Function Records have an 8-byte layout. This layout encodes information to
reconstruct a call stack of instrumented function and their durations.
-+---------------+--------------+-----------------------------------------------+
-| Field | Size (bits) | Description |
-+===============+==============+===============================================+
-| discriminant | ``1`` | Indicates whether a reader should read a |
-| | | Function or Metadata record. Set to ``0`` for |
-| | | Function records. |
-+---------------+--------------+-----------------------------------------------+
-| action | ``3`` | Specifies whether the function is being |
-| | | entered, exited, or is a non-standard entry |
-| | | or exit produced by optimizations. |
-+---------------+--------------+-----------------------------------------------+
-| function_id | ``28`` | A numeric ID for the function. Resolved to a |
-| | | name via the xray instrumentation map. The |
-| | | instrumentation map is built by xray at |
-| | | compile time into an object file and pairs |
-| | | the function ids to addresses. It is used for |
-| | | patching and as a lookup into the binary's |
-| | | symbols to obtain names. |
-+---------------+--------------+-----------------------------------------------+
-| tsc_delta | ``32`` | The number of ticks of the timestamp counter |
-| | | since a previous record recorded a delta or |
-| | | other TSC resetting event. |
-+---------------+--------------+-----------------------------------------------+
+| Field | Size (bits) | Description |
+| ------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| discriminant | `1` | Indicates whether a reader should read a Function or Metadata record. Set to `0` for Function records. |
+| action | `3` | Specifies whether the function is being entered, exited, or is a non-standard entry or exit produced by optimizations. |
+| function_id | `28` | A numeric ID for the function. Resolved to a name via the xray instrumentation map. The instrumentation map is built by xray at compile time into an object file and pairs the function ids to addresses. It is used for patching and as a lookup into the binary's symbols to obtain names. |
+| tsc_delta | `32` | The number of ticks of the timestamp counter since a previous record recorded a delta or other TSC resetting event. |
On little-endian machines, the bitfields are ordered from least significant bit
bit to most significant bit. A reader can read an 8-bit value and apply the mask
-``0x01`` for the discriminant. Similarly, they can read 32 bits and unsigned
-shift right by ``0x04`` to obtain the function_id field.
+`0x01` for the discriminant. Similarly, they can read 32 bits and unsigned
+shift right by `0x04` to obtain the function_id field.
On big-endian machine, the bitfields are written in order from most significant
bit to least significant bit. A reader would read an 8-bit value and unsigned
shift right by 7 bits for the discriminant. The function_id field could be
-obtained by reading a 32-bit value and applying the mask ``0x0FFFFFFF``.
+obtained by reading a 32-bit value and applying the mask `0x0FFFFFFF`.
Function action types are as follows.
-+---------------+--------------+-----------------------------------------------+
-| Type | Number | Description |
-+===============+==============+===============================================+
-| Entry | ``0`` | Typical function entry. |
-+---------------+--------------+-----------------------------------------------+
-| Exit | ``1`` | Typical function exit. |
-+---------------+--------------+-----------------------------------------------+
-| Tail_Exit | ``2`` | An exit from a function due to tail call |
-| | | optimization. |
-+---------------+--------------+-----------------------------------------------+
-| Entry_Args | ``3`` | A function entry that records arguments. |
-+---------------+--------------+-----------------------------------------------+
+| Type | Number | Description |
+| ---------- | ------ | ------------------------------------------------------ |
+| Entry | `0` | Typical function entry. |
+| Exit | `1` | Typical function exit. |
+| Tail_Exit | `2` | An exit from a function due to tail call optimization. |
+| Entry_Args | `3` | A function entry that records arguments. |
Entry_Args records do not contain the arguments themselves. Instead, metadata
records for each of the logged args follow the function record in the stream.
-
-Metadata Records
-----------------
+### Metadata Records
Interspersed throughout the buffer are 16-byte Metadata records. For typically
instrumented binaries, they will be sparser than Function records, and they
@@ -187,81 +123,50 @@ The same bit field rules described for function records apply to the first byte
of MetadataRecords. Within this byte, little endian machines use lsb to msb
ordering and big endian machines use msb to lsb ordering.
-+---------------+--------------+-----------------------------------------------+
-| Field | Size | Description |
-+===============+==============+===============================================+
-| discriminant | ``1 bit`` | Indicates whether a reader should read a |
-| | | Function or Metadata record. Set to ``1`` for |
-| | | Metadata records. |
-+---------------+--------------+-----------------------------------------------+
-| record_kind | ``7 bits`` | The type of Metadata record. |
-+---------------+--------------+-----------------------------------------------+
-| data | ``15 bytes`` | A data field used differently for each record |
-| | | type. |
-+---------------+--------------+-----------------------------------------------+
+| Field | Size | Description |
+| ------------ | ---------- | ------------------------------------------------------------------------------------------------------ |
+| discriminant | `1 bit` | Indicates whether a reader should read a Function or Metadata record. Set to `1` for Metadata records. |
+| record_kind | `7 bits` | The type of Metadata record. |
+| data | `15 bytes` | A data field used differently for each record type. |
Here is a table of the enumerated record kinds.
-+--------+---------------------------+
-| Number | Type |
-+========+===========================+
-| 0 | NewBuffer |
-+--------+---------------------------+
-| 1 | EndOfBuffer |
-+--------+---------------------------+
-| 2 | NewCPUId |
-+--------+---------------------------+
-| 3 | TSCWrap |
-+--------+---------------------------+
-| 4 | WallTimeMarker |
-+--------+---------------------------+
-| 5 | CustomEventMarker |
-+--------+---------------------------+
-| 6 | CallArgument |
-+--------+---------------------------+
-
-
-NewBuffer Records
------------------
+| Number | Type |
+| ------ | ----------------- |
+| 0 | NewBuffer |
+| 1 | EndOfBuffer |
+| 2 | NewCPUId |
+| 3 | TSCWrap |
+| 4 | WallTimeMarker |
+| 5 | CustomEventMarker |
+| 6 | CallArgument |
+
+### NewBuffer Records
Each buffer begins with a NewBuffer record immediately after the header.
It records the thread ID of the thread that the trace belongs to.
Its data segment is as follows.
-+---------------+--------------+-----------------------------------------------+
-| Field | Size (bytes) | Description |
-+===============+==============+===============================================+
-| thread_Id | ``2`` | Thread ID for buffer. |
-+---------------+--------------+-----------------------------------------------+
-| reserved | ``13`` | Unused. |
-+---------------+--------------+-----------------------------------------------+
+| Field | Size (bytes) | Description |
+| --------- | ------------ | --------------------- |
+| thread_Id | `2` | Thread ID for buffer. |
+| reserved | `13` | Unused. |
-
-WallClockTime Records
----------------------
+### WallClockTime Records
Following the NewBuffer record, each buffer records an absolute time as a frame
of reference for the durations recorded by timestamp counter deltas.
Its data segment is as follows.
-+---------------+--------------+-----------------------------------------------+
-| Field | Size (bytes) | Description |
-+===============+==============+===============================================+
-| seconds | ``8`` | Seconds on absolute timescale. The starting |
-| | | point is unspecified and depends on the |
-| | | implementation and platform configured by the |
-| | | tracer. |
-+---------------+--------------+-----------------------------------------------+
-| microseconds | ``4`` | The microsecond component of the time. |
-+---------------+--------------+-----------------------------------------------+
-| reserved | ``3`` | Unused. |
-+---------------+--------------+-----------------------------------------------+
-
+| Field | Size (bytes) | Description |
+| ------------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
+| seconds | `8` | Seconds on absolute timescale. The starting point is unspecified and depends on the implementation and platform configured by the tracer. |
+| microseconds | `4` | The microsecond component of the time. |
+| reserved | `3` | Unused. |
-NewCpuId Records
-----------------
+### NewCpuId Records
Each function entry invokes a routine to determine what CPU is executing.
Typically, this is done with readtscp, which reads the timestamp counter at the
@@ -272,19 +177,13 @@ first instrumented entry point, the tracer will output a NewCpuId record.
Its data segment is as follows.
-+---------------+--------------+-----------------------------------------------+
-| Field | Size (bytes) | Description |
-+===============+==============+===============================================+
-| cpu_id | ``2`` | CPU Id. |
-+---------------+--------------+-----------------------------------------------+
-| absolute_tsc | ``8`` | The absolute value of the timestamp counter. |
-+---------------+--------------+-----------------------------------------------+
-| reserved | ``5`` | Unused. |
-+---------------+--------------+-----------------------------------------------+
-
+| Field | Size (bytes) | Description |
+| ------------ | ------------ | -------------------------------------------- |
+| cpu_id | `2` | CPU Id. |
+| absolute_tsc | `8` | The absolute value of the timestamp counter. |
+| reserved | `5` | Unused. |
-TSCWrap Records
----------------
+### TSCWrap Records
Since each function record uses a 32-bit value to represent the number of ticks
of the timestamp counter since the last reference, it is possible for this value
@@ -295,17 +194,12 @@ timestamp counter record is written in the form of a TSCWrap record.
Its data segment is as follows.
-+---------------+--------------+-----------------------------------------------+
-| Field | Size (bytes) | Description |
-+===============+==============+===============================================+
-| absolute_tsc | ``8`` | Timestamp counter value. |
-+---------------+--------------+-----------------------------------------------+
-| reserved | ``7`` | Unused. |
-+---------------+--------------+-----------------------------------------------+
+| Field | Size (bytes) | Description |
+| ------------ | ------------ | ------------------------ |
+| absolute_tsc | `8` | Timestamp counter value. |
+| reserved | `7` | Unused. |
-
-CallArgument Records
---------------------
+### CallArgument Records
Immediately following an Entry_Args type function record, there may be one or
more CallArgument records that contain the traced function's parameter values.
@@ -315,17 +209,12 @@ order of the function parameters.
CallArgument data segment:
-+---------------+--------------+-----------------------------------------------+
-| Field | Size (bytes) | Description |
-+===============+==============+===============================================+
-| argument | ``8`` | Numeric argument (may be pointer address). |
-+---------------+--------------+-----------------------------------------------+
-| reserved | ``7`` | Unused. |
-+---------------+--------------+-----------------------------------------------+
-
+| Field | Size (bytes) | Description |
+| -------- | ------------ | ------------------------------------------ |
+| argument | `8` | Numeric argument (may be pointer address). |
+| reserved | `7` | Unused. |
-CustomEventMarker Records
--------------------------
+### CustomEventMarker Records
XRay provides the feature of logging custom events. This may be leveraged to
record tracing info for RPCs or similarly trace data that is application
@@ -337,27 +226,19 @@ CustomEventMarkers to indicate their presence and size.
CustomEventMarker data segment:
-+---------------+--------------+-----------------------------------------------+
-| Field | Size (bytes) | Description |
-+===============+==============+===============================================+
-| event_size | ``4`` | Size of preceded event. |
-+---------------+--------------+-----------------------------------------------+
-| absolute_tsc | ``8`` | A timestamp counter of the event. |
-+---------------+--------------+-----------------------------------------------+
-| reserved | ``3`` | Unused. |
-+---------------+--------------+-----------------------------------------------+
+| Field | Size (bytes) | Description |
+| ------------ | ------------ | --------------------------------- |
+| event_size | `4` | Size of preceded event. |
+| absolute_tsc | `8` | A timestamp counter of the event. |
+| reserved | `3` | Unused. |
-
-EndOfBuffer Records
--------------------
+### EndOfBuffer Records
An EndOfBuffer record type indicates that there is no more trace data in this
buffer. The reader is expected to seek past the remaining buffer_size expressed
before the start of buffer and look for either another header or EOF.
-
-Format Grammar and Invariants
-=============================
+## Format Grammar and Invariants
Not all sequences of Metadata records and Function records are valid data. A
sequence should be parsed as a state machine. The expectations for a valid
@@ -365,35 +246,26 @@ format can be expressed as a context free grammar.
This is an attempt to explain the format with statements in EBNF format.
-- Format := Header ThreadBuffer* EOF
-
-- ThreadBuffer := NewBuffer WallClockTime NewCPUId BodySequence* End
-
+- Format := Header ThreadBuffer\* EOF
+- ThreadBuffer := NewBuffer WallClockTime NewCPUId BodySequence\* End
- BodySequence := NewCPUId | TSCWrap | Function | CustomEvent
-
-- Function := (Function_Entry_Args CallArgument*) | Function_Other_Type
-
+- Function := (Function_Entry_Args CallArgument\*) | Function_Other_Type
- CustomEvent := CustomEventMarker CustomEventUnstructuredMemory
-
- End := EndOfBuffer RemainingBufferSizeToSkip
-
-Function Record Order
----------------------
+### Function Record Order
There are a few clarifications that may help understand what is expected of
Function records.
- Functions with an Exit are expected to have a corresponding Entry or
Entry_Args function record precede them in the trace.
-
- Tail_Exit Function records record the Function ID of the function whose return
address the program counter will take. In other words, the final function that
would be popped off of the call stack if tail call optimization was not used.
-
- Not all functions marked for instrumentation are necessarily in the trace. The
tracer uses heuristics to preserve the trace for non-trivial functions.
-
- Not every entry must have a traced Exit or Tail Exit. The buffer may run out
of space or the program may request for the tracer to finalize toreturn the
buffer before an instrumented function exits.
+
diff --git a/llvm/docs/YamlIO.md b/llvm/docs/YamlIO.md
index a5f7069ac1d40..77ca63550e0df 100644
--- a/llvm/docs/YamlIO.md
+++ b/llvm/docs/YamlIO.md
@@ -1,71 +1,63 @@
-=====================
-YAML I/O
-=====================
+# YAML I/O
+## Introduction to YAML
-Introduction to YAML
-====================
+YAML is a human-readable data serialization language. The full YAML language
+spec can be read at [yaml.org](http://www.yaml.org/spec/1.2/spec.html#Introduction). The simplest form of
+YAML is just "scalars", "mappings", and "sequences". A scalar is any number
+or string. The pound/hash symbol (`#`) begins a comment line. A mapping is
+a set of key-value pairs where the key ends with a colon. For example:
-YAML is a human-readable data serialization language. The full YAML language
-spec can be read at `yaml.org
-<http://www.yaml.org/spec/1.2/spec.html#Introduction>`_. The simplest form of
-YAML is just "scalars", "mappings", and "sequences". A scalar is any number
-or string. The pound/hash symbol (``#``) begins a comment line. A mapping is
-a set of key-value pairs where the key ends with a colon. For example:
+```yaml
+# a mapping
+name: Tom
+hat-size: 7
+```
-.. code-block:: yaml
-
- # a mapping
- name: Tom
- hat-size: 7
-
-A sequence is a list of items where each item starts with a leading dash (``-``).
+A sequence is a list of items where each item starts with a leading dash (`-`).
For example:
-.. code-block:: yaml
-
- # a sequence
- - x86
- - x86_64
- - PowerPC
+```yaml
+# a sequence
+- x86
+- x86_64
+- PowerPC
+```
-You can combine mappings and sequences by indenting. For example a sequence
+You can combine mappings and sequences by indenting. For example a sequence
of mappings in which one of the mapping values is itself a sequence:
-.. code-block:: yaml
-
- # a sequence of mappings with one key's value being a sequence
- - name: Tom
- cpus:
- - x86
- - x86_64
- - name: Bob
- cpus:
- - x86
- - name: Dan
- cpus:
- - PowerPC
- - x86
+```yaml
+# a sequence of mappings with one key's value being a sequence
+- name: Tom
+ cpus:
+ - x86
+ - x86_64
+- name: Bob
+ cpus:
+ - x86
+- name: Dan
+ cpus:
+ - PowerPC
+ - x86
+```
Sometimes sequences are known to be short and the one entry per line is too
verbose, so YAML offers an alternative syntax for sequences called a "Flow
Sequence" in which you put comma separated sequence elements into square
-brackets. The above example could then be simplified to:
-
-
-.. code-block:: yaml
-
- # a sequence of mappings with one key's value being a flow sequence
- - name: Tom
- cpus: [ x86, x86_64 ]
- - name: Bob
- cpus: [ x86 ]
- - name: Dan
- cpus: [ PowerPC, x86 ]
+brackets. The above example could then be simplified to:
+```yaml
+# a sequence of mappings with one key's value being a flow sequence
+- name: Tom
+ cpus: [ x86, x86_64 ]
+- name: Bob
+ cpus: [ x86 ]
+- name: Dan
+ cpus: [ PowerPC, x86 ]
+```
-Introduction to YAML I/O
-========================
+## Introduction to YAML I/O
The use of indenting makes the YAML easy for a human to read and understand,
but having a program read and write YAML involves a lot of tedious details.
@@ -73,987 +65,952 @@ The YAML I/O library structures and simplifies reading and writing YAML
documents.
YAML I/O assumes you have some "native" data structures which you want to be
-able to dump as YAML and recreate from YAML. The first step is to try
+able to dump as YAML and recreate from YAML. The first step is to try
writing example YAML for your data structures. You may find after looking at
possible YAML representations that a direct mapping of your data structures
-to YAML is not very readable. Often, the fields are not in an order that
-a human would find readable. Or the same information is replicated in multiple
+to YAML is not very readable. Often, the fields are not in an order that
+a human would find readable. Or the same information is replicated in multiple
locations, making it hard for a human to write such YAML correctly.
In relational database theory there is a design step called normalization in
-which you reorganize fields and tables. The same considerations need to
-go into the design of your YAML encoding. But, you may not want to change
-your existing native data structures. Therefore, when writing out YAML,
+which you reorganize fields and tables. The same considerations need to
+go into the design of your YAML encoding. But, you may not want to change
+your existing native data structures. Therefore, when writing out YAML,
there may be a normalization step, and when reading YAML there would be a
corresponding denormalization step.
-YAML I/O uses a non-invasive, traits-based design. YAML I/O defines some
-abstract base templates. You specialize those templates on your data types.
-For instance, if you have an enumerated type ``FooBar`` you could specialize
-``ScalarEnumerationTraits`` on that type and define the ``enumeration()`` method:
+YAML I/O uses a non-invasive, traits-based design. YAML I/O defines some
+abstract base templates. You specialize those templates on your data types.
+For instance, if you have an enumerated type `FooBar` you could specialize
+`ScalarEnumerationTraits` on that type and define the `enumeration()` method:
-.. code-block:: c++
+```c++
+using llvm::yaml::ScalarEnumerationTraits;
+using llvm::yaml::IO;
- using llvm::yaml::ScalarEnumerationTraits;
- using llvm::yaml::IO;
+template <>
+struct ScalarEnumerationTraits<FooBar> {
+ static void enumeration(IO &io, FooBar &value) {
+ ...
+ }
+};
+```
- template <>
- struct ScalarEnumerationTraits<FooBar> {
- static void enumeration(IO &io, FooBar &value) {
- ...
- }
- };
-
-
-As with all YAML I/O template specializations, the ``ScalarEnumerationTraits`` is used for
+As with all YAML I/O template specializations, the `ScalarEnumerationTraits` is used for
both reading and writing YAML. That is, the mapping between in-memory enum
values and the YAML string representation is only in one place.
This assures that the code for writing and parsing of YAML stays in sync.
To specify YAML mappings, you define a specialization on
-``llvm::yaml::MappingTraits``.
+`llvm::yaml::MappingTraits`.
If your native data structure happens to be a struct that is already normalized,
-then the specialization is simple. For example:
-
-.. code-block:: c++
+then the specialization is simple. For example:
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
+```c++
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
- template <>
- struct MappingTraits<Person> {
- static void mapping(IO &io, Person &info) {
- io.mapRequired("name", info.name);
- io.mapOptional("hat-size", info.hatSize);
- }
- };
+template <>
+struct MappingTraits<Person> {
+ static void mapping(IO &io, Person &info) {
+ io.mapRequired("name", info.name);
+ io.mapOptional("hat-size", info.hatSize);
+ }
+};
+```
-
-A YAML sequence is automatically inferred if your data type has ``begin()``/``end()``
-iterators and a ``push_back()`` method. Therefore any of the STL containers
-(such as ``std::vector<>``) will automatically translate to YAML sequences.
+A YAML sequence is automatically inferred if your data type has `begin()`/`end()`
+iterators and a `push_back()` method. Therefore any of the STL containers
+(such as `std::vector<>`) will automatically translate to YAML sequences.
Once you have defined specializations for your data types, you can
programmatically use YAML I/O to write a YAML document:
-.. code-block:: c++
-
- using llvm::yaml::Output;
+```c++
+using llvm::yaml::Output;
- Person tom;
- tom.name = "Tom";
- tom.hatSize = 8;
- Person dan;
- dan.name = "Dan";
- dan.hatSize = 7;
- std::vector<Person> persons;
- persons.push_back(tom);
- persons.push_back(dan);
+Person tom;
+tom.name = "Tom";
+tom.hatSize = 8;
+Person dan;
+dan.name = "Dan";
+dan.hatSize = 7;
+std::vector<Person> persons;
+persons.push_back(tom);
+persons.push_back(dan);
- Output yout(llvm::outs());
- yout << persons;
+Output yout(llvm::outs());
+yout << persons;
+```
This would write the following:
-.. code-block:: yaml
-
- - name: Tom
- hat-size: 8
- - name: Dan
- hat-size: 7
+```yaml
+- name: Tom
+ hat-size: 8
+- name: Dan
+ hat-size: 7
+```
And you can also read such YAML documents with the following code:
-.. code-block:: c++
-
- using llvm::yaml::Input;
+```c++
+using llvm::yaml::Input;
- typedef std::vector<Person> PersonList;
- std::vector<PersonList> docs;
+typedef std::vector<Person> PersonList;
+std::vector<PersonList> docs;
- Input yin(document.getBuffer());
- yin >> docs;
+Input yin(document.getBuffer());
+yin >> docs;
- if ( yin.error() )
- return;
+if ( yin.error() )
+ return;
- // Process read document
- for ( PersonList &pl : docs ) {
- for ( Person &person : pl ) {
- cout << "name=" << person.name;
- }
- }
+// Process read document
+for ( PersonList &pl : docs ) {
+ for ( Person &person : pl ) {
+ cout << "name=" << person.name;
+ }
+}
+```
One other feature of YAML is the ability to define multiple documents in a
-single file. That is why reading YAML produces a vector of your document type.
-
-
+single file. That is why reading YAML produces a vector of your document type.
-Error Handling
-==============
+## Error Handling
When parsing a YAML document, if the input does not match your schema (as
-expressed in your ``XxxTraits<>`` specializations). YAML I/O
-will print out an error message and your Input object's ``error()`` method will
+expressed in your `XxxTraits<>` specializations). YAML I/O
+will print out an error message and your Input object's `error()` method will
return true. For instance, the following document:
-.. code-block:: yaml
+```yaml
+- name: Tom
+ shoe-size: 12
+- name: Dan
+ hat-size: 7
+```
- - name: Tom
- shoe-size: 12
- - name: Dan
- hat-size: 7
-
-Has a key (shoe-size) that is not defined in the schema. YAML I/O will
+Has a key (shoe-size) that is not defined in the schema. YAML I/O will
automatically generate this error:
-.. code-block:: yaml
-
- YAML:2:2: error: unknown key 'shoe-size'
- shoe-size: 12
- ^~~~~~~~~
+```yaml
+YAML:2:2: error: unknown key 'shoe-size'
+ shoe-size: 12
+ ^~~~~~~~~
+```
Similar errors are produced for other input not conforming to the schema.
+## Scalars
-Scalars
-=======
-
-YAML scalars are just strings (i.e., not a sequence or mapping). The YAML I/O
+YAML scalars are just strings (i.e., not a sequence or mapping). The YAML I/O
library provides support for translating between YAML scalars and specific
C++ types.
+### Built-in types
-Built-in types
---------------
The following types have built-in support in YAML I/O:
-* ``bool``
-* ``float``
-* ``double``
-* ``StringRef``
-* ``std::string``
-* ``int64_t``
-* ``int32_t``
-* ``int16_t``
-* ``int8_t``
-* ``uint64_t``
-* ``uint32_t``
-* ``uint16_t``
-* ``uint8_t``
-
-That is, you can use those types in fields of ``MappingTraits`` or as the element type
-in a sequence. When reading, YAML I/O will validate that the string found
+- `bool`
+- `float`
+- `double`
+- `StringRef`
+- `std::string`
+- `int64_t`
+- `int32_t`
+- `int16_t`
+- `int8_t`
+- `uint64_t`
+- `uint32_t`
+- `uint16_t`
+- `uint8_t`
+
+That is, you can use those types in fields of `MappingTraits` or as the element type
+in a sequence. When reading, YAML I/O will validate that the string found
is convertible to that type and error out if not.
+### Unique types
-Unique types
-------------
Given that YAML I/O is trait based, the selection of how to convert your data
-to YAML is based on the type of your data. But in C++ type matching, typedefs
-do not generate unique type names. That means if you have two typedefs of
-unsigned int, to YAML I/O both types look exactly like unsigned int. To
+to YAML is based on the type of your data. But in C++ type matching, typedefs
+do not generate unique type names. That means if you have two typedefs of
+unsigned int, to YAML I/O both types look exactly like unsigned int. To
facilitate making unique type names, YAML I/O provides a macro which is used
like a typedef on built-in types, but expands to create a class with conversion
-operators to and from the base type. For example:
+operators to and from the base type. For example:
-.. code-block:: c++
+```c++
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyFooFlags)
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyBarFlags)
+```
- LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyFooFlags)
- LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyBarFlags)
-
-This generates two classes ``MyFooFlags`` and ``MyBarFlags`` which you can use in your
-native data structures instead of ``uint32_t``. They are implicitly
-converted to and from ``uint32_t``. The point of creating these unique types
+This generates two classes `MyFooFlags` and `MyBarFlags` which you can use in your
+native data structures instead of `uint32_t`. They are implicitly
+converted to and from `uint32_t`. The point of creating these unique types
is that you can now specify traits on them to get different YAML conversions.
-Hex types
----------
+### Hex types
+
An example use of a unique type is that YAML I/O provides fixed-sized unsigned
integers that are written with YAML I/O as hexadecimal instead of the decimal
format used by the built-in integer types:
-* ``Hex64``
-* ``Hex32``
-* ``Hex16``
-* ``Hex8``
+- `Hex64`
+- `Hex32`
+- `Hex16`
+- `Hex8`
-You can use ``llvm::yaml::Hex32`` instead of ``uint32_t``. The only difference will
+You can use `llvm::yaml::Hex32` instead of `uint32_t`. The only difference will
be that when YAML I/O writes out that type it will be formatted in hexadecimal.
+### ScalarEnumerationTraits
-ScalarEnumerationTraits
------------------------
YAML I/O supports translating between in-memory enumerations and a set of string
-values in YAML documents. This is done by specializing ``ScalarEnumerationTraits<>``
-on your enumeration type and defining an ``enumeration()`` method.
+values in YAML documents. This is done by specializing `ScalarEnumerationTraits<>`
+on your enumeration type and defining an `enumeration()` method.
For instance, suppose you had an enumeration of CPUs and a struct with it as
a field:
-.. code-block:: c++
+```c++
+enum CPUs {
+ cpu_x86_64 = 5,
+ cpu_x86 = 7,
+ cpu_PowerPC = 8
+};
- enum CPUs {
- cpu_x86_64 = 5,
- cpu_x86 = 7,
- cpu_PowerPC = 8
- };
-
- struct Info {
- CPUs cpu;
- uint32_t flags;
- };
+struct Info {
+ CPUs cpu;
+ uint32_t flags;
+};
+```
To support reading and writing of this enumeration, you can define a
-``ScalarEnumerationTraits`` specialization on CPUs, which can then be used
+`ScalarEnumerationTraits` specialization on CPUs, which can then be used
as a field type:
-.. code-block:: c++
-
- using llvm::yaml::ScalarEnumerationTraits;
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
-
- template <>
- struct ScalarEnumerationTraits<CPUs> {
- static void enumeration(IO &io, CPUs &value) {
- io.enumCase(value, "x86_64", cpu_x86_64);
- io.enumCase(value, "x86", cpu_x86);
- io.enumCase(value, "PowerPC", cpu_PowerPC);
- }
- };
-
- template <>
- struct MappingTraits<Info> {
- static void mapping(IO &io, Info &info) {
- io.mapRequired("cpu", info.cpu);
- io.mapOptional("flags", info.flags, 0);
- }
- };
+```c++
+using llvm::yaml::ScalarEnumerationTraits;
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
+
+template <>
+struct ScalarEnumerationTraits<CPUs> {
+ static void enumeration(IO &io, CPUs &value) {
+ io.enumCase(value, "x86_64", cpu_x86_64);
+ io.enumCase(value, "x86", cpu_x86);
+ io.enumCase(value, "PowerPC", cpu_PowerPC);
+ }
+};
+
+template <>
+struct MappingTraits<Info> {
+ static void mapping(IO &io, Info &info) {
+ io.mapRequired("cpu", info.cpu);
+ io.mapOptional("flags", info.flags, 0);
+ }
+};
+```
When reading YAML, if the string found does not match any of the strings
-specified by ``enumCase()`` methods, an error is automatically generated.
+specified by `enumCase()` methods, an error is automatically generated.
When writing YAML, if the value being written does not match any of the values
-specified by the ``enumCase()`` methods, a runtime assertion is triggered.
+specified by the `enumCase()` methods, a runtime assertion is triggered.
+### BitValue
-BitValue
---------
Another common data structure in C++ is a field where each bit has a unique
-meaning. This is often used in a "flags" field. YAML I/O has support for
-converting such fields to a flow sequence. For instance suppose you
+meaning. This is often used in a "flags" field. YAML I/O has support for
+converting such fields to a flow sequence. For instance suppose you
had the following bit flags defined:
-.. code-block:: c++
-
- enum {
- flagsPointy = 1
- flagsHollow = 2
- flagsFlat = 4
- flagsRound = 8
- };
-
- LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyFlags)
-
-To support reading and writing of ``MyFlags``, you specialize ``ScalarBitSetTraits<>``
-on ``MyFlags`` and provide the bit values and their names.
-
-.. code-block:: c++
-
- using llvm::yaml::ScalarBitSetTraits;
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
-
- template <>
- struct ScalarBitSetTraits<MyFlags> {
- static void bitset(IO &io, MyFlags &value) {
- io.bitSetCase(value, "hollow", flagHollow);
- io.bitSetCase(value, "flat", flagFlat);
- io.bitSetCase(value, "round", flagRound);
- io.bitSetCase(value, "pointy", flagPointy);
- }
- };
-
- struct Info {
- StringRef name;
- MyFlags flags;
- };
-
- template <>
- struct MappingTraits<Info> {
- static void mapping(IO &io, Info& info) {
- io.mapRequired("name", info.name);
- io.mapRequired("flags", info.flags);
- }
- };
+```c++
+enum {
+ flagsPointy = 1
+ flagsHollow = 2
+ flagsFlat = 4
+ flagsRound = 8
+};
+
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, MyFlags)
+```
+
+To support reading and writing of `MyFlags`, you specialize `ScalarBitSetTraits<>`
+on `MyFlags` and provide the bit values and their names.
+
+```c++
+using llvm::yaml::ScalarBitSetTraits;
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
+
+template <>
+struct ScalarBitSetTraits<MyFlags> {
+ static void bitset(IO &io, MyFlags &value) {
+ io.bitSetCase(value, "hollow", flagHollow);
+ io.bitSetCase(value, "flat", flagFlat);
+ io.bitSetCase(value, "round", flagRound);
+ io.bitSetCase(value, "pointy", flagPointy);
+ }
+};
+
+struct Info {
+ StringRef name;
+ MyFlags flags;
+};
+
+template <>
+struct MappingTraits<Info> {
+ static void mapping(IO &io, Info& info) {
+ io.mapRequired("name", info.name);
+ io.mapRequired("flags", info.flags);
+ }
+};
+```
With the above, YAML I/O (when writing) will test mask each value in the
bitset trait against the flags field, and each that matches will
-cause the corresponding string to be added to the flow sequence. The opposite
+cause the corresponding string to be added to the flow sequence. The opposite
is done when reading and any unknown string values will result in an error. With
the above schema, a same valid YAML document is:
-.. code-block:: yaml
-
- name: Tom
- flags: [ pointy, flat ]
+```yaml
+name: Tom
+flags: [ pointy, flat ]
+```
Sometimes a "flags" field might contain an enumeration part
defined by a bit-mask.
-.. code-block:: c++
-
- enum {
- flagsFeatureA = 1,
- flagsFeatureB = 2,
- flagsFeatureC = 4,
+```c++
+enum {
+ flagsFeatureA = 1,
+ flagsFeatureB = 2,
+ flagsFeatureC = 4,
- flagsCPUMask = 24,
+ flagsCPUMask = 24,
- flagsCPU1 = 8,
- flagsCPU2 = 16
- };
+ flagsCPU1 = 8,
+ flagsCPU2 = 16
+};
+```
-To support reading and writing such fields, you need to use the ``maskedBitSet()``
+To support reading and writing such fields, you need to use the `maskedBitSet()`
method and provide the bit values, their names and the enumeration mask.
-.. code-block:: c++
-
- template <>
- struct ScalarBitSetTraits<MyFlags> {
- static void bitset(IO &io, MyFlags &value) {
- io.bitSetCase(value, "featureA", flagsFeatureA);
- io.bitSetCase(value, "featureB", flagsFeatureB);
- io.bitSetCase(value, "featureC", flagsFeatureC);
- io.maskedBitSetCase(value, "CPU1", flagsCPU1, flagsCPUMask);
- io.maskedBitSetCase(value, "CPU2", flagsCPU2, flagsCPUMask);
- }
- };
+```c++
+template <>
+struct ScalarBitSetTraits<MyFlags> {
+ static void bitset(IO &io, MyFlags &value) {
+ io.bitSetCase(value, "featureA", flagsFeatureA);
+ io.bitSetCase(value, "featureB", flagsFeatureB);
+ io.bitSetCase(value, "featureC", flagsFeatureC);
+ io.maskedBitSetCase(value, "CPU1", flagsCPU1, flagsCPUMask);
+ io.maskedBitSetCase(value, "CPU2", flagsCPU2, flagsCPUMask);
+ }
+};
+```
YAML I/O (when writing) will apply the enumeration mask to the flags field,
and compare the result and values from the bitset. As in case of a regular
bitset, each that matches will cause the corresponding string to be added
to the flow sequence.
-Custom Scalar
--------------
+### Custom Scalar
+
Sometimes, for readability, a scalar needs to be formatted in a custom way. For
instance, your internal data structure may use an integer for time (seconds since
some epoch), but in YAML it would be much nicer to express that integer in
-some time format (e.g., ``4-May-2012 10:30pm``). YAML I/O has a way to support
-custom formatting and parsing of scalar types by specializing ``ScalarTraits<>`` on
-your data type. When writing, YAML I/O will provide the native type and
-your specialization must create a temporary ``llvm::StringRef``. When reading,
-YAML I/O will provide an ``llvm::StringRef`` of scalar and your specialization
-must convert that to your native data type. An outline of a custom scalar type
+some time format (e.g., `4-May-2012 10:30pm`). YAML I/O has a way to support
+custom formatting and parsing of scalar types by specializing `ScalarTraits<>` on
+your data type. When writing, YAML I/O will provide the native type and
+your specialization must create a temporary `llvm::StringRef`. When reading,
+YAML I/O will provide an `llvm::StringRef` of scalar and your specialization
+must convert that to your native data type. An outline of a custom scalar type
looks like:
-.. code-block:: c++
-
- using llvm::yaml::ScalarTraits;
- using llvm::yaml::IO;
-
- template <>
- struct ScalarTraits<MyCustomType> {
- static void output(const MyCustomType &value, void*,
- llvm::raw_ostream &out) {
- out << value; // do custom formatting here
- }
- static StringRef input(StringRef scalar, void*, MyCustomType &value) {
- // do custom parsing here. Return the empty string on success,
- // or an error message on failure.
- return StringRef();
- }
- // Determine if this scalar needs quotes.
- static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
- };
-
-Block Scalars
--------------
+```c++
+using llvm::yaml::ScalarTraits;
+using llvm::yaml::IO;
+
+template <>
+struct ScalarTraits<MyCustomType> {
+ static void output(const MyCustomType &value, void*,
+ llvm::raw_ostream &out) {
+ out << value; // do custom formatting here
+ }
+ static StringRef input(StringRef scalar, void*, MyCustomType &value) {
+ // do custom parsing here. Return the empty string on success,
+ // or an error message on failure.
+ return StringRef();
+ }
+ // Determine if this scalar needs quotes.
+ static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+};
+```
+
+### Block Scalars
YAML block scalars are string literals that are represented in YAML using the
literal block notation, just like the example shown below:
-.. code-block:: yaml
-
- text: |
- First line
- Second line
+```yaml
+text: |
+ First line
+ Second line
+```
The YAML I/O library provides support for translating between YAML block scalars
-and specific C++ types by allowing you to specialize ``BlockScalarTraits<>`` on
+and specific C++ types by allowing you to specialize `BlockScalarTraits<>` on
your data type. The library doesn't provide any built-in support for block
-scalar I/O for types like ``std::string`` and ``llvm::StringRef`` as they are already
+scalar I/O for types like `std::string` and `llvm::StringRef` as they are already
supported by YAML I/O and use the ordinary scalar notation by default.
-``BlockScalarTraits`` specializations are very similar to the
-``ScalarTraits`` specialization - YAML I/O will provide the native type and your
-specialization must create a temporary ``llvm::StringRef`` when writing, and
-it will also provide an ``llvm::StringRef`` that has the value of that block scalar
+`BlockScalarTraits` specializations are very similar to the
+`ScalarTraits` specialization - YAML I/O will provide the native type and your
+specialization must create a temporary `llvm::StringRef` when writing, and
+it will also provide an `llvm::StringRef` that has the value of that block scalar
and your specialization must convert that to your native data type when reading.
An example of a custom type with an appropriate specialization of
-``BlockScalarTraits`` is shown below:
-
-.. code-block:: c++
-
- using llvm::yaml::BlockScalarTraits;
- using llvm::yaml::IO;
-
- struct MyStringType {
- std::string Str;
- };
-
- template <>
- struct BlockScalarTraits<MyStringType> {
- static void output(const MyStringType &Value, void *Ctxt,
- llvm::raw_ostream &OS) {
- OS << Value.Str;
- }
-
- static StringRef input(StringRef Scalar, void *Ctxt,
- MyStringType &Value) {
- Value.Str = Scalar.str();
- return StringRef();
- }
- };
-
-
-
-Mappings
-========
-
-To be translated to or from a YAML mapping for your type ``T``, you must specialize
-``llvm::yaml::MappingTraits`` on ``T`` and implement the ``void mapping(IO &io, T&)``
+`BlockScalarTraits` is shown below:
+
+```c++
+using llvm::yaml::BlockScalarTraits;
+using llvm::yaml::IO;
+
+struct MyStringType {
+ std::string Str;
+};
+
+template <>
+struct BlockScalarTraits<MyStringType> {
+ static void output(const MyStringType &Value, void *Ctxt,
+ llvm::raw_ostream &OS) {
+ OS << Value.Str;
+ }
+
+ static StringRef input(StringRef Scalar, void *Ctxt,
+ MyStringType &Value) {
+ Value.Str = Scalar.str();
+ return StringRef();
+ }
+};
+```
+
+## Mappings
+
+To be translated to or from a YAML mapping for your type `T`, you must specialize
+`llvm::yaml::MappingTraits` on `T` and implement the `void mapping(IO &io, T&)`
method. If your native data structures use pointers to a class everywhere,
-you can specialize on the class pointer. Examples:
-
-.. code-block:: c++
-
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
-
- // Example of struct Foo which is used by value
- template <>
- struct MappingTraits<Foo> {
- static void mapping(IO &io, Foo &foo) {
- io.mapOptional("size", foo.size);
- ...
- }
- };
-
- // Example of struct Bar which is natively always a pointer
- template <>
- struct MappingTraits<Bar*> {
- static void mapping(IO &io, Bar *&bar) {
- io.mapOptional("size", bar->size);
- ...
- }
- };
+you can specialize on the class pointer. Examples:
+
+```c++
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
+
+// Example of struct Foo which is used by value
+template <>
+struct MappingTraits<Foo> {
+ static void mapping(IO &io, Foo &foo) {
+ io.mapOptional("size", foo.size);
+ ...
+ }
+};
+
+// Example of struct Bar which is natively always a pointer
+template <>
+struct MappingTraits<Bar*> {
+ static void mapping(IO &io, Bar *&bar) {
+ io.mapOptional("size", bar->size);
+ ...
+ }
+};
+```
There are circumstances where we want to allow the entire mapping to be
-read as an enumeration. For example, say some configuration option
-started as an enumeration. Then it got more complex so it is now a
-mapping. But it is necessary to support the old configuration files.
-In that case, add a function ``enumInput`` like for
-``ScalarEnumerationTraits::enumeration``. Examples:
-
-.. code-block:: c++
-
- struct FooBarEnum {
- int Foo;
- int Bar;
- bool operator==(const FooBarEnum &R) const {
- return Foo == R.Foo && Bar == R.Bar;
- }
- };
-
- template <> struct MappingTraits<FooBarEnum> {
- static void enumInput(IO &io, FooBarEnum &Val) {
- io.enumCase(Val, "OnlyFoo", FooBarEnum({1, 0}));
- io.enumCase(Val, "OnlyBar", FooBarEnum({0, 1}));
- }
- static void mapping(IO &io, FooBarEnum &Val) {
- io.mapOptional("Foo", Val.Foo);
- io.mapOptional("Bar", Val.Bar);
- }
- };
-
-
-No Normalization
-----------------
-
-The ``mapping()`` method is responsible, if needed, for normalizing and
+read as an enumeration. For example, say some configuration option
+started as an enumeration. Then it got more complex so it is now a
+mapping. But it is necessary to support the old configuration files.
+In that case, add a function `enumInput` like for
+`ScalarEnumerationTraits::enumeration`. Examples:
+
+```c++
+struct FooBarEnum {
+ int Foo;
+ int Bar;
+ bool operator==(const FooBarEnum &R) const {
+ return Foo == R.Foo && Bar == R.Bar;
+ }
+};
+
+template <> struct MappingTraits<FooBarEnum> {
+ static void enumInput(IO &io, FooBarEnum &Val) {
+ io.enumCase(Val, "OnlyFoo", FooBarEnum({1, 0}));
+ io.enumCase(Val, "OnlyBar", FooBarEnum({0, 1}));
+ }
+ static void mapping(IO &io, FooBarEnum &Val) {
+ io.mapOptional("Foo", Val.Foo);
+ io.mapOptional("Bar", Val.Bar);
+ }
+};
+```
+
+### No Normalization
+
+The `mapping()` method is responsible, if needed, for normalizing and
denormalizing. In a simple case where the native data structure requires no
-normalization, the mapping method just uses ``mapOptional()`` or ``mapRequired()`` to
-bind the struct's fields to YAML key names. For example:
+normalization, the mapping method just uses `mapOptional()` or `mapRequired()` to
+bind the struct's fields to YAML key names. For example:
-.. code-block:: c++
+```c++
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
+template <>
+struct MappingTraits<Person> {
+ static void mapping(IO &io, Person &info) {
+ io.mapRequired("name", info.name);
+ io.mapOptional("hat-size", info.hatSize);
+ }
+};
+```
- template <>
- struct MappingTraits<Person> {
- static void mapping(IO &io, Person &info) {
- io.mapRequired("name", info.name);
- io.mapOptional("hat-size", info.hatSize);
- }
- };
+### Normalization
-
-Normalization
-----------------
-
-When [de]normalization is required, the ``mapping()`` method needs a way to access
+When [de]normalization is required, the `mapping()` method needs a way to access
normalized values as fields. To help with this, there is
-a template ``MappingNormalization<>`` which you can then use to automatically
-do the normalization and denormalization. The template is used to create
-a local variable in your ``mapping()`` method which contains the normalized keys.
+a template `MappingNormalization<>` which you can then use to automatically
+do the normalization and denormalization. The template is used to create
+a local variable in your `mapping()` method which contains the normalized keys.
Suppose you have native data type
Polar which specifies a position in polar coordinates (distance, angle):
-.. code-block:: c++
-
- struct Polar {
- float distance;
- float angle;
- };
+```c++
+struct Polar {
+ float distance;
+ float angle;
+};
+```
but you've decided the normalized YAML form should be in x,y coordinates. That
is, you want the yaml to look like:
-.. code-block:: yaml
+```yaml
+x: 10.3
+y: -4.7
+```
- x: 10.3
- y: -4.7
-
-You can support this by defining a ``MappingTraits`` that normalizes the polar
+You can support this by defining a `MappingTraits` that normalizes the polar
coordinates to x,y coordinates when writing YAML and denormalizes x,y
coordinates into polar when reading YAML.
-.. code-block:: c++
-
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
+```c++
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
- template <>
- struct MappingTraits<Polar> {
+template <>
+struct MappingTraits<Polar> {
- class NormalizedPolar {
- public:
- NormalizedPolar(IO &io)
- : x(0.0), y(0.0) {
- }
- NormalizedPolar(IO &, Polar &polar)
- : x(polar.distance * cos(polar.angle)),
- y(polar.distance * sin(polar.angle)) {
- }
- Polar denormalize(IO &) {
- return Polar(sqrt(x*x+y*y), arctan(x,y));
- }
+ class NormalizedPolar {
+ public:
+ NormalizedPolar(IO &io)
+ : x(0.0), y(0.0) {
+ }
+ NormalizedPolar(IO &, Polar &polar)
+ : x(polar.distance * cos(polar.angle)),
+ y(polar.distance * sin(polar.angle)) {
+ }
+ Polar denormalize(IO &) {
+ return Polar(sqrt(x*x+y*y), arctan(x,y));
+ }
- float x;
- float y;
- };
+ float x;
+ float y;
+ };
- static void mapping(IO &io, Polar &polar) {
- MappingNormalization<NormalizedPolar, Polar> keys(io, polar);
+ static void mapping(IO &io, Polar &polar) {
+ MappingNormalization<NormalizedPolar, Polar> keys(io, polar);
- io.mapRequired("x", keys->x);
- io.mapRequired("y", keys->y);
- }
- };
+ io.mapRequired("x", keys->x);
+ io.mapRequired("y", keys->y);
+ }
+};
+```
When writing YAML, the local variable "keys" will be a stack allocated
-instance of ``NormalizedPolar``, constructed from the supplied polar object which
-initializes it x and y fields. The ``mapRequired()`` methods then write out the x
+instance of `NormalizedPolar`, constructed from the supplied polar object which
+initializes it x and y fields. The `mapRequired()` methods then write out the x
and y values as key/value pairs.
When reading YAML, the local variable "keys" will be a stack allocated instance
-of ``NormalizedPolar``, constructed by the empty constructor. The ``mapRequired()``
+of `NormalizedPolar`, constructed by the empty constructor. The `mapRequired()`
methods will find the matching key in the YAML document and fill in the x and y
-fields of the ``NormalizedPolar`` object keys. At the end of the ``mapping()`` method
-when the local keys variable goes out of scope, the ``denormalize()`` method will
+fields of the `NormalizedPolar` object keys. At the end of the `mapping()` method
+when the local keys variable goes out of scope, the `denormalize()` method will
automatically be called to convert the read values back to polar coordinates,
-and then assigned back to the second parameter to ``mapping()``.
+and then assigned back to the second parameter to `mapping()`.
In some cases, the normalized class may be a subclass of the native type and
-could be returned by the ``denormalize()`` method, except that the temporary
-normalized instance is stack allocated. In these cases, the utility template
-``MappingNormalizationHeap<>`` can be used instead. It just like
-``MappingNormalization<>`` except that it heap allocates the normalized object
-when reading YAML. It never destroys the normalized object. The ``denormalize()``
-method can this return ``this``.
+could be returned by the `denormalize()` method, except that the temporary
+normalized instance is stack allocated. In these cases, the utility template
+`MappingNormalizationHeap<>` can be used instead. It just like
+`MappingNormalization<>` except that it heap allocates the normalized object
+when reading YAML. It never destroys the normalized object. The `denormalize()`
+method can this return `this`.
+### Default values
-Default values
---------------
-Within a ``mapping()`` method, calls to ``io.mapRequired()`` mean that that key is
+Within a `mapping()` method, calls to `io.mapRequired()` mean that that key is
required to exist when parsing YAML documents; otherwise, YAML I/O will issue an
error.
-On the other hand, keys registered with ``io.mapOptional()`` are allowed to not
-exist in the YAML document being read. So what value is put in the field
+On the other hand, keys registered with `io.mapOptional()` are allowed to not
+exist in the YAML document being read. So what value is put in the field
for those optional keys?
There are two steps to how those optional fields are filled in. First, the
-second parameter to the ``mapping()`` method is a reference to a native class. That
-native class must have a default constructor. Whatever value the default
+second parameter to the `mapping()` method is a reference to a native class. That
+native class must have a default constructor. Whatever value the default
constructor initially sets for an optional field will be that field's value.
-Second, the ``mapOptional()`` method has an optional third parameter. If provided
-it is the value that ``mapOptional()`` should set that field to if the YAML document
+Second, the `mapOptional()` method has an optional third parameter. If provided
+it is the value that `mapOptional()` should set that field to if the YAML document
does not have that key.
There is one important difference between those two ways (default constructor
-and third parameter to ``mapOptional()``). When YAML I/O generates a YAML document,
-if the ``mapOptional()`` third parameter is used, if the actual value being written
-is the same as (using ``==``) the default value, then that key/value is not written.
-
+and third parameter to `mapOptional()`). When YAML I/O generates a YAML document,
+if the `mapOptional()` third parameter is used, if the actual value being written
+is the same as (using `==`) the default value, then that key/value is not written.
-Order of Keys
---------------
+### Order of Keys
When writing out a YAML document, the keys are written in the order that the
-calls to ``mapRequired()``/``mapOptional()`` are made in the ``mapping()`` method. This
+calls to `mapRequired()`/`mapOptional()` are made in the `mapping()` method. This
gives you a chance to write the fields in an order that a human reader of
-the YAML document would find natural. This may be different that the order
+the YAML document would find natural. This may be different that the order
of the fields in the native class.
When reading in a YAML document, the keys in the document can be in any order,
-but they are processed in the order that the calls to ``mapRequired()``/``mapOptional()``
-are made in the ``mapping()`` method. That enables some interesting
-functionality. For instance, if the first field bound is the cpu and the second
+but they are processed in the order that the calls to `mapRequired()`/`mapOptional()`
+are made in the `mapping()` method. That enables some interesting
+functionality. For instance, if the first field bound is the cpu and the second
field bound is flags, and the flags are cpu specific, you can programmatically
switch how the flags are converted to and from YAML based on the cpu.
This works for both reading and writing. For example:
-.. code-block:: c++
-
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
-
- struct Info {
- CPUs cpu;
- uint32_t flags;
- };
-
- template <>
- struct MappingTraits<Info> {
- static void mapping(IO &io, Info &info) {
- io.mapRequired("cpu", info.cpu);
- // flags must come after cpu for this to work when reading yaml
- if ( info.cpu == cpu_x86_64 )
- io.mapRequired("flags", *(My86_64Flags*)info.flags);
- else
- io.mapRequired("flags", *(My86Flags*)info.flags);
- }
- };
-
-
-Tags
-----
+```c++
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
+
+struct Info {
+ CPUs cpu;
+ uint32_t flags;
+};
+
+template <>
+struct MappingTraits<Info> {
+ static void mapping(IO &io, Info &info) {
+ io.mapRequired("cpu", info.cpu);
+ // flags must come after cpu for this to work when reading yaml
+ if ( info.cpu == cpu_x86_64 )
+ io.mapRequired("flags", *(My86_64Flags*)info.flags);
+ else
+ io.mapRequired("flags", *(My86Flags*)info.flags);
+ }
+};
+```
+
+### Tags
The YAML syntax supports tags as a way to specify the type of a node before
-it is parsed. This allows dynamic types of nodes. But the YAML I/O model uses
+it is parsed. This allows dynamic types of nodes. But the YAML I/O model uses
static typing, so there are limits to how you can use tags with the YAML I/O
model. Recently, we added support to YAML I/O for checking/setting the optional
tag on a map. Using this functionality it is even possible to support different
mappings, as long as they are convertible.
-To check a tag, inside your ``mapping()`` method you can use ``io.mapTag()`` to specify
-what the tag should be. This will also add that tag when writing YAML.
+To check a tag, inside your `mapping()` method you can use `io.mapTag()` to specify
+what the tag should be. This will also add that tag when writing YAML.
-Validation
-----------
+### Validation
Sometimes in a YAML map, each key/value pair is valid, but the combination is
-not. This is similar to something having no syntax errors, but still having
-semantic errors. To support semantic-level checking, YAML I/O allows
-an optional ``validate()`` method in a MappingTraits template specialization.
+not. This is similar to something having no syntax errors, but still having
+semantic errors. To support semantic-level checking, YAML I/O allows
+an optional `validate()` method in a MappingTraits template specialization.
-When parsing YAML, the ``validate()`` method is called *after* all key/values in
-the map have been processed. Any error message returned by the ``validate()``
+When parsing YAML, the `validate()` method is called *after* all key/values in
+the map have been processed. Any error message returned by the `validate()`
method during input will be printed just like a syntax error would be printed.
-When writing YAML, the ``validate()`` method is called *before* the YAML
-key/values are written. Any error during output will trigger an ``assert()``
+When writing YAML, the `validate()` method is called *before* the YAML
+key/values are written. Any error during output will trigger an `assert()`
because it is a programming error to have invalid struct values.
+```c++
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
+
+struct Stuff {
+ ...
+};
+
+template <>
+struct MappingTraits<Stuff> {
+ static void mapping(IO &io, Stuff &stuff) {
+ ...
+ }
+ static std::string validate(IO &io, Stuff &stuff) {
+ // Look at all fields in 'stuff' and if there
+ // are any bad values return a string describing
+ // the error. Otherwise return an empty string.
+ return std::string{};
+ }
+};
+```
+
+### Flow Mapping
-.. code-block:: c++
-
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
-
- struct Stuff {
- ...
- };
-
- template <>
- struct MappingTraits<Stuff> {
- static void mapping(IO &io, Stuff &stuff) {
- ...
- }
- static std::string validate(IO &io, Stuff &stuff) {
- // Look at all fields in 'stuff' and if there
- // are any bad values return a string describing
- // the error. Otherwise return an empty string.
- return std::string{};
- }
- };
-
-Flow Mapping
-------------
A YAML "flow mapping" is a mapping that uses the inline notation
(e.g { x: 1, y: 0 } ) when written to YAML. To specify that a type should be
written in YAML using flow mapping, your MappingTraits specialization should
-add ``static constexpr bool flow = true;``. For instance:
-
-.. code-block:: c++
+add `static constexpr bool flow = true;`. For instance:
- using llvm::yaml::MappingTraits;
- using llvm::yaml::IO;
+```c++
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
- struct Stuff {
- ...
- };
+struct Stuff {
+ ...
+};
- template <>
- struct MappingTraits<Stuff> {
- static void mapping(IO &io, Stuff &stuff) {
- ...
- }
+template <>
+struct MappingTraits<Stuff> {
+ static void mapping(IO &io, Stuff &stuff) {
+ ...
+ }
- static constexpr bool flow = true;
- }
+ static constexpr bool flow = true;
+}
+```
-Flow mappings are subject to line wrapping according to the ``Output`` object
+Flow mappings are subject to line wrapping according to the `Output` object
configuration.
-Sequence
-========
-
-To be translated to or from a YAML sequence for your type ``T``, you must specialize
-``llvm::yaml::SequenceTraits`` on ``T`` and implement two methods:
-``size_t size(IO &io, T&)`` and
-``T::value_type& element(IO &io, T&, size_t indx)``. For example:
-
-.. code-block:: c++
-
- template <>
- struct SequenceTraits<MySeq> {
- static size_t size(IO &io, MySeq &list) { ... }
- static MySeqEl &element(IO &io, MySeq &list, size_t index) { ... }
- };
-
-The ``size()`` method returns how many elements are currently in your sequence.
-The ``element()`` method returns a reference to the i'th element in the sequence.
-When parsing YAML, the ``element()`` method may be called with an index one bigger
-than the current size. Your ``element()`` method should allocate space for one
+## Sequence
+
+To be translated to or from a YAML sequence for your type `T`, you must specialize
+`llvm::yaml::SequenceTraits` on `T` and implement two methods:
+`size_t size(IO &io, T&)` and
+`T::value_type& element(IO &io, T&, size_t indx)`. For example:
+
+```c++
+template <>
+struct SequenceTraits<MySeq> {
+ static size_t size(IO &io, MySeq &list) { ... }
+ static MySeqEl &element(IO &io, MySeq &list, size_t index) { ... }
+};
+```
+
+The `size()` method returns how many elements are currently in your sequence.
+The `element()` method returns a reference to the i'th element in the sequence.
+When parsing YAML, the `element()` method may be called with an index one bigger
+than the current size. Your `element()` method should allocate space for one
more element (using default constructor if element is a C++ object) and return
a reference to that new allocated space.
+### Flow Sequence
-Flow Sequence
--------------
A YAML "flow sequence" is a sequence that when written to YAML it uses the
-inline notation (e.g., ``[ foo, bar ]`` ). To specify that a sequence type should
+inline notation (e.g., `[ foo, bar ]` ). To specify that a sequence type should
be written in YAML as a flow sequence, your SequenceTraits specialization should
-add ``static constexpr bool flow = true;``. For instance:
-
-.. code-block:: c++
+add `static constexpr bool flow = true;`. For instance:
- template <>
- struct SequenceTraits<MyList> {
- static size_t size(IO &io, MyList &list) { ... }
- static MyListEl &element(IO &io, MyList &list, size_t index) { ... }
+```c++
+template <>
+struct SequenceTraits<MyList> {
+ static size_t size(IO &io, MyList &list) { ... }
+ static MyListEl &element(IO &io, MyList &list, size_t index) { ... }
- // The existence of this member causes YAML I/O to use a flow sequence
- static constexpr bool flow = true;
- };
+ // The existence of this member causes YAML I/O to use a flow sequence
+ static constexpr bool flow = true;
+};
+```
-With the above, if you used ``MyList`` as the data type in your native data
+With the above, if you used `MyList` as the data type in your native data
structures, then when converted to YAML, a flow sequence of integers
-will be used (e.g., ``[ 10, -3, 4 ]``).
+will be used (e.g., `[ 10, -3, 4 ]`).
Flow sequences are subject to line wrapping according to the Output object
configuration.
-Utility Macros
---------------
-Since a common source of sequences is ``std::vector<>``, YAML I/O provides macros:
-``LLVM_YAML_IS_SEQUENCE_VECTOR()`` and ``LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR()`` which
-can be used to easily specify ``SequenceTraits<>`` on a ``std::vector`` type. YAML
-I/O does not partial specialize ``SequenceTraits`` on ``std::vector<>`` because that
-would force all vectors to be sequences. An example use of the macros:
-
-.. code-block:: c++
-
- std::vector<MyType1>;
- std::vector<MyType2>;
- LLVM_YAML_IS_SEQUENCE_VECTOR(MyType1)
- LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyType2)
+### Utility Macros
+Since a common source of sequences is `std::vector<>`, YAML I/O provides macros:
+`LLVM_YAML_IS_SEQUENCE_VECTOR()` and `LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR()` which
+can be used to easily specify `SequenceTraits<>` on a `std::vector` type. YAML
+I/O does not partial specialize `SequenceTraits` on `std::vector<>` because that
+would force all vectors to be sequences. An example use of the macros:
+```c++
+std::vector<MyType1>;
+std::vector<MyType2>;
+LLVM_YAML_IS_SEQUENCE_VECTOR(MyType1)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyType2)
+```
-Document List
-=============
+## Document List
-YAML allows you to define multiple "documents" in a single YAML file. Each
-new document starts with a left aligned ``---`` token. The end of all documents
-is denoted with a left aligned ``...`` token. Many users of YAML will never
-have need for multiple documents. The top level node in their YAML schema
+YAML allows you to define multiple "documents" in a single YAML file. Each
+new document starts with a left aligned `---` token. The end of all documents
+is denoted with a left aligned `...` token. Many users of YAML will never
+have need for multiple documents. The top level node in their YAML schema
will be a mapping or sequence. For those cases, the following is not needed.
But for cases where you do want multiple documents, you can specify a
-trait for you document list type. The trait has the same methods as
-``SequenceTraits`` but is named ``DocumentListTraits``. For example:
+trait for you document list type. The trait has the same methods as
+`SequenceTraits` but is named `DocumentListTraits`. For example:
-.. code-block:: c++
-
- template <>
- struct DocumentListTraits<MyDocList> {
- static size_t size(IO &io, MyDocList &list) { ... }
- static MyDocType element(IO &io, MyDocList &list, size_t index) { ... }
- };
+```c++
+template <>
+struct DocumentListTraits<MyDocList> {
+ static size_t size(IO &io, MyDocList &list) { ... }
+ static MyDocType element(IO &io, MyDocList &list, size_t index) { ... }
+};
+```
+## User Context Data
-User Context Data
-=================
-When an ``llvm::yaml::Input`` or ``llvm::yaml::Output`` object is created, its
-constructor takes an optional "context" parameter. This is a pointer to
+When an `llvm::yaml::Input` or `llvm::yaml::Output` object is created, its
+constructor takes an optional "context" parameter. This is a pointer to
whatever state information you might need.
For instance, in a previous example we showed how the conversion type for a
flags field could be determined at runtime based on the value of another field
in the mapping. But what if an inner mapping needs to know some field value
-of an outer mapping? That is where the "context" parameter comes in. You
-can set values in the context in the outer map's ``mapping()`` method and
-retrieve those values in the inner map's ``mapping()`` method.
+of an outer mapping? That is where the "context" parameter comes in. You
+can set values in the context in the outer map's `mapping()` method and
+retrieve those values in the inner map's `mapping()` method.
-The context value is just a ``void*``. All your traits which use the context
+The context value is just a `void*`. All your traits which use the context
and operate on your native data types, need to agree what the context value
-actually is. It could be a pointer to an object or struct which your various
+actually is. It could be a pointer to an object or struct which your various
traits use to share context sensitive information.
+## Output
-Output
-======
-
-The ``llvm::yaml::Output`` class is used to generate a YAML document from your
+The `llvm::yaml::Output` class is used to generate a YAML document from your
in-memory data structures, using traits defined on your data types.
-To instantiate an ``Output`` object you need an ``llvm::raw_ostream``, an optional
+To instantiate an `Output` object you need an `llvm::raw_ostream`, an optional
context pointer and an optional wrapping column:
-.. code-block:: c++
+```c++
+class Output : public IO {
+public:
+ Output(llvm::raw_ostream &, void *context = NULL, int WrapColumn = 70);
+```
- class Output : public IO {
- public:
- Output(llvm::raw_ostream &, void *context = NULL, int WrapColumn = 70);
-
-Once you have an ``Output`` object, you can use the C++ stream operator on it
+Once you have an `Output` object, you can use the C++ stream operator on it
to write your native data as YAML. One thing to recall is that a YAML file
-can contain multiple "documents". If the top level data structure you are
-streaming as YAML is a mapping, scalar, or sequence, then ``Output`` assumes you
+can contain multiple "documents". If the top level data structure you are
+streaming as YAML is a mapping, scalar, or sequence, then `Output` assumes you
are generating one document and wraps the mapping output
-with ``---`` and trailing ``...``.
+with `---` and trailing `...`.
-The ``WrapColumn`` parameter will cause the flow mappings and sequences to
+The `WrapColumn` parameter will cause the flow mappings and sequences to
line-wrap when they go over the supplied column. Pass 0 to completely
suppress the wrapping.
-.. code-block:: c++
-
- using llvm::yaml::Output;
+```c++
+using llvm::yaml::Output;
- void dumpMyMapDoc(const MyMapType &info) {
- Output yout(llvm::outs());
- yout << info;
- }
+void dumpMyMapDoc(const MyMapType &info) {
+ Output yout(llvm::outs());
+ yout << info;
+}
+```
The above could produce output like:
-.. code-block:: yaml
-
- ---
- name: Tom
- hat-size: 7
- ...
+```yaml
+---
+name: Tom
+hat-size: 7
+...
+```
On the other hand, if the top level data structure you are streaming as YAML
-has a ``DocumentListTraits`` specialization, then Output walks through each element
-of your DocumentList and generates a ``---`` before the start of each element
-and ends with a ``...``.
+has a `DocumentListTraits` specialization, then Output walks through each element
+of your DocumentList and generates a `---` before the start of each element
+and ends with a `...`.
-.. code-block:: c++
+```c++
+using llvm::yaml::Output;
- using llvm::yaml::Output;
-
- void dumpMyMapDoc(const MyDocListType &docList) {
- Output yout(llvm::outs());
- yout << docList;
- }
+void dumpMyMapDoc(const MyDocListType &docList) {
+ Output yout(llvm::outs());
+ yout << docList;
+}
+```
The above could produce output like:
-.. code-block:: yaml
-
- ---
- name: Tom
- hat-size: 7
- ---
- name: Tom
- shoe-size: 11
- ...
-
-Input
-=====
-
-The ``llvm::yaml::Input`` class is used to parse YAML document(s) into your native
-data structures. To instantiate an ``Input``
-object you need a ``StringRef`` to the entire YAML file, and optionally a context
+```yaml
+---
+name: Tom
+hat-size: 7
+---
+name: Tom
+shoe-size: 11
+...
+```
+
+## Input
+
+The `llvm::yaml::Input` class is used to parse YAML document(s) into your native
+data structures. To instantiate an `Input`
+object you need a `StringRef` to the entire YAML file, and optionally a context
pointer:
-.. code-block:: c++
-
- class Input : public IO {
- public:
- Input(StringRef inputContent, void *context=NULL);
-
-Once you have an ``Input`` object, you can use the C++ stream operator to read
-the document(s). If you expect there might be multiple YAML documents in
-one file, you'll need to specialize ``DocumentListTraits`` on a list of your
-document type and stream in that document list type. Otherwise, you can
-just stream in the document type. Also, you can check if there was
-any syntax errors in the YAML by calling the ``error()`` method on the ``Input``
-object. For example:
-
-.. code-block:: c++
+```c++
+class Input : public IO {
+public:
+ Input(StringRef inputContent, void *context=NULL);
+```
- // Reading a single document
- using llvm::yaml::Input;
+Once you have an `Input` object, you can use the C++ stream operator to read
+the document(s). If you expect there might be multiple YAML documents in
+one file, you'll need to specialize `DocumentListTraits` on a list of your
+document type and stream in that document list type. Otherwise, you can
+just stream in the document type. Also, you can check if there was
+any syntax errors in the YAML by calling the `error()` method on the `Input`
+object. For example:
- Input yin(mb.getBuffer());
+```c++
+// Reading a single document
+using llvm::yaml::Input;
- // Parse the YAML file
- MyDocType theDoc;
- yin >> theDoc;
+Input yin(mb.getBuffer());
- // Check for error
- if ( yin.error() )
- return;
+// Parse the YAML file
+MyDocType theDoc;
+yin >> theDoc;
+// Check for error
+if ( yin.error() )
+ return;
+```
-.. code-block:: c++
+```c++
+// Reading multiple documents in one file
+using llvm::yaml::Input;
- // Reading multiple documents in one file
- using llvm::yaml::Input;
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyDocType)
- LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyDocType)
+Input yin(mb.getBuffer());
- Input yin(mb.getBuffer());
+// Parse the YAML file
+std::vector<MyDocType> theDocList;
+yin >> theDocList;
- // Parse the YAML file
- std::vector<MyDocType> theDocList;
- yin >> theDocList;
+// Check for error
+if ( yin.error() )
+ return;
+```
- // Check for error
- if ( yin.error() )
- return;
>From 8986fca36402189f212d34264b62a9c267abe996 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Fri, 11 Sep 2026 17:31:10 +0000
Subject: [PATCH 3/4] [LLVM][docs] Finish MyST migration for remaining docs
(batch 11)
---
llvm/docs/MarkedUpDisassembly.md | 3 +-
llvm/docs/MeetupGuidelines.md | 3 +-
llvm/docs/MemoryModelRelaxationAnnotations.md | 15 +-
llvm/docs/PCSectionsMetadata.md | 26 +--
llvm/docs/Projects.md | 185 +++++++++---------
llvm/docs/Proposals/GitHubMove.md | 92 ++++-----
llvm/docs/Proposals/TestSuite.md | 171 ++++++++--------
llvm/docs/Proposals/VectorPredication.md | 14 +-
llvm/docs/QualGroup.md | 13 +-
llvm/docs/ScudoHardenedAllocator.md | 3 +-
llvm/docs/Security.md | 9 +-
llvm/docs/SecurityTransparencyReports.md | 96 ++++-----
llvm/docs/SegmentedStacks.md | 5 +-
llvm/docs/StackMaps.md | 25 +--
llvm/docs/Statepoints.md | 13 +-
llvm/docs/SupportPolicy.md | 11 +-
llvm/docs/TableGen/BackEnds.md | 5 +-
llvm/docs/TableGen/BackGuide.md | 27 ++-
llvm/docs/TableGen/ProgRef.md | 124 ++++++------
llvm/docs/TransformMetadata.md | 35 ++--
llvm/docs/TypeMetadata.md | 41 ++--
llvm/docs/VectorizationPlan.md | 104 +++++-----
llvm/docs/XRay.md | 27 +--
llvm/docs/XRayExample.md | 11 +-
llvm/docs/XRayFDRFormat.md | 9 +-
25 files changed, 533 insertions(+), 534 deletions(-)
diff --git a/llvm/docs/MarkedUpDisassembly.md b/llvm/docs/MarkedUpDisassembly.md
index b3fc4da1c5527..ca19c1ad7cb7e 100644
--- a/llvm/docs/MarkedUpDisassembly.md
+++ b/llvm/docs/MarkedUpDisassembly.md
@@ -29,7 +29,7 @@ with the marked up annotations.
## Instruction Annotations
-(contextual-markups)=
+(contextual markups)=
### Contextual markups
@@ -74,4 +74,3 @@ The intended consumers of this information use the C API, therefore the new C
API function for the disassembler will be added to provide an option to produce
disassembled instructions with annotations, `LLVMSetDisasmOptions()` and the
`LLVMDisassembler_Option_UseMarkup` option (see above).
-
diff --git a/llvm/docs/MeetupGuidelines.md b/llvm/docs/MeetupGuidelines.md
index 33fa2b4cd4668..e882c352e02ae 100644
--- a/llvm/docs/MeetupGuidelines.md
+++ b/llvm/docs/MeetupGuidelines.md
@@ -15,7 +15,7 @@ best for your specific situation.
- We highly recommend that you join the official LLVM meetup organization. In
addition to covering the cost of the meetup, all LLVM meetups are advertised
together and easily found by potential attendees. Please contact
- <mailto:tanyalattner at llvm.org> for more details.
+ [tanyalattner at llvm.org](mailto:tanyalattner at llvm.org) for more details.
- Beware of cultural differences: what works well in one region may not work in
other part of the world.
- Do not be alone to organize the meetup. Try to work with a couple other
@@ -72,4 +72,3 @@ best for your specific situation.
but the people who live in the city may not attend.
- Make a poll, but beware that not every responder will join (we had ~20 votes
on the poll, while only ~8 people attended).
-
diff --git a/llvm/docs/MemoryModelRelaxationAnnotations.md b/llvm/docs/MemoryModelRelaxationAnnotations.md
index 81fe32c85083f..fda7fcc0768be 100644
--- a/llvm/docs/MemoryModelRelaxationAnnotations.md
+++ b/llvm/docs/MemoryModelRelaxationAnnotations.md
@@ -47,13 +47,13 @@ tag
`prefix:suffix` notation.
For example:
- ```{code-block}
+ :::{code-block}
:caption: 'Example: Tags in Metadata'
!0 = !{!"scope", !"workgroup"} # scope:workgroup
!1 = !{!"scope", !"device"} # scope:device
!2 = !{!"scope", !"system"} # scope:system
- ```
+ :::
:::{note}
The only semantics relevant to the optimizer is the
@@ -65,13 +65,13 @@ tag
to specify all of the tags they belong to. Such a list
is referred to as a "set of tags".
- ```{code-block}
+ :::{code-block}
:caption: 'Example: Set of Tags in Metadata'
!0 = !{!"scope", !"workgroup"}
!1 = !{!"sync-as", !"private"}
!2 = !{!0, !2}
- ```
+ :::
:::{note}
If an operation does not have MMRA metadata, it's treated as if
@@ -88,12 +88,12 @@ tag
For the sake of readability in examples below,
we use a (non-functional) short syntax to represent MMMRA metadata:
- ```{code-block}
+ :::{code-block}
:caption: Short Syntax Example
store %ptr1 # foo:bar
store %ptr1 !mmra !{!"foo", !"bar"}
- ```
+ :::
These two notations can be used in this document and are strictly
equivalent. However, only the second version is functional.
@@ -112,7 +112,7 @@ compatibility
correctness. In other words, the memory model cannot be relaxed further
by deleting metadata from instructions.
-(happensbefore)=
+(HappensBefore)=
## The *happens-before* Relation
@@ -477,4 +477,3 @@ B: store release %ptr2 # foo:x, bar:y
# No tags with "foo" or "bar" in A, so no tags added.
U: store release %ptr3
```
-
diff --git a/llvm/docs/PCSectionsMetadata.md b/llvm/docs/PCSectionsMetadata.md
index 22b29f43af29a..d09c70a7c0e32 100644
--- a/llvm/docs/PCSectionsMetadata.md
+++ b/llvm/docs/PCSectionsMetadata.md
@@ -56,8 +56,8 @@ the entry size is just 32 bits.
Optional encoding options can be passed in the first `MDString` operator:
`<section>!<options>`. The following options are available:
-> - `C` -- Compress constant integers of size 2-8 bytes as ULEB128; this
-> includes the function size (but excludes the PC entry).
+- `C` -- Compress constant integers of size 2-8 bytes as ULEB128; this
+ includes the function size (but excludes the PC entry).
For example, `foo!C` will emit into section `foo` with all constants
encoded as ULEB128.
@@ -84,21 +84,24 @@ As with other LLVM IR metadata, there are no requirements for LLVM IR
transformation passes to preserve `!pcsections` metadata, with the following
exceptions:
-> - The `AtomicExpandPass` shall preserve `!pcsections` metadata
-> according to the below rules 1-4.
+- The `AtomicExpandPass` shall preserve `!pcsections` metadata
+ according to the below rules 1-4.
When translating LLVM IR to MIR, the `!pcsections` metadata shall be copied
from the source `Instruction` to the target `MachineInstr` (set with
`MachineInstr::setPCSections()`). The instruction selectors and MIR
optimization passes shall preserve PC sections metadata as follows:
-> 1. Replacements will preserve PC sections metadata of the replaced
-> instruction.
-> 2. Duplications will preserve PC sections metadata of the copied
-> instruction.
-> 3. Merging will preserve PC sections metadata of one of the two
-> instructions (no guarantee on which instruction's metadata is used).
-> 4. Deletions will lose PC sections metadata.
+1. Replacements will preserve PC sections metadata of the replaced
+ instruction.
+
+2. Duplications will preserve PC sections metadata of the copied
+ instruction.
+
+3. Merging will preserve PC sections metadata of one of the two
+ instructions (no guarantee on which instruction's metadata is used).
+
+4. Deletions will lose PC sections metadata.
This is similar to debug info, and the `BuildMI()` helper provides a
convenient way to propagate debug info and `!pcsections` metadata in the
@@ -110,4 +113,3 @@ Use cases for `!pcsections` metadata should either be fully tolerant to
missing metadata, or the passes inserting `!pcsections` metadata should run
*after* all LLVM IR optimization passes to preserve the metadata until being
translated to MIR.
-
diff --git a/llvm/docs/Projects.md b/llvm/docs/Projects.md
index 0896364892227..a9e9c631a3430 100644
--- a/llvm/docs/Projects.md
+++ b/llvm/docs/Projects.md
@@ -44,38 +44,38 @@ Underneath your top level directory, you should have the following directories:
**lib**
-> This subdirectory should contain all of your library source code. For each
-> library that you build, you will have one directory in **lib** that will
-> contain that library's source code.
->
-> Libraries can be object files, archives, or dynamic libraries. The **lib**
-> directory is just a convenient place for libraries as it places them all in
-> a directory from which they can be linked later.
+: This subdirectory should contain all of your library source code. For each
+ library that you build, you will have one directory in **lib** that will
+ contain that library's source code.
+
+ Libraries can be object files, archives, or dynamic libraries. The **lib**
+ directory is just a convenient place for libraries as it places them all in
+ a directory from which they can be linked later.
**include**
-> This subdirectory should contain any header files that are global to your
-> project. By global, we mean that they are used by more than one library or
-> executable of your project.
->
-> By placing your header files in **include**, they will be found
-> automatically by the LLVM build system. For example, if you have a file
-> **include/jazz/note.h**, then your source files can include it simply with
-> **#include "jazz/note.h"**.
+: This subdirectory should contain any header files that are global to your
+ project. By global, we mean that they are used by more than one library or
+ executable of your project.
+
+ By placing your header files in **include**, they will be found
+ automatically by the LLVM build system. For example, if you have a file
+ **include/jazz/note.h**, then your source files can include it simply with
+ **#include "jazz/note.h"**.
**tools**
-> This subdirectory should contain all of your source code for executables.
-> For each program that you build, you will have one directory in **tools**
-> that will contain that program's source code.
+: This subdirectory should contain all of your source code for executables.
+ For each program that you build, you will have one directory in **tools**
+ that will contain that program's source code.
**test**
-> This subdirectory should contain tests that verify that your code works
-> correctly. Automated tests are especially useful.
->
-> Currently, the LLVM build system provides basic support for tests. The LLVM
-> system provides the following:
+: This subdirectory should contain tests that verify that your code works
+ correctly. Automated tests are especially useful.
+
+ Currently, the LLVM build system provides basic support for tests. The LLVM
+ system provides the following:
- LLVM contains regression tests in `llvm/test`. These tests are run by the
{doc}`Lit <CommandGuide/lit>` testing tool. This test procedure uses `RUN`
@@ -105,101 +105,101 @@ do:
`LEVEL`
-> This variable is the relative path from this `Makefile` to the top
-> directory of your project's source code. For example, if your source code
-> is in `/tmp/src`, then the `Makefile` in `/tmp/src/jump/high`
-> would set `LEVEL` to `"../.."`.
+: This variable is the relative path from this `Makefile` to the top
+ directory of your project's source code. For example, if your source code
+ is in `/tmp/src`, then the `Makefile` in `/tmp/src/jump/high`
+ would set `LEVEL` to `"../.."`.
### Variables for Building Subdirectories
`DIRS`
-> This is a space separated list of subdirectories that should be built. They
-> will be built, one at a time, in the order specified.
+: This is a space separated list of subdirectories that should be built. They
+ will be built, one at a time, in the order specified.
`PARALLEL_DIRS`
-> This is a list of directories that can be built in parallel. These will be
-> built after the directories in DIRS have been built.
+: This is a list of directories that can be built in parallel. These will be
+ built after the directories in DIRS have been built.
`OPTIONAL_DIRS`
-> This is a list of directories that can be built if they exist, but will not
-> cause an error if they do not exist. They are built serially in the order
-> in which they are listed.
+: This is a list of directories that can be built if they exist, but will not
+ cause an error if they do not exist. They are built serially in the order
+ in which they are listed.
### Variables for Building Libraries
`LIBRARYNAME`
-> This variable contains the base name of the library that will be built. For
-> example, to build a library named `libsample.a`, `LIBRARYNAME` should
-> be set to `sample`.
+: This variable contains the base name of the library that will be built. For
+ example, to build a library named `libsample.a`, `LIBRARYNAME` should
+ be set to `sample`.
`BUILD_ARCHIVE`
-> By default, a library is a `.o` file that is linked directly into a
-> program. To build an archive (also known as a static library), set the
-> `BUILD_ARCHIVE` variable.
+: By default, a library is a `.o` file that is linked directly into a
+ program. To build an archive (also known as a static library), set the
+ `BUILD_ARCHIVE` variable.
`SHARED_LIBRARY`
-> If `SHARED_LIBRARY` is defined in your Makefile, a shared (or dynamic)
-> library will be built.
+: If `SHARED_LIBRARY` is defined in your Makefile, a shared (or dynamic)
+ library will be built.
### Variables for Building Programs
`TOOLNAME`
-> This variable contains the name of the program that will be built. For
-> example, to build an executable named `sample`, `TOOLNAME` should be set
-> to `sample`.
+: This variable contains the name of the program that will be built. For
+ example, to build an executable named `sample`, `TOOLNAME` should be set
+ to `sample`.
`USEDLIBS`
-> This variable holds a space separated list of libraries that should be
-> linked into the program. These libraries must be libraries that come from
-> your **lib** directory. The libraries must be specified without their
-> `lib` prefix. For example, to link `libsample.a`, you would set
-> `USEDLIBS` to `sample.a`.
->
-> Note that this works only for statically linked libraries.
+: This variable holds a space separated list of libraries that should be
+ linked into the program. These libraries must be libraries that come from
+ your **lib** directory. The libraries must be specified without their
+ `lib` prefix. For example, to link `libsample.a`, you would set
+ `USEDLIBS` to `sample.a`.
+
+ Note that this works only for statically linked libraries.
`LLVMLIBS`
-> This variable holds a space separated list of libraries that should be
-> linked into the program. These libraries must be LLVM libraries. The
-> libraries must be specified without their `lib` prefix. For example, to
-> link with a driver that performs an IR transformation you might set
-> `LLVMLIBS` to this minimal set of libraries `LLVMSupport.a LLVMCore.a
-> LLVMBitReader.a LLVMAsmParser.a LLVMAnalysis.a LLVMTransformUtils.a
-> LLVMScalarOpts.a LLVMTarget.a`.
->
-> Note that this works only for statically linked libraries. LLVM is split
-> into a large number of static libraries, and the list of libraries you
-> require may be much longer than the list above. To see a full list of
-> libraries use: `llvm-config --libs all`. Using `LINK_COMPONENTS` as
-> described below, obviates the need to set `LLVMLIBS`.
+: This variable holds a space separated list of libraries that should be
+ linked into the program. These libraries must be LLVM libraries. The
+ libraries must be specified without their `lib` prefix. For example, to
+ link with a driver that performs an IR transformation you might set
+ `LLVMLIBS` to this minimal set of libraries `LLVMSupport.a LLVMCore.a
+ LLVMBitReader.a LLVMAsmParser.a LLVMAnalysis.a LLVMTransformUtils.a
+ LLVMScalarOpts.a LLVMTarget.a`.
+
+ Note that this works only for statically linked libraries. LLVM is split
+ into a large number of static libraries, and the list of libraries you
+ require may be much longer than the list above. To see a full list of
+ libraries use: `llvm-config --libs all`. Using `LINK_COMPONENTS` as
+ described below, obviates the need to set `LLVMLIBS`.
`LINK_COMPONENTS`
-> This variable holds a space separated list of components that the LLVM
-> `Makefiles` pass to the `llvm-config` tool to generate a link line for
-> the program. For example, to link with all LLVM libraries use
-> `LINK_COMPONENTS = all`.
+: This variable holds a space separated list of components that the LLVM
+ `Makefiles` pass to the `llvm-config` tool to generate a link line for
+ the program. For example, to link with all LLVM libraries use
+ `LINK_COMPONENTS = all`.
`LIBS`
-> To link dynamic libraries, add `-l<library base name>` to the `LIBS`
-> variable. The LLVM build system will look in the same places for dynamic
-> libraries as it does for static libraries.
->
-> For example, to link `libsample.so`, you would have the following line in
-> your `Makefile`:
->
-> > ```makefile
-> > LIBS += -lsample
-> > ```
+: To link dynamic libraries, add `-l<library base name>` to the `LIBS`
+ variable. The LLVM build system will look in the same places for dynamic
+ libraries as it does for static libraries.
+
+ For example, to link `libsample.so`, you would have the following line in
+ your `Makefile`:
+
+ ```makefile
+ LIBS += -lsample
+ ```
Note that `LIBS` must occur in the Makefile after the inclusion of
`Makefile.common`.
@@ -208,13 +208,13 @@ Note that `LIBS` must occur in the Makefile after the inclusion of
`CFLAGS` & `CPPFLAGS`
-> This variable can be used to add options to the C and C++ compiler,
-> respectively. It is typically used to add options that tell the compiler
-> the location of additional directories to search for header files.
->
-> It is highly suggested that you append to `CFLAGS` and `CPPFLAGS` as
-> opposed to overwriting them. The LLVM `Makefiles` may already have
-> useful options in them that you may not want to overwrite.
+: This variable can be used to add options to the C and C++ compiler,
+ respectively. It is typically used to add options that tell the compiler
+ the location of additional directories to search for header files.
+
+ It is highly suggested that you append to `CFLAGS` and `CPPFLAGS` as
+ opposed to overwriting them. The LLVM `Makefiles` may already have
+ useful options in them that you may not want to overwrite.
## Placement of Object Code
@@ -223,19 +223,18 @@ you do a `Debug`, `Release`, or `Profile` build.
Libraries
-> All libraries (static and dynamic) will be stored in
-> `PROJ_OBJ_ROOT/<type>/lib`, where *type* is `Debug`, `Release`, or
-> `Profile` for a debug, optimized, or profiled build, respectively.
+: All libraries (static and dynamic) will be stored in
+ `PROJ_OBJ_ROOT/<type>/lib`, where *type* is `Debug`, `Release`, or
+ `Profile` for a debug, optimized, or profiled build, respectively.
Executables
-> All executables will be stored in `PROJ_OBJ_ROOT/<type>/bin`, where *type*
-> is `Debug`, `Release`, or `Profile` for a debug, optimized, or
-> profiled build, respectively.
+: All executables will be stored in `PROJ_OBJ_ROOT/<type>/bin`, where *type*
+ is `Debug`, `Release`, or `Profile` for a debug, optimized, or
+ profiled build, respectively.
## Further Help
If you have any questions or need any help creating an LLVM project, the LLVM
team would be more than happy to help. You can always post your questions to
the [Discourse forums](https://discourse.llvm.org).
-
diff --git a/llvm/docs/Proposals/GitHubMove.md b/llvm/docs/Proposals/GitHubMove.md
index 100e38c24b8fb..dc49131b1ee05 100644
--- a/llvm/docs/Proposals/GitHubMove.md
+++ b/llvm/docs/Proposals/GitHubMove.md
@@ -1,3 +1,8 @@
+---
+myst:
+ footnote_transition: false
+---
+
# Moving LLVM Projects to GitHub
## Current Status
@@ -98,14 +103,14 @@ past discussions about Git:
- "The 'branch' I most care about is mainline, and losing the ability to say
'fixed in r1234' (with some sort of monotonically increasing number) would
- be a tragic loss." [^cite_lattnerrevnum]
+ be a tragic loss." [^lattnerrevnum]
- "I like those results sorted by time and the chronology should be obvious, but
timestamps are incredibly cumbersome and make it difficult to verify that a
- given checkout matches a given set of results." [^cite_trickrevnum]
+ given checkout matches a given set of results." [^trickrevnum]
- "There is still the major regression with unreadable version numbers.
Given the amount of Bugzilla traffic with 'Fixed in...', that's a
- non-trivial issue." [^cite_jsonnrevnum]
-- "Sequential IDs are important for LNT and llvmlab bisection tool." [^cite_matthewsrevnum].
+ non-trivial issue." [^jsonnrevnum]
+- "Sequential IDs are important for LNT and llvmlab bisection tool." [^matthewsrevnum].
However, Git can emulate this increasing revision number:
`git rev-list --count <commit-hash>`. This identifier is unique only
@@ -128,7 +133,7 @@ policy. We must rely on the community to avoid pushing merge commits.
GitHub offers a feature called `Status Checks`: a branch protected by
`status checks` requires commits to be explicitly allowed before the push can happen.
We could supply a pre-push hook on the client side that would run and check the
-history, before allowing the commit being pushed [^cite_statuschecks].
+history, before allowing the commit being pushed [^statuschecks].
However this solution would be somewhat fragile (how do you update a script
installed on every developer machine?) and prevents SVN access to the
repository.
@@ -156,7 +161,7 @@ email format unchanged besides the commit URL.
provide infrastructure testing.
5. Update Phabricator to pick up commits from the GitHub repository.
6. LNT and llvmlab have to be updated: they rely on unique monotonically
- increasing integer across branch [^cite_matthewsrevnum].
+ increasing integer across branch [^matthewsrevnum].
7. Instruct downstream integrators to pick up commits from the GitHub
repository.
8. Review and prepare an update for the LLVM documentation.
@@ -194,24 +199,24 @@ For example, www/ and test-suite/ are not part of the monorepo.
Putting all sub-projects in a single checkout makes cross-project refactoring
naturally simple:
-> - New sub-projects can be trivially split out for better reuse and/or layering
-> (e.g., to allow libSupport and/or LIT to be used by runtimes without adding a
-> dependency on LLVM).
-> - Changing an API in LLVM and upgrading the sub-projects will always be done in
-> a single commit, designing away a common source of temporary build breakage.
-> - Moving code across sub-project (during refactoring for instance) in a single
-> commit enables accurate `git blame` when tracking code change history.
-> - Tooling based on `git grep` works natively across sub-projects, allowing to
-> easier find refactoring opportunities across projects (for example reusing a
-> datastructure initially in LLDB by moving it into libSupport).
-> - Having all the sources present encourages maintaining the other sub-projects
-> when changing API.
+- New sub-projects can be trivially split out for better reuse and/or layering
+ (e.g., to allow libSupport and/or LIT to be used by runtimes without adding a
+ dependency on LLVM).
+- Changing an API in LLVM and upgrading the sub-projects will always be done in
+ a single commit, designing away a common source of temporary build breakage.
+- Moving code across sub-project (during refactoring for instance) in a single
+ commit enables accurate `git blame` when tracking code change history.
+- Tooling based on `git grep` works natively across sub-projects, allowing to
+ easier find refactoring opportunities across projects (for example reusing a
+ datastructure initially in LLDB by moving it into libSupport).
+- Having all the sources present encourages maintaining the other sub-projects
+ when changing API.
Finally, the monorepo maintains the property of the existing SVN repository that
the sub-projects move synchronously, and a single revision number (or commit
hash) identifies the state of the development across all projects.
-(build-single-project)=
+(build_single_project)=
#### Building a single sub-project
@@ -249,28 +254,28 @@ so it's not clear if this is something that will be supported going forward.
### Monorepo Drawbacks
-> - Using the monolithic repository may add overhead for those contributing to a
-> standalone sub-project, particularly on runtimes like libcxx and compiler-rt
-> that don't rely on LLVM; currently, a fresh clone of libcxx is only 15MB (vs.
-> 1GB for the monorepo), and the commit rate of LLVM may cause more frequent
-> `git push` collisions when upstreaming. Affected contributors may be able to
-> use the SVN bridge or the single-subproject Git mirrors. However, it's
-> undecided if these projects will continue to be maintained.
-> - Using the monolithic repository may add overhead for those *integrating* a
-> standalone sub-project, even if they aren't contributing to it, due to the
-> same disk space concern as the point above. The availability of the
-> sub-project Git mirrors would addresses this.
-> - Preservation of the existing read/write SVN-based workflows relies on the
-> GitHub SVN bridge, which is an extra dependency. Maintaining this locks us
-> into GitHub and could restrict future workflow changes.
+- Using the monolithic repository may add overhead for those contributing to a
+ standalone sub-project, particularly on runtimes like libcxx and compiler-rt
+ that don't rely on LLVM; currently, a fresh clone of libcxx is only 15MB (vs.
+ 1GB for the monorepo), and the commit rate of LLVM may cause more frequent
+ `git push` collisions when upstreaming. Affected contributors may be able to
+ use the SVN bridge or the single-subproject Git mirrors. However, it's
+ undecided if these projects will continue to be maintained.
+- Using the monolithic repository may add overhead for those *integrating* a
+ standalone sub-project, even if they aren't contributing to it, due to the
+ same disk space concern as the point above. The availability of the
+ sub-project Git mirrors would addresses this.
+- Preservation of the existing read/write SVN-based workflows relies on the
+ GitHub SVN bridge, which is an extra dependency. Maintaining this locks us
+ into GitHub and could restrict future workflow changes.
#### Workflows
-> - {ref}`Checkout/Clone a Single Project, without Commit Access <workflow-checkout-commit>`.
-> - {ref}`Checkout/Clone Multiple Projects, with Commit Access <workflow-monocheckout-multicommit>`.
-> - {ref}`Commit an API Change in LLVM and Update the Sub-projects <workflow-cross-repo-commit>`.
-> - {ref}`Branching/Stashing/Updating for Local Development or Experiments <workflow-mono-branching>`.
-> - {ref}`Bisecting <workflow-mono-bisecting>`.
+- {ref}`Checkout/Clone a Single Project, without Commit Access <workflow-checkout-commit>`.
+- {ref}`Checkout/Clone Multiple Projects, with Commit Access <workflow-monocheckout-multicommit>`.
+- {ref}`Commit an API Change in LLVM and Update the Sub-projects <workflow-cross-repo-commit>`.
+- {ref}`Branching/Stashing/Updating for Local Development or Experiments <workflow-mono-branching>`.
+- {ref}`Bisecting <workflow-mono-bisecting>`.
## Workflow Before/After
@@ -1074,13 +1079,12 @@ happy hacking!
## References
-[^cite_lattnerrevnum]: Chris Lattner, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041739.html>
-
-[^cite_trickrevnum]: Andrew Trick, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041721.html>
+[^lattnerrevnum]: Chris Lattner, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041739.html>
-[^cite_jsonnrevnum]: Joerg Sonnenberger, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041688.html>
+[^trickrevnum]: Andrew Trick, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041721.html>
-[^cite_matthewsrevnum]: Chris Matthews, <http://lists.llvm.org/pipermail/cfe-dev/2016-July/049886.html>
+[^jsonnrevnum]: Joerg Sonnenberger, <http://lists.llvm.org/pipermail/llvm-dev/2011-July/041688.html>
-[^cite_statuschecks]: GitHub status-checks, <https://help.github.com/articles/about-required-status-checks/>
+[^matthewsrevnum]: Chris Matthews, <http://lists.llvm.org/pipermail/cfe-dev/2016-July/049886.html>
+[^statuschecks]: GitHub status-checks, <https://help.github.com/articles/about-required-status-checks/>
diff --git a/llvm/docs/Proposals/TestSuite.md b/llvm/docs/Proposals/TestSuite.md
index e606312049d54..eef4095703909 100644
--- a/llvm/docs/Proposals/TestSuite.md
+++ b/llvm/docs/Proposals/TestSuite.md
@@ -11,12 +11,14 @@ Most probably, the reason why the programs below have not been added to
the test-suite yet is that nobody has found time to do it. But there
might be other issues as well, such as
-> - Licensing (Support can still be added as external module,
-> : like for the SPEC benchmarks)
-> - Language (in particular, there is no official LLVM frontend
-> : for FORTRAN yet)
-> - Parallelism (currently, all programs in test-suite use
-> : one thread only)
+- Licensing (Support can still be added as external module,
+ like for the SPEC benchmarks)
+
+- Language (in particular, there is no official LLVM frontend
+ for FORTRAN yet)
+
+- Parallelism (currently, all programs in test-suite use
+ one thread only)
## Benchmarks
@@ -34,33 +36,33 @@ Note that CMake's Ninja generator has difficulties with Fortran. See the
[CMake documentation](https://cmake.org/cmake/help/v3.13/generator/Ninja.html#fortran-support)
for details.
-> - 503.bwaves_r/603.bwaves_s
-> - 507.cactuBSSN_r
-> - 521.wrf_r/621.wrf_s
-> - 527.cam4_r/627.cam4_s
-> - 628.pop2_s
-> - 548.exchange2_r/648.exchange2_s
-> - 549.fotonik3d_r/649.fotonik3d_s
-> - 554.roms_r/654.roms_s
+- 503.bwaves_r/603.bwaves_s
+- 507.cactuBSSN_r
+- 521.wrf_r/621.wrf_s
+- 527.cam4_r/627.cam4_s
+- 628.pop2_s
+- 548.exchange2_r/648.exchange2_s
+- 549.fotonik3d_r/649.fotonik3d_s
+- 554.roms_r/654.roms_s
### SPEC OMP2012
<https://www.spec.org/omp2012/>
-> - 350.md
-> - 351.bwaves
-> - 352.nab
-> - 357.bt331
-> - 358.botsalgn
-> - 359.botsspar
-> - 360.ilbdc
-> - 362.fma3d
-> - 363.swim
-> - 367.imagick
-> - 370.mgrid331
-> - 371.applu331
-> - 372.smithwa
-> - 376.kdtree
+- 350.md
+- 351.bwaves
+- 352.nab
+- 357.bt331
+- 358.botsalgn
+- 359.botsspar
+- 360.ilbdc
+- 362.fma3d
+- 363.swim
+- 367.imagick
+- 370.mgrid331
+- 371.applu331
+- 372.smithwa
+- 376.kdtree
### OpenCV
@@ -109,21 +111,21 @@ and is itself a collection of benchmark suites
Rodinia has already been partially included in
MultiSource/Benchmarks/Rodinia. Benchmarks still missing are:
-> - streamcluster
-> - particlefilter
-> - nw
-> - nn
-> - myocyte
-> - mummergpu
-> - lud
-> - leukocyte
-> - lavaMD
-> - kmeans
-> - hotspot3D
-> - heartwall
-> - cfd
-> - bfs
-> - b+tree
+- streamcluster
+- particlefilter
+- nw
+- nn
+- myocyte
+- mummergpu
+- lud
+- leukocyte
+- lavaMD
+- kmeans
+- hotspot3D
+- heartwall
+- cfd
+- bfs
+- b+tree
### vecmathlib tests harness
@@ -185,23 +187,23 @@ Many of its programs have already been integrated in
MultiSource/Benchmarks/DOE-ProxyApps-C and
MultiSource/Benchmarks/DOE-ProxyApps-C++.
-> - Nekbone
-> - QMCPack
-> - LAMMPS
-> - Kripke
-> - Quicksilver
-> - PENNANT
-> - Big Data Analytic Suite
-> - Deep Learning Suite
-> - Stream
-> - Stride
-> - ML/DL micro-benchmark
-> - Pynamic
-> - ACME
-> - VPIC
-> - Laghos
-> - Parallel Integer Sort
-> - Havoq
+- Nekbone
+- QMCPack
+- LAMMPS
+- Kripke
+- Quicksilver
+- PENNANT
+- Big Data Analytic Suite
+- Deep Learning Suite
+- Stream
+- Stride
+- ML/DL micro-benchmark
+- Pynamic
+- ACME
+- VPIC
+- Laghos
+- Parallel Integer Sort
+- Havoq
### NWChem
@@ -258,45 +260,44 @@ into the test-suite repository.
#### Resampling
-> - Bilinear
-> - Bicubic
-> - Lanczos
+- Bilinear
+- Bicubic
+- Lanczos
#### Dither
-> - Threshold
-> - Random
-> - Halftone
-> - Bayer
-> - Floyd-Steinberg
-> - Jarvis
-> - Stucki
-> - Burkes
-> - Sierra
-> - Atkinson
-> - Gradient-based
+- Threshold
+- Random
+- Halftone
+- Bayer
+- Floyd-Steinberg
+- Jarvis
+- Stucki
+- Burkes
+- Sierra
+- Atkinson
+- Gradient-based
#### Feature detection
-> - Harris
-> - Histogram of Oriented Gradients
+- Harris
+- Histogram of Oriented Gradients
#### Color conversion
-> - RGB to grayscale
-> - HSL to RGB
+- RGB to grayscale
+- HSL to RGB
### Graph
#### Search Algorithms
-> - Breadth-First-Search
-> - Depth-First-Search
-> - Dijkstra's algorithm
-> - A-Star
+- Breadth-First-Search
+- Depth-First-Search
+- Dijkstra's algorithm
+- A-Star
#### Spanning Tree
-> - Kruskal's algorithm
-> - Prim's algorithm
-
+- Kruskal's algorithm
+- Prim's algorithm
diff --git a/llvm/docs/Proposals/VectorPredication.md b/llvm/docs/Proposals/VectorPredication.md
index db0456c0c1d3a..5f90e24cf36ac 100644
--- a/llvm/docs/Proposals/VectorPredication.md
+++ b/llvm/docs/Proposals/VectorPredication.md
@@ -1,3 +1,8 @@
+---
+myst:
+ footnote_transition: false
+---
+
# Vector Predication Roadmap
## Motivation
@@ -7,12 +12,12 @@ specifically for vector instructions with a mask and/or an explicit vector
length. LLVM currently has no target-independent means to model predicated
vector instructions for modern SIMD ISAs such as AVX512, ARM SVE, the RISC-V V
extension and NEC SX-Aurora. Only some predicated vector operations, such as
-masked loads and stores, are available through intrinsics [^cite_maskedir].
+masked loads and stores, are available through intrinsics [^maskedir].
The Vector Predication (VP) extensions is a concrete RFC and prototype
implementation to achieve native vector predication in LLVM. The VP prototype
and all related discussions can be found in the VP patch on Phabricator
-[^cite_vprfc].
+[^vprfc].
## Roadmap
@@ -67,9 +72,8 @@ Result: Native vector predication in IR.
## References
-[^cite_maskedir]: `llvm.masked.*` intrinsics,
+[^maskedir]: `llvm.masked.*` intrinsics,
<https://llvm.org/docs/LangRef.html#masked-vector-load-and-store-intrinsics>
-[^cite_vprfc]: RFC: Prototype & Roadmap for vector predication in LLVM,
+[^vprfc]: RFC: Prototype & Roadmap for vector predication in LLVM,
<https://reviews.llvm.org/D57504>
-
diff --git a/llvm/docs/QualGroup.md b/llvm/docs/QualGroup.md
index f3b2c17b27183..902c184f7034e 100644
--- a/llvm/docs/QualGroup.md
+++ b/llvm/docs/QualGroup.md
@@ -124,18 +124,18 @@ Membership in the LLVM Qualification Group is intended for individuals with rele
**Individual Contributors**
-> - Experience in software/tool qualification (e.g., reliability, quality, safety, security); OR
-> - Active involvement in LLVM-related qualification efforts; OR
-> - Significant LLVM contributions related to qualification in the past year (code, discussion, resolving related challenges).
+- Experience in software/tool qualification (e.g., reliability, quality, safety, security); OR
+- Active involvement in LLVM-related qualification efforts; OR
+- Significant LLVM contributions related to qualification in the past year (code, discussion, resolving related challenges).
**Researchers**
-> - Active research, publication, or development of methodologies, frameworks, or tools aimed at improving LLVM quality and reliability.
+- Active research, publication, or development of methodologies, frameworks, or tools aimed at improving LLVM quality and reliability.
**Vendor Contacts**
-> - Represent organizations building or using LLVM-based tools in safety-critical environments; OR
-> - Require involvement due to organizational role in qualification or compliance.
+- Represent organizations building or using LLVM-based tools in safety-critical environments; OR
+- Require involvement due to organizational role in qualification or compliance.
### Nomination Process
@@ -342,4 +342,3 @@ For more information or to get involved:
- Refer to our initial [RFC: Proposal to Establish a Safety Group in LLVM](https://discourse.llvm.org/t/rfc-proposal-to-establish-a-safety-group-in-llvm/86916) on the LLVM Discourse forum.
- Join the conversation on the LLVM Community Discord in the [#fusa-qual-wg](https://discord.com/channels/636084430946959380/1389362444169773117) channel.
-
diff --git a/llvm/docs/ScudoHardenedAllocator.md b/llvm/docs/ScudoHardenedAllocator.md
index a1982c978ef0b..36b2869791fcc 100644
--- a/llvm/docs/ScudoHardenedAllocator.md
+++ b/llvm/docs/ScudoHardenedAllocator.md
@@ -249,7 +249,7 @@ The following "string" options are available:
```
Additional flags can be specified, for example if Scudo if compiled with
-[GWP-ASan](https://llvm.org/docs/GwpAsan.html) support.
+{doc}`GWP-ASan <GwpAsan>` support.
The following "mallopt" options are available (options are defined in
`include/scudo/interface.h`):
@@ -336,4 +336,3 @@ Here is a list of the current error messages and their potential cause:
Several other error messages relate to parameter checking on the libc allocation
APIs and are fairly straightforward to understand.
-
diff --git a/llvm/docs/Security.md b/llvm/docs/Security.md
index 108532838faad..582a6a92f0612 100644
--- a/llvm/docs/Security.md
+++ b/llvm/docs/Security.md
@@ -26,7 +26,7 @@ We aim to acknowledge your report within two business days since you first reach
The members of the group represent a wide cross-section of the community, and
meet the criteria for inclusion below. The list is in the format
-`* ${full_name} (${affiliation}) [${github_username}]`. If a github
+{title-reference}`* ${full_name} (${affiliation}) [${github_username}]`. If a github
username for an individual isn't available, the brackets will be empty.
- Abhay Kanhere (Apple) [@AbhayKanhere]
@@ -94,7 +94,7 @@ If a nomination for LLVM Security Response Group membership is supported by a ma
### Accepting membership
-Before new LLVM Security Response Group membership is finalized, the successful nominee should accept membership and agree to abide by this security policy, particularly [Privileges and Responsibilities of LLVM Security Response Group Members] below.
+Before new LLVM Security Response Group membership is finalized, the successful nominee should accept membership and agree to abide by this security policy, particularly [Privileges and Responsibilities of LLVM Security Response Group Members](#privileges-and-responsibilities-of-llvm-security-response-group-members) below.
### Keeping Membership Current
@@ -114,7 +114,7 @@ The transparency reports are published at {doc}`SecurityTransparencyReports`.
### Access
-LLVM Security Response Group members will be subscribed to a private [Discussion Medium]. It will be used for technical discussions of security issues, as well as process discussions about matters such as disclosure timelines and group membership. Members have access to all security issues.
+LLVM Security Response Group members will be subscribed to a private [Discussion Medium](#discussion-medium). It will be used for technical discussions of security issues, as well as process discussions about matters such as disclosure timelines and group membership. Members have access to all security issues.
### Confidentiality
@@ -199,7 +199,7 @@ as security-sensitive but need significant work to get to the stage where that's
manageable. The LLVM community will need to decide whether it wants to invest in
making these parts of the code securable, and maintain these security properties
over time. In all cases the LLVM Security Response Group
-[should be consulted][security-group-discussion-medium], since they'll be
+{ref}`should be consulted <security-group-discussion-medium>`, since they'll be
responding to security issues filed against these parts of the codebase.
The security-sensitive parts of the LLVM Project currently are the following:
@@ -253,4 +253,3 @@ in the report, as well as update this document through the above process.
[llvm/llvm-security-repo]: https://github.com/llvm/llvm-security-repo/security
[mitre]: https://cve.mitre.org
[report a vulnerability]: https://github.com/llvm/llvm-security-repo/security/advisories/new
-
diff --git a/llvm/docs/SecurityTransparencyReports.md b/llvm/docs/SecurityTransparencyReports.md
index 6cdb1fd2fbddb..5a0ba8552eaf1 100644
--- a/llvm/docs/SecurityTransparencyReports.md
+++ b/llvm/docs/SecurityTransparencyReports.md
@@ -1,9 +1,10 @@
---
-substitutions:
- br: |-
- ```{raw} html
- <br/>
- ```
+myst:
+ substitutions:
+ br: |-
+ ```{raw} html
+ <br/>
+ ```
---
# LLVM Security Group Transparency Reports
@@ -107,44 +108,52 @@ that were received earlier, but were disclosed in 2023.
9 of these were judged to be security issues:
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=36> reports the presence of
-> .git folder in <https://llvm.org/.git>. Redirect:
-> <https://issuetracker.google.com/issues/42410029> archive:
-> <https://github.com/llvm/llvm-project/issues/131841>
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=66> reports the presence of a
-> GitHub Personal Access token in a DockerHub imaage. Redirect
-> <https://issuetracker.google.com/issues/42410060> archive:
-> <https://github.com/llvm/llvm-project/issues/131846>
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=42> reports a potential gap
-> in the Armv8.1-m BTI protection, involving a combination of large switch statements
-> and \_\_builtin_unreachable() in the default case. Redirect:
-> <https://issuetracker.google.com/issues/42410035> archive:
-> <https://github.com/llvm/llvm-project/issues/131848>
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=43> reports a dependency
-> on an old version of xml2js with a CVE filed against it. Redirect:
-> <https://issuetracker.google.com/issues/42410036> archive:
-> <https://github.com/llvm/llvm-project/issues/131849>
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=45> reports a number of
-> dependencies that have had vulnerabilities reported against them. Redirect:
-> <https://issuetracker.google.com/issues/42410038> archive:
-> <https://github.com/llvm/llvm-project/issues/131851>
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=46> is related to
-> issue 43. Redirect <https://issuetracker.google.com/issues/42410039> archive:
-> <https://github.com/llvm/llvm-project/issues/131852>
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=48> reports a buffer overflow in
-> std::format from -fexperimental-library. Redirect:
-> https://issuetracker.google.com/issues/42410041 archive:
-> https://github.com/llvm/llvm-project/issues/131856
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=54> reports a memory leak in
-> basic_string move assignment when built with libc++ versions \<=6.0 and run against
-> newer libc++ shared/dylibs. Redirect:
-> <https://issuetracker.google.com/issues/42410047> archive:
-> <https://github.com/llvm/llvm-project/issues/131857>
-> - <https://bugs.chromium.org/p/llvm/issues/detail?id=56> reports an out
-> of bounds buffer store introduced by LLVM backends, that regressed
-> due to a procedural oversight. Redirect
-> <https://issuetracker.google.com/issues/42410049> archive:
-> <https://github.com/llvm/llvm-project/issues/131858>
+- https://bugs.chromium.org/p/llvm/issues/detail?id=36 reports the presence of
+ .git folder in https://llvm.org/.git. Redirect:
+ https://issuetracker.google.com/issues/42410029 archive:
+ https://github.com/llvm/llvm-project/issues/131841
+
+- https://bugs.chromium.org/p/llvm/issues/detail?id=66 reports the presence of a
+ GitHub Personal Access token in a DockerHub imaage. Redirect
+ https://issuetracker.google.com/issues/42410060 archive:
+ https://github.com/llvm/llvm-project/issues/131846
+
+- https://bugs.chromium.org/p/llvm/issues/detail?id=42 reports a potential gap
+ in the Armv8.1-m BTI protection, involving a combination of large switch statements
+ and __builtin_unreachable() in the default case. Redirect:
+ https://issuetracker.google.com/issues/42410035 archive:
+ https://github.com/llvm/llvm-project/issues/131848
+
+- https://bugs.chromium.org/p/llvm/issues/detail?id=43 reports a dependency
+ on an old version of xml2js with a CVE filed against it. Redirect:
+ https://issuetracker.google.com/issues/42410036 archive:
+ https://github.com/llvm/llvm-project/issues/131849
+
+- https://bugs.chromium.org/p/llvm/issues/detail?id=45 reports a number of
+ dependencies that have had vulnerabilities reported against them. Redirect:
+ https://issuetracker.google.com/issues/42410038 archive:
+ https://github.com/llvm/llvm-project/issues/131851
+
+- https://bugs.chromium.org/p/llvm/issues/detail?id=46 is related to
+ issue 43. Redirect https://issuetracker.google.com/issues/42410039 archive:
+ https://github.com/llvm/llvm-project/issues/131852
+
+- https://bugs.chromium.org/p/llvm/issues/detail?id=48 reports a buffer overflow in
+ std::format from -fexperimental-library. Redirect:
+ https://issuetracker.google.com/issues/42410041 archive:
+ https://github.com/llvm/llvm-project/issues/131856
+
+- https://bugs.chromium.org/p/llvm/issues/detail?id=54 reports a memory leak in
+ basic_string move assignment when built with libc++ versions <=6.0 and run against
+ newer libc++ shared/dylibs. Redirect:
+ https://issuetracker.google.com/issues/42410047 archive:
+ https://github.com/llvm/llvm-project/issues/131857
+
+- https://bugs.chromium.org/p/llvm/issues/detail?id=56 reports an out
+ of bounds buffer store introduced by LLVM backends, that regressed
+ due to a procedural oversight. Redirect
+ https://issuetracker.google.com/issues/42410049 archive:
+ https://github.com/llvm/llvm-project/issues/131858
No dedicated LLVM releases were made for any of the above issues.
@@ -455,4 +464,3 @@ were not related to the LLVM project. The subject lines for these were:
3. “I was recently hacked... maybe you folks might know the dev?”
4. “ASP.NETconfiguration: Creating Debug Binary in `[](https://github.com/llvm/llvm-project/actions/workflows`”
5. “ASP.NETconfiguration: Creating Debug Binary in `[](https://github.com/llvm/llvm-project/actions/workflows`”
-
diff --git a/llvm/docs/SegmentedStacks.md b/llvm/docs/SegmentedStacks.md
index a23541379612d..a11592d325163 100644
--- a/llvm/docs/SegmentedStacks.md
+++ b/llvm/docs/SegmentedStacks.md
@@ -14,7 +14,7 @@ The runtime functionality is [already there in libgcc](http://gcc.gnu.org/wiki/S
## Implementation Details
-(allocating-stacklets)=
+(allocating stacklets)=
### Allocating Stacklets
@@ -53,7 +53,7 @@ second return, which returns control to the correct caller.
### Variable Sized Allocas
-The section on [allocating stacklets] automatically assumes that every stack
+The section on {ref}`allocating stacklets <allocating stacklets>` automatically assumes that every stack
frame will be of fixed size. However, LLVM allows the use of the `llvm.alloca`
intrinsic to allocate dynamically sized blocks of memory on the stack. When
faced with such a variable-sized alloca, code is generated to:
@@ -65,4 +65,3 @@ faced with such a variable-sized alloca, code is generated to:
The memory allocated from the heap is linked into a list in the current
stacklet, and freed along with the same. This prevents a memory leak.
-
diff --git a/llvm/docs/StackMaps.md b/llvm/docs/StackMaps.md
index 2d07a0aaa2c3c..652b23a6750df 100644
--- a/llvm/docs/StackMaps.md
+++ b/llvm/docs/StackMaps.md
@@ -44,10 +44,10 @@ releases is not guaranteed.
The stack map functionality described in this document is separate
from the functionality described in
-{ref}`stack-map`. `GCFunctionMetadata` provides the location of
-pointers into a collected heap captured by the `GCRoot` intrinsic,
+{ref}`stack-map`. *GCFunctionMetadata* provides the location of
+pointers into a collected heap captured by the *GCRoot* intrinsic,
which can also be considered a "stack map". Unlike the stack maps
-defined above, the `GCFunctionMetadata` stack map interface does not
+defined above, the *GCFunctionMetadata* stack map interface does not
provide a way to associate live register values of arbitrary type with
an instruction address, nor does it specify a format for the resulting
stack map. The stack maps described here could potentially provide
@@ -341,17 +341,13 @@ StkMapRecord[NumRecords] {
The first byte of each location encodes a type that indicates how to
interpret the `RegNum` and `Offset` fields as follows:
-```{eval-rst}
-======== ========== =================== ===========================
-Encoding Type Value Description
--------- ---------- ------------------- ---------------------------
-0x1 Register Reg Value in a register
-0x2 Direct Reg + Offset Frame index value
-0x3 Indirect [Reg + Offset] Spilled value
-0x4 Constant Offset Small constant
-0x5 ConstIndex Constants[Offset] Large constant
-======== ========== =================== ===========================
-```
+| Encoding | Type | Value | Description |
+| -------- | ---------- | ----------------- | ------------------- |
+| 0x1 | Register | Reg | Value in a register |
+| 0x2 | Direct | Reg + Offset | Frame index value |
+| 0x3 | Indirect | [Reg + Offset] | Spilled value |
+| 0x4 | Constant | Offset | Small constant |
+| 0x5 | ConstIndex | Constants[Offset] | Large constant |
In the common case, a value is available in a register, and the
`Offset` field will be zero. Values spilled to the stack are encoded
@@ -492,4 +488,3 @@ Support for StackMap generation and the related intrinsics requires
some code for each backend. Today, only a subset of LLVM's backends
are supported. The currently supported architectures are X86_64,
PowerPC, AArch64 and SystemZ.
-
diff --git a/llvm/docs/Statepoints.md b/llvm/docs/Statepoints.md
index 5a39f643e0f00..6d24effc7b54d 100644
--- a/llvm/docs/Statepoints.md
+++ b/llvm/docs/Statepoints.md
@@ -321,7 +321,7 @@ lowering both the base and derived pointer operands are required to be live
over the associated call safepoint even if the base is otherwise unused
afterwards.
-(gc-transition-args)=
+(gc_transition_args)=
### GC Transitions
@@ -419,7 +419,7 @@ This special section is encoded per the
The general expectation is that a JIT compiler will parse and discard this
format; it is not particularly memory efficient. If you need an alternate
format (e.g. for an ahead of time compiler), see discussion under
-\:ref: `open work items <OpenWork>` below.
+{ref}`open work items <OpenWork>` below.
Each statepoint generates the following Locations:
@@ -510,7 +510,7 @@ experimenting with the current version.
## Utility Passes for Safepoint Insertion
-(rewritestatepointsforgc)=
+(RewriteStatepointsForGC)=
### RewriteStatepointsForGC
@@ -587,7 +587,7 @@ In practice, RewriteStatepointsForGC should be run much later in the pass
pipeline, after most optimization is already done. This helps to improve
the quality of the generated code when compiled with garbage collection support.
-(rewritestatepointsforgc-intrinsic-lowering)=
+(RewriteStatepointsForGC_intrinsic_lowering)=
### RewriteStatepointsForGC intrinsic lowering
@@ -633,7 +633,7 @@ declare void @__llvm_memcpy_element_unordered_atomic_safepoint_1(
i64 %length)
```
-(placesafepoints)=
+(PlaceSafepoints)=
### PlaceSafepoints
@@ -701,7 +701,7 @@ here.
Support for statepoint generation requires some code for each backend.
Today, only Aarch64 and X86_64 are supported.
-(openwork)=
+(OpenWork)=
## Limitations and Half Baked Ideas
@@ -757,4 +757,3 @@ for [Statepoint] in the summary field. When filing new bugs, please
use this tag so that interested parties see the newly filed bug. As
with most LLVM features, design discussions take place on the [Discourse forums](https://discourse.llvm.org) and patches
should be sent to [llvm-commits](http://lists.llvm.org/mailman/listinfo/llvm-commits) for review.
-
diff --git a/llvm/docs/SupportPolicy.md b/llvm/docs/SupportPolicy.md
index 3f22b36ea15db..7e052bee3da2a 100644
--- a/llvm/docs/SupportPolicy.md
+++ b/llvm/docs/SupportPolicy.md
@@ -169,11 +169,11 @@ burden on maintaining other components (core or peripheral).
There are multiple types of issues that might trigger a request for deprecation,
including (but not limited to):
-> - Changes in a component consistently break other areas of the project.
-> - Components go broken for long periods of time (weeks or more).
-> - Clearly superior alternatives are in use and maintenance is painful.
-> - Builds and tests are harder / take longer, increasing the cost of
-> maintenance, overtaking the perceived benefits.
+- Changes in a component consistently break other areas of the project.
+- Components go broken for long periods of time (weeks or more).
+- Clearly superior alternatives are in use and maintenance is painful.
+- Builds and tests are harder / take longer, increasing the cost of
+ maintenance, overtaking the perceived benefits.
If the maintenance cost is higher than it is acceptable by the majority of
developers, it means that either the sub-community is too small (and the extra
@@ -229,4 +229,3 @@ overall maintenance costs to a minimum and will need to show steps to mitigate
all of the issues that were listed as reasons for its original removal.
Failing on those again, will lead to become a candidate for removal yet again.
-
diff --git a/llvm/docs/TableGen/BackEnds.md b/llvm/docs/TableGen/BackEnds.md
index 47b7be492332f..03df57b33cb27 100644
--- a/llvm/docs/TableGen/BackEnds.md
+++ b/llvm/docs/TableGen/BackEnds.md
@@ -221,7 +221,7 @@ from TableGen records. The ARM and AArch64 targets use this backend to generate
tables of system registers; the AMDGPU target uses it to generate meta-data
about complex image and memory buffer instructions.
-See [SearchableTables Reference] for a detailed description.
+See [SearchableTables Reference](#searchabletables-reference) for a detailed description.
### CTags
@@ -1068,7 +1068,7 @@ function. This class provides three fields.
- `GenericTable Table`. The name of the table that is to receive another
lookup function.
- `list<string> Key`. The list of fields that make up the secondary key.
-- `bit EarlyOut`. See the third example in [Generic Tables].
+- `bit EarlyOut`. See the third example in [Generic Tables](#generic-tables).
Here is an example of a secondary key added to the `CTable` above. The
generated function looks up entries based on the `Name` and `Kind` fields.
@@ -1124,4 +1124,3 @@ const CEntry *lookupCEntryByName(StringRef Name, unsigned Kind) {
return &CTable[Idx->_index];
}
```
-
diff --git a/llvm/docs/TableGen/BackGuide.md b/llvm/docs/TableGen/BackGuide.md
index 1e232c1cbeb28..bc1ce3c82c583 100644
--- a/llvm/docs/TableGen/BackGuide.md
+++ b/llvm/docs/TableGen/BackGuide.md
@@ -1,9 +1,7 @@
# TableGen Backend Developer's Guide
-```{eval-rst}
-.. sectnum::
-
-```
+:::{sectnum}
+:::
## Introduction
@@ -46,7 +44,7 @@ is usually abbreviated `RK`.
There are two maps in the recordkeeper, one for classes and one for records
(the latter often referred to as *defs*). Each map maps the class or record
-name to an instance of the `Record` class (see [Record]), which contains
+name to an instance of the `Record` class (see [Record](#record)), which contains
all the information about that class or record.
In addition to the two maps, the `RecordKeeper` instance contains:
@@ -73,10 +71,10 @@ classes and one for the records. The primary data members of a record are
the record name, the vector of field names and their values, and the vector of
superclasses of the record.
-The record name is stored as a pointer to an `Init` (see [Init]), which
+The record name is stored as a pointer to an `Init` (see [Init](#init)), which
is a class whose instances hold TableGen values (sometimes referred to as
*initializers*). The field names and values are stored in a vector of
-`RecordVal` instances (see [RecordVal]), each of which contains both the
+`RecordVal` instances (see [RecordVal](#recordval)), each of which contains both the
field name and its value. The superclass vector contains a sequence of
pairs, with each pair including the superclass record and its source
file location.
@@ -86,7 +84,7 @@ In addition to those members, a `Record` instance contains:
- A vector of source file locations that includes the record definition
itself, plus the locations of any multiclasses involved in its definition.
- For a class record, a vector of the class's template arguments.
-- An instance of `DefInit` (see [DefInit]) corresponding to this record.
+- An instance of `DefInit` (see [DefInit](#definit)) corresponding to this record.
- A unique record ID.
- A boolean that specifies whether this is a class definition.
- A boolean that specifies whether this is an anonymous record.
@@ -99,7 +97,7 @@ The `Record` class provides many useful functions.
superclasses.
- Functions to get a particular field value by specifying its name in various
forms and returning its value in various forms
- (see [Getting Record Names and Fields]).
+ (see [Getting Record Names and Fields](#getting-record-names-and-fields)).
- Boolean functions to check the various attributes of the record.
A `Record` instance can be printed to an output stream with the `<<`
@@ -117,7 +115,7 @@ In addition to those primary members, the `RecordVal` has other data members.
- The source file location of the field definition.
- The type of the field, stored as an instance
- of the `RecTy` class (see [RecTy]).
+ of the `RecTy` class (see [RecTy](#recty)).
The `RecordVal` class provides some useful functions.
@@ -127,7 +125,7 @@ The `RecordVal` class provides some useful functions.
- A function to get the source file location.
Note that field values are more easily obtained directly from the `Record`
-instance (see [Record]).
+instance (see [Record](#record)).
A `RecordVal` instance can be printed to an output stream with the `<<`
operator.
@@ -480,7 +478,7 @@ for (Record *AttrRec : AttrRecords) {
## Getting Record Names and Fields
-As described above (see [Record]), there are multiple functions that
+As described above (see [Record](#record)), there are multiple functions that
return the name of a record. One particularly useful one is
`getNameInitAsString()`, which returns the name as a `std::string`.
@@ -610,10 +608,10 @@ Each of these five functions is overloaded four times.
source file locations is typically taken from a `Record` instance.
- `PrintError(const Record *Rec, const Twine &Msg)`:
Prints the message followed by the source line associated with the
- specified record (see [Record]).
+ specified record (see [Record](#record)).
- `PrintError(const RecordVal *RecVal, const Twine &Msg)`:
Prints the message followed by the source line associated with the
- specified record field (see [RecordVal]).
+ specified record field (see [RecordVal](#recordval)).
Using these functions, the goal is to produce the most specific error report
possible.
@@ -760,4 +758,3 @@ The backend has been divided into four phases and timed separately.
If you want to instrument a backend, refer to the backend `DAGISelEmitter.cpp`
and search for `Records.startTimer`.
-
diff --git a/llvm/docs/TableGen/ProgRef.md b/llvm/docs/TableGen/ProgRef.md
index 4c2c802fc9fe5..ff8a271ab24a6 100644
--- a/llvm/docs/TableGen/ProgRef.md
+++ b/llvm/docs/TableGen/ProgRef.md
@@ -1,9 +1,7 @@
# TableGen Programmer's Reference
-```{eval-rst}
-.. sectnum::
-
-```
+:::{sectnum}
+:::
## Introduction
@@ -103,23 +101,23 @@ multiple concrete records all at once. A multiclass can inherit from other
multiclasses, which means that the multiclass inherits all the definitions
from its parent multiclasses.
-[Appendix C: Sample Record] illustrates a complex record in the Intel X86
+[Appendix C: Sample Record](#appendix-c-sample-record) illustrates a complex record in the Intel X86
target and the simple way in which it is defined.
## Source Files
TableGen source files are plain ASCII text files. The files can contain
-statements, comments, and blank lines (see [Lexical Analysis]). The standard file
+statements, comments, and blank lines (see [Lexical Analysis](#lexical-analysis)). The standard file
extension for TableGen files is `.td`.
TableGen files can grow quite large, so there is an include mechanism that
allows one file to include the content of another file (see [Include
-Files][include files]). This allows large files to be broken up into smaller ones, and
+Files](#include-files)). This allows large files to be broken up into smaller ones, and
also provides a simple library mechanism where multiple source files can
include the same library file.
TableGen supports a simple preprocessor that can be used to conditionalize
-portions of `.td` files. See [Preprocessing Facilities] for more
+portions of `.td` files. See [Preprocessing Facilities](#preprocessing-facilities) for more
information.
## Lexical Analysis
@@ -132,7 +130,7 @@ implied whitespace between tokens.
TableGen supports BCPL-style comments (`// ...`) and nestable C-style
comments (`/* ... */`).
-TableGen also provides simple [Preprocessing Facilities].
+TableGen also provides simple [Preprocessing Facilities](#preprocessing-facilities).
Formfeed characters may be used freely in files to produce page breaks when
the file is printed for review.
@@ -237,7 +235,7 @@ syntax compared to other bang operators, so it is defined separately:
CondOperator: !cond
```
-See [Appendix A: Bang Operators] for a description of each bang operator.
+See [Appendix A: Bang Operators](#appendix-a-bang-operators) for a description of each bang operator.
### Include files
@@ -321,7 +319,7 @@ wide range of records conveniently and compactly.
another `dag` object, allowing an arbitrary tree of nodes and edges.
As an example, DAGs are used to represent code patterns for use by
the code generator instruction selection algorithms. See [Directed
- acyclic graphs (DAGs)][directed acyclic graphs (dags)] for more details;
+ acyclic graphs (DAGs)](#directed-acyclic-graphs-dags) for more details;
{token}`ClassID`
@@ -451,7 +449,7 @@ sometimes not when the value is the empty list (`[]`).
This represents a DAG initializer (note the parentheses). The first
{token}`DagArg` is called the "operator" of the DAG and must be a record.
-See [Directed acyclic graphs (DAGs)] for more details.
+See [Directed acyclic graphs (DAGs)](#directed-acyclic-graphs-dags) for more details.
```{eval-rst}
.. productionlist::
@@ -474,7 +472,7 @@ sense after reading the remainder of this guide.
```
- The implicit template argument `NAME` in a `class` or `multiclass`
- definition (see [NAME]).
+ definition (see [NAME](#name)).
- A field local to a `class`, such as the use of `Bar` in:
@@ -533,11 +531,11 @@ sense after reading the remainder of this guide.
This form creates a new anonymous record definition (as would be created by an
unnamed `def` inheriting from the given class with the given template
-arguments; see [def]) and the value is that record. A field of the record can be
-obtained using a suffix; see [Suffixed Values].
+arguments; see [def](#def)) and the value is that record. A field of the record can be
+obtained using a suffix; see [Suffixed Values](#suffixed-values).
Invoking a class in this manner can provide a simple subroutine facility.
-See [Using Classes as Subroutines] for more information.
+See [Using Classes as Subroutines](#using-classes-as-subroutines) for more information.
```{eval-rst}
.. productionlist::
@@ -551,9 +549,9 @@ simple values. Except in the case of `!cond`, a bang operator takes a list
of arguments enclosed in parentheses and performs some function on those
arguments, producing a value for that bang operator. The `!cond` operator
takes a list of pairs of arguments separated by colons. See [Appendix A:
-Bang Operators][appendix a: bang operators] for a description of each bang operator.
+Bang Operators](#appendix-a-bang-operators) for a description of each bang operator.
-The `Type` is only accepted for certain bang operators, and must not be
+The *Type* is only accepted for certain bang operators, and must not be
`code`.
### Suffixed values
@@ -573,13 +571,13 @@ primary value. Here are the possible suffixes for some primary *value*.
*value*`[i]`
-: The final value is element `i` of the list *value* (note the brackets).
+: The final value is element *i* of the list *value* (note the brackets).
In other words, the brackets act as a subscripting operator on the list.
This is the case only when a single element is specified.
*value*`[i,]`
-: The final value is a list that contains a single element `i` of the list.
+: The final value is a list that contains a single element *i* of the list.
In short, a list slice with a single element.
*value*`[4...7,17,2...3,4]`
@@ -592,8 +590,8 @@ primary value. Here are the possible suffixes for some primary *value*.
*value*`[i,m...n,j,ls]`
: Each element may be an expression (variables, bang operators).
- The type of `m` and `n` should be `int`.
- The type of `i`, `j`, and `ls` should be either `int` or `list<int>`.
+ The type of *m* and *n* should be *int*.
+ The type of *i*, *j*, and *ls* should be either *int* or *list\<int>*.
*value*`.`*field*
@@ -621,7 +619,7 @@ left-hand-side operand is treated normally.
Values can have a trailing paste operator, in which case the left-hand-side
operand is concatenated to an empty string.
-[Appendix B: Paste Operator Examples] presents examples of the behavior of
+[Appendix B: Paste Operator Examples](#appendix-b-paste-operator-examples) presents examples of the behavior of
the paste operator.
## Statements
@@ -683,14 +681,14 @@ forward declaration. Note that records derived from a forward-declared
class will inherit no fields from it, because those records are built when
their declarations are parsed, and thus before the class is finally defined.
-(name)=
+(NAME)=
Every class has an implicit template argument named `NAME` (uppercase),
which is bound to the name of the {token}`Def` or {token}`Defm` inheriting
from the class. If the class is inherited by an anonymous record, the name
is unspecified but globally unique.
-See [Examples: classes and records] for examples.
+See [Examples: classes and records](#examples-classes-and-records) for examples.
#### Record Bodies
@@ -788,7 +786,7 @@ The `defvar` form defines a variable whose value can be used in other
value expressions within the body. The variable is not a field: it does not
become a field of the class or record being defined. Variables are provided
to hold temporary values while processing the body. See [Defvar in a Record
-Body][defvar in a record body] for more details.
+Body](#defvar-in-a-record-body) for more details.
When class `C2` inherits from class `C1`, it acquires all the field
definitions of `C1`. As those definitions are merged into class `C2`, any
@@ -841,9 +839,9 @@ The DAG `(ops rec1)` is passed as a template argument to class `A`. Notice
that the DAG includes `rec1`, the record being defined.
The steps taken to create a new record are somewhat complex. See [How
-records are built][how records are built].
+records are built](#how-records-are-built).
-See [Examples: classes and records] for examples.
+See [Examples: classes and records](#examples-classes-and-records) for examples.
### Examples: classes and records
@@ -1051,7 +1049,7 @@ contains a series of statements that define records, using {token}`Def` and
The {token}`If` and {token}`Assert` statements can also be used.
Also as with regular classes, the multiclass has the implicit template
-argument `NAME` (see [NAME]). When a named (non-anonymous) record is
+argument `NAME` (see [NAME](#name)). When a named (non-anonymous) record is
defined in a multiclass and the record's name does not include a use of the
template argument `NAME`, such a use is automatically *prepended*
to the name. That is, the following are equivalent inside a multiclass:
@@ -1067,7 +1065,7 @@ definition. Each `def` statement in the multiclass produces a record. As
with top-level `def` statements, these definitions can inherit from
multiple parent classes.
-See [Examples: multiclasses and defms] for examples.
+See [Examples: multiclasses and defms](#examples-multiclasses-and-defms) for examples.
### `defm` --- invoke multiclasses to define multiple records
@@ -1119,7 +1117,7 @@ defm Foo : SomeMultiClass<...>;
defm NAME # Foo : SomeMultiClass<...>;
```
-See [Examples: multiclasses and defms] for examples.
+See [Examples: multiclasses and defms](#examples-multiclasses-and-defms) for examples.
### Examples: multiclasses and defms
@@ -1348,7 +1346,7 @@ The identifier on the left of the `=` is defined to be a type name
whose actual type is given by the type expression on the right of the `=`.
Currently, only primitive types and type aliases are supported to be the source
-type and `deftype` statements can only appear at the top level.
+type and *deftype* statements can only appear at the top level.
### `defvar` --- define a variable
@@ -1375,7 +1373,7 @@ defvar i = !add(i, 1);
```
Variables can also be defined with `defvar` in a record body. See
-[Defvar in a Record Body] for more details.
+[Defvar in a Record Body](#defvar-in-a-record-body) for more details.
### `foreach` --- iterate over a sequence of statements
@@ -1419,7 +1417,7 @@ A `dump` statement prints the input string to standard error
output. It is intended for debugging purposes.
- At top level, the message is printed immediately.
-- Within a record/class/multiclass, `dump` gets evaluated at each
+- Within a record/class/multiclass, *dump* gets evaluated at each
instantiation point of the containing record.
```{eval-rst}
@@ -1428,7 +1426,7 @@ output. It is intended for debugging purposes.
```
The {token}`Value` is an arbitrary string expression.
-For example, it can be used in combination with `!repr` to investigate
+For example, it can be used in combination with *!repr* to investigate
the values passed to a multiclass:
```text
@@ -1462,7 +1460,7 @@ the usual way: in a case like `if v1 then if v2 then {...} else {...}`, the
The {token}`IfBody` of the then and else arms of the `if` establish an
inner scope. Any `defvar` variables defined in the bodies go out of scope
-when the bodies are finished (see [Defvar in a Record Body] for more details).
+when the bodies are finished (see [Defvar in a Record Body](#defvar-in-a-record-body) for more details).
The `if` statement can also be used in a record {token}`Body`.
@@ -1579,24 +1577,29 @@ defvar i = !add(i, 1)
The following steps are taken by TableGen when a record is built. Classes are simply
abstract records and so go through the same steps.
-1. Build the record name ({token}`NameValue`) and create an empty record.
-2. Parse the parent classes in the {token}`ParentClassList` from left to
+```{eval-rst}
+1. Build the record name (:token:`NameValue`) and create an empty record.
+
+2. Parse the parent classes in the :token:`ParentClassList` from left to
right, visiting each parent class's ancestor classes from top to bottom.
-> 1. Add the fields from the parent class to the record.
-> 2. Substitute the template arguments into those fields.
-> 3. Add the parent class to the record's list of inherited classes.
+ a. Add the fields from the parent class to the record.
+ b. Substitute the template arguments into those fields.
+ c. Add the parent class to the record's list of inherited classes.
-3. Apply any top-level `let` bindings to the record. Recall that top-level
+3. Apply any top-level ``let`` bindings to the record. Recall that top-level
bindings only apply to inherited fields.
+
4. Parse the body of the record.
-> - Add any fields to the record.
-> - Modify the values of fields according to local `let` statements.
-> - Define any `defvar` variables.
+ * Add any fields to the record.
+ * Modify the values of fields according to local ``let`` statements.
+ * Define any ``defvar`` variables.
5. Make a pass over all the fields to resolve any inter-field references.
+
6. Add the record to the final record list.
+```
Because references between fields are resolved (step 5) after `let` bindings are
applied (step 3), the `let` statement has unusual power. For example:
@@ -1639,7 +1642,7 @@ def rec2 { // C
## Using Classes as Subroutines
-As described in [Simple values], a class can be invoked in an expression
+As described in [Simple values](#simple-values), a class can be invoked in an expression
and passed template arguments. This causes TableGen to create a new anonymous
record inheriting from that class. As usual, the record receives all the
fields defined in the class.
@@ -1850,14 +1853,14 @@ and non-0 as true.
`!filter(`*var*`,` *list*`,` *predicate*`)`
-> This operator creates a new `list` by filtering the elements in
-> *list*. To perform the filtering, TableGen binds the variable *var* to each
-> element and then evaluates the *predicate* expression, which presumably
-> refers to *var*. The predicate must
-> produce a boolean value (`bit`, `bits`, or `int`). The value is
-> interpreted as with `!if`:
-> if the value is 0, the element is not included in the new list. If the value
-> is anything else, the element is included.
+: This operator creates a new `list` by filtering the elements in
+ *list*. To perform the filtering, TableGen binds the variable *var* to each
+ element and then evaluates the *predicate* expression, which presumably
+ refers to *var*. The predicate must
+ produce a boolean value (`bit`, `bits`, or `int`). The value is
+ interpreted as with `!if`:
+ if the value is 0, the element is not included in the new list. If the value
+ is anything else, the element is included.
`!find(`*string1*`,` *string2*\[`,` *start*\]`)`
@@ -2067,10 +2070,10 @@ and non-0 as true.
For example:
- `!range(4)` is equivalent to `!range(0, 4, 1)` and the result is
- `[0, 1, 2, 3]`.
+ *[0, 1, 2, 3]*.
- `!range(1, 4)` is equivalent to `!range(1, 4, 1)` and the result is
- `[1, 2, 3]`.
- - The result of `!range(0, 4, 2)` is `[0, 2]`.
+ *[1, 2, 3]*.
+ - The result of `!range(0, 4, 2)` is *[0, 2]*.
- The results of `!range(0, 4, -1)` and `!range(4, 0, 1)` are empty.
`!range(`*list*`)`
@@ -2129,11 +2132,9 @@ and non-0 as true.
For example, to sort a list of records by their `Name` field:
+ ```text
+ list<Thing> sorted = !sort(t, Things, t.Name);
```
- .. code-block:: text
- ```
-
- > list\<Thing> sorted = !sort(t, Things, t.Name);
`!sra(`*a*`,` *count*`)`
@@ -2407,4 +2408,3 @@ from all the parent classes; for example, `IsIndirectBranch` is inherited
from the `Instruction` class.
[python's]: http://docs.python.org/py3k/reference/introduction.html#notation
-
diff --git a/llvm/docs/TransformMetadata.md b/llvm/docs/TransformMetadata.md
index 302a35944db72..588e8bb3546c6 100644
--- a/llvm/docs/TransformMetadata.md
+++ b/llvm/docs/TransformMetadata.md
@@ -390,7 +390,7 @@ if (rtc) {
```
The runtime condition (`rtc`) checks that the array `A` and the
-element `B[0]` do not alias.
+element {title-reference}`B[0]` do not alias.
Currently, this transformation does not support followup-attributes.
@@ -407,28 +407,28 @@ to change. The default optimization pipeline (anything higher than
When using the legacy pass manager:
-> - LoopInterchange (if enabled)
-> - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
-> - VersioningLICM (if enabled)
-> - LoopDistribute
-> - LoopVectorizer
-> - LoopUnrollAndJam (if enabled)
-> - LoopUnroll (partial and runtime unrolling)
+- LoopInterchange (if enabled)
+- SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
+- VersioningLICM (if enabled)
+- LoopDistribute
+- LoopVectorizer
+- LoopUnrollAndJam (if enabled)
+- LoopUnroll (partial and runtime unrolling)
When using the legacy pass manager with LTO:
-> - LoopInterchange (if enabled)
-> - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
-> - LoopVectorizer
-> - LoopUnroll (partial and runtime unrolling)
+- LoopInterchange (if enabled)
+- SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
+- LoopVectorizer
+- LoopUnroll (partial and runtime unrolling)
When using the new pass manager:
-> - SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
-> - LoopDistribute
-> - LoopVectorizer
-> - LoopUnrollAndJam (if enabled)
-> - LoopUnroll (partial and runtime unrolling)
+- SimpleLoopUnroll/LoopFullUnroll (only performs full unrolling)
+- LoopDistribute
+- LoopVectorizer
+- LoopUnrollAndJam (if enabled)
+- LoopUnroll (partial and runtime unrolling)
## Leftover Transformations
@@ -455,4 +455,3 @@ case.
Future versions of LLVM may fix this by executing transformations using
a dynamic ordering.
-
diff --git a/llvm/docs/TypeMetadata.md b/llvm/docs/TypeMetadata.md
index 8626fd39598d0..c286cccd99020 100644
--- a/llvm/docs/TypeMetadata.md
+++ b/llvm/docs/TypeMetadata.md
@@ -56,15 +56,14 @@ struct D : A, C {
The virtual table objects for A, B, C and D look like this (under the Itanium ABI):
-```{eval-rst}
-.. csv-table:: Virtual Table Layout for A, B, C, D
- :header: Class, 0, 1, 2, 3, 4, 5, 6
+:::{csv-table} Virtual Table Layout for A, B, C, D
+:header: Class, 0, 1, 2, 3, 4, 5, 6
- A, A::offset-to-top, &A::rtti, &A::f
- B, B::offset-to-top, &B::rtti, &B::f, &B::g
- C, C::offset-to-top, &C::rtti, &C::h
- D, D::offset-to-top, &D::rtti, &D::f, &D::h, D::offset-to-top, &D::rtti, thunk for &D::h
-```
+A, A::offset-to-top, &A::rtti, &A::f
+B, B::offset-to-top, &B::rtti, &B::f, &B::g
+C, C::offset-to-top, &C::rtti, &C::h
+D, D::offset-to-top, &D::rtti, &D::f, &D::h, D::offset-to-top, &D::rtti, thunk for &D::h
+:::
When an object of type A is constructed, the address of `&A::f` in A's
virtual table object is stored in the object's vtable pointer. In ABI parlance
@@ -84,18 +83,17 @@ shown below. The following table shows the name of a class, the offset of an
address point within that class's vtable and the name of one of the classes
with which that address point is compatible.
-```{eval-rst}
-.. csv-table:: Type Offsets for A, B, C, D
- :header: VTable for, Offset, Compatible Class
-
- A, 16, A
- B, 16, A
- , , B
- C, 16, C
- D, 16, A
- , , D
- , 48, C
-```
+:::{csv-table} Type Offsets for A, B, C, D
+:header: VTable for, Offset, Compatible Class
+
+A, 16, A
+B, 16, A
+ , , B
+C, 16, C
+D, 16, A
+ , , D
+ , 48, C
+:::
The next step is to encode this compatibility information into the IR. The way
this is done is to create type metadata named after each of the compatible
@@ -156,6 +154,8 @@ as the former will be the jump table entry if a jump table is necessary.
The [GlobalLayoutBuilder][globallayoutbuilder] class is responsible for laying out the globals
efficiently to minimize the sizes of the underlying bitsets.
+**Example:**
+
```
target datalayout = "e-p:32:32"
@@ -284,4 +284,3 @@ normal loads.
[control flow integrity]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
[control flow integrity design document]: https://clang.llvm.org/docs/ControlFlowIntegrityDesign.html
[globallayoutbuilder]: https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h
-
diff --git a/llvm/docs/VectorizationPlan.md b/llvm/docs/VectorizationPlan.md
index 6df336f3c28e6..560f9080a95d9 100644
--- a/llvm/docs/VectorizationPlan.md
+++ b/llvm/docs/VectorizationPlan.md
@@ -1,9 +1,14 @@
+---
+myst:
+ footnote_transition: false
+---
+
# Vectorization Plan
## Abstract
The vectorization transformation can be rather complicated, involving several
-potential alternatives, especially for outer-loops [^footnote-1] but also possibly for
+potential alternatives, especially for outer-loops [^1] but also possibly for
innermost loops. These alternatives may have significant performance impact,
both positive and negative. A cost model is therefore employed to identify the
best alternative, including the alternative of avoiding any transformation
@@ -20,7 +25,7 @@ VPlan is currently used to drive code-generation in LoopVectorize. VPlans are
constructed after all cost-based and most legality-related decisions have been
taken. As def-use chains between recipes are now fully modeled in VPlan,
VPlan-based analyses and transformations are used to simplify and modularize
-the vectorization process [^footnote-10]. Those include transformations to
+the vectorization process [^10]. Those include transformations to
1. Legalize the initial VPlan, e.g. by introducing specialized recipes for
reductions and interleave groups.
@@ -104,8 +109,8 @@ The design of VPlan follows several high-level guidelines:
3. Combinations of the above, including nested vectorization: vectorizing
both an inner loop and an outer-loop at the same time (each with its own
VF and UF), mixed vectorization: vectorizing a loop with SLP patterns
- inside [^footnote-4], (re)vectorizing input IR containing vector code.
- 4. Function vectorization [^footnote-2].
+ inside [^4], (re)vectorizing input IR containing vector code.
+ 4. Function vectorization [^2].
4. Support multiple candidates efficiently. In particular, similar candidates
related to a range of possible VF's and UF's must be represented efficiently.
@@ -131,39 +136,44 @@ The design of VPlan follows several high-level guidelines:
The low-level design of VPlan comprises of the following classes.
-```{eval-rst}
+LoopVectorizationPlanner
+: A LoopVectorizationPlanner is designed to handle the vectorization of a loop
+ or a loop nest. It can construct, optimize and discard one or more VPlans,
+ each VPlan modelling a distinct way to vectorize the loop or the loop nest.
+ Once the best VPlan is determined, including the best VF and UF, this VPlan
+ drives the generation of output IR.
-:VPlan:
- A model of a vectorized candidate for a given input IR loop or loop nest. This
+VPlan
+: A model of a vectorized candidate for a given input IR loop or loop nest. This
candidate is represented using a Hierarchical CFG. VPlan supports estimating
the cost and driving the generation of the output IR code it represents.
-:Hierarchical CFG:
- A control-flow graph whose nodes are basic-blocks or Hierarchical CFG's. The
- Hierarchical CFG data structure is similar to the Tile Tree [5]_, where
+Hierarchical CFG
+: A control-flow graph whose nodes are basic-blocks or Hierarchical CFG's. The
+ Hierarchical CFG data structure is similar to the Tile Tree [^5], where
cross-Tile edges are lifted to connect Tiles instead of the original
- basic-blocks as in Sharir [6]_, promoting the Tile encapsulation. The terms
- Region and Block are used rather than Tile [5]_ to avoid confusion with loop
+ basic-blocks as in Sharir [^6], promoting the Tile encapsulation. The terms
+ Region and Block are used rather than Tile [^5] to avoid confusion with loop
tiling.
-:VPBlockBase:
- The building block of the Hierarchical CFG. A pure-virtual base-class of
+VPBlockBase
+: The building block of the Hierarchical CFG. A pure-virtual base-class of
VPBasicBlock and VPRegionBlock, see below. VPBlockBase models the hierarchical
control-flow relations with other VPBlocks. Note that in contrast to the IR
BasicBlock, a VPBlockBase models its control-flow successors and predecessors
directly, rather than through a Terminator branch or through predecessor
branches that "use" the VPBlockBase.
-:VPBasicBlock:
- VPBasicBlock is a subclass of VPBlockBase, and serves as the leaves of the
+VPBasicBlock
+: VPBasicBlock is a subclass of VPBlockBase, and serves as the leaves of the
Hierarchical CFG. It represents a sequence of output IR instructions that will
appear consecutively in an output IR basic-block. The instructions of this
basic-block originate from one or more VPBasicBlocks. VPBasicBlock holds a
sequence of zero or more VPRecipes that model the cost and generation of the
output IR instructions.
-:VPRegionBlock:
- VPRegionBlock is a subclass of VPBlockBase. It models a collection of
+VPRegionBlock
+: VPRegionBlock is a subclass of VPBlockBase. It models a collection of
VPBasicBlocks and VPRegionBlocks which form a SESE subgraph of the output IR
CFG. A VPRegionBlock may indicate that its contents are to be replicated a
constant number of times when output IR is generated, effectively representing
@@ -171,46 +181,39 @@ The low-level design of VPlan comprises of the following classes.
to support scalarized and predicated instructions with a single model for
multiple candidate VF's and UF's.
-:VPRecipeBase:
- A pure-virtual base class modeling a sequence of one or more output IR
+VPRecipeBase
+: A pure-virtual base class modeling a sequence of one or more output IR
instructions, possibly based on one or more input IR instructions. These
input IR instructions are referred to as "Ingredients" of the Recipe. A Recipe
may specify how its ingredients are to be transformed to produce the output IR
instructions; e.g., cloned once, replicated multiple times or widened
according to selected VF.
-:VPValue:
- The base of VPlan's def-use relations class hierarchy. When instantiated, it
+VPValue
+: The base of VPlan's def-use relations class hierarchy. When instantiated, it
models a constant or a live-in Value in VPlan. It has users, which are of type
VPUser, but no operands.
-:VPUser:
- A VPUser represents an entity that uses a number of VPValues as operands.
+VPUser
+: A VPUser represents an entity that uses a number of VPValues as operands.
VPUser is similar in some aspects to LLVM's User class.
-:VPDef:
- A VPDef represents an entity that defines zero, one or multiple VPValues.
+VPDef
+: A VPDef represents an entity that defines zero, one or multiple VPValues.
It is used to model the fact that recipes in VPlan can define multiple
VPValues.
-:VPInstruction:
- A VPInstruction is a recipe characterized by a single opcode and optional
+VPInstruction
+: A VPInstruction is a recipe characterized by a single opcode and optional
flags, free of ingredients or other meta-data. VPInstructions also extend
LLVM IR's opcodes with idiomatic operations that enrich the Vectorizer's
semantics.
-:VPTransformState:
- Stores information used for generating output IR, passed from
+VPTransformState
+: Stores information used for generating output IR, passed from
LoopVectorizationPlanner to its selected VPlan for execution, and used to pass
additional information down to VPBlocks and VPRecipes.
-The Planning Process and VPlan Roadmap
-======================================
-
-Transforming the Loop Vectorizer to use VPlan follows a staged approach. First,
-VPlan was only used to record the final vectorization decisions, and to execute
-```
-
## The Planning Process and VPlan Roadmap
Transforming the Loop Vectorizer to use VPlan follows a staged approach. First,
@@ -246,43 +249,42 @@ idiom groups having synergistic cost.
### Related LLVM components
1. SLP Vectorizer: one can compare the VPlan model with LLVM's existing SLP
- tree, where TSLP [^footnote-3] adds Plan Step 2.b.
+ tree, where TSLP [^3] adds Plan Step 2.b.
2. RegionInfo: one can compare VPlan's H-CFG with the Region Analysis as used by
- Polly [^footnote-7].
+ Polly [^7].
3. Loop Vectorizer: the Vectorization Plan aims to upgrade the infrastructure of
- the Loop Vectorizer and extend it to handle outer loops [^footnote-8], [^footnote-9].
+ the Loop Vectorizer and extend it to handle outer loops [^8], [^9].
### References
-[^footnote-1]: "Outer-loop vectorization: revisited for short SIMD architectures", Dorit
+[^1]: "Outer-loop vectorization: revisited for short SIMD architectures", Dorit
Nuzman and Ayal Zaks, PACT 2008.
-[^footnote-2]: "Proposal for function vectorization and loop vectorization with function
+[^2]: "Proposal for function vectorization and loop vectorization with function
calls", Xinmin Tian, \[[cfe-dev](http://lists.llvm.org/pipermail/cfe-dev/2016-March/047732.html)\].,
March 2, 2016.
See also [review](https://reviews.llvm.org/D22792).
-[^footnote-3]: "Throttling Automatic Vectorization: When Less is More", Vasileios
+[^3]: "Throttling Automatic Vectorization: When Less is More", Vasileios
Porpodas and Tim Jones, PACT 2015 and LLVM Developers' Meeting 2015.
-[^footnote-4]: "Exploiting mixed SIMD parallelism by reducing data reorganization
+[^4]: "Exploiting mixed SIMD parallelism by reducing data reorganization
overhead", Hao Zhou and Jingling Xue, CGO 2016.
-[^footnote-5]: "Register Allocation via Hierarchical Graph Coloring", David Callahan and
+[^5]: "Register Allocation via Hierarchical Graph Coloring", David Callahan and
Brian Koblenz, PLDI 1991
-[^footnote-6]: "Structural analysis: A new approach to flow analysis in optimizing
+[^6]: "Structural analysis: A new approach to flow analysis in optimizing
compilers", M. Sharir, Journal of Computer Languages, Jan. 1980
-[^footnote-7]: "Enabling Polyhedral Optimizations in LLVM", Tobias Grosser, Diploma
+[^7]: "Enabling Polyhedral Optimizations in LLVM", Tobias Grosser, Diploma
thesis, 2011.
-[^footnote-8]: "Introducing VPlan to the Loop Vectorizer", Gil Rapaport and Ayal Zaks,
+[^8]: "Introducing VPlan to the Loop Vectorizer", Gil Rapaport and Ayal Zaks,
European LLVM Developers' Meeting 2017.
-[^footnote-9]: "Extending LoopVectorizer: OpenMP4.5 SIMD and Outer Loop
+[^9]: "Extending LoopVectorizer: OpenMP4.5 SIMD and Outer Loop
Auto-Vectorization", Intel Vectorizer Team, LLVM Developers' Meeting 2016.
-[^footnote-10]: "VPlan: Status Update and Future Roadmap", Ayal Zaks and Florian Hahn,
+[^10]: "VPlan: Status Update and Future Roadmap", Ayal Zaks and Florian Hahn,
LLVM Developers' Meeting 2023, <https://www.youtube.com/watch?v=SzGP4PgMuLE>
-
diff --git a/llvm/docs/XRay.md b/llvm/docs/XRay.md
index 6a306e067a891..6744d3a7195ab 100644
--- a/llvm/docs/XRay.md
+++ b/llvm/docs/XRay.md
@@ -1,9 +1,9 @@
----
-Version: 1 as of 2016-11-08
----
-
# XRay Instrumentation
+```{eval-rst}
+:Version: 1 as of 2016-11-08
+```
+
## Introduction
XRay is a function call tracing system which combines compiler-inserted
@@ -80,10 +80,10 @@ void alt_never_instrumented() __attribute__((xray_never_instrument));
```
When linking a binary, you can either manually link in the [XRay Runtime
-Library][xray runtime library] or use `clang` to link it in automatically with the
+Library](#xray-runtime-library) or use `clang` to link it in automatically with the
`-fxray-instrument` flag. Alternatively, you can statically link-in the XRay
runtime library from compiler-rt -- those archive files will take the name of
-`libclang_rt.xray-{arch}` where `{arch}` is the mnemonic supported by clang
+{title-reference}`libclang_rt.xray-{arch}` where {title-reference}`{arch}` is the mnemonic supported by clang
(x86_64, arm7, etc.).
### LLVM Function Attribute
@@ -240,7 +240,7 @@ variable. Programmatic configuration can be done by calling
selected/installed.
When the buffers are flushed to disk, the result is a binary trace format
-described by [XRay FDR format](XRayFDRFormat.html)
+described by {doc}`XRay FDR format <XRayFDRFormat>`
When FDR mode is on, it will keep writing and recycling memory buffers until
the logging implementation is finalized -- at which point it can be flushed and
@@ -274,9 +274,11 @@ format. All the trace analysis tools (and the trace reading library) will
support all versions of the FDR mode format as we add more functionality and
record types in the future.
-> **NOTE:** We do not promise perpetual support for when we update the log
-> versions we support going forward. Deprecation of the formats will be
-> announced and discussed on the developers mailing list.
+:::{note}
+We do not promise perpetual support for when we update the log
+versions we support going forward. Deprecation of the formats will be
+announced and discussed on the developers mailing list.
+:::
### Trace Analysis Tools
@@ -292,7 +294,7 @@ supports the following subcommands:
- `convert`: Converts an XRay log file from one format to another. We can
convert from binary XRay traces (both basic and FDR mode) to YAML,
[flame-graph](https://github.com/brendangregg/FlameGraph) friendly text
- formats, as well as `Chrome Trace Viewer (catapult)
+ formats, as well as {title-reference}`Chrome Trace Viewer (catapult)
<https://github.com/catapult-project/catapult>` formats.
- `graph`: Generates a DOT graph of the function call relationships between
functions found in an XRay trace.
@@ -360,7 +362,6 @@ the XRay instrumentation system.
We're looking forward to contributions to port XRay to more architectures and
operating systems.
-% References...
+<!-- References... -->
[xray whitepaper]: http://research.google.com/pubs/pub45287.html
-
diff --git a/llvm/docs/XRayExample.md b/llvm/docs/XRayExample.md
index dc2d591eda85e..e1393049bfbac 100644
--- a/llvm/docs/XRayExample.md
+++ b/llvm/docs/XRayExample.md
@@ -7,7 +7,7 @@ compiling some sample LLVM IR generated by Clang.
## Building with XRay
To debug an application with XRay instrumentation, we need to build it with a
-Clang that supports the `-fxray-instrument` option. See [XRay](XRay.html)
+Clang that supports the `-fxray-instrument` option. See {doc}`XRay`
for more technical details of how XRay works for background information.
In our example, we need to add `-fxray-instrument` to the list of flags
@@ -321,8 +321,7 @@ llvm-xray tool, please feel free to propose them on the llvm-dev@ mailing list.
The following are some ideas to inspire you in getting involved and potentially
making things better.
-> - Implement a query/filtering library that allows for finding patterns in the
-> XRay traces.
-> - Collecting function call stacks and how often they're encountered in the
-> XRay trace.
-
+- Implement a query/filtering library that allows for finding patterns in the
+ XRay traces.
+- Collecting function call stacks and how often they're encountered in the
+ XRay trace.
diff --git a/llvm/docs/XRayFDRFormat.md b/llvm/docs/XRayFDRFormat.md
index 19005b5a4aca7..766329a03d905 100644
--- a/llvm/docs/XRayFDRFormat.md
+++ b/llvm/docs/XRayFDRFormat.md
@@ -1,9 +1,9 @@
----
-Version: 1 as of 2017-07-20
----
-
# XRay Flight Data Recorder Trace Format
+```{eval-rst}
+:Version: 1 as of 2017-07-20
+```
+
## Introduction
When gathering XRay traces in Flight Data Recorder mode, each thread of an
@@ -268,4 +268,3 @@ Function records.
- Not every entry must have a traced Exit or Tail Exit. The buffer may run out
of space or the program may request for the tracer to finalize toreturn the
buffer before an instrumented function exits.
-
>From 32a0ee2afeb665d12b7dd4ef9a59cf3792ac3055 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Sat, 12 Sep 2026 00:08:59 +0000
Subject: [PATCH 4/4] [LLVM][docs] Convert remaining batch 11 tables to MyST
---
llvm/docs/QualGroup.md | 82 ++++++-----
llvm/docs/ScudoHardenedAllocator.md | 207 +++++++++++++++-------------
llvm/docs/TypeMetadata.md | 44 +++---
3 files changed, 169 insertions(+), 164 deletions(-)
diff --git a/llvm/docs/QualGroup.md b/llvm/docs/QualGroup.md
index 902c184f7034e..366a24ee95ccd 100644
--- a/llvm/docs/QualGroup.md
+++ b/llvm/docs/QualGroup.md
@@ -40,48 +40,46 @@ The members of the LLVM Qualification Group represent a diverse cross-section of
They meet the criteria for inclusion described in the sub-sections below and are identified as [active contributors](#contribution-principles).
Knowing their handles help us keep track of who’s who across platforms, coordinate activities, and recognize contributions.
-```{eval-rst}
-.. list-table::
- :widths: 20 20 20 20 20
- :header-rows: 1
-
- * - Name
- - Affiliation
- - Discourse handle
- - Discord handle
- - GitHub handle
- * - Carlos Andrés Ramírez
- - Woven by Toyota
- - CarlosAndresRamirez
- - carlos\_andres\_ramirez
- - CarlosAndresRamirez
- * - Oscar Slotosch
- - Validas
- - slotosch
- - oscarslotosch_66740
- - slotosch
- * - Petter Berntsson
- - Arm Limited
- - petbernt
- - petbernt
- - petbernt
- * - Wendi Urribarri
- - Woven by Toyota
- - uwendi
- - uwendi
- - uwendi
- * - YoungJun Lee
- - NSHC
- - YoungJunLee
- - YoungJunLee
- - IamYJLee
- * - Zaky Hermawan
- - (No affiliation)
- - ZakyHermawan
- - quarkz99
- - zakyHermawan
-
-```
+:::{list-table}
+:widths: 20 20 20 20 20
+:header-rows: 1
+
+* - Name
+ - Affiliation
+ - Discourse handle
+ - Discord handle
+ - GitHub handle
+* - Carlos Andrés Ramírez
+ - Woven by Toyota
+ - CarlosAndresRamirez
+ - carlos_andres_ramirez
+ - CarlosAndresRamirez
+* - Oscar Slotosch
+ - Validas
+ - slotosch
+ - oscarslotosch_66740
+ - slotosch
+* - Petter Berntsson
+ - Arm Limited
+ - petbernt
+ - petbernt
+ - petbernt
+* - Wendi Urribarri
+ - Woven by Toyota
+ - uwendi
+ - uwendi
+ - uwendi
+* - YoungJun Lee
+ - NSHC
+ - YoungJunLee
+ - YoungJunLee
+ - IamYJLee
+* - Zaky Hermawan
+ - (No affiliation)
+ - ZakyHermawan
+ - quarkz99
+ - zakyHermawan
+:::
Organizations are limited to three representatives within the group to maintain diversity.
diff --git a/llvm/docs/ScudoHardenedAllocator.md b/llvm/docs/ScudoHardenedAllocator.md
index 36b2869791fcc..fa79e0296b488 100644
--- a/llvm/docs/ScudoHardenedAllocator.md
+++ b/llvm/docs/ScudoHardenedAllocator.md
@@ -188,65 +188,76 @@ extern "C" const char *__scudo_default_options() {
The following "string" options are available:
-```{eval-rst}
-+---------------------------------+----------------+-------------------------------------------------+
-| Option | Default | Description |
-+---------------------------------+----------------+-------------------------------------------------+
-| quarantine_size_kb | 0 | The size (in Kb) of quarantine used to delay |
-| | | the actual deallocation of chunks. Lower value |
-| | | may reduce memory usage but decrease the |
-| | | effectiveness of the mitigation; a negative |
-| | | value will fallback to the defaults. Setting |
-| | | *both* this and thread_local_quarantine_size_kb |
-| | | to zero will disable the quarantine entirely. |
-+---------------------------------+----------------+-------------------------------------------------+
-| quarantine_max_chunk_size | 0 | Size (in bytes) up to which chunks can be |
-| | | quarantined. |
-+---------------------------------+----------------+-------------------------------------------------+
-| thread_local_quarantine_size_kb | 0 | The size (in Kb) of per-thread cache use to |
-| | | offload the global quarantine. Lower value may |
-| | | reduce memory usage but might increase |
-| | | contention on the global quarantine. Setting |
-| | | *both* this and quarantine_size_kb to zero will |
-| | | disable the quarantine entirely. |
-+---------------------------------+----------------+-------------------------------------------------+
-| dealloc_type_mismatch | false | Whether or not we report errors on |
-| | | malloc/delete, new/free, new/delete[], etc. |
-+---------------------------------+----------------+-------------------------------------------------+
-| delete_size_mismatch | true | Whether or not we report errors on mismatch |
-| | | between sizes of new and delete. |
-+---------------------------------+----------------+-------------------------------------------------+
-| zero_contents | false | Whether or not we zero chunk contents on |
-| | | allocation. |
-+---------------------------------+----------------+-------------------------------------------------+
-| pattern_fill_contents | false | Whether or not we fill chunk contents with a |
-| | | byte pattern on allocation. |
-+---------------------------------+----------------+-------------------------------------------------+
-| may_return_null | true | Whether or not a non-fatal failure can return a |
-| | | NULL pointer (as opposed to terminating). |
-+---------------------------------+----------------+-------------------------------------------------+
-| release_to_os_interval_ms | 5000 | The minimum interval (in ms) at which a release |
-| | | can be attempted (a negative value disables |
-| | | reclaiming). |
-+---------------------------------+----------------+-------------------------------------------------+
-| allocation_ring_buffer_size | 32768 | If stack trace collection is requested, how |
-| | | many previous allocations to keep in the |
-| | | allocation ring buffer. |
-| | | |
-| | | This buffer is used to provide allocation and |
-| | | deallocation stack traces for MTE fault |
-| | | reports. The larger the buffer, the more |
-| | | unrelated allocations can happen between |
-| | | (de)allocation and the fault. |
-| | | If your sync-mode MTE faults do not have |
-| | | (de)allocation stack traces, try increasing the |
-| | | buffer size. |
-| | | |
-| | | Stack trace collection can be requested using |
-| | | the scudo_malloc_set_track_allocation_stacks |
-| | | function. |
-+---------------------------------+----------------+-------------------------------------------------+
-```
+:::{list-table}
+
+* - Option
+ - Default
+ - Description
+* - quarantine_size_kb
+ - 0
+ - The size (in Kb) of quarantine used to delay
+ the actual deallocation of chunks. Lower value
+ may reduce memory usage but decrease the
+ effectiveness of the mitigation; a negative
+ value will fallback to the defaults. Setting
+ *both* this and thread_local_quarantine_size_kb
+ to zero will disable the quarantine entirely.
+* - quarantine_max_chunk_size
+ - 0
+ - Size (in bytes) up to which chunks can be
+ quarantined.
+* - thread_local_quarantine_size_kb
+ - 0
+ - The size (in Kb) of per-thread cache use to
+ offload the global quarantine. Lower value may
+ reduce memory usage but might increase
+ contention on the global quarantine. Setting
+ *both* this and quarantine_size_kb to zero will
+ disable the quarantine entirely.
+* - dealloc_type_mismatch
+ - false
+ - Whether or not we report errors on
+ malloc/delete, new/free, new/delete[], etc.
+* - delete_size_mismatch
+ - true
+ - Whether or not we report errors on mismatch
+ between sizes of new and delete.
+* - zero_contents
+ - false
+ - Whether or not we zero chunk contents on
+ allocation.
+* - pattern_fill_contents
+ - false
+ - Whether or not we fill chunk contents with a
+ byte pattern on allocation.
+* - may_return_null
+ - true
+ - Whether or not a non-fatal failure can return a
+ NULL pointer (as opposed to terminating).
+* - release_to_os_interval_ms
+ - 5000
+ - The minimum interval (in ms) at which a release
+ can be attempted (a negative value disables
+ reclaiming).
+* - allocation_ring_buffer_size
+ - 32768
+ - If stack trace collection is requested, how
+ many previous allocations to keep in the
+ allocation ring buffer.
+
+ This buffer is used to provide allocation and
+ deallocation stack traces for MTE fault
+ reports. The larger the buffer, the more
+ unrelated allocations can happen between
+ (de)allocation and the fault.
+ If your sync-mode MTE faults do not have
+ (de)allocation stack traces, try increasing the
+ buffer size.
+
+ Stack trace collection can be requested using
+ the scudo_malloc_set_track_allocation_stacks
+ function.
+:::
Additional flags can be specified, for example if Scudo if compiled with
{doc}`GWP-ASan <GwpAsan>` support.
@@ -254,45 +265,45 @@ Additional flags can be specified, for example if Scudo if compiled with
The following "mallopt" options are available (options are defined in
`include/scudo/interface.h`):
-```{eval-rst}
-+---------------------------+-------------------------------------------------------+
-| Option | Description |
-+---------------------------+-------------------------------------------------------+
-| M_DECAY_TIME | Sets the release interval option to the specified |
-| | value (Android only allows 0 or 1 to respectively set |
-| | the interval to the minimum and maximum value as |
-| | specified at compile time). |
-+---------------------------+-------------------------------------------------------+
-| M_PURGE | Forces immediate memory reclaiming but does not |
-| | reclaim everything. For smaller size classes, there |
-| | is still some memory that is not reclaimed due to the |
-| | extra time it takes and the small amount of memory |
-| | that can be reclaimed. |
-| | The value is ignored. |
-+---------------------------+-------------------------------------------------------+
-| M_PURGE_ALL | Same as M_PURGE but will force release all possible |
-| | memory regardless of how long it takes. |
-| | The value is ignored. |
-+---------------------------+-------------------------------------------------------+
-| M_MEMTAG_TUNING | Tunes the allocator's choice of memory tags to make |
-| | it more likely that a certain class of memory errors |
-| | will be detected. The value argument should be one of |
-| | the enumerators of ``scudo_memtag_tuning``. |
-+---------------------------+-------------------------------------------------------+
-| M_THREAD_DISABLE_MEM_INIT | Tunes the per-thread memory initialization, 0 being |
-| | the normal behavior, 1 disabling the automatic heap |
-| | initialization. |
-+---------------------------+-------------------------------------------------------+
-| M_CACHE_COUNT_MAX | Set the maximum number of entries than can be cached |
-| | in the Secondary cache. |
-+---------------------------+-------------------------------------------------------+
-| M_CACHE_SIZE_MAX | Sets the maximum size of entries that can be cached |
-| | in the Secondary cache. |
-+---------------------------+-------------------------------------------------------+
-| M_TSDS_COUNT_MAX | Increases the maximum number of TSDs that can be used |
-| | up to the limit specified at compile time. |
-+---------------------------+-------------------------------------------------------+
-```
+:::{list-table}
+
+* - Option
+ - Description
+* - M_DECAY_TIME
+ - Sets the release interval option to the specified
+ value (Android only allows 0 or 1 to respectively set
+ the interval to the minimum and maximum value as
+ specified at compile time).
+* - M_PURGE
+ - Forces immediate memory reclaiming but does not
+ reclaim everything. For smaller size classes, there
+ is still some memory that is not reclaimed due to the
+ extra time it takes and the small amount of memory
+ that can be reclaimed.
+ The value is ignored.
+* - M_PURGE_ALL
+ - Same as M_PURGE but will force release all possible
+ memory regardless of how long it takes.
+ The value is ignored.
+* - M_MEMTAG_TUNING
+ - Tunes the allocator's choice of memory tags to make
+ it more likely that a certain class of memory errors
+ will be detected. The value argument should be one of
+ the enumerators of `scudo_memtag_tuning`.
+* - M_THREAD_DISABLE_MEM_INIT
+ - Tunes the per-thread memory initialization, 0 being
+ the normal behavior, 1 disabling the automatic heap
+ initialization.
+* - M_CACHE_COUNT_MAX
+ - Set the maximum number of entries than can be cached
+ in the Secondary cache.
+* - M_CACHE_SIZE_MAX
+ - Sets the maximum size of entries that can be cached
+ in the Secondary cache.
+* - M_TSDS_COUNT_MAX
+ - Increases the maximum number of TSDs that can be used
+ up to the limit specified at compile time.
+:::
## Error Types
diff --git a/llvm/docs/TypeMetadata.md b/llvm/docs/TypeMetadata.md
index c286cccd99020..7ebd026138313 100644
--- a/llvm/docs/TypeMetadata.md
+++ b/llvm/docs/TypeMetadata.md
@@ -248,30 +248,26 @@ from classes with hidden visibility), then this optimisation would be valid.
This concept is represented in IR by the `!vcall_visibility` metadata
attached to vtable objects, with the following values:
-```{eval-rst}
-.. list-table::
- :header-rows: 1
- :widths: 10 90
-
- * - Value
- - Behavior
-
- * - 0 (or omitted)
- - **Public**
- Virtual function calls using this vtable could be made from external
- code.
-
- * - 1
- - **Linkage Unit**
- All virtual function calls which might use this vtable are in the
- current LTO unit, meaning they will be in the current module once
- LTO linking has been performed.
-
- * - 2
- - **Translation Unit**
- All virtual function calls which might use this vtable are in the
- current module.
-```
+:::{list-table}
+:header-rows: 1
+:widths: 10 90
+
+* - Value
+ - Behavior
+* - 0 (or omitted)
+ - **Public**
+ : Virtual function calls using this vtable could be made from external
+ code.
+* - 1
+ - **Linkage Unit**
+ : All virtual function calls which might use this vtable are in the
+ current LTO unit, meaning they will be in the current module once
+ LTO linking has been performed.
+* - 2
+ - **Translation Unit**
+ : All virtual function calls which might use this vtable are in the
+ current module.
+:::
In addition, all function pointer loads from a vtable marked with the
`!vcall_visibility` metadata (with a non-zero value) must be done using the
More information about the llvm-branch-commits
mailing list