This PR aims to organise BOLT's docs in preparation for hosting.
- Added a landing page into `index.rst`, much like
[clang.llvm.org](https://clang.llvm.org/docs/index.html).
- Moved Getting Started content from `index.rst` into its own
`GettingStarted.rst`.
- Enables Markdown content to be rendered. A current
[discussion](https://discourse.llvm.org/t/rfc-make-myst-markdown-the-llvm-docs-format-rip-rest/90840)
is being had about MD/RST on discourse, but for now I have decided to
support the mix of formats currently in BOLT.
- Included AArch64 optimization status page.
- Fixes some links/anchors.
**Landing Page**
<img width="531" height="311" alt="image"
src="https://github.com/user-attachments/assets/4fa376bf-cdf1-4ad1-8be5-1de57597ac10"
/>
**Build with Sphinx**
`sphinx-build -b html bolt/docs bolt-docs-html`
Requires Sphinx and myst_parser.
llvm-project is home to many sphinx documentation sites, each with
configuration quirks and bespoke extensions.
The sphinx config model makes sharing code somewhat difficult. There
are options like sphinx-multiproject, but some of our docs builds are
out of the source tree while some are done out of the binary tree, so
the multiproject configuration itself would need to be generated. It
also would impose more uniformity around extensions than required.
This change instead creates a python package at utils/docs/llvm_sphinx
and makes it available to all sphinx-build processes via PYTHONPATH.
Each conf.py does not modify its own sys.path because not all builds are
out of the source tree, so there isn't a stable relative path to use to
refer to the utils/docs/ directory.
Type checking via pyright in new package is pinned to being python 3.8
compatible.
The myst slug script from llvm/docs is promoted to be the default,
with a slight edit to targets needed in FlangDriver.md to adapt to the
change.
The ghlinks extension from clang gets lifted to be the first generic
extension, although it is still only used in clang currently. I used it
as an example of a general extension that might be useful for other
projects, but I also intend to add a new generic extension in a future
patch.
As part of the move ghlinks is refactored a bit:
* Rather than have a main function directly to run its tests, those
tests are now run via the command-line entrypoint to the new package,
e.g. `python utils/docs --test` will now replace
`python clang/docs/ghlinks.py --test`. This makes the command-line
more pithy (`python utils/docs/llvm_sphinx/ext/ghlinks --test` is a
bit long), and makes the default behavior when running be to
include utils/docs in the sys.path, so imports can be absolute and
the behavior is as close to the CMake targets as possible.
* The static files that were previously written to a tempdir during
testing are just committed directly in git. The assumption here is
that the original version was taking pains to avoid polluting the
clang/docs directory with test files that would confuse sphinx-build,
and without that limitation the workaround can be removed.
* Some typing-related changes to make it strictly python 3.8 compatible.
Change-Id: Ie16de273f74973f163dbf7fe9d22d80a466d051f
Building docs-bolt-html fails with:
Warning, treated as error:
/home/slinder1/llvm-project/scratch/bolt/docs/BOLTAArch64OptimizationStatus.rst:document
isn't included in any toctree
Just add the orphan document to the toctree in the index to silence
this. If there is a better parent it can be moved somewhere else in the
tree.
Change-Id: I1d26d96d5485d97d29231da89f8c8408b375c41f
Extend pre-aggregated format with an optional mispredictions field.
Update parsing and pre-aggregated profile writer.
Test Plan:
added PreAggregatedX86TestHelper.OptionalMispredField
updated pre-aggregated-records.s
The previous attempt at this (b7da956501)
still broke standalone builds. Now I have locally tested standalone
flang, runtimes (with openmp), lldb, combined builds, and the utils
script. Hopefully that covers everything this time, and gets everything
into a more consistent state (always using the HandleDoxygen script in
the same way, included exactly once as required by the cmake design).
Reverts llvm/llvm-project#191501 as cmake CI is having an issue with it:
```
-- Doxygen enabled (1.14.0).
CMake Error at /work/as-worker-4/publish-doxygen-docs/llvm-project/cmake/Modules/HandleDoxygen.cmake:29 (add_custom_target):
add_custom_target cannot create target "doxygen" because another target
with the same name already exists. The existing target is a custom target
created in source directory
"/work/as-worker-4/publish-doxygen-docs/llvm-project/llvm". See
documentation for policy CMP0002 for more details.
Call Stack (most recent call first):
docs/CMakeLists.txt:59 (include)
```
Add a pre-aggregated profile output format (`--profile-format=preagg`)
so perf.data can be pre-parsed/aggregated and used as input with -pa.
Supports branch (T traces) and basic samples (S records).
Currently only covers main binary, can be extended to cover multi-DSO.
Test Plan: Updated perf_test.test, added perf_brstack.test
Reviewers:
yota9, ayermolo, yozhu, maksfb, yavtuk, paschalis-mpeis, rafaelauler
Reviewed By: paschalis-mpeis
Pull Request: https://github.com/llvm/llvm-project/pull/199465
Update the documentation to reflect the changes made to the original
prototype.
Co-authored-by: Kristof Beyls <kristof.beyls@arm.com>
Co-authored-by: Harald van Dijk <hdijk@accesssoftek.com>
Handle signed values in parseHexField by falling back to int64_t parsing
when uint64_t fails. This allows pre-aggregated profile tools to use -1
for BR_ONLY, -2 for FT_EXTERNAL_ORIGIN, -3 for FT_EXTERNAL_RETURN.
Guard the external address reset loop in parseAggregatedLBREntry to
preserve sentinel values (offsets >= FT_EXTERNAL_RETURN).
Add tests for -1/-2/-3 in parseHexField and T entries with -1,
ffffffffffffffff, and buildid:-1 as BR_ONLY.
Create bolt/docs/profiles.md documenting all accepted profile formats:
perf.data, fdata, YAML, and pre-aggregated. Covers collection methods,
format syntax, examples, and known limitations.
Add reference from bolt/docs/index.rst.
On x86-64, PLT optimization does not require the binary to be linked
with -znow because indirect calls through GOT work correctly with lazy
binding. At runtime, the dynamic linker's resolver will populate the GOT
entry on the first call, just like with a regular PLT call.
This change removes the -znow requirement specifically for x86-64 while
keeping it for other architectures. I haven't checked RISV-V, but it's
still necessary on AArch64.
Rename passes to names that better reflect their intent,
and describe their relationship to each other.
InsertNegateRAStatePass renamed to PointerAuthCFIFixup,
MarkRAStates renamed to PointerAuthCFIAnalyzer.
Added the --print-<passname> flags for these passes.
During InsertNegateRAState pass we check the annotations on
instructions,
to decide where to generate the OpNegateRAState CFIs in the output
binary.
As only instructions in the input binary were annotated, we have to make
a judgement on instructions generated by other BOLT passes.
Incorrect placement may cause issues when an (async) unwind request
is received during the new "unknown" instructions.
This patch adds more logic to make a more informed decision on by taking
into account:
- unknown instructions in a BasicBlock with other instruction have the
same RAState. Previously, if the BasicBlock started with an unknown
instruction,
the RAState was copied from the preceding block. Now, the RAState is
copied from
the succeeding instructions in the same block.
- Some BasicBlocks may only contain instructions with unknown RAState,
As explained in issue #160989, these blocks already have incorrect
unwind info. Because of this, the last known RAState based on the layout order
is copied.
Updated bolt/docs/PacRetDesign.md to reflect changes.
Major part of this PR is commit implementing support for DT_INIT_ARRAY
for BOLT runtime libraries initialization. Also, it adds related
hook-init test & fixes couple of X86 instrumentation tests.
This commit follows implementation of instrumentation hook via
DT_FINI_ARRAY (https://github.com/llvm/llvm-project/pull/67348) and
extends it for BOLT runtime libraries (including instrumentation
library) initialization hooking.
Initialization has has differences compared to finalization:
- Executables always use ELF entry point address. Update code checks it
and updates init_array entry if ELF is shared library (have no interp
entry) and have no DT_INIT entry. Also this commit introduces
"runtime-lib-init-hook" option to select primary initialization hook
(entry_point, init, init_array) with fall back to next available hook in
input binary. e.g. in case of libc we can explicitly set it to
init_array.
- Shared library init_array entries relocations usually has
R_AARCH64_ABS64 type on AArch64 binaries. We check relocation type and
adjust methods for reading init_array relocations in discovery and
update methods.
---------
Co-authored-by: Vasily Leonenko <vasily.leonenko@huawei.com>
Since the "--write-dwp" option has been removed in
[PR](https://github.com/llvm/llvm-project/pull/100771), this patch also
cleans up the corresponding document and test to avoid misleading
issues.
The `--nl` flag, originally for Non-LBR mode, is deprecated and will be
replaced by `--basic-events` (alias `--ba`).
`--nl` remains as a deprecated alias for backward compatibility.
Update guides to use brstack, with a mention to BRBE for AArch64. Use
brstack in user-facing outputs.
---------
Co-authored-by: Amir Ayupov <aaupov@fb.com>
Reapply "[BOLT][AArch64] Handle OpNegateRAState to enable optimizing
binaries with pac-ret hardening (#120064)" (#162353)
This reverts commit c7d776b068.
#120064 was reverted for breaking builders.
Fix: changed the mismatched type in MarkRAStates.cpp to `auto`.
---
Original message:
OpNegateRAState is an AArch64-specific DWARF CFI used to change the value
of the RA_SIGN_STATE pseudoregister. The RA_SIGN_STATE register records
whether the current return address has been signed with PAC.
OpNegateRAState requires special handling in BOLT because its placement
depends on the function layout. Since BOLT reorders basic blocks during
optimization, these CFIs must be regenerated after layout is finalized.
This patch introduces two new passes:
- MarkRAStates (runs before optimizations): assigns a signedness annotation to each
instruction based on OpNegateRAState CFIs in the input binary.
- InsertNegateRAStates (runs after optimizations): reads the annotations and emits
new OpNegateRAState CFIs where RA state changes between instructions.
Design details are described in: `bolt/docs/PacRetDesign.md`.
OpNegateRAState is an AArch64-specific DWARF CFI used to change the value
of the RA_SIGN_STATE pseudoregister. The RA_SIGN_STATE register records
if the current return address has been signed with PAC.
OpNegateRAState requires special handling in BOLT because its placement
depends on the function layout. Since BOLT reorders basic blocks during
optimization, these CFIs must be regenerated after layout is finalized.
This patch introduces two new passes:
- MarkRAStates (runs before optimizations): assigns a signedness annotation to each
instruction based on OpNegateRAState CFIs in the input binary.
- InsertNegateRAStates (runs after optimizations): reads the annotations and emits
new OpNegateRAState CFIs where RA state changes between instructions.
Design details are described in: `bolt/docs/PacRetDesign.md`.
The pass for inlining memcpy in BOLT was currently X86-specific and was
using the instruction `rep movsb`.
This patch implements a static size analysis system for AArch64 memcpy
inlining that extracts copy sizes from preceding instructions to then
use it to generate the optimal width-specific load/store sequences.
## Change:
* Added `--dump-dot-func` command-line option that allows users to dump
CFGs only for specific functions instead of dumping all functions (the
current only available option being `--dump-dot-all`)
## Usage:
* Users can now specify function names or regex patterns (e.g.,
`--dump-dot-func=main,helper` or `--dump-dot-func="init.*`") to generate
.dot files only for functions of interest
* Aims to save time when analysing specific functions in large binaries
(e.g., only dumping graphs for performance-critical functions identified
through profiling) and we can now avoid reduce output clutter from
generating thousands of unnecessary .dot files when analysing large
binaries
## Testing
The introduced test `dump-dot-func.test` confirms the new option does
the following:
- [x] 1. `dump-dot-func` can correctly filter a specified functions
- [x] 2. Can achieve the above with regexes
- [x] 3. Can do 1. with a list of functions
- [x] No option specified creates no dot files
- [x] Passing in a non-existent function generates no dumping messages
- [x] `dump-dot-all` continues to work as expected
Add a capability to produce multiple heatmaps with given bucket sizes.
The default heatmap block size (64B) could be too fine-grained for
large binaries. Extend the option `block-size` to accept a list of
bucket sizes for additional heatmaps with coarser granularity. The
heatmap is simply rescaled so provided sizes should be multiples of
each other. Human-readable suffixes can be used, e.g. 4K, 16kb, 1MiB.
New defaults: 64B (base bucket size), 4KB (default page size),
256KB (for large binaries).
Test Plan: updated heatmap-preagg.test
Despite our attempt (build-docs.sh)
to build the documentation with SVG,
it still uses PNG https://llvm.org/doxygen/classllvm_1_1StringRef.html,
and that renders terribly on any high dpi display.
SVG leads to smasller installation and works fine
on all browser (that has been true for _a while_
https://caniuse.com/svg), so this patch just unconditionally build all
dot graphs as SVG in all subprojects and remove the option.
Identical Code Folding (ICF) folds functions that are identical into one
function, and updates symbol addresses to the new address. This reduces
the size of a binary, but can lead to problems. For example when
function pointers are compared. This can be done either explicitly in
the code or generated IR by optimization passes like Indirect Call
Promotion (ICP). After ICF what used to be two different addresses
become the same address. This can lead to a different code path being
taken.
This is where safe ICF comes in. Linker (LLD) does it using address
significant section generated by clang. If symbol is in it, or an object
doesn't have this section symbols are not folded.
BOLT does not have the information regarding which objects do not have
this section, so can't re-use this mechanism.
This implementation scans code section and conservatively marks
functions symbols as unsafe. It treats symbols as unsafe if they are
used in non-control flow instruction. It also scans through the data
relocation sections and does the same for relocations that reference a
function symbol. The latter handles the case when function pointer is
stored in a local or global variable, etc. If a relocation address
points within a vtable these symbols are skipped.
Implemented call graph function matching. First, two call graphs are
constructed for both profiled and binary functions. Then functions are
hashed based on the names of their callee/caller functions. Finally,
functions are matched based on these neighbor hashes and the
longest common prefix of their names. The `match-with-call-graph`
flag turns this matching on.
Test Plan: Added match-with-call-graph.test. Matched 164 functions
in a large binary with 10171 profiled functions.
A mapping - from namespace to associated binary functions - is used to
match function profiles to binary based on the
'--name-similarity-function-matching-threshold' flag set edit distance
threshold. The flag is set to 0 (exact name matching) by default as it is
expensive, requiring the processing of all BFs.
Test Plan: Added name-similarity-function-matching.test. On a binary
with 5M functions, rewrite passes took ~520s without the flag and
~2018s with the flag set to 20.
Added flag '--match-profile-with-function-hash' to match functions
based on exact hash. After identical and LTO name matching, more
functions can be recovered for inference with exact hash, in the case
of function renaming with no functional changes. Collisions are
possible in the unlikely case where multiple functions share the same
exact hash. The flag is off by default as it requires the processing of
all binary functions and subsequently is expensive.
Test Plan: added hashing-based-function-matching.test.