diff --git a/.ci/compute-projects.sh b/.ci/compute-projects.sh
new file mode 100644
index 0000000000000..32baf26b4f0a0
--- /dev/null
+++ b/.ci/compute-projects.sh
@@ -0,0 +1,194 @@
+#!/usr/bin/env bash
+#===----------------------------------------------------------------------===##
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+#===----------------------------------------------------------------------===##
+
+#
+# This file contains functions to compute which projects should be built by CI
+# systems and is intended to provide common functionality applicable across
+# multiple systems during a transition period.
+#
+
+function compute-projects-to-test() {
+ isForWindows=$1
+ shift
+ projects=${@}
+ for project in ${projects}; do
+ echo "${project}"
+ case ${project} in
+ lld)
+ for p in bolt cross-project-tests; do
+ echo $p
+ done
+ ;;
+ llvm)
+ for p in bolt clang clang-tools-extra lld lldb mlir polly; do
+ echo $p
+ done
+ # Flang is not stable in Windows CI at the moment
+ if [[ $isForWindows == 0 ]]; then
+ echo flang
+ fi
+ ;;
+ clang)
+ # lldb is temporarily removed to alleviate Linux pre-commit CI waiting times
+ for p in clang-tools-extra compiler-rt cross-project-tests; do
+ echo $p
+ done
+ ;;
+ clang-tools-extra)
+ echo libc
+ ;;
+ mlir)
+ # Flang is not stable in Windows CI at the moment
+ if [[ $isForWindows == 0 ]]; then
+ echo flang
+ fi
+ ;;
+ *)
+ # Nothing to do
+ ;;
+ esac
+ done
+}
+
+function compute-runtimes-to-test() {
+ projects=${@}
+ for project in ${projects}; do
+ case ${project} in
+ clang)
+ for p in libcxx libcxxabi libunwind; do
+ echo $p
+ done
+ ;;
+ *)
+ # Nothing to do
+ ;;
+ esac
+ done
+}
+
+function add-dependencies() {
+ projects=${@}
+ for project in ${projects}; do
+ echo "${project}"
+ case ${project} in
+ bolt)
+ for p in clang lld llvm; do
+ echo $p
+ done
+ ;;
+ cross-project-tests)
+ for p in lld clang; do
+ echo $p
+ done
+ ;;
+ clang-tools-extra)
+ for p in llvm clang; do
+ echo $p
+ done
+ ;;
+ compiler-rt|libc|openmp)
+ echo clang lld
+ ;;
+ flang|lldb|libclc)
+ for p in llvm clang; do
+ echo $p
+ done
+ ;;
+ lld|mlir|polly)
+ echo llvm
+ ;;
+ *)
+ # Nothing to do
+ ;;
+ esac
+ done
+}
+
+function exclude-linux() {
+ projects=${@}
+ for project in ${projects}; do
+ case ${project} in
+ cross-project-tests) ;; # tests failing
+ openmp) ;; # https://github.com/google/llvm-premerge-checks/issues/410
+ *)
+ echo "${project}"
+ ;;
+ esac
+ done
+}
+
+function exclude-windows() {
+ projects=${@}
+ for project in ${projects}; do
+ case ${project} in
+ cross-project-tests) ;; # tests failing
+ compiler-rt) ;; # tests taking too long
+ openmp) ;; # TODO: having trouble with the Perl installation
+ libc) ;; # no Windows support
+ lldb) ;; # custom environment requirements (https://github.com/llvm/llvm-project/pull/94208#issuecomment-2146256857)
+ bolt) ;; # tests are not supported yet
+ *)
+ echo "${project}"
+ ;;
+ esac
+ done
+}
+
+# Prints only projects that are both present in $modified_dirs and the passed
+# list.
+function keep-modified-projects() {
+ projects=${@}
+ for project in ${projects}; do
+ if echo "$modified_dirs" | grep -q -E "^${project}$"; then
+ echo "${project}"
+ fi
+ done
+}
+
+function check-targets() {
+ # Do not use "check-all" here because if there is "check-all" plus a
+ # project specific target like "check-clang", that project's tests
+ # will be run twice.
+ projects=${@}
+ for project in ${projects}; do
+ case ${project} in
+ clang-tools-extra)
+ echo "check-clang-tools"
+ ;;
+ compiler-rt)
+ echo "check-compiler-rt"
+ ;;
+ cross-project-tests)
+ echo "check-cross-project"
+ ;;
+ libcxx)
+ echo "check-cxx"
+ ;;
+ libcxxabi)
+ echo "check-cxxabi"
+ ;;
+ libunwind)
+ echo "check-unwind"
+ ;;
+ lldb)
+ echo "check-lldb"
+ ;;
+ pstl)
+ # Currently we do not run pstl tests in CI.
+ ;;
+ libclc)
+ # Currently there is no testing for libclc.
+ ;;
+ *)
+ echo "check-${project}"
+ ;;
+ esac
+ done
+}
+
diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge
index 190dd1e5ba5af..9d9ca32183944 100755
--- a/.ci/generate-buildkite-pipeline-premerge
+++ b/.ci/generate-buildkite-pipeline-premerge
@@ -52,184 +52,7 @@ modified_dirs=$(echo "$MODIFIED_FILES" | cut -d'/' -f1 | sort -u)
echo "Directories modified:" >&2
echo "$modified_dirs" >&2
-function compute-projects-to-test() {
- isForWindows=$1
- shift
- projects=${@}
- for project in ${projects}; do
- echo "${project}"
- case ${project} in
- lld)
- for p in bolt cross-project-tests; do
- echo $p
- done
- ;;
- llvm)
- for p in bolt clang clang-tools-extra lld lldb mlir polly; do
- echo $p
- done
- # Flang is not stable in Windows CI at the moment
- if [[ $isForWindows == 0 ]]; then
- echo flang
- fi
- ;;
- clang)
- # lldb is temporarily removed to alleviate Linux pre-commit CI waiting times
- for p in clang-tools-extra compiler-rt cross-project-tests; do
- echo $p
- done
- ;;
- clang-tools-extra)
- echo libc
- ;;
- mlir)
- # Flang is not stable in Windows CI at the moment
- if [[ $isForWindows == 0 ]]; then
- echo flang
- fi
- ;;
- *)
- # Nothing to do
- ;;
- esac
- done
-}
-
-function compute-runtimes-to-test() {
- projects=${@}
- for project in ${projects}; do
- case ${project} in
- clang)
- for p in libcxx libcxxabi libunwind; do
- echo $p
- done
- ;;
- *)
- # Nothing to do
- ;;
- esac
- done
-}
-
-function add-dependencies() {
- projects=${@}
- for project in ${projects}; do
- echo "${project}"
- case ${project} in
- bolt)
- for p in clang lld llvm; do
- echo $p
- done
- ;;
- cross-project-tests)
- for p in lld clang; do
- echo $p
- done
- ;;
- clang-tools-extra)
- for p in llvm clang; do
- echo $p
- done
- ;;
- compiler-rt|libc|openmp)
- echo clang lld
- ;;
- flang|lldb|libclc)
- for p in llvm clang; do
- echo $p
- done
- ;;
- lld|mlir|polly)
- echo llvm
- ;;
- *)
- # Nothing to do
- ;;
- esac
- done
-}
-
-function exclude-linux() {
- projects=${@}
- for project in ${projects}; do
- case ${project} in
- cross-project-tests) ;; # tests failing
- openmp) ;; # https://github.com/google/llvm-premerge-checks/issues/410
- *)
- echo "${project}"
- ;;
- esac
- done
-}
-
-function exclude-windows() {
- projects=${@}
- for project in ${projects}; do
- case ${project} in
- cross-project-tests) ;; # tests failing
- compiler-rt) ;; # tests taking too long
- openmp) ;; # TODO: having trouble with the Perl installation
- libc) ;; # no Windows support
- lldb) ;; # custom environment requirements (https://github.com/llvm/llvm-project/pull/94208#issuecomment-2146256857)
- bolt) ;; # tests are not supported yet
- *)
- echo "${project}"
- ;;
- esac
- done
-}
-
-# Prints only projects that are both present in $modified_dirs and the passed
-# list.
-function keep-modified-projects() {
- projects=${@}
- for project in ${projects}; do
- if echo "$modified_dirs" | grep -q -E "^${project}$"; then
- echo "${project}"
- fi
- done
-}
-
-function check-targets() {
- # Do not use "check-all" here because if there is "check-all" plus a
- # project specific target like "check-clang", that project's tests
- # will be run twice.
- projects=${@}
- for project in ${projects}; do
- case ${project} in
- clang-tools-extra)
- echo "check-clang-tools"
- ;;
- compiler-rt)
- echo "check-compiler-rt"
- ;;
- cross-project-tests)
- echo "check-cross-project"
- ;;
- libcxx)
- echo "check-cxx"
- ;;
- libcxxabi)
- echo "check-cxxabi"
- ;;
- libunwind)
- echo "check-unwind"
- ;;
- lldb)
- echo "check-lldb"
- ;;
- pstl)
- # Currently we do not run pstl tests in CI.
- ;;
- libclc)
- # Currently there is no testing for libclc.
- ;;
- *)
- echo "check-${project}"
- ;;
- esac
- done
-}
+. ./.ci/compute-projects.sh
# Project specific pipelines.
diff --git a/.ci/generate_test_report.py b/.ci/generate_test_report.py
index c44936b19dab9..ff601a0cde106 100644
--- a/.ci/generate_test_report.py
+++ b/.ci/generate_test_report.py
@@ -5,6 +5,7 @@
# python3 -m unittest discover -p generate_test_report.py
import argparse
+import os
import subprocess
import unittest
from io import StringIO
@@ -267,6 +268,46 @@ def test_report_dont_list_failures(self):
),
)
+ def test_report_dont_list_failures_link_to_log(self):
+ self.assertEqual(
+ _generate_report(
+ "Foo",
+ [
+ junit_from_xml(
+ dedent(
+ """\
+
+
+
+
+
+
+
+ """
+ )
+ )
+ ],
+ list_failures=False,
+ buildkite_info={
+ "BUILDKITE_ORGANIZATION_SLUG": "organization_slug",
+ "BUILDKITE_PIPELINE_SLUG": "pipeline_slug",
+ "BUILDKITE_BUILD_NUMBER": "build_number",
+ "BUILDKITE_JOB_ID": "job_id",
+ },
+ ),
+ (
+ dedent(
+ """\
+ # Foo
+
+ * 1 test failed
+
+ Failed tests and their output was too large to report. [Download](https://buildkite.com/organizations/organization_slug/pipelines/pipeline_slug/builds/build_number/jobs/job_id/download.txt) the build's log file to see the details."""
+ ),
+ "error",
+ ),
+ )
+
def test_report_size_limit(self):
self.assertEqual(
_generate_report(
@@ -308,7 +349,13 @@ def test_report_size_limit(self):
# listed. This minimal report will always fit into an annotation.
# If include failures is False, total number of test will be reported but their names
# and output will not be.
-def _generate_report(title, junit_objects, size_limit=1024 * 1024, list_failures=True):
+def _generate_report(
+ title,
+ junit_objects,
+ size_limit=1024 * 1024,
+ list_failures=True,
+ buildkite_info=None,
+):
if not junit_objects:
return ("", "success")
@@ -354,11 +401,21 @@ def plural(num_tests):
report.append(f"* {tests_failed} {plural(tests_failed)} failed")
if not list_failures:
+ if buildkite_info is not None:
+ log_url = (
+ "https://buildkite.com/organizations/{BUILDKITE_ORGANIZATION_SLUG}/"
+ "pipelines/{BUILDKITE_PIPELINE_SLUG}/builds/{BUILDKITE_BUILD_NUMBER}/"
+ "jobs/{BUILDKITE_JOB_ID}/download.txt".format(**buildkite_info)
+ )
+ download_text = f"[Download]({log_url})"
+ else:
+ download_text = "Download"
+
report.extend(
[
"",
"Failed tests and their output was too large to report. "
- "Download the build's log file to see the details.",
+ f"{download_text} the build's log file to see the details.",
]
)
elif failures:
@@ -381,13 +438,23 @@ def plural(num_tests):
report = "\n".join(report)
if len(report.encode("utf-8")) > size_limit:
- return _generate_report(title, junit_objects, size_limit, list_failures=False)
+ return _generate_report(
+ title,
+ junit_objects,
+ size_limit,
+ list_failures=False,
+ buildkite_info=buildkite_info,
+ )
return report, style
-def generate_report(title, junit_files):
- return _generate_report(title, [JUnitXml.fromfile(p) for p in junit_files])
+def generate_report(title, junit_files, buildkite_info):
+ return _generate_report(
+ title,
+ [JUnitXml.fromfile(p) for p in junit_files],
+ buildkite_info=buildkite_info,
+ )
if __name__ == "__main__":
@@ -399,7 +466,18 @@ def generate_report(title, junit_files):
parser.add_argument("junit_files", help="Paths to JUnit report files.", nargs="*")
args = parser.parse_args()
- report, style = generate_report(args.title, args.junit_files)
+ # All of these are required to build a link to download the log file.
+ env_var_names = [
+ "BUILDKITE_ORGANIZATION_SLUG",
+ "BUILDKITE_PIPELINE_SLUG",
+ "BUILDKITE_BUILD_NUMBER",
+ "BUILDKITE_JOB_ID",
+ ]
+ buildkite_info = {k: v for k, v in os.environ.items() if k in env_var_names}
+ if len(buildkite_info) != len(env_var_names):
+ buildkite_info = None
+
+ report, style = generate_report(args.title, args.junit_files, buildkite_info)
if report:
p = subprocess.Popen(
diff --git a/.ci/monolithic-linux.sh b/.ci/monolithic-linux.sh
index a4aeea7a16add..4bfebd5f75279 100755
--- a/.ci/monolithic-linux.sh
+++ b/.ci/monolithic-linux.sh
@@ -34,8 +34,11 @@ function at-exit {
# If building fails there will be no results files.
shopt -s nullglob
- python3 "${MONOREPO_ROOT}"/.ci/generate_test_report.py ":linux: Linux x64 Test Results" \
- "linux-x64-test-results" "${BUILD_DIR}"/test-results.*.xml
+ if command -v buildkite-agent 2>&1 >/dev/null
+ then
+ python3 "${MONOREPO_ROOT}"/.ci/generate_test_report.py ":linux: Linux x64 Test Results" \
+ "linux-x64-test-results" "${BUILD_DIR}"/test-results.*.xml
+ fi
}
trap at-exit EXIT
diff --git a/.ci/monolithic-windows.sh b/.ci/monolithic-windows.sh
index 4ead122212f4f..25cdd2f419f47 100755
--- a/.ci/monolithic-windows.sh
+++ b/.ci/monolithic-windows.sh
@@ -33,8 +33,11 @@ function at-exit {
# If building fails there will be no results files.
shopt -s nullglob
- python "${MONOREPO_ROOT}"/.ci/generate_test_report.py ":windows: Windows x64 Test Results" \
- "windows-x64-test-results" "${BUILD_DIR}"/test-results.*.xml
+ if command -v buildkite-agent 2>&1 >/dev/null
+ then
+ python "${MONOREPO_ROOT}"/.ci/generate_test_report.py ":windows: Windows x64 Test Results" \
+ "windows-x64-test-results" "${BUILD_DIR}"/test-results.*.xml
+ fi
}
trap at-exit EXIT
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 86be15b72fb64..9ef0713ef8af1 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -94,3 +94,6 @@ b6262880b34629e9d7a72b5a42f315a3c9ed8139
39c7dc7207e76e72da21cf4fedda21b5311bf62d
e80bc777749331e9519575f416c342f7626dd14d
7e5cd8f1b6c5263ed5e2cc03d60c8779a8d3e9f7
+
+# NFC: clang-format test_demangle.pass.cpp but keep test "lines"
+d33bf2e9df578ff7e44fd22504d6ad5a122b7ee6
diff --git a/.github/workflows/build-ci-container-windows.yml b/.github/workflows/build-ci-container-windows.yml
new file mode 100644
index 0000000000000..bba34066a97cd
--- /dev/null
+++ b/.github/workflows/build-ci-container-windows.yml
@@ -0,0 +1,75 @@
+name: Build Windows CI Container
+
+permissions:
+ contents: read
+
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - .github/workflows/build-ci-container-windows.yml
+ - '.github/workflows/containers/github-action-ci-windows/**'
+ pull_request:
+ branches:
+ - main
+ paths:
+ - .github/workflows/build-ci-container-windows.yml
+ - '.github/workflows/containers/github-action-ci-windows/**'
+
+jobs:
+ build-ci-container-windows:
+ if: github.repository_owner == 'llvm'
+ runs-on: windows-2019
+ outputs:
+ container-name: ${{ steps.vars.outputs.container-name }}
+ container-name-tag: ${{ steps.vars.outputs.container-name-tag }}
+ container-filename: ${{ steps.vars.outputs.container-filename }}
+ steps:
+ - name: Checkout LLVM
+ uses: actions/checkout@v4
+ with:
+ sparse-checkout: .github/workflows/containers/github-action-ci-windows
+ - name: Write Variables
+ id: vars
+ run: |
+ $tag = [int64](Get-Date -UFormat %s)
+ $container_name="ghcr.io/$env:GITHUB_REPOSITORY_OWNER/ci-windows-2019"
+ echo "container-name=${container_name}" >> $env:GITHUB_OUTPUT
+ echo "container-name-tag=${container_name}:${tag}" >> $env:GITHUB_OUTPUT
+ echo "container-filename=ci-windows-${tag}.tar" >> $env:GITHUB_OUTPUT
+ - name: Build Container
+ working-directory: .github/workflows/containers/github-action-ci-windows
+ run: |
+ docker build -t ${{ steps.vars.outputs.container-name-tag }} .
+ - name: Save container image
+ run: |
+ docker save ${{ steps.vars.outputs.container-name-tag }} > ${{ steps.vars.outputs.container-filename }}
+ - name: Upload container image
+ uses: actions/upload-artifact@v4
+ with:
+ name: container
+ path: ${{ steps.vars.outputs.container-filename }}
+ retention-days: 14
+
+ push-ci-container:
+ if: github.event_name == 'push'
+ needs:
+ - build-ci-container-windows
+ permissions:
+ packages: write
+ runs-on: windows-2019
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ steps:
+ - name: Download container
+ uses: actions/download-artifact@v4
+ with:
+ name: container
+ - name: Push Container
+ run: |
+ docker load -i ${{ needs.build-ci-container-windows.outputs.container-filename }}
+ docker tag ${{ needs.build-ci-container-windows.outputs.container-name-tag }} ${{ needs.build-ci-container-windows.outputs.container-name }}:latest
+ docker login -u ${{ github.actor }} -p $env:GITHUB_TOKEN ghcr.io
+ docker push ${{ needs.build-ci-container-windows.outputs.container-name-tag }}
+ docker push ${{ needs.build-ci-container-windows.outputs.container-name }}:latest
diff --git a/.github/workflows/build-ci-container.yml b/.github/workflows/build-ci-container.yml
index 28fc7de2ee065..50729e0173506 100644
--- a/.github/workflows/build-ci-container.yml
+++ b/.github/workflows/build-ci-container.yml
@@ -18,44 +18,18 @@ on:
- '.github/workflows/containers/github-action-ci/**'
jobs:
- # TODO(boomanaiden154): Switch this back to a single stage build when we can
- # run this on the self-hosted runners and don't have to do it this way to
- # avoid timeouts.
- build-ci-container-stage1:
+ build-ci-container:
if: github.repository_owner == 'llvm'
- runs-on: ubuntu-latest
+ runs-on: depot-ubuntu-22.04-16
+ outputs:
+ container-name: ${{ steps.vars.outputs.container-name }}
+ container-name-tag: ${{ steps.vars.outputs.container-name-tag }}
+ container-filename: ${{ steps.vars.outputs.container-filename }}
steps:
- name: Checkout LLVM
uses: actions/checkout@v4
with:
sparse-checkout: .github/workflows/containers/github-action-ci/
- - name: Change podman Root Direcotry
- run: |
- mkdir -p ~/.config/containers
- sudo mkdir -p /mnt/podman
- sudo chown `whoami`:`whoami` /mnt/podman
- cp ./.github/workflows/containers/github-action-ci/storage.conf ~/.config/containers/storage.conf
- podman info
- - name: Build container stage1
- working-directory: ./.github/workflows/containers/github-action-ci/
- run: |
- podman build -t stage1-toolchain --target stage1-toolchain -f stage1.Dockerfile .
- - name: Save container image
- run: |
- podman save stage1-toolchain > stage1-toolchain.tar
- - name: Upload container image
- uses: actions/upload-artifact@v4
- with:
- name: stage1-toolchain
- path: stage1-toolchain.tar
- retention-days: 1
- build-ci-container-stage2:
- if: github.repository_owner == 'llvm'
- runs-on: ubuntu-latest
- needs: build-ci-container-stage1
- permissions:
- packages: write
- steps:
- name: Write Variables
id: vars
run: |
@@ -63,50 +37,51 @@ jobs:
container_name="ghcr.io/$GITHUB_REPOSITORY_OWNER/ci-ubuntu-22.04"
echo "container-name=$container_name" >> $GITHUB_OUTPUT
echo "container-name-tag=$container_name:$tag" >> $GITHUB_OUTPUT
-
- - name: Checkout LLVM
- uses: actions/checkout@v4
- with:
- sparse-checkout: .github/workflows/containers/github-action-ci/
-
- - name: Change podman Root Direcotry
+ echo "container-filename=$(echo $container_name:$tag | sed -e 's/\//-/g' -e 's/:/-/g').tar" >> $GITHUB_OUTPUT
+ - name: Build container
+ working-directory: ./.github/workflows/containers/github-action-ci/
run: |
- mkdir -p ~/.config/containers
- sudo mkdir -p /mnt/podman
- sudo chown `whoami`:`whoami` /mnt/podman
- cp ./.github/workflows/containers/github-action-ci/storage.conf ~/.config/containers/storage.conf
- podman info
-
- # Download the container image into /mnt/podman rather than
- # $GITHUB_WORKSPACE to avoid space limitations on the default drive
- # and use the permissions setup for /mnt/podman.
- - name: Download stage1-toolchain
- uses: actions/download-artifact@v4
- with:
- name: stage1-toolchain
- path: /mnt/podman
+ podman build -t ${{ steps.vars.outputs.container-name-tag }} .
- - name: Load stage1-toolchain
+ # Save the container so we have it in case the push fails. This also
+ # allows us to separate the push step into a different job so we can
+ # maintain minimal permissions while building the container.
+ - name: Save container image
run: |
- podman load -i /mnt/podman/stage1-toolchain.tar
+ podman save ${{ steps.vars.outputs.container-name-tag }} > ${{ steps.vars.outputs.container-filename }}
- - name: Build Container
- working-directory: ./.github/workflows/containers/github-action-ci/
- run: |
- podman build -t ${{ steps.vars.outputs.container-name-tag }} -f stage2.Dockerfile .
- podman tag ${{ steps.vars.outputs.container-name-tag }} ${{ steps.vars.outputs.container-name }}:latest
+ - name: Upload container image
+ uses: actions/upload-artifact@v4
+ with:
+ name: container
+ path: ${{ steps.vars.outputs.container-filename }}
+ retention-days: 14
- name: Test Container
run: |
for image in ${{ steps.vars.outputs.container-name-tag }} ${{ steps.vars.outputs.container-name }}; do
- podman run --rm -it $image /usr/bin/bash -x -c 'printf '\''#include \nint main(int argc, char **argv) { std::cout << "Hello\\n"; }'\'' | clang++ -x c++ - && ./a.out | grep Hello'
+ podman run --rm -it $image /usr/bin/bash -x -c 'cd $HOME && printf '\''#include \nint main(int argc, char **argv) { std::cout << "Hello\\n"; }'\'' | clang++ -x c++ - && ./a.out | grep Hello'
done
+ push-ci-container:
+ if: github.event_name == 'push'
+ needs:
+ - build-ci-container
+ permissions:
+ packages: write
+ runs-on: ubuntu-24.04
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ steps:
+ - name: Download container
+ uses: actions/download-artifact@v4
+ with:
+ name: container
+
- name: Push Container
- if: github.event_name == 'push'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
+ podman load -i ${{ needs.build-ci-container.outputs.container-filename }}
+ podman tag ${{ needs.build-ci-container.outputs.container-name-tag }} ${{ needs.build-ci-container.outputs.container-name }}:latest
podman login -u ${{ github.actor }} -p $GITHUB_TOKEN ghcr.io
- podman push ${{ steps.vars.outputs.container-name-tag }}
- podman push ${{ steps.vars.outputs.container-name }}:latest
+ podman push ${{ needs.build-ci-container.outputs.container-name-tag }}
+ podman push ${{ needs.build-ci-container.outputs.container-name }}:latest
diff --git a/.github/workflows/commit-access-review.py b/.github/workflows/commit-access-review.py
index 8ea9b1fcc2fb0..91d3a61cdcb17 100644
--- a/.github/workflows/commit-access-review.py
+++ b/.github/workflows/commit-access-review.py
@@ -62,57 +62,9 @@ def __repr__(self):
)
-def run_graphql_query(
- query: str, variables: dict, token: str, retry: bool = True
-) -> dict:
- """
- This function submits a graphql query and returns the results as a
- dictionary.
- """
- s = requests.Session()
- retries = requests.adapters.Retry(total=8, backoff_factor=2, status_forcelist=[504])
- s.mount("https://", requests.adapters.HTTPAdapter(max_retries=retries))
-
- headers = {
- "Authorization": "bearer {}".format(token),
- # See
- # https://github.blog/2021-11-16-graphql-global-id-migration-update/
- "X-Github-Next-Global-ID": "1",
- }
- request = s.post(
- url="https://api.github.com/graphql",
- json={"query": query, "variables": variables},
- headers=headers,
- )
-
- rate_limit = request.headers.get("X-RateLimit-Remaining")
- print(rate_limit)
- if rate_limit and int(rate_limit) < 10:
- reset_time = int(request.headers["X-RateLimit-Reset"])
- while reset_time - int(time.time()) > 0:
- time.sleep(60)
- print(
- "Waiting until rate limit reset",
- reset_time - int(time.time()),
- "seconds remaining",
- )
-
- if request.status_code == 200:
- if "data" not in request.json():
- print(request.json())
- sys.exit(1)
- return request.json()["data"]
- elif retry:
- return run_graphql_query(query, variables, token, False)
- else:
- raise Exception(
- "Failed to run graphql query\nquery: {}\nerror: {}".format(
- query, request.json()
- )
- )
-
-
-def check_manual_requests(start_date: datetime.datetime, token: str) -> list[str]:
+def check_manual_requests(
+ gh: github.Github, start_date: datetime.datetime
+) -> list[str]:
"""
Return a list of users who have been asked since ``start_date`` if they
want to keep their commit access.
@@ -137,10 +89,13 @@ def check_manual_requests(start_date: datetime.datetime, token: str) -> list[str
"""
formatted_start_date = start_date.strftime("%Y-%m-%dT%H:%M:%S")
variables = {
- "query": f"type:issue created:>{formatted_start_date} org:llvm repo:llvm-project label:infrastructure:commit-access"
+ "query": f"type:issue created:>{formatted_start_date} org:llvm repo:llvm-project label:infra:commit-access"
}
- data = run_graphql_query(query, variables, token)
+ res_header, res_data = gh._Github__requester.graphql_query(
+ query=query, variables=variables
+ )
+ data = res_data["data"]
users = []
for issue in data["search"]["nodes"]:
users.extend([user[1:] for user in re.findall("@[^ ,\n]+", issue["body"])])
@@ -148,7 +103,7 @@ def check_manual_requests(start_date: datetime.datetime, token: str) -> list[str
return users
-def get_num_commits(user: str, start_date: datetime.datetime, token: str) -> int:
+def get_num_commits(gh: github.Github, user: str, start_date: datetime.datetime) -> int:
"""
Get number of commits that ``user`` has been made since ``start_date`.
"""
@@ -166,7 +121,10 @@ def get_num_commits(user: str, start_date: datetime.datetime, token: str) -> int
}
"""
- data = run_graphql_query(user_query, variables, token)
+ res_header, res_data = gh._Github__requester.graphql_query(
+ query=user_query, variables=variables
+ )
+ data = res_data["data"]
variables["user_id"] = data["user"]["id"]
query = """
@@ -193,7 +151,10 @@ def get_num_commits(user: str, start_date: datetime.datetime, token: str) -> int
}
"""
count = 0
- data = run_graphql_query(query, variables, token)
+ res_header, res_data = gh._Github__requester.graphql_query(
+ query=query, variables=variables
+ )
+ data = res_data["data"]
for repo in data["organization"]["teams"]["nodes"][0]["repositories"]["nodes"]:
count += int(repo["ref"]["target"]["history"]["totalCount"])
if count >= User.THRESHOLD:
@@ -202,7 +163,7 @@ def get_num_commits(user: str, start_date: datetime.datetime, token: str) -> int
def is_new_committer_query_repo(
- user: str, start_date: datetime.datetime, token: str
+ gh: github.Github, user: str, start_date: datetime.datetime
) -> bool:
"""
Determine if ``user`` is a new committer. A new committer can keep their
@@ -220,7 +181,10 @@ def is_new_committer_query_repo(
}
"""
- data = run_graphql_query(user_query, variables, token)
+ res_header, res_data = gh._Github__requester.graphql_query(
+ query=user_query, variables=variables
+ )
+ data = res_data["data"]
variables["owner"] = "llvm"
variables["user_id"] = data["user"]["id"]
variables["start_date"] = start_date.strftime("%Y-%m-%dT%H:%M:%S")
@@ -245,7 +209,10 @@ def is_new_committer_query_repo(
}
"""
- data = run_graphql_query(query, variables, token)
+ res_header, res_data = gh._Github__requester.graphql_query(
+ query=query, variables=variables
+ )
+ data = res_data["data"]
repo = data["organization"]["repository"]
commits = repo["ref"]["target"]["history"]["nodes"]
if len(commits) == 0:
@@ -256,18 +223,22 @@ def is_new_committer_query_repo(
return True
-def is_new_committer(user: str, start_date: datetime.datetime, token: str) -> bool:
+def is_new_committer(
+ gh: github.Github, user: str, start_date: datetime.datetime
+) -> bool:
"""
Wrapper around is_new_commiter_query_repo to handle exceptions.
"""
try:
- return is_new_committer_query_repo(user, start_date, token)
+ return is_new_committer_query_repo(gh, user, start_date)
except:
pass
return True
-def get_review_count(user: str, start_date: datetime.datetime, token: str) -> int:
+def get_review_count(
+ gh: github.Github, user: str, start_date: datetime.datetime
+) -> int:
"""
Return the number of reviews that ``user`` has done since ``start_date``.
"""
@@ -286,11 +257,14 @@ def get_review_count(user: str, start_date: datetime.datetime, token: str) -> in
"query": f"type:pr commenter:{user} -author:{user} merged:>{formatted_start_date} org:llvm",
}
- data = run_graphql_query(query, variables, token)
+ res_header, res_data = gh._Github__requester.graphql_query(
+ query=query, variables=variables
+ )
+ data = res_data["data"]
return int(data["search"]["issueCount"])
-def count_prs(triage_list: dict, start_date: datetime.datetime, token: str):
+def count_prs(gh: github.Github, triage_list: dict, start_date: datetime.datetime):
"""
Fetch all the merged PRs for the project since ``start_date`` and update
``triage_list`` with the number of PRs merged for each user.
@@ -329,7 +303,10 @@ def count_prs(triage_list: dict, start_date: datetime.datetime, token: str):
has_next_page = True
while has_next_page:
print(variables)
- data = run_graphql_query(query, variables, token)
+ res_header, res_data = gh._Github__requester.graphql_query(
+ query=query, variables=variables
+ )
+ data = res_data["data"]
for pr in data["search"]["nodes"]:
# Users can be None if the user has been deleted.
if not pr["author"]:
@@ -365,14 +342,14 @@ def main():
print("Start:", len(triage_list), "triagers")
# Step 0 Check if users have requested commit access in the last year.
- for user in check_manual_requests(one_year_ago, token):
+ for user in check_manual_requests(gh, one_year_ago):
if user in triage_list:
print(user, "requested commit access in the last year.")
del triage_list[user]
print("After Request Check:", len(triage_list), "triagers")
# Step 1 count all PRs authored or merged
- count_prs(triage_list, one_year_ago, token)
+ count_prs(gh, triage_list, one_year_ago)
print("After PRs:", len(triage_list), "triagers")
@@ -381,7 +358,7 @@ def main():
# Step 2 check for reviews
for user in list(triage_list.keys()):
- review_count = get_review_count(user, one_year_ago, token)
+ review_count = get_review_count(gh, user, one_year_ago)
triage_list[user].add_reviewed(review_count)
print("After Reviews:", len(triage_list), "triagers")
@@ -391,7 +368,7 @@ def main():
# Step 3 check for number of commits
for user in list(triage_list.keys()):
- num_commits = get_num_commits(user, one_year_ago, token)
+ num_commits = get_num_commits(gh, user, one_year_ago)
# Override the total number of commits to not double count commits and
# authored PRs.
triage_list[user].set_authored(num_commits)
@@ -401,7 +378,7 @@ def main():
# Step 4 check for new committers
for user in list(triage_list.keys()):
print("Checking", user)
- if is_new_committer(user, one_year_ago, token):
+ if is_new_committer(gh, user, one_year_ago):
print("Removing new committer: ", user)
del triage_list[user]
diff --git a/.github/workflows/containers/github-action-ci-windows/Dockerfile b/.github/workflows/containers/github-action-ci-windows/Dockerfile
new file mode 100644
index 0000000000000..bc56e20935500
--- /dev/null
+++ b/.github/workflows/containers/github-action-ci-windows/Dockerfile
@@ -0,0 +1,118 @@
+# Agent image for LLVM org cluster.
+# .net 4.8 is required by chocolately package manager.
+FROM mcr.microsoft.com/dotnet/framework/sdk:4.8-windowsservercore-ltsc2019
+
+# Restore the default Windows shell for correct batch processing.
+SHELL ["cmd", "/S", "/C"]
+
+# Download the Build Tools bootstrapper.
+ADD https://aka.ms/vs/16/release/vs_buildtools.exe /TEMP/vs_buildtools.exe
+
+RUN powershell -Command Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
+
+# Download channel for fixed install.
+ARG CHANNEL_URL=https://aka.ms/vs/16/release/channel
+ADD ${CHANNEL_URL} /TEMP/VisualStudio.chman
+
+# Install Build Tools with C++ workload.
+# - Documentation for docker installation
+# https://docs.microsoft.com/en-us/visualstudio/install/build-tools-container?view=vs-2019
+# - Documentation on workloads
+# https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2019#c-build-tools
+# - Documentation on flags
+# https://docs.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio?view=vs-2019
+RUN /TEMP/vs_buildtools.exe --quiet --wait --norestart --nocache \
+ --channelUri C:\TEMP\VisualStudio.chman \
+ --installChannelUri C:\TEMP\VisualStudio.chman \
+ --installPath C:\BuildTools \
+ --add Microsoft.VisualStudio.Workload.VCTools \
+ --add Microsoft.VisualStudio.Component.VC.ATL \
+ --includeRecommended \
+ || IF "%ERRORLEVEL%"=="3010" EXIT 0
+
+# Register DIA dll (Debug Interface Access) so it can be used to symbolize
+# the stack traces. Register dll for 32 and 64 bit.
+# see https://developercommunity.visualstudio.com/content/problem/290674/msdia140dll-is-not-registered-on-vs2017-hosts.html
+
+RUN regsvr32 /S "C:\BuildTools\DIA SDK\bin\amd64\msdia140.dll" & \
+ regsvr32 /S "C:\BuildTools\DIA SDK\bin\msdia140.dll"
+
+# install tools as described in https://llvm.org/docs/GettingStartedVS.html
+# and a few more that were not documented...
+RUN choco install -y ninja git
+# Pin an older version of Python; the current Python 3.10 fails when
+# doing "pip install" for the other dependencies, as it fails to find libxml
+# while compiling some package.
+RUN choco install -y python3 --version 3.9.7
+
+# ActivePerl is currently not installable via Chocolatey, see
+# http://disq.us/p/2ipditb. Install StrawberryPerl instead. Unfortunately,
+# StrawberryPerl not only installs Perl, but also a redundant C/C++ compiler
+# toolchain, and a copy of pkg-config which can cause misdetections for other
+# built products, see
+# https://github.com/StrawberryPerl/Perl-Dist-Strawberry/issues/11 for further
+# details. Remove the redundant and unnecessary parts of the StrawberryPerl
+# install.
+RUN choco install -y strawberryperl && \
+ rmdir /q /s c:\strawberry\c && \
+ del /q c:\strawberry\perl\bin\pkg-config*
+
+# libcxx requires clang(-cl) to be available
+RUN choco install -y sccache llvm
+RUN pip install psutil
+
+RUN curl -LO https://github.com/mstorsjo/llvm-mingw/releases/download/20230320/llvm-mingw-20230320-ucrt-x86_64.zip && \
+ powershell Expand-Archive llvm-mingw-*-ucrt-x86_64.zip -DestinationPath . && \
+ del llvm-mingw-*-ucrt-x86_64.zip && \
+ ren llvm-mingw-20230320-ucrt-x86_64 llvm-mingw
+
+# configure Python encoding
+ENV PYTHONIOENCODING=UTF-8
+
+# update the path variable
+# C:\Program Files\Git\usr\bin contains a usable bash and other unix tools.
+# C:\llvm-mingw\bin contains Clang configured for mingw targets and
+# corresponding sysroots. Both the 'llvm' package (with Clang defaulting
+# to MSVC targets) and this directory contains executables named
+# 'clang.exe' - add this last to let the other one have precedence.
+# To use these compilers, use the triple prefixed form, e.g.
+# x86_64-w64-mingw32-clang.
+# C:\buildtools and SDK paths are ones that are set by c:\BuildTools\Common7\Tools\VsDevCmd.bat -arch=amd64 -host_arch=amd64
+RUN powershell -Command \
+ [System.Environment]::SetEnvironmentVariable('PATH', \
+ [System.Environment]::GetEnvironmentVariable('PATH', 'machine') + ';C:\Program Files\Git\usr\bin;C:\llvm-mingw\bin' \
+ + ';C:\BuildTools\Common7\IDE\' \
+ + ';C:\BuildTools\Common7\IDE\CommonExt ensions\Microsoft\TeamFoundation\Team Explorer' \
+ + ';C:\BuildTools\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin' \
+ + ';C:\BuildTools\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja' \
+ + ';C:\BuildTools\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer' \
+ + ';C:\BuildTools\Common7\IDE\CommonExtensions\Microsoft\TestWindow' \
+ + ';C:\BuildTools\Common7\IDE\VC\VCPackages' \
+ + ';C:\BuildTools\Common7\Tools\' \
+ + ';C:\BuildTools\Common7\Tools\devinit' \
+ + ';C:\BuildTools\MSBuild\Current\Bin' \
+ + ';C:\BuildTools\MSBuild\Current\bin\Roslyn' \
+ + ';C:\BuildTools\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64' \
+ + ';C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\' \
+ + ';C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64' \
+ + ';C:\Program Files (x86)\Windows Kits\10\bin\x64' \
+ + ';C:\Windows\Microsoft.NET\Framework64\v4.0.30319' \
+ ,'machine')
+
+# support long file names during git checkout
+RUN git config --system core.longpaths true & \
+ git config --global core.autocrlf false
+
+# handle for debugging of files beeing locked by some processes.
+RUN choco install -y handle
+
+RUN pip3 install pywin32 buildbot-worker==2.8.4
+
+ARG RUNNER_VERSION=2.319.1
+ENV RUNNER_VERSION=$RUNNER_VERSION
+
+RUN powershell -Command \
+ Invoke-WebRequest -Uri https://github.com/actions/runner/releases/download/v${env:RUNNER_VERSION}/actions-runner-win-x64-${env:RUNNER_VERSION}.zip -OutFile actions-runner-win.zip ; \
+ Add-Type -AssemblyName System.IO.Compression.FileSystem ; \
+ [System.IO.Compression.ZipFile]::ExtractToDirectory('actions-runner-win.zip', $PWD) ;\
+ rm actions-runner-win.zip
diff --git a/.github/workflows/containers/github-action-ci/Dockerfile b/.github/workflows/containers/github-action-ci/Dockerfile
new file mode 100644
index 0000000000000..58355d261c43c
--- /dev/null
+++ b/.github/workflows/containers/github-action-ci/Dockerfile
@@ -0,0 +1,77 @@
+FROM docker.io/library/ubuntu:22.04 as base
+ENV LLVM_SYSROOT=/opt/llvm
+
+FROM base as stage1-toolchain
+ENV LLVM_VERSION=19.1.5
+
+RUN apt-get update && \
+ apt-get install -y \
+ wget \
+ gcc \
+ g++ \
+ cmake \
+ ninja-build \
+ python3 \
+ git \
+ curl
+
+RUN curl -O -L https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-$LLVM_VERSION.tar.gz && tar -xf llvmorg-$LLVM_VERSION.tar.gz
+
+WORKDIR /llvm-project-llvmorg-$LLVM_VERSION
+
+# Patch to enable better PGO profile data.
+# TODO: Remove this for llvm 20
+ADD https://github.com/llvm/llvm-project/commit/738250989ce516f02f809bdfde474a039c77e81f.patch .
+
+RUN patch -p1 < 738250989ce516f02f809bdfde474a039c77e81f.patch
+
+RUN cmake -B ./build -G Ninja ./llvm \
+ -C ./clang/cmake/caches/BOLT-PGO.cmake \
+ -DBOOTSTRAP_LLVM_ENABLE_LLD=ON \
+ -DBOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LLD=ON \
+ -DPGO_INSTRUMENT_LTO=Thin \
+ -DLLVM_ENABLE_RUNTIMES="compiler-rt" \
+ -DCMAKE_INSTALL_PREFIX="$LLVM_SYSROOT" \
+ -DLLVM_ENABLE_PROJECTS="bolt;clang;lld;clang-tools-extra" \
+ -DLLVM_DISTRIBUTION_COMPONENTS="lld;compiler-rt;clang-format;scan-build" \
+ -DCLANG_DEFAULT_LINKER="lld"
+
+RUN ninja -C ./build stage2-clang-bolt stage2-install-distribution && ninja -C ./build install-distribution
+
+FROM base
+
+COPY --from=stage1-toolchain $LLVM_SYSROOT $LLVM_SYSROOT
+
+# Need to install curl for hendrikmuhs/ccache-action
+# Need nodejs for some of the GitHub actions.
+# Need perl-modules for clang analyzer tests.
+# Need git for SPIRV-Tools tests.
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y \
+ binutils \
+ cmake \
+ curl \
+ git \
+ libstdc++-11-dev \
+ ninja-build \
+ nodejs \
+ perl-modules \
+ python3-psutil \
+
+ # These are needed by the premerge pipeline. Pip is used to install
+ # dependent python packages and ccache is used for build caching. File and
+ # tzdata are used for tests.
+ python3-pip \
+ ccache \
+ file \
+ tzdata
+
+ENV LLVM_SYSROOT=$LLVM_SYSROOT
+ENV PATH=${LLVM_SYSROOT}/bin:${PATH}
+
+# Create a new user to avoid test failures related to a lack of expected
+# permissions issues in some tests. Set the user id to 1001 as that is the
+# user id that Github Actions uses to perform the checkout action.
+RUN useradd gha -u 1001 -m -s /bin/bash
+USER gha
+
diff --git a/.github/workflows/containers/github-action-ci/bootstrap.patch b/.github/workflows/containers/github-action-ci/bootstrap.patch
deleted file mode 100644
index 55631c54a396f..0000000000000
--- a/.github/workflows/containers/github-action-ci/bootstrap.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/clang/cmake/caches/BOLT-PGO.cmake b/clang/cmake/caches/BOLT-PGO.cmake
-index 1a04ca9a74e5..d092820e4115 100644
---- a/clang/cmake/caches/BOLT-PGO.cmake
-+++ b/clang/cmake/caches/BOLT-PGO.cmake
-@@ -4,6 +4,8 @@ set(CLANG_BOOTSTRAP_TARGETS
- stage2-clang-bolt
- stage2-distribution
- stage2-install-distribution
-+ clang
-+ lld
- CACHE STRING "")
- set(BOOTSTRAP_CLANG_BOOTSTRAP_TARGETS
- clang-bolt
diff --git a/.github/workflows/containers/github-action-ci/stage1.Dockerfile b/.github/workflows/containers/github-action-ci/stage1.Dockerfile
deleted file mode 100644
index 3e2c1ab11d58b..0000000000000
--- a/.github/workflows/containers/github-action-ci/stage1.Dockerfile
+++ /dev/null
@@ -1,42 +0,0 @@
-FROM docker.io/library/ubuntu:22.04 as base
-ENV LLVM_SYSROOT=/opt/llvm
-
-FROM base as stage1-toolchain
-ENV LLVM_VERSION=19.1.2
-
-RUN apt-get update && \
- apt-get install -y \
- wget \
- gcc \
- g++ \
- cmake \
- ninja-build \
- python3 \
- git \
- curl
-
-RUN curl -O -L https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-$LLVM_VERSION.tar.gz && tar -xf llvmorg-$LLVM_VERSION.tar.gz
-
-WORKDIR /llvm-project-llvmorg-$LLVM_VERSION
-
-COPY bootstrap.patch /
-
-# TODO(boomanaiden154): Remove the bootstrap patch once we unsplit the build
-# and no longer need to explicitly build the stage2 dependencies.
-RUN cat /bootstrap.patch | patch -p1
-
-RUN mkdir build
-
-RUN cmake -B ./build -G Ninja ./llvm \
- -C ./clang/cmake/caches/BOLT-PGO.cmake \
- -DBOOTSTRAP_LLVM_ENABLE_LLD=ON \
- -DBOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LLD=ON \
- -DPGO_INSTRUMENT_LTO=Thin \
- -DLLVM_ENABLE_RUNTIMES="compiler-rt" \
- -DCMAKE_INSTALL_PREFIX="$LLVM_SYSROOT" \
- -DLLVM_ENABLE_PROJECTS="bolt;clang;lld;clang-tools-extra" \
- -DLLVM_DISTRIBUTION_COMPONENTS="lld;compiler-rt;clang-format;scan-build" \
- -DCLANG_DEFAULT_LINKER="lld" \
- -DBOOTSTRAP_CLANG_PGO_TRAINING_DATA_SOURCE_DIR=/llvm-project-llvmorg-$LLVM_VERSION/llvm
-
-RUN ninja -C ./build stage2-instrumented-clang stage2-instrumented-lld
diff --git a/.github/workflows/containers/github-action-ci/stage2.Dockerfile b/.github/workflows/containers/github-action-ci/stage2.Dockerfile
deleted file mode 100644
index 0ca0da87734c4..0000000000000
--- a/.github/workflows/containers/github-action-ci/stage2.Dockerfile
+++ /dev/null
@@ -1,29 +0,0 @@
-FROM docker.io/library/ubuntu:22.04 as base
-ENV LLVM_SYSROOT=/opt/llvm
-
-FROM stage1-toolchain AS stage2-toolchain
-
-RUN ninja -C ./build stage2-clang-bolt stage2-install-distribution && ninja -C ./build install-distribution && rm -rf ./build
-
-FROM base
-
-COPY --from=stage2-toolchain $LLVM_SYSROOT $LLVM_SYSROOT
-
-# Need to install curl for hendrikmuhs/ccache-action
-# Need nodejs for some of the GitHub actions.
-# Need perl-modules for clang analyzer tests.
-# Need git for SPIRV-Tools tests.
-RUN apt-get update && \
- apt-get install -y \
- binutils \
- cmake \
- curl \
- git \
- libstdc++-11-dev \
- ninja-build \
- nodejs \
- perl-modules \
- python3-psutil
-
-ENV LLVM_SYSROOT=$LLVM_SYSROOT
-ENV PATH=${LLVM_SYSROOT}/bin:${PATH}
diff --git a/.github/workflows/containers/github-action-ci/storage.conf b/.github/workflows/containers/github-action-ci/storage.conf
deleted file mode 100644
index 60f295ff1e969..0000000000000
--- a/.github/workflows/containers/github-action-ci/storage.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-[storage]
- driver = "overlay"
- runroot = "/mnt/podman/container"
- graphroot = "/mnt/podman/image"
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 0bb018b780a2a..8441589bb716e 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -94,6 +94,8 @@ jobs:
flang:
- 'flang/docs/**'
- 'flang/include/flang/Optimizer/Dialect/FIROps.td'
+ workflow:
+ - '.github/workflows/docs.yml'
- name: Fetch LLVM sources (PR)
if: ${{ github.event_name == 'pull_request' }}
uses: actions/checkout@v4
@@ -115,77 +117,99 @@ jobs:
- name: Setup output folder
run: mkdir built-docs
- name: Build LLVM docs
- if: steps.docs-changed-subprojects.outputs.llvm_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.llvm_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B llvm-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C llvm-build docs-llvm-html docs-llvm-man
mkdir built-docs/llvm
cp -r llvm-build/docs/* built-docs/llvm/
- name: Build Clang docs
- if: steps.docs-changed-subprojects.outputs.clang_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.clang_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B clang-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C clang-build docs-clang-html docs-clang-man
mkdir built-docs/clang
cp -r clang-build/docs/* built-docs/clang/
- name: Build clang-tools-extra docs
- if: steps.docs-changed-subprojects.outputs.clang-tools-extra_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.clang-tools-extra_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B clang-tools-extra-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C clang-tools-extra-build docs-clang-tools-html docs-clang-tools-man
mkdir built-docs/clang-tools-extra
cp -r clang-tools-extra-build/docs/* built-docs/clang-tools-extra/
- name: Build LLDB docs
- if: steps.docs-changed-subprojects.outputs.lldb_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.lldb_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B lldb-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C lldb-build docs-lldb-html docs-lldb-man
mkdir built-docs/lldb
cp -r lldb-build/docs/* built-docs/lldb/
- name: Build libunwind docs
- if: steps.docs-changed-subprojects.outputs.libunwind_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.libunwind_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B libunwind-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libunwind" -DLLVM_ENABLE_SPHINX=ON ./runtimes
TZ=UTC ninja -C libunwind-build docs-libunwind-html
mkdir built-docs/libunwind
cp -r libunwind-build/libunwind/docs/* built-docs/libunwind
- name: Build libcxx docs
- if: steps.docs-changed-subprojects.outputs.libcxx_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.libcxx_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B libcxx-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libcxxabi;libcxx;libunwind" -DLLVM_ENABLE_SPHINX=ON ./runtimes
TZ=UTC ninja -C libcxx-build docs-libcxx-html
mkdir built-docs/libcxx
cp -r libcxx-build/libcxx/docs/* built-docs/libcxx/
- name: Build libc docs
- if: steps.docs-changed-subprojects.outputs.libc_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.libc_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B libc-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libc" -DLLVM_ENABLE_SPHINX=ON ./runtimes
TZ=UTC ninja -C libc-build docs-libc-html
mkdir built-docs/libc
cp -r libc-build/libc/docs/* built-docs/libc/
- name: Build LLD docs
- if: steps.docs-changed-subprojects.outputs.lld_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.lld_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B lld-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="lld" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C lld-build docs-lld-html
mkdir built-docs/lld
cp -r lld-build/docs/* built-docs/lld/
- name: Build OpenMP docs
- if: steps.docs-changed-subprojects.outputs.openmp_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.openmp_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B openmp-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;openmp" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C openmp-build docs-openmp-html
mkdir built-docs/openmp
cp -r openmp-build/docs/* built-docs/openmp/
- name: Build Polly docs
- if: steps.docs-changed-subprojects.outputs.polly_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.polly_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B polly-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="polly" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C polly-build docs-polly-html docs-polly-man
mkdir built-docs/polly
cp -r polly-build/docs/* built-docs/polly/
- name: Build Flang docs
- if: steps.docs-changed-subprojects.outputs.flang_any_changed == 'true'
+ if: |
+ steps.docs-changed-subprojects.outputs.flang_any_changed == 'true' ||
+ steps.docs-changed-subprojects.outputs.workflow_any_changed == 'true'
run: |
cmake -B flang-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;mlir;flang" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C flang-build docs-flang-html
diff --git a/.github/workflows/libc-fullbuild-tests.yml b/.github/workflows/libc-fullbuild-tests.yml
new file mode 100644
index 0000000000000..58e15ce29546e
--- /dev/null
+++ b/.github/workflows/libc-fullbuild-tests.yml
@@ -0,0 +1,89 @@
+# This workflow is for pre-commit testing of the LLVM-libc project.
+name: LLVM-libc Pre-commit Fullbuild Tests
+permissions:
+ contents: read
+on:
+ pull_request:
+ branches: [ "main" ]
+ paths:
+ - 'libc/**'
+ - '.github/workflows/libc-fullbuild-tests.yml'
+
+jobs:
+ build:
+ runs-on: ubuntu-24.04
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - c_compiler: clang
+ cpp_compiler: clang++
+ # TODO: add back gcc build when it is fixed
+ # - c_compiler: gcc
+ # cpp_compiler: g++
+ steps:
+ - uses: actions/checkout@v4
+
+ # Libc's build is relatively small comparing with other components of LLVM.
+ # A fresh fullbuild takes about 190MiB of uncompressed disk space, which can
+ # be compressed into ~40MiB. Limiting the cache size to 1G should be enough.
+ # Prefer sccache as it is more modern.
+ # Do not use direct GHAC access even though it is supported by sccache. GHAC rejects
+ # frequent small object writes.
+ - name: Setup ccache
+ uses: hendrikmuhs/ccache-action@v1.2
+ with:
+ max-size: 1G
+ key: libc_fullbuild_${{ matrix.c_compiler }}
+ variant: sccache
+
+ # Notice:
+ # - MPFR is required by some of the mathlib tests.
+ # - Debian has a multilib setup, so we need to symlink the asm directory.
+ # For more information, see https://wiki.debian.org/Multiarch/LibraryPathOverview
+ - name: Prepare dependencies (Ubuntu)
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y libmpfr-dev libgmp-dev libmpc-dev ninja-build linux-libc-dev
+ sudo ln -sf /usr/include/$(uname -p)-linux-gnu/asm /usr/include/asm
+
+ - name: Set reusable strings
+ id: strings
+ shell: bash
+ run: |
+ echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
+ echo "build-install-dir=${{ github.workspace }}/install" >> "$GITHUB_OUTPUT"
+
+ # Configure libc fullbuild with scudo.
+ # Use MinSizeRel to reduce the size of the build.
+ - name: Configure CMake
+ run: >
+ cmake -B ${{ steps.strings.outputs.build-output-dir }}
+ -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
+ -DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
+ -DCMAKE_BUILD_TYPE=MinSizeRel
+ -DCMAKE_C_COMPILER_LAUNCHER=sccache
+ -DCMAKE_CXX_COMPILER_LAUNCHER=sccache
+ -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.build-install-dir }}
+ -DLLVM_ENABLE_RUNTIMES="libc;compiler-rt"
+ -DLLVM_LIBC_FULL_BUILD=ON
+ -DLLVM_LIBC_INCLUDE_SCUDO=ON
+ -DCOMPILER_RT_BUILD_SCUDO_STANDALONE_WITH_LLVM_LIBC=ON
+ -DCOMPILER_RT_BUILD_GWP_ASAN=OFF
+ -DCOMPILER_RT_SCUDO_STANDALONE_BUILD_SHARED=OFF
+ -G Ninja
+ -S ${{ github.workspace }}/runtimes
+
+ - name: Build
+ run: >
+ cmake
+ --build ${{ steps.strings.outputs.build-output-dir }}
+ --parallel
+ --target install
+
+ - name: Test
+ run: >
+ cmake
+ --build ${{ steps.strings.outputs.build-output-dir }}
+ --parallel
+ --target check-libc
diff --git a/.github/workflows/libc-overlay-tests.yml b/.github/workflows/libc-overlay-tests.yml
new file mode 100644
index 0000000000000..8b59d76aed4a8
--- /dev/null
+++ b/.github/workflows/libc-overlay-tests.yml
@@ -0,0 +1,106 @@
+# This workflow is for pre-commit testing of the LLVM-libc project.
+name: LLVM-libc Pre-commit Overlay Tests
+permissions:
+ contents: read
+on:
+ pull_request:
+ branches: [ "main" ]
+ paths:
+ - 'libc/**'
+ - '.github/workflows/libc-overlay-tests.yml'
+
+jobs:
+ build:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations.
+ fail-fast: false
+ matrix:
+ include:
+ # TODO: add linux gcc when it is fixed
+ - os: ubuntu-24.04
+ compiler:
+ c_compiler: clang
+ cpp_compiler: clang++
+ - os: windows-2022
+ compiler:
+ c_compiler: clang-cl
+ cpp_compiler: clang-cl
+ - os: macos-14
+ compiler:
+ c_compiler: clang
+ cpp_compiler: clang++
+
+ steps:
+ - uses: actions/checkout@v4
+
+ # Libc's build is relatively small comparing with other components of LLVM.
+ # A fresh linux overlay takes about 180MiB of uncompressed disk space, which can
+ # be compressed into ~40MiB. MacOS and Windows overlay builds are less than 10MiB
+ # after compression. Limiting the cache size to 1G should be enough.
+ # Prefer sccache as it is modern and it has a guarantee to work with MSVC.
+ # Do not use direct GHAC access even though it is supported by sccache. GHAC rejects
+ # frequent small object writes.
+ - name: Setup ccache
+ uses: hendrikmuhs/ccache-action@v1
+ with:
+ max-size: 1G
+ key: libc_overlay_build_${{ matrix.os }}_${{ matrix.compiler.c_compiler }}
+ variant: sccache
+
+ # MPFR is required by some of the mathlib tests.
+ - name: Prepare dependencies (Ubuntu)
+ if: runner.os == 'Linux'
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y libmpfr-dev libgmp-dev libmpc-dev ninja-build
+
+ # Chocolatey is shipped with Windows runners. Windows Server 2025 recommends WinGet.
+ # Consider migrating to WinGet when Windows Server 2025 is available.
+ - name: Prepare dependencies (Windows)
+ if: runner.os == 'Windows'
+ run: |
+ choco install ninja
+
+ - name: Prepare dependencies (macOS)
+ if: runner.os == 'macOS'
+ run: |
+ brew install ninja
+
+ - name: Set reusable strings
+ id: strings
+ shell: bash
+ run: |
+ echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
+
+ # Use MinSizeRel to reduce the size of the build.
+ # Notice that CMP0141=NEW and MSVC_DEBUG_INFORMATION_FORMAT=Embedded are required
+ # by the sccache tool.
+ - name: Configure CMake
+ run: >
+ cmake -B ${{ steps.strings.outputs.build-output-dir }}
+ -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cpp_compiler }}
+ -DCMAKE_C_COMPILER=${{ matrix.compiler.c_compiler }}
+ -DCMAKE_BUILD_TYPE=MinSizeRel
+ -DCMAKE_C_COMPILER_LAUNCHER=sccache
+ -DCMAKE_CXX_COMPILER_LAUNCHER=sccache
+ -DCMAKE_POLICY_DEFAULT_CMP0141=NEW
+ -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded
+ -DLLVM_ENABLE_RUNTIMES=libc
+ -G Ninja
+ -S ${{ github.workspace }}/runtimes
+
+ - name: Build
+ run: >
+ cmake
+ --build ${{ steps.strings.outputs.build-output-dir }}
+ --parallel
+ --config MinSizeRel
+ --target libc
+
+ - name: Test
+ run: >
+ cmake
+ --build ${{ steps.strings.outputs.build-output-dir }}
+ --parallel
+ --target check-libc
diff --git a/.github/workflows/libcxx-restart-preempted-jobs.yaml b/.github/workflows/libcxx-restart-preempted-jobs.yaml
index cb454974f7287..82d84c01c92af 100644
--- a/.github/workflows/libcxx-restart-preempted-jobs.yaml
+++ b/.github/workflows/libcxx-restart-preempted-jobs.yaml
@@ -133,19 +133,19 @@ jobs:
restart-test:
if: github.repository_owner == 'llvm' && (github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'cancelled') && github.event.actor.login == 'ldionne' # TESTING ONLY
- name: "Restart Job"
+ name: "Restart Job (test)"
permissions:
statuses: read
checks: write
actions: write
runs-on: ubuntu-latest
steps:
- - name: "Restart Job"
+ - name: "Restart Job (test)"
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1
with:
script: |
const FAILURE_REGEX = /Process completed with exit code 1./
- const PREEMPTION_REGEX = /The runner has received a shutdown signal|The operation was canceled/
+ const PREEMPTION_REGEX = /(The runner has received a shutdown signal)|(The operation was canceled)/
function log(msg) {
core.notice(msg)
diff --git a/.github/workflows/premerge.yaml b/.github/workflows/premerge.yaml
new file mode 100644
index 0000000000000..d002e65047015
--- /dev/null
+++ b/.github/workflows/premerge.yaml
@@ -0,0 +1,69 @@
+name: LLVM Premerge Checks
+
+permissions:
+ contents: read
+
+on:
+ pull_request:
+ paths:
+ - .github/workflows/premerge.yaml
+ push:
+ branches:
+ - 'main'
+
+jobs:
+ premerge-checks-linux:
+ if: github.repository_owner == 'llvm'
+ runs-on: llvm-premerge-linux-runners
+ concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.push.head }}
+ cancel-in-progress: true
+ container:
+ image: ghcr.io/llvm/ci-ubuntu-22.04:latest
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout LLVM
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 2
+ - name: Setup ccache
+ uses: hendrikmuhs/ccache-action@v1.2.14
+ - name: Build and Test
+ run: |
+ git config --global --add safe.directory '*'
+
+ modified_files=$(git diff --name-only HEAD~1...HEAD)
+ modified_dirs=$(echo "$modified_files" | cut -d'/' -f1 | sort -u)
+
+ echo $modified_files
+ echo $modified_dirs
+
+ . ./.ci/compute-projects.sh
+
+ all_projects="bolt clang clang-tools-extra compiler-rt cross-project-tests flang libc libclc lld lldb llvm mlir openmp polly pstl"
+ modified_projects="$(keep-modified-projects ${all_projects})"
+
+ linux_projects_to_test=$(exclude-linux $(compute-projects-to-test 0 ${modified_projects}))
+ linux_check_targets=$(check-targets ${linux_projects_to_test} | sort | uniq)
+ linux_projects=$(add-dependencies ${linux_projects_to_test} | sort | uniq)
+
+ linux_runtimes_to_test=$(compute-runtimes-to-test ${linux_projects_to_test})
+ linux_runtime_check_targets=$(check-targets ${linux_runtimes_to_test} | sort | uniq)
+ linux_runtimes=$(echo ${linux_runtimes_to_test} | sort | uniq)
+
+ if [[ "${linux_projects}" == "" ]]; then
+ echo "No projects to build"
+ exit 0
+ fi
+
+ echo "Building projects: ${linux_projects}"
+ echo "Running project checks targets: ${linux_check_targets}"
+ echo "Building runtimes: ${linux_runtimes}"
+ echo "Running runtimes checks targets: ${linux_runtime_check_targets}"
+
+ export CC=/opt/llvm/bin/clang
+ export CXX=/opt/llvm/bin/clang++
+
+ ./.ci/monolithic-linux.sh "$(echo ${linux_projects} | tr ' ' ';')" "$(echo ${linux_check_targets})" "$(echo ${linux_runtimes} | tr ' ' ';')" "$(echo ${linux_runtime_check_targets})"
diff --git a/.gitignore b/.gitignore
index 0e7c6c7900133..a84268a7f6863 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,6 +59,8 @@ autoconf/autom4te.cache
# VS2017 and VSCode config files.
.vscode
.vs
+#zed config files
+.zed
# pythonenv for github Codespaces
pythonenv*
# clangd index. (".clangd" is a config file now, thus trailing slash)
diff --git a/bolt/docs/BinaryAnalysis.md b/bolt/docs/BinaryAnalysis.md
new file mode 100644
index 0000000000000..f91b77d046de8
--- /dev/null
+++ b/bolt/docs/BinaryAnalysis.md
@@ -0,0 +1,20 @@
+# BOLT-based binary analysis
+
+As part of post-link-time optimizing, BOLT needs to perform a range of analyses
+on binaries such as recontructing control flow graphs, and more.
+
+The `llvm-bolt-binary-analysis` tool enables running requested binary analyses
+on binaries, and generating reports. It does this by building on top of the
+analyses implemented in the BOLT libraries.
+
+## Which binary analyses are implemented?
+
+At the moment, no binary analyses are implemented.
+
+The goal is to make it easy using a plug-in framework to add your own analyses.
+
+## How to add your own binary analysis
+
+_TODO: this section needs to be written. Ideally, we should have a simple
+"example" or "template" analysis that can be the starting point for implementing
+custom analyses_
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index c9b0e103ed514..115e59ca0697e 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -28,6 +28,7 @@
#include "llvm/ADT/iterator.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
@@ -276,11 +277,10 @@ class BinaryContext {
void deregisterSectionName(const BinarySection &Section);
public:
- static Expected>
- createBinaryContext(Triple TheTriple, StringRef InputFileName,
- SubtargetFeatures *Features, bool IsPIC,
- std::unique_ptr DwCtx,
- JournalingStreams Logger);
+ static Expected> createBinaryContext(
+ Triple TheTriple, std::shared_ptr SSP,
+ StringRef InputFileName, SubtargetFeatures *Features, bool IsPIC,
+ std::unique_ptr DwCtx, JournalingStreams Logger);
/// Superset of compiler units that will contain overwritten code that needs
/// new debug info. In a few cases, functions may end up not being
@@ -372,6 +372,7 @@ class BinaryContext {
bool hasSymbolsWithFileName() const { return HasSymbolsWithFileName; }
void setHasSymbolsWithFileName(bool Value) { HasSymbolsWithFileName = Value; }
+ std::shared_ptr getSymbolStringPool() { return SSP; }
/// Return true if relocations against symbol with a given name
/// must be created.
bool forceSymbolRelocations(StringRef SymbolName) const;
@@ -631,6 +632,8 @@ class BinaryContext {
std::unique_ptr TheTriple;
+ std::shared_ptr SSP;
+
const Target *TheTarget;
std::string TripleName;
@@ -807,8 +810,10 @@ class BinaryContext {
BinaryContext(std::unique_ptr Ctx,
std::unique_ptr DwCtx,
- std::unique_ptr TheTriple, const Target *TheTarget,
- std::string TripleName, std::unique_ptr MCE,
+ std::unique_ptr TheTriple,
+ std::shared_ptr SSP,
+ const Target *TheTarget, std::string TripleName,
+ std::unique_ptr MCE,
std::unique_ptr MOFI,
std::unique_ptr AsmInfo,
std::unique_ptr MII,
diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h
index d1acba0f26c78..bd22c536c56fc 100644
--- a/bolt/include/bolt/Core/DIEBuilder.h
+++ b/bolt/include/bolt/Core/DIEBuilder.h
@@ -162,7 +162,7 @@ class DIEBuilder {
/// Clone an attribute in reference format.
void cloneDieOffsetReferenceAttribute(
- DIE &Die, const DWARFUnit &U, const DWARFDie &InputDIE,
+ DIE &Die, DWARFUnit &U, const DWARFDie &InputDIE,
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, uint64_t Ref);
/// Clone an attribute in block format.
diff --git a/bolt/include/bolt/Core/DebugNames.h b/bolt/include/bolt/Core/DebugNames.h
index 0e61a0e4f9d9f..cc4e13a481b2d 100644
--- a/bolt/include/bolt/Core/DebugNames.h
+++ b/bolt/include/bolt/Core/DebugNames.h
@@ -72,8 +72,8 @@ class DWARF5AcceleratorTable {
return std::move(FullTableBuffer);
}
/// Adds a DIE that is referenced across CUs.
- void addCrossCUDie(const DIE *Die) {
- CrossCUDies.insert({Die->getOffset(), Die});
+ void addCrossCUDie(DWARFUnit *Unit, const DIE *Die) {
+ CrossCUDies.insert({Die->getOffset(), {Unit, Die}});
}
/// Returns true if the DIE can generate an entry for a cross cu reference.
/// This only checks TAGs of a DIE because when this is invoked DIE might not
@@ -145,7 +145,7 @@ class DWARF5AcceleratorTable {
llvm::DenseMap CUOffsetsToPatch;
// Contains a map of Entry ID to Entry relative offset.
llvm::DenseMap EntryRelativeOffsets;
- llvm::DenseMap CrossCUDies;
+ llvm::DenseMap> CrossCUDies;
/// Adds Unit to either CUList, LocalTUList or ForeignTUList.
/// Input Unit being processed, and DWO ID if Unit is being processed comes
/// from a DWO section.
@@ -191,6 +191,29 @@ class DWARF5AcceleratorTable {
void emitData();
/// Emit augmentation string.
void emitAugmentationString() const;
+ /// Creates a new entry for a given DIE.
+ std::optional
+ addEntry(DWARFUnit &DU, const DIE &CurrDie,
+ const std::optional &DWOID,
+ const std::optional &Parent,
+ const std::optional &Name,
+ const uint32_t NumberParentsInChain);
+ /// Returns UnitID for a given DWARFUnit.
+ uint32_t getUnitID(const DWARFUnit &Unit,
+ const std::optional &DWOID, bool &IsTU);
+ std::optional getName(DWARFUnit &DU,
+ const std::optional &DWOID,
+ const std::string &NameToUse,
+ DIEValue ValName);
+ /// Processes a DIE with references to other DIEs for DW_AT_name and
+ /// DW_AT_linkage_name resolution.
+ /// If DW_AT_name exists method creates a new entry for this DIE and returns
+ /// it.
+ std::optional processReferencedDie(
+ DWARFUnit &Unit, const DIE &Die, const std::optional &DWOID,
+ const std::optional &Parent,
+ const std::string &NameToUse, const uint32_t NumberParentsInChain,
+ const dwarf::Attribute &Attr);
};
} // namespace bolt
} // namespace llvm
diff --git a/bolt/include/bolt/Passes/ADRRelaxationPass.h b/bolt/include/bolt/Passes/ADRRelaxationPass.h
index 1d35a335c0250..b9f92dec7f03b 100644
--- a/bolt/include/bolt/Passes/ADRRelaxationPass.h
+++ b/bolt/include/bolt/Passes/ADRRelaxationPass.h
@@ -25,7 +25,8 @@ namespace bolt {
class ADRRelaxationPass : public BinaryFunctionPass {
public:
- explicit ADRRelaxationPass() : BinaryFunctionPass(false) {}
+ explicit ADRRelaxationPass(const cl::opt &PrintPass)
+ : BinaryFunctionPass(PrintPass) {}
const char *getName() const override { return "adr-relaxation"; }
diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 73d2857f946cc..42094cb732107 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -164,6 +164,9 @@ class RewriteInstance {
void preregisterSections();
+ /// run analyses requested in binary analysis mode.
+ void runBinaryAnalyses();
+
/// Run optimizations that operate at the binary, or post-linker, level.
void runOptimizationPasses();
diff --git a/bolt/include/bolt/Utils/CommandLineOpts.h b/bolt/include/bolt/Utils/CommandLineOpts.h
index 04bf7db5de952..111eb650c3746 100644
--- a/bolt/include/bolt/Utils/CommandLineOpts.h
+++ b/bolt/include/bolt/Utils/CommandLineOpts.h
@@ -18,6 +18,7 @@
namespace opts {
extern bool HeatmapMode;
+extern bool BinaryAnalysisMode;
extern llvm::cl::OptionCategory BoltCategory;
extern llvm::cl::OptionCategory BoltDiffCategory;
@@ -27,6 +28,7 @@ extern llvm::cl::OptionCategory BoltOutputCategory;
extern llvm::cl::OptionCategory AggregatorCategory;
extern llvm::cl::OptionCategory BoltInstrCategory;
extern llvm::cl::OptionCategory HeatmapCategory;
+extern llvm::cl::OptionCategory BinaryAnalysisCategory;
extern llvm::cl::opt AlignText;
extern llvm::cl::opt AlignFunctions;
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index a808ece12da19..ac96b836ed579 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -123,6 +123,7 @@ void BinaryContext::logBOLTErrorsAndQuitOnFatal(Error E) {
BinaryContext::BinaryContext(std::unique_ptr Ctx,
std::unique_ptr DwCtx,
std::unique_ptr TheTriple,
+ std::shared_ptr SSP,
const Target *TheTarget, std::string TripleName,
std::unique_ptr MCE,
std::unique_ptr MOFI,
@@ -136,12 +137,12 @@ BinaryContext::BinaryContext(std::unique_ptr Ctx,
std::unique_ptr DisAsm,
JournalingStreams Logger)
: Ctx(std::move(Ctx)), DwCtx(std::move(DwCtx)),
- TheTriple(std::move(TheTriple)), TheTarget(TheTarget),
- TripleName(TripleName), MCE(std::move(MCE)), MOFI(std::move(MOFI)),
- AsmInfo(std::move(AsmInfo)), MII(std::move(MII)), STI(std::move(STI)),
- InstPrinter(std::move(InstPrinter)), MIA(std::move(MIA)),
- MIB(std::move(MIB)), MRI(std::move(MRI)), DisAsm(std::move(DisAsm)),
- Logger(Logger), InitialDynoStats(isAArch64()) {
+ TheTriple(std::move(TheTriple)), SSP(std::move(SSP)),
+ TheTarget(TheTarget), TripleName(TripleName), MCE(std::move(MCE)),
+ MOFI(std::move(MOFI)), AsmInfo(std::move(AsmInfo)), MII(std::move(MII)),
+ STI(std::move(STI)), InstPrinter(std::move(InstPrinter)),
+ MIA(std::move(MIA)), MIB(std::move(MIB)), MRI(std::move(MRI)),
+ DisAsm(std::move(DisAsm)), Logger(Logger), InitialDynoStats(isAArch64()) {
RegularPageSize = isAArch64() ? RegularPageSizeAArch64 : RegularPageSizeX86;
PageAlign = opts::NoHugePages ? RegularPageSize : HugePageSize;
}
@@ -159,8 +160,9 @@ BinaryContext::~BinaryContext() {
/// Create BinaryContext for a given architecture \p ArchName and
/// triple \p TripleName.
Expected> BinaryContext::createBinaryContext(
- Triple TheTriple, StringRef InputFileName, SubtargetFeatures *Features,
- bool IsPIC, std::unique_ptr DwCtx, JournalingStreams Logger) {
+ Triple TheTriple, std::shared_ptr SSP,
+ StringRef InputFileName, SubtargetFeatures *Features, bool IsPIC,
+ std::unique_ptr DwCtx, JournalingStreams Logger) {
StringRef ArchName = "";
std::string FeaturesStr = "";
switch (TheTriple.getArch()) {
@@ -283,8 +285,8 @@ Expected> BinaryContext::createBinaryContext(
auto BC = std::make_unique(
std::move(Ctx), std::move(DwCtx), std::make_unique(TheTriple),
- TheTarget, std::string(TripleName), std::move(MCE), std::move(MOFI),
- std::move(AsmInfo), std::move(MII), std::move(STI),
+ std::move(SSP), TheTarget, std::string(TripleName), std::move(MCE),
+ std::move(MOFI), std::move(AsmInfo), std::move(MII), std::move(STI),
std::move(InstructionPrinter), std::move(MIA), nullptr, std::move(MRI),
std::move(DisAsm), Logger);
diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp
index f34a94c577921..5019cf31beee3 100644
--- a/bolt/lib/Core/BinaryEmitter.cpp
+++ b/bolt/lib/Core/BinaryEmitter.cpp
@@ -46,13 +46,17 @@ BreakFunctionNames("break-funcs",
cl::Hidden,
cl::cat(BoltCategory));
-static cl::list
-FunctionPadSpec("pad-funcs",
- cl::CommaSeparated,
- cl::desc("list of functions to pad with amount of bytes"),
- cl::value_desc("func1:pad1,func2:pad2,func3:pad3,..."),
- cl::Hidden,
- cl::cat(BoltCategory));
+cl::list
+ FunctionPadSpec("pad-funcs", cl::CommaSeparated,
+ cl::desc("list of functions to pad with amount of bytes"),
+ cl::value_desc("func1:pad1,func2:pad2,func3:pad3,..."),
+ cl::Hidden, cl::cat(BoltCategory));
+
+cl::list FunctionPadBeforeSpec(
+ "pad-funcs-before", cl::CommaSeparated,
+ cl::desc("list of functions to pad with amount of bytes"),
+ cl::value_desc("func1:pad1,func2:pad2,func3:pad3,..."), cl::Hidden,
+ cl::cat(BoltCategory));
static cl::opt MarkFuncs(
"mark-funcs",
@@ -70,11 +74,12 @@ X86AlignBranchBoundaryHotOnly("x86-align-branch-boundary-hot-only",
cl::init(true),
cl::cat(BoltOptCategory));
-size_t padFunction(const BinaryFunction &Function) {
+size_t padFunction(const cl::list &Spec,
+ const BinaryFunction &Function) {
static std::map FunctionPadding;
- if (FunctionPadding.empty() && !FunctionPadSpec.empty()) {
- for (std::string &Spec : FunctionPadSpec) {
+ if (FunctionPadding.empty() && !Spec.empty()) {
+ for (const std::string &Spec : Spec) {
size_t N = Spec.find(':');
if (N == std::string::npos)
continue;
@@ -319,6 +324,32 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
Streamer.emitCodeAlignment(Function.getAlign(), &*BC.STI);
}
+ if (size_t Padding =
+ opts::padFunction(opts::FunctionPadBeforeSpec, Function)) {
+ // Handle padFuncsBefore after the above alignment logic but before
+ // symbol addresses are decided.
+ if (!BC.HasRelocations) {
+ BC.errs() << "BOLT-ERROR: -pad-before-funcs is not supported in "
+ << "non-relocation mode\n";
+ exit(1);
+ }
+
+ // Preserve Function.getMinAlign().
+ if (!isAligned(Function.getMinAlign(), Padding)) {
+ BC.errs() << "BOLT-ERROR: user-requested " << Padding
+ << " padding bytes before function " << Function
+ << " is not a multiple of the minimum function alignment ("
+ << Function.getMinAlign().value() << ").\n";
+ exit(1);
+ }
+
+ LLVM_DEBUG(dbgs() << "BOLT-DEBUG: padding before function " << Function
+ << " with " << Padding << " bytes\n");
+
+ // Since the padding is not executed, it can be null bytes.
+ Streamer.emitFill(Padding, 0);
+ }
+
MCContext &Context = Streamer.getContext();
const MCAsmInfo *MAI = Context.getAsmInfo();
@@ -373,7 +404,7 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
emitFunctionBody(Function, FF, /*EmitCodeOnly=*/false);
// Emit padding if requested.
- if (size_t Padding = opts::padFunction(Function)) {
+ if (size_t Padding = opts::padFunction(opts::FunctionPadSpec, Function)) {
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: padding function " << Function << " with "
<< Padding << " bytes\n");
Streamer.emitFill(Padding, MAI->getTextAlignFillValue());
@@ -730,30 +761,16 @@ void BinaryEmitter::emitJumpTables(const BinaryFunction &BF) {
continue;
if (opts::PrintJumpTables)
JT.print(BC.outs());
- if (opts::JumpTables == JTS_BASIC && BC.HasRelocations) {
+ if (opts::JumpTables == JTS_BASIC) {
JT.updateOriginal();
} else {
MCSection *HotSection, *ColdSection;
- if (opts::JumpTables == JTS_BASIC) {
- // In non-relocation mode we have to emit jump tables in local sections.
- // This way we only overwrite them when the corresponding function is
- // overwritten.
- std::string Name = ".local." + JT.Labels[0]->getName().str();
- std::replace(Name.begin(), Name.end(), '/', '.');
- BinarySection &Section =
- BC.registerOrUpdateSection(Name, ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
- Section.setAnonymous(true);
- JT.setOutputSection(Section);
- HotSection = BC.getDataSection(Name);
- ColdSection = HotSection;
+ if (BF.isSimple()) {
+ HotSection = ReadOnlySection;
+ ColdSection = ReadOnlyColdSection;
} else {
- if (BF.isSimple()) {
- HotSection = ReadOnlySection;
- ColdSection = ReadOnlyColdSection;
- } else {
- HotSection = BF.hasProfile() ? ReadOnlySection : ReadOnlyColdSection;
- ColdSection = HotSection;
- }
+ HotSection = BF.hasProfile() ? ReadOnlySection : ReadOnlyColdSection;
+ ColdSection = HotSection;
}
emitJumpTable(JT, HotSection, ColdSection);
}
diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp
index 414912ea1c207..80ad583e079d4 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -622,7 +622,7 @@ DWARFDie DIEBuilder::resolveDIEReference(
}
void DIEBuilder::cloneDieOffsetReferenceAttribute(
- DIE &Die, const DWARFUnit &U, const DWARFDie &InputDIE,
+ DIE &Die, DWARFUnit &U, const DWARFDie &InputDIE,
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, uint64_t Ref) {
DIE *NewRefDie = nullptr;
DWARFUnit *RefUnit = nullptr;
@@ -654,7 +654,7 @@ void DIEBuilder::cloneDieOffsetReferenceAttribute(
// Adding referenced DIE to DebugNames to be used when entries are created
// that contain cross cu references.
if (DebugNamesTable.canGenerateEntryWithCrossCUReference(U, Die, AttrSpec))
- DebugNamesTable.addCrossCUDie(DieInfo.Die);
+ DebugNamesTable.addCrossCUDie(&U, DieInfo.Die);
// no matter forward reference or backward reference, we are supposed
// to calculate them in `finish` due to the possible modification of
// the DIE.
diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp
index 640b29ec36d5c..366c22c38e616 100644
--- a/bolt/lib/Core/DebugNames.cpp
+++ b/bolt/lib/Core/DebugNames.cpp
@@ -143,7 +143,8 @@ static bool shouldIncludeVariable(const DWARFUnit &Unit, const DIE &Die) {
Unit.getFormParams().Format);
for (const DWARFExpression::Operation &Expr : LocExpr)
if (Expr.getCode() == dwarf::DW_OP_addrx ||
- Expr.getCode() == dwarf::DW_OP_form_tls_address)
+ Expr.getCode() == dwarf::DW_OP_form_tls_address ||
+ Expr.getCode() == dwarf::DW_OP_GNU_push_tls_address)
return true;
return false;
}
@@ -161,6 +162,7 @@ bool static canProcess(const DWARFUnit &Unit, const DIE &Die,
case dwarf::DW_TAG_structure_type:
case dwarf::DW_TAG_typedef:
case dwarf::DW_TAG_unspecified_type:
+ case dwarf::DW_TAG_union_type:
if (TagsOnly || Die.findAttribute(dwarf::Attribute::DW_AT_name))
return true;
return false;
@@ -221,134 +223,113 @@ static uint64_t getEntryID(const BOLTDWARF5AccelTableData &Entry) {
return reinterpret_cast(&Entry);
}
-std::optional
-DWARF5AcceleratorTable::addAccelTableEntry(
- DWARFUnit &Unit, const DIE &Die, const std::optional &DWOID,
- const uint32_t NumberParentsInChain,
- std::optional &Parent) {
- if (Unit.getVersion() < 5 || !NeedToCreate)
- return std::nullopt;
- std::string NameToUse = "";
-
- auto getUnitID = [&](const DWARFUnit &Unit, bool &IsTU,
- uint32_t &DieTag) -> uint32_t {
- IsTU = Unit.isTypeUnit();
- DieTag = Die.getTag();
- if (IsTU) {
- if (DWOID) {
- const uint64_t TUHash = cast(&Unit)->getTypeHash();
- auto Iter = TUHashToIndexMap.find(TUHash);
- assert(Iter != TUHashToIndexMap.end() &&
- "Could not find TU hash in map");
- return Iter->second;
- }
- return LocalTUList.size() - 1;
+uint32_t DWARF5AcceleratorTable::getUnitID(const DWARFUnit &Unit,
+ const std::optional &DWOID,
+ bool &IsTU) {
+ IsTU = Unit.isTypeUnit();
+ if (IsTU) {
+ if (DWOID) {
+ const uint64_t TUHash = cast(&Unit)->getTypeHash();
+ auto Iter = TUHashToIndexMap.find(TUHash);
+ assert(Iter != TUHashToIndexMap.end() && "Could not find TU hash in map");
+ return Iter->second;
}
- return CUList.size() - 1;
- };
+ return LocalTUList.size() - 1;
+ }
+ return CUList.size() - 1;
+}
- if (!canProcess(Unit, Die, NameToUse, false))
+std::optional DWARF5AcceleratorTable::getName(
+ DWARFUnit &Unit, const std::optional &DWOID,
+ const std::string &NameToUse, DIEValue ValName) {
+ if ((!ValName || ValName.getForm() == dwarf::DW_FORM_string) &&
+ NameToUse.empty())
return std::nullopt;
-
- // Addes a Unit to either CU, LocalTU or ForeignTU list the first time we
- // encounter it.
- // Invoking it here so that we don't add Units that don't have any entries.
- if (&Unit != CurrentUnit) {
- CurrentUnit = &Unit;
- addUnit(Unit, DWOID);
+ std::string Name = "";
+ uint64_t NameIndexOffset = 0;
+ if (NameToUse.empty()) {
+ NameIndexOffset = ValName.getDIEInteger().getValue();
+ if (ValName.getForm() != dwarf::DW_FORM_strp)
+ NameIndexOffset = getNameOffset(BC, Unit, NameIndexOffset);
+ // Counts on strings end with '\0'.
+ Name = std::string(&StrSection.data()[NameIndexOffset]);
+ } else {
+ Name = NameToUse;
}
-
- auto getName = [&](DIEValue ValName) -> std::optional {
- if ((!ValName || ValName.getForm() == dwarf::DW_FORM_string) &&
- NameToUse.empty())
- return std::nullopt;
- std::string Name = "";
- uint64_t NameIndexOffset = 0;
- if (NameToUse.empty()) {
- NameIndexOffset = ValName.getDIEInteger().getValue();
- if (ValName.getForm() != dwarf::DW_FORM_strp)
- NameIndexOffset = getNameOffset(BC, Unit, NameIndexOffset);
- // Counts on strings end with '\0'.
- Name = std::string(&StrSection.data()[NameIndexOffset]);
- } else {
- Name = NameToUse;
- }
- auto &It = Entries[Name];
- if (It.Values.empty()) {
- if (DWOID && NameToUse.empty()) {
- // For DWO Unit the offset is in the .debug_str.dwo section.
- // Need to find offset for the name in the .debug_str section.
- llvm::hash_code Hash = llvm::hash_value(llvm::StringRef(Name));
- auto ItCache = StrCacheToOffsetMap.find(Hash);
- if (ItCache == StrCacheToOffsetMap.end())
- NameIndexOffset = MainBinaryStrWriter.addString(Name);
- else
- NameIndexOffset = ItCache->second;
- }
- if (!NameToUse.empty())
+ auto &It = Entries[Name];
+ if (It.Values.empty()) {
+ if (DWOID && NameToUse.empty()) {
+ // For DWO Unit the offset is in the .debug_str.dwo section.
+ // Need to find offset for the name in the .debug_str section.
+ llvm::hash_code Hash = llvm::hash_value(llvm::StringRef(Name));
+ auto ItCache = StrCacheToOffsetMap.find(Hash);
+ if (ItCache == StrCacheToOffsetMap.end())
NameIndexOffset = MainBinaryStrWriter.addString(Name);
- It.StrOffset = NameIndexOffset;
- // This the same hash function used in DWARF5AccelTableData.
- It.HashValue = caseFoldingDjbHash(Name);
+ else
+ NameIndexOffset = ItCache->second;
}
- return Name;
- };
+ if (!NameToUse.empty())
+ NameIndexOffset = MainBinaryStrWriter.addString(Name);
+ It.StrOffset = NameIndexOffset;
+ // This is the same hash function used in DWARF5AccelTableData.
+ It.HashValue = caseFoldingDjbHash(Name);
+ }
+ return Name;
+}
- auto addEntry =
- [&](DIEValue ValName) -> std::optional {
- std::optional Name = getName(ValName);
- if (!Name)
- return std::nullopt;
+std::optional DWARF5AcceleratorTable::addEntry(
+ DWARFUnit &DU, const DIE &CurrDie, const std::optional &DWOID,
+ const std::optional &Parent,
+ const std::optional &Name,
+ const uint32_t NumberParentsInChain) {
+ if (!Name)
+ return std::nullopt;
- auto &It = Entries[*Name];
- bool IsTU = false;
- uint32_t DieTag = 0;
- uint32_t UnitID = getUnitID(Unit, IsTU, DieTag);
- std::optional SecondIndex = std::nullopt;
- if (IsTU && DWOID) {
- auto Iter = CUOffsetsToPatch.find(*DWOID);
- if (Iter == CUOffsetsToPatch.end())
- BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
- "DWO ID in CU offsets for second Unit Index "
- << *Name << ". For DIE at offset: "
- << Twine::utohexstr(CurrentUnitOffset + Die.getOffset())
- << ".\n";
- SecondIndex = Iter->second;
- }
- std::optional ParentOffset =
- (Parent ? std::optional(getEntryID(**Parent)) : std::nullopt);
- // This will be populated later in writeEntry.
- // This way only parent entries get tracked.
- // Keeping memory footprint down.
- if (ParentOffset)
- EntryRelativeOffsets.insert({*ParentOffset, 0});
- bool IsParentRoot = false;
- // If there is no parent and no valid Entries in parent chain this is a root
- // to be marked with a flag.
- if (!Parent && !NumberParentsInChain)
- IsParentRoot = true;
- It.Values.push_back(new (Allocator) BOLTDWARF5AccelTableData(
- Die.getOffset(), ParentOffset, DieTag, UnitID, IsParentRoot, IsTU,
- SecondIndex));
- return It.Values.back();
- };
+ auto &It = Entries[*Name];
+ bool IsTU = false;
+ uint32_t DieTag = CurrDie.getTag();
+ uint32_t UnitID = getUnitID(DU, DWOID, IsTU);
+ std::optional SecondIndex = std::nullopt;
+ if (IsTU && DWOID) {
+ auto Iter = CUOffsetsToPatch.find(*DWOID);
+ if (Iter == CUOffsetsToPatch.end())
+ BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
+ "DWO ID in CU offsets for second Unit Index "
+ << *Name << ". For DIE at offset: "
+ << Twine::utohexstr(CurrentUnitOffset + CurrDie.getOffset())
+ << ".\n";
+ SecondIndex = Iter->second;
+ }
+ std::optional ParentOffset =
+ (Parent ? std::optional(getEntryID(**Parent)) : std::nullopt);
+ // This will be only populated in writeEntry, in order to keep only the parent
+ // entries, and keep the footprint down.
+ if (ParentOffset)
+ EntryRelativeOffsets.insert({*ParentOffset, 0});
+ bool IsParentRoot = false;
+ // If there is no parent and no valid Entries in parent chain this is a root
+ // to be marked with a flag.
+ if (!Parent && !NumberParentsInChain)
+ IsParentRoot = true;
+ It.Values.push_back(new (Allocator) BOLTDWARF5AccelTableData(
+ CurrDie.getOffset(), ParentOffset, DieTag, UnitID, IsParentRoot, IsTU,
+ SecondIndex));
+ return It.Values.back();
+}
- // Minor optimization not to add entry twice for DW_TAG_namespace if it has no
- // DW_AT_name.
- if (!(Die.getTag() == dwarf::DW_TAG_namespace &&
- !Die.findAttribute(dwarf::Attribute::DW_AT_name)))
- addEntry(Die.findAttribute(dwarf::Attribute::DW_AT_linkage_name));
- // For the purposes of determining whether a debugging information entry has a
- // particular attribute (such as DW_AT_name), if debugging information entry A
- // has a DW_AT_specification or DW_AT_abstract_origin attribute pointing to
- // another debugging information entry B, any attributes of B are considered
- // to be part of A.
- auto processReferencedDie = [&](const dwarf::Attribute &Attr)
- -> std::optional {
- const DIEValue Value = Die.findAttribute(Attr);
+std::optional
+DWARF5AcceleratorTable::processReferencedDie(
+ DWARFUnit &Unit, const DIE &Die, const std::optional &DWOID,
+ const std::optional &Parent,
+ const std::string &NameToUse, const uint32_t NumberParentsInChain,
+ const dwarf::Attribute &Attr) {
+ DIEValue Value = Die.findAttribute(Attr);
+ if (!Value)
+ return std::nullopt;
+ auto getReferenceDie = [&](const DIEValue &Value, const DIE *RefDieUsed)
+ -> std::optional> {
if (!Value)
return std::nullopt;
- const DIE *EntryDie = nullptr;
if (Value.getForm() == dwarf::DW_FORM_ref_addr) {
auto Iter = CrossCUDies.find(Value.getDIEInteger().getValue());
if (Iter == CrossCUDies.end()) {
@@ -358,24 +339,97 @@ DWARF5AcceleratorTable::addAccelTableEntry(
<< ".\n";
return std::nullopt;
}
- EntryDie = Iter->second;
- } else {
- const DIEEntry &DIEENtry = Value.getDIEEntry();
- EntryDie = &DIEENtry.getEntry();
+ return Iter->second;
}
-
- addEntry(EntryDie->findAttribute(dwarf::Attribute::DW_AT_linkage_name));
- return addEntry(EntryDie->findAttribute(dwarf::Attribute::DW_AT_name));
+ const DIEEntry &DIEENtry = Value.getDIEEntry();
+ return {{&Unit, &DIEENtry.getEntry()}};
};
- if (std::optional Entry =
- processReferencedDie(dwarf::Attribute::DW_AT_abstract_origin))
+ DIEValue AttrValLinkageName;
+ DIEValue AttrValName = Die.findAttribute(dwarf::Attribute::DW_AT_name);
+ DWARFUnit *RefUnit = &Unit;
+ const DIE *RefDieUsed = &Die;
+ // It is possible to have DW_TAG_subprogram only with DW_AT_linkage_name that
+ // DW_AT_abstract_origin/DW_AT_specification point to.
+ while (!AttrValName) {
+ std::optional> RefDUDie =
+ getReferenceDie(Value, RefDieUsed);
+ if (!RefDUDie)
+ break;
+ RefUnit = RefDUDie->first;
+ const DIE &RefDie = *RefDUDie->second;
+ RefDieUsed = &RefDie;
+ if (!AttrValLinkageName)
+ AttrValLinkageName =
+ RefDie.findAttribute(dwarf::Attribute::DW_AT_linkage_name);
+ AttrValName = RefDie.findAttribute(dwarf::Attribute::DW_AT_name);
+ Value = RefDie.findAttribute(dwarf::Attribute::DW_AT_abstract_origin);
+ if (!Value)
+ Value = RefDie.findAttribute(dwarf::Attribute::DW_AT_specification);
+ }
+ addEntry(Unit, Die, DWOID, Parent,
+ getName(*RefUnit, DWOID, NameToUse, AttrValLinkageName),
+ NumberParentsInChain);
+ return addEntry(Unit, Die, DWOID, Parent,
+ getName(*RefUnit, DWOID, NameToUse, AttrValName),
+ NumberParentsInChain);
+}
+
+std::optional
+DWARF5AcceleratorTable::addAccelTableEntry(
+ DWARFUnit &Unit, const DIE &Die, const std::optional &DWOID,
+ const uint32_t NumberParentsInChain,
+ std::optional &Parent) {
+ if (Unit.getVersion() < 5 || !NeedToCreate)
+ return std::nullopt;
+ std::string NameToUse = "";
+
+ if (!canProcess(Unit, Die, NameToUse, false))
+ return std::nullopt;
+
+ // Adds a Unit to either CU, LocalTU or ForeignTU list the first time we
+ // encounter it.
+ // Invoking it here so that we don't add Units that don't have any entries.
+ if (&Unit != CurrentUnit) {
+ CurrentUnit = &Unit;
+ addUnit(Unit, DWOID);
+ }
+
+ // Minor optimization not to add entry twice for DW_TAG_namespace if it has no
+ // DW_AT_name.
+ std::optional LinkageEntry = std::nullopt;
+ DIEValue NameVal = Die.findAttribute(dwarf::Attribute::DW_AT_name);
+ DIEValue LinkageNameVal =
+ Die.findAttribute(dwarf::Attribute::DW_AT_linkage_name);
+ if (!(Die.getTag() == dwarf::DW_TAG_namespace && !NameVal))
+ LinkageEntry = addEntry(Unit, Die, DWOID, Parent,
+ getName(Unit, DWOID, NameToUse, LinkageNameVal),
+ NumberParentsInChain);
+
+ std::optional NameEntry =
+ addEntry(Unit, Die, DWOID, Parent,
+ getName(Unit, DWOID, NameToUse, NameVal), NumberParentsInChain);
+ if (NameEntry)
+ return NameEntry;
+
+ // The DIE doesn't have DW_AT_name or DW_AT_linkage_name, so we need to see if
+ // we can follow other attributes to find them. For the purposes of
+ // determining whether a debug information entry has a particular
+ // attribute (such as DW_AT_name), if debug information entry A has a
+ // DW_AT_specification or DW_AT_abstract_origin attribute pointing to another
+ // debug information entry B, any attributes of B are considered to be
+ // part of A.
+ if (std::optional Entry = processReferencedDie(
+ Unit, Die, DWOID, Parent, NameToUse, NumberParentsInChain,
+ dwarf::Attribute::DW_AT_abstract_origin))
return *Entry;
- if (std::optional Entry =
- processReferencedDie(dwarf::Attribute::DW_AT_specification))
+ if (std::optional Entry = processReferencedDie(
+ Unit, Die, DWOID, Parent, NameToUse, NumberParentsInChain,
+ dwarf::Attribute::DW_AT_specification))
return *Entry;
- return addEntry(Die.findAttribute(dwarf::Attribute::DW_AT_name));
+ // This point can be hit by DW_TAG_varialbe that has no DW_AT_name.
+ return std::nullopt;
}
/// Algorithm from llvm implementation.
diff --git a/bolt/lib/Passes/LongJmp.cpp b/bolt/lib/Passes/LongJmp.cpp
index c1b8c03324e0e..e6bd417705e6f 100644
--- a/bolt/lib/Passes/LongJmp.cpp
+++ b/bolt/lib/Passes/LongJmp.cpp
@@ -138,9 +138,9 @@ BinaryBasicBlock *LongJmpPass::lookupStubFromGroup(
const std::pair &RHS) {
return LHS.first < RHS.first;
});
- if (Cand == Candidates.end())
- return nullptr;
- if (Cand != Candidates.begin()) {
+ if (Cand == Candidates.end()) {
+ Cand = std::prev(Cand);
+ } else if (Cand != Candidates.begin()) {
const StubTy *LeftCand = std::prev(Cand);
if (Cand->first - DotAddress > DotAddress - LeftCand->first)
Cand = LeftCand;
diff --git a/bolt/lib/Passes/ReorderFunctions.cpp b/bolt/lib/Passes/ReorderFunctions.cpp
index 1256d71342b13..f8f6a01526dcc 100644
--- a/bolt/lib/Passes/ReorderFunctions.cpp
+++ b/bolt/lib/Passes/ReorderFunctions.cpp
@@ -28,7 +28,9 @@ extern cl::OptionCategory BoltOptCategory;
extern cl::opt Verbosity;
extern cl::opt RandomSeed;
-extern size_t padFunction(const bolt::BinaryFunction &Function);
+extern size_t padFunction(const cl::list &Spec,
+ const bolt::BinaryFunction &Function);
+extern cl::list FunctionPadSpec, FunctionPadBeforeSpec;
extern cl::opt ReorderFunctions;
cl::opt ReorderFunctions(
@@ -304,8 +306,12 @@ Error ReorderFunctions::runOnFunctions(BinaryContext &BC) {
return false;
if (B->isIgnored())
return true;
- const size_t PadA = opts::padFunction(*A);
- const size_t PadB = opts::padFunction(*B);
+ const size_t PadA =
+ opts::padFunction(opts::FunctionPadSpec, *A) +
+ opts::padFunction(opts::FunctionPadBeforeSpec, *A);
+ const size_t PadB =
+ opts::padFunction(opts::FunctionPadSpec, *B) +
+ opts::padFunction(opts::FunctionPadBeforeSpec, *B);
if (!PadA || !PadB) {
if (PadA)
return true;
diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp
index b090604183348..6f074d5d1191f 100644
--- a/bolt/lib/Rewrite/BinaryPassManager.cpp
+++ b/bolt/lib/Rewrite/BinaryPassManager.cpp
@@ -126,6 +126,11 @@ static cl::opt PrintJTFootprintReduction(
cl::desc("print function after jt-footprint-reduction pass"), cl::Hidden,
cl::cat(BoltOptCategory));
+static cl::opt
+ PrintAdrRelaxation("print-adr-relaxation",
+ cl::desc("print functions after ADR Relaxation pass"),
+ cl::Hidden, cl::cat(BoltOptCategory));
+
static cl::opt
PrintLongJmp("print-longjmp",
cl::desc("print functions after longjmp pass"), cl::Hidden,
@@ -493,7 +498,8 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
Manager.registerPass(std::make_unique());
if (BC.isAArch64()) {
- Manager.registerPass(std::make_unique());
+ Manager.registerPass(
+ std::make_unique(PrintAdrRelaxation));
// Tighten branches according to offset differences between branch and
// targets. No extra instructions after this pass, otherwise we may have
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 1b5ba8b49d363..308881081321a 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -1691,7 +1691,8 @@ namespace {
std::unique_ptr
createDwarfOnlyBC(const object::ObjectFile &File) {
return cantFail(BinaryContext::createBinaryContext(
- File.makeTriple(), File.getFileName(), nullptr, false,
+ File.makeTriple(), std::make_shared(),
+ File.getFileName(), nullptr, false,
DWARFContext::create(File, DWARFContext::ProcessDebugRelocations::Ignore,
nullptr, "", WithColor::defaultErrorHandler,
WithColor::defaultWarningHandler),
diff --git a/bolt/lib/Rewrite/JITLinkLinker.cpp b/bolt/lib/Rewrite/JITLinkLinker.cpp
index be8f9dd03467e..ba483ae4711df 100644
--- a/bolt/lib/Rewrite/JITLinkLinker.cpp
+++ b/bolt/lib/Rewrite/JITLinkLinker.cpp
@@ -122,7 +122,7 @@ struct JITLinkLinker::Context : jitlink::JITLinkContext {
jitlink::AsyncLookupResult AllResults;
for (const auto &Symbol : Symbols) {
- std::string SymName = Symbol.first.str();
+ std::string SymName = (*Symbol.first).str();
LLVM_DEBUG(dbgs() << "BOLT: looking for " << SymName << "\n");
if (auto Address = Linker.lookupSymbol(SymName)) {
@@ -167,7 +167,9 @@ struct JITLinkLinker::Context : jitlink::JITLinkContext {
Error notifyResolved(jitlink::LinkGraph &G) override {
for (auto *Symbol : G.defined_symbols()) {
SymbolInfo Info{Symbol->getAddress().getValue(), Symbol->getSize()};
- Linker.Symtab.insert({Symbol->getName().str(), Info});
+ auto Name =
+ Symbol->hasName() ? (*Symbol->getName()).str() : std::string();
+ Linker.Symtab.insert({std::move(Name), Info});
}
return Error::success();
@@ -189,7 +191,7 @@ JITLinkLinker::~JITLinkLinker() { cantFail(MM->deallocate(std::move(Allocs))); }
void JITLinkLinker::loadObject(MemoryBufferRef Obj,
SectionsMapper MapSections) {
- auto LG = jitlink::createLinkGraphFromObject(Obj);
+ auto LG = jitlink::createLinkGraphFromObject(Obj, BC.getSymbolStringPool());
if (auto E = LG.takeError()) {
errs() << "BOLT-ERROR: JITLink failed: " << E << '\n';
exit(1);
diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp
index c328232de61a3..2f05b03290ba3 100644
--- a/bolt/lib/Rewrite/MachORewriteInstance.cpp
+++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp
@@ -74,7 +74,8 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile,
ErrorAsOutParameter EAO(&Err);
Relocation::Arch = InputFile->makeTriple().getArch();
auto BCOrErr = BinaryContext::createBinaryContext(
- InputFile->makeTriple(), InputFile->getFileName(), nullptr,
+ InputFile->makeTriple(), std::make_shared(),
+ InputFile->getFileName(), nullptr,
/* IsPIC */ true, DWARFContext::create(*InputFile),
{llvm::outs(), llvm::errs()});
if (Error E = BCOrErr.takeError()) {
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 3b8baa3821459..04e073152f081 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -78,7 +78,6 @@ namespace opts {
extern cl::list HotTextMoveSections;
extern cl::opt Hugify;
extern cl::opt Instrument;
-extern cl::opt JumpTables;
extern cl::opt KeepNops;
extern cl::opt Lite;
extern cl::list ReorderData;
@@ -356,7 +355,8 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc,
Relocation::Arch = TheTriple.getArch();
auto BCOrErr = BinaryContext::createBinaryContext(
- TheTriple, File->getFileName(), Features.get(), IsPIC,
+ TheTriple, std::make_shared(), File->getFileName(),
+ Features.get(), IsPIC,
DWARFContext::create(*File, DWARFContext::ProcessDebugRelocations::Ignore,
nullptr, opts::DWPPathName,
WithColor::defaultErrorHandler,
@@ -698,6 +698,11 @@ Error RewriteInstance::run() {
if (opts::DiffOnly)
return Error::success();
+ if (opts::BinaryAnalysisMode) {
+ runBinaryAnalyses();
+ return Error::success();
+ }
+
preregisterSections();
runOptimizationPasses();
@@ -3474,6 +3479,8 @@ void RewriteInstance::runOptimizationPasses() {
BC->logBOLTErrorsAndQuitOnFatal(BinaryFunctionPassManager::runAllPasses(*BC));
}
+void RewriteInstance::runBinaryAnalyses() {}
+
void RewriteInstance::preregisterSections() {
// Preregister sections before emission to set their order in the output.
const unsigned ROFlags = BinarySection::getFlags(/*IsReadOnly*/ true,
@@ -3840,20 +3847,6 @@ void RewriteInstance::mapCodeSections(BOLTLinker::SectionMapper MapSection) {
assert(Function.getImageSize() <= Function.getMaxSize() &&
"Unexpected large function");
- // Map jump tables if updating in-place.
- if (opts::JumpTables == JTS_BASIC) {
- for (auto &JTI : Function.JumpTables) {
- JumpTable *JT = JTI.second;
- BinarySection &Section = JT->getOutputSection();
- Section.setOutputAddress(JT->getAddress());
- Section.setOutputFileOffset(getFileOffsetForAddress(JT->getAddress()));
- LLVM_DEBUG(dbgs() << "BOLT-DEBUG: mapping JT " << Section.getName()
- << " to 0x" << Twine::utohexstr(JT->getAddress())
- << '\n');
- MapSection(Section, JT->getAddress());
- }
- }
-
if (!Function.isSplit())
continue;
@@ -5636,26 +5629,8 @@ void RewriteInstance::rewriteFile() {
if (Function->getImageAddress() == 0 || Function->getImageSize() == 0)
continue;
- if (Function->getImageSize() > Function->getMaxSize()) {
- assert(!BC->isX86() && "Unexpected large function.");
- if (opts::Verbosity >= 1)
- BC->errs() << "BOLT-WARNING: new function size (0x"
- << Twine::utohexstr(Function->getImageSize())
- << ") is larger than maximum allowed size (0x"
- << Twine::utohexstr(Function->getMaxSize())
- << ") for function " << *Function << '\n';
-
- // Remove jump table sections that this function owns in non-reloc mode
- // because we don't want to write them anymore.
- if (!BC->HasRelocations && opts::JumpTables == JTS_BASIC) {
- for (auto &JTI : Function->JumpTables) {
- JumpTable *JT = JTI.second;
- BinarySection &Section = JT->getOutputSection();
- BC->deregisterSection(Section);
- }
- }
- continue;
- }
+ assert(Function->getImageSize() <= Function->getMaxSize() &&
+ "Unexpected large function");
const auto HasAddress = [](const FunctionFragment &FF) {
return FF.empty() ||
diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp
index de82420a16713..17f090aa61ee9 100644
--- a/bolt/lib/Utils/CommandLineOpts.cpp
+++ b/bolt/lib/Utils/CommandLineOpts.cpp
@@ -29,6 +29,7 @@ const char *BoltRevision =
namespace opts {
bool HeatmapMode = false;
+bool BinaryAnalysisMode = false;
cl::OptionCategory BoltCategory("BOLT generic options");
cl::OptionCategory BoltDiffCategory("BOLTDIFF generic options");
@@ -38,6 +39,7 @@ cl::OptionCategory BoltOutputCategory("Output options");
cl::OptionCategory AggregatorCategory("Data aggregation options");
cl::OptionCategory BoltInstrCategory("BOLT instrumentation options");
cl::OptionCategory HeatmapCategory("Heatmap options");
+cl::OptionCategory BinaryAnalysisCategory("BinaryAnalysis options");
cl::opt AlignText("align-text",
cl::desc("alignment of .text section"), cl::Hidden,
diff --git a/bolt/test/AArch64/long-jmp-one-stub.s b/bolt/test/AArch64/long-jmp-one-stub.s
new file mode 100644
index 0000000000000..cd9e0875a43c4
--- /dev/null
+++ b/bolt/test/AArch64/long-jmp-one-stub.s
@@ -0,0 +1,32 @@
+## This test verifies that no unnecessary stubs are inserted when each DotAddress increases during a lookup.
+
+# REQUIRES: system-linux, asserts
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
+# RUN: %clang %cflags -O0 %t.o -o %t.exe -Wl,-q
+# RUN: link_fdata %s %t.o %t.fdata
+# RUN: llvm-bolt %t.exe -o %t.bolt \
+# RUN: --data %t.fdata | FileCheck %s
+
+# CHECK: BOLT-INFO: Inserted 1 stubs in the hot area and 0 stubs in the cold area.
+
+ .section .text
+ .global _start
+ .global far_away_func
+
+ .align 4
+ .global _start
+ .type _start, %function
+_start:
+# FDATA: 0 [unknown] 0 1 _start 0 0 100
+ bl far_away_func
+ bl far_away_func
+ ret
+ .space 0x8000000
+ .global far_away_func
+ .type far_away_func, %function
+far_away_func:
+ add x0, x0, #1
+ ret
+
+.reloc 0, R_AARCH64_NONE
diff --git a/bolt/test/AArch64/pad-before-funcs.s b/bolt/test/AArch64/pad-before-funcs.s
new file mode 100644
index 0000000000000..3ce0ee5e38389
--- /dev/null
+++ b/bolt/test/AArch64/pad-before-funcs.s
@@ -0,0 +1,29 @@
+# Test checks that --pad-before-funcs is working as expected.
+# It should be able to introduce a configurable offset for the _start symbol.
+# It should reject requests which don't obey the code alignment requirement.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -Wl,--section-start=.text=0x4000
+# RUN: llvm-bolt %t.exe -o %t.bolt.0 --pad-funcs-before=_start:0
+# RUN: llvm-bolt %t.exe -o %t.bolt.4 --pad-funcs-before=_start:4
+# RUN: llvm-bolt %t.exe -o %t.bolt.8 --pad-funcs-before=_start:8
+
+# RUN: not llvm-bolt %t.exe -o %t.bolt.8 --pad-funcs-before=_start:1 2>&1 | FileCheck --check-prefix=CHECK-BAD-ALIGN %s
+
+# CHECK-BAD-ALIGN: user-requested 1 padding bytes before function _start(*2) is not a multiple of the minimum function alignment (4).
+
+# RUN: llvm-objdump --section=.text --disassemble %t.bolt.0 | FileCheck --check-prefix=CHECK-0 %s
+# RUN: llvm-objdump --section=.text --disassemble %t.bolt.4 | FileCheck --check-prefix=CHECK-4 %s
+# RUN: llvm-objdump --section=.text --disassemble %t.bolt.8 | FileCheck --check-prefix=CHECK-8 %s
+
+# Trigger relocation mode in bolt.
+.reloc 0, R_AARCH64_NONE
+
+.section .text
+.globl _start
+
+# CHECK-0: 0000000000400000 <_start>
+# CHECK-4: 0000000000400004 <_start>
+# CHECK-8: 0000000000400008 <_start>
+_start:
+ ret
diff --git a/bolt/test/CMakeLists.txt b/bolt/test/CMakeLists.txt
index d468ff984840f..6e18b028bddfc 100644
--- a/bolt/test/CMakeLists.txt
+++ b/bolt/test/CMakeLists.txt
@@ -37,6 +37,7 @@ list(APPEND BOLT_TEST_DEPS
lld
llvm-config
llvm-bolt
+ llvm-bolt-binary-analysis
llvm-bolt-heatmap
llvm-bat-dump
llvm-dwarfdump
diff --git a/bolt/test/X86/dwarf5-debug-names-abstract-origin-linkage-name-only.s b/bolt/test/X86/dwarf5-debug-names-abstract-origin-linkage-name-only.s
new file mode 100644
index 0000000000000..8c9817ce91edb
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-names-abstract-origin-linkage-name-only.s
@@ -0,0 +1,568 @@
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
+# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe
+# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-names %tmain.exe.bolt > %tlog.txt
+# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s
+
+## Tests that bolt can correctly generate debug_names when there is an DW_TAG_inlined_subroutine
+## with DW_AT_abstract_origin that points to DW_TAG_subprogram that only has DW_AT_linkage_name.
+
+# BOLT: Name Index @ 0x0 {
+# BOLT-NEXT: Header {
+# BOLT-NEXT: Length: 0xA2
+# BOLT-NEXT: Format: DWARF32
+# BOLT-NEXT: Version: 5
+# BOLT-NEXT: CU count: 1
+# BOLT-NEXT: Local TU count: 0
+# BOLT-NEXT: Foreign TU count: 0
+# BOLT-NEXT: Bucket count: 4
+# BOLT-NEXT: Name count: 4
+# BOLT-NEXT: Abbreviations table size: 0x19
+# BOLT-NEXT: Augmentation: 'BOLT'
+# BOLT-NEXT: }
+# BOLT-NEXT: Compilation Unit offsets [
+# BOLT-NEXT: CU[0]: 0x00000000
+# BOLT-NEXT: ]
+# BOLT-NEXT: Abbreviations [
+# BOLT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 0 [
+# BOLT-NEXT: Name 1 {
+# BOLT-NEXT: Hash: 0xB888030
+# BOLT-NEXT: String: {{.+}} "int"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: 0x1
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000004a
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 1 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 2 [
+# BOLT-NEXT: Name 2 {
+# BOLT-NEXT: Hash: 0x7C9A7F6A
+# BOLT-NEXT: String: {{.+}} "main"
+# BOLT-NEXT: Entry @ [[REF1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Abbrev: [[ABBREV2]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000004e
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 3 {
+# BOLT-NEXT: Hash: 0xB5063CFE
+# BOLT-NEXT: String: {{.+}} "_Z3fooi"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV2]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000024
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: Entry @ 0x96 {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000007e
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[REF1]]
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 3 [
+# BOLT-NEXT: Name 4 {
+# BOLT-NEXT: Hash: 0x7C952063
+# BOLT-NEXT: String: {{.+}} "char"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000009f
+# BOLT-NEXT: DW_IDX_parent:
+
+## int foo(int i) {
+## return i ++;
+## }
+## int main(int argc, char* argv[]) {
+## int i = 0;
+## [[clang::always_inline]] i = foo(argc);
+## return i;
+## }
+## Test was manually modified so that DW_TAG_subprogram only had DW_AT_linkage_name.
+
+ .text
+ .file "main.cpp"
+ .globl _Z3fooi
+ .p2align 4, 0x90
+ .type _Z3fooi,@function
+_Z3fooi:
+.Lfunc_begin0:
+ .file 0 "/abstractChain" "main.cpp" md5 0x2e29d55fc1320801a8057a4c50643ea1
+ .loc 0 1 0
+ .loc 0 2 12 prologue_end
+ .loc 0 2 3 epilogue_begin is_stmt 0
+ retq
+.Lfunc_end0:
+ .size _Z3fooi, .Lfunc_end0-_Z3fooi
+
+ .globl main
+ .p2align 4, 0x90
+ .type main,@function
+main:
+.Lfunc_begin1:
+ .loc 0 4 0 is_stmt 1
+.Ltmp2:
+ .loc 0 5 7 prologue_end
+ .loc 0 6 36
+ movl -12(%rbp), %eax
+.Ltmp3:
+ .loc 0 2 12
+.Ltmp4:
+ .loc 0 6 30
+ .loc 0 7 10
+ .loc 0 7 3 epilogue_begin is_stmt 0
+ retq
+.Ltmp5:
+.Lfunc_end1:
+ .size main, .Lfunc_end1-main
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ #.byte 3 # DW_AT_name
+ #.byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 32 # DW_AT_inline
+ .byte 33 # DW_FORM_implicit_const
+ .byte 1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 7 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 8 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 9 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 10 # Abbreviation Code
+ .byte 29 # DW_TAG_inlined_subroutine
+ .byte 1 # DW_CHILDREN_yes
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 88 # DW_AT_call_file
+ .byte 11 # DW_FORM_data1
+ .byte 89 # DW_AT_call_line
+ .byte 11 # DW_FORM_data1
+ .byte 87 # DW_AT_call_column
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 11 # Abbreviation Code
+ .byte 15 # DW_TAG_pointer_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0x98 DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 1 # DW_AT_name
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .byte 2 # DW_AT_comp_dir
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x23:0x15 DW_TAG_subprogram
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long 56 # DW_AT_abstract_origin
+ .byte 3 # Abbrev [3] 0x2f:0x8 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 124
+ .long 64 # DW_AT_abstract_origin Manually Modified
+ .byte 0 # End Of Children Mark
+ .byte 4 # Abbrev [4] 0x38:0x12 DW_TAG_subprogram
+ .byte 3 # DW_AT_linkage_name
+ #.byte 4 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 74 # DW_AT_type
+ # DW_AT_external
+ # DW_AT_inline
+ .byte 5 # Abbrev [5] 0x41:0x8 DW_TAG_formal_parameter
+ .byte 6 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 74 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0x4a:0x4 DW_TAG_base_type
+ .byte 5 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 7 # Abbrev [7] 0x4e:0x47 DW_TAG_subprogram
+ .byte 1 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .byte 7 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 73 # DW_AT_type Manually Modified
+ # DW_AT_external
+ .byte 8 # Abbrev [8] 0x5d:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 116
+ .byte 8 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 73 # DW_AT_type Manually Modified
+ .byte 8 # Abbrev [8] 0x68:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 104
+ .byte 9 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 148 # DW_AT_type Manually Modified
+ .byte 9 # Abbrev [9] 0x73:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 100
+ .byte 6 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 5 # DW_AT_decl_line
+ .long 73 # DW_AT_type Manually Modified
+ .byte 10 # Abbrev [10] 0x7e:0x16 DW_TAG_inlined_subroutine
+ .long 56 # DW_AT_abstract_origin
+ .byte 2 # DW_AT_low_pc
+ .long .Ltmp4-.Ltmp3 # DW_AT_high_pc
+ .byte 0 # DW_AT_call_file
+ .byte 6 # DW_AT_call_line
+ .byte 32 # DW_AT_call_column
+ .byte 3 # Abbrev [3] 0x8b:0x8 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 124
+ .long 64 # DW_AT_abstract_origin Manually Modified
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 11 # Abbrev [11] 0x95:0x5 DW_TAG_pointer_type
+ .long 153 # DW_AT_type Manually Modified
+ .byte 11 # Abbrev [11] 0x9a:0x5 DW_TAG_pointer_type
+ .long 158 # DW_AT_type Manually Modified
+ .byte 6 # Abbrev [6] 0x9f:0x4 DW_TAG_base_type
+ .byte 10 # DW_AT_name
+ .byte 6 # DW_AT_encoding
+ .byte 1 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 48 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 20.0.0git" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=24
+.Linfo_string2:
+ .asciz "/abstractChain" # string offset=33
+.Linfo_string3:
+ .asciz "foo" # string offset=85
+.Linfo_string4:
+ .asciz "_Z3fooi" # string offset=89
+.Linfo_string5:
+ .asciz "int" # string offset=97
+.Linfo_string6:
+ .asciz "i" # string offset=101
+.Linfo_string7:
+ .asciz "main" # string offset=103
+.Linfo_string8:
+ .asciz "argc" # string offset=108
+.Linfo_string9:
+ .asciz "argv" # string offset=113
+.Linfo_string10:
+ .asciz "char" # string offset=118
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string4
+ .long .Linfo_string3
+ .long .Linfo_string5
+ .long .Linfo_string6
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .long .Linfo_string9
+ .long .Linfo_string10
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+ .quad .Lfunc_begin1
+ .quad .Ltmp3
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 5 # Header: bucket count
+ .long 5 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 0 # Bucket 0
+ .long 1 # Bucket 1
+ .long 0 # Bucket 2
+ .long 3 # Bucket 3
+ .long 4 # Bucket 4
+ .long 2090499946 # Hash in Bucket 1
+ .long -1257882370 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 3
+ .long 193491849 # Hash in Bucket 4
+ .long 2090147939 # Hash in Bucket 4
+ .long .Linfo_string7 # String in Bucket 1: main
+ .long .Linfo_string4 # String in Bucket 1: _Z3fooi
+ .long .Linfo_string5 # String in Bucket 3: int
+ .long .Linfo_string3 # String in Bucket 4: foo
+ .long .Linfo_string10 # String in Bucket 4: char
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 4
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 4
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 29 # DW_TAG_inlined_subroutine
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames3:
+.L2:
+ .byte 1 # Abbreviation code
+ .long 78 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: main
+.Lnames1:
+.L0:
+ .byte 1 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+.L3: # DW_IDX_parent
+ .byte 2 # Abbreviation code
+ .long 126 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: _Z3fooi
+.Lnames2:
+.L1:
+ .byte 3 # Abbreviation code
+ .long 74 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames0:
+ .byte 1 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 2 # DW_IDX_parent
+ # Abbreviation code
+ .long 126 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: foo
+.Lnames4:
+.L4:
+ .byte 3 # Abbreviation code
+ .long 159 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: char
+ .p2align 2, 0x0
+.Lnames_end0:
+ .ident "clang version 20.0.0git"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf5-debug-names-abstract-origin-specification.s b/bolt/test/X86/dwarf5-debug-names-abstract-origin-specification.s
new file mode 100644
index 0000000000000..2075640d6761c
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-names-abstract-origin-specification.s
@@ -0,0 +1,829 @@
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
+# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe
+# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-names %tmain.exe.bolt > %tlog.txt
+# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s
+
+## This test checks that BOLT correctly generates .debug_names section when there is transative
+## DW_AT_name/DW_AT_linkage_name resolution.
+
+# BOLT: Abbreviations [
+# BOLT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_class_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 0 [
+# BOLT-NEXT: Name 1 {
+# BOLT-NEXT: Hash: 0xD72418AA
+# BOLT-NEXT: String: {{.+}} "_ZL3fooi"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000ba
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 1 [
+# BOLT-NEXT: Name 2 {
+# BOLT-NEXT: Hash: 0x10614A06
+# BOLT-NEXT: String: {{.+}} "State"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV2]]
+# BOLT-NEXT: Tag: DW_TAG_class_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000002b
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: Entry @ [[REF1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000089
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000a3
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[REF1]]
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 2 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 3 [
+# BOLT-NEXT: Name 3 {
+# BOLT-NEXT: Hash: 0xB888030
+# BOLT-NEXT: String: {{.+}} "int"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV4]]
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000085
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 4 {
+# BOLT-NEXT: Hash: 0x7C9A7F6A
+# BOLT-NEXT: String: {{.+}} "main"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000042
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 4 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 5 [
+# BOLT-NEXT: Name 5 {
+# BOLT-NEXT: Hash: 0xB887389
+# BOLT-NEXT: String: {{.+}} "foo"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000ba
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 6 {
+# BOLT-NEXT: Hash: 0x7C952063
+# BOLT-NEXT: String: {{.+}} "char"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV4]]
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000d9
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 7 {
+# BOLT-NEXT: Hash: 0xFBBDC812
+# BOLT-NEXT: String: {{.+}} "_ZN5StateC2Ev"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000089
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000a3
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[REF1]]
+
+## static int foo(int i) {
+## return i ++;
+## }
+## class State {
+## public:
+## State() {[[clang::always_inline]] foo(3);}
+## };
+##
+## int main(int argc, char* argv[]) {
+## State S;
+## return 0;
+## }
+
+## Test manually modified to redirect DW_TAG_inlined_subroutine to DW_TAG_subprogram with DW_AT_specification.
+
+ .text
+ .file "main.cpp"
+ .file 0 "abstractChainTwo" "main.cpp" md5 0x17ad726b6a1fd49ee59559a1302da539
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@function
+main: # @main
+.Lfunc_begin0:
+ .loc 0 9 0 # main.cpp:9:0
+.Ltmp0:
+ .loc 0 10 9 prologue_end # main.cpp:10:9
+ callq _ZN5StateC2Ev
+ .loc 0 11 3 # main.cpp:11:3
+ .loc 0 11 3 epilogue_begin is_stmt 0 # main.cpp:11:3
+ retq
+.Ltmp1:
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+ # -- End function
+ .section .text._ZN5StateC2Ev,"axG",@progbits,_ZN5StateC2Ev,comdat
+ .weak _ZN5StateC2Ev # -- Begin function _ZN5StateC2Ev
+ .p2align 4, 0x90
+ .type _ZN5StateC2Ev,@function
+_ZN5StateC2Ev: # @_ZN5StateC2Ev
+.Lfunc_begin1:
+ .loc 0 6 0 is_stmt 1 # main.cpp:6:0
+ .cfi_startproc
+# %bb.0:
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ movq %rdi, -16(%rbp)
+ movl $3, -4(%rbp)
+.Ltmp2:
+ .loc 0 2 12 prologue_end # main.cpp:2:12
+ movl -4(%rbp), %eax
+ addl $1, %eax
+ movl %eax, -4(%rbp)
+.Ltmp3:
+ .loc 0 6 44 epilogue_begin # main.cpp:6:44
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp4:
+.Lfunc_end1:
+ .size _ZN5StateC2Ev, .Lfunc_end1-_ZN5StateC2Ev
+ .cfi_endproc
+ # -- End function
+ .text
+ .p2align 4, 0x90 # -- Begin function _ZL3fooi
+ .type _ZL3fooi,@function
+_ZL3fooi: # @_ZL3fooi
+.Lfunc_begin2:
+ .loc 0 1 0 # main.cpp:1:0
+ .cfi_startproc
+# %bb.0:
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ movl %edi, -4(%rbp)
+.Ltmp5:
+ .loc 0 2 12 prologue_end # main.cpp:2:12
+ movl -4(%rbp), %eax
+ movl %eax, %ecx
+ addl $1, %ecx
+ movl %ecx, -4(%rbp)
+ .loc 0 2 3 epilogue_begin is_stmt 0 # main.cpp:2:3
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp6:
+.Lfunc_end2:
+ .size _ZL3fooi, .Lfunc_end2-_ZL3fooi
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 85 # DW_AT_ranges
+ .byte 35 # DW_FORM_rnglistx
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 116 # DW_AT_rnglists_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 2 # DW_TAG_class_type
+ .byte 1 # DW_CHILDREN_yes
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 60 # DW_AT_declaration
+ .byte 25 # DW_FORM_flag_present
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 50 # DW_AT_accessibility
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 52 # DW_AT_artificial
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 15 # DW_TAG_pointer_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 7 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 8 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 9 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 32 # DW_AT_inline
+ .byte 33 # DW_FORM_implicit_const
+ .byte 1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 10 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 11 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 12 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 100 # DW_AT_object_pointer
+ .byte 19 # DW_FORM_ref4
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ .byte 71 # DW_AT_specification
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 13 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 52 # DW_AT_artificial
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 14 # Abbreviation Code
+ .byte 29 # DW_TAG_inlined_subroutine
+ .byte 1 # DW_CHILDREN_yes
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 88 # DW_AT_call_file
+ .byte 11 # DW_FORM_data1
+ .byte 89 # DW_AT_call_line
+ .byte 11 # DW_FORM_data1
+ .byte 87 # DW_AT_call_column
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 15 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 16 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0xd7 DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 1 # DW_AT_name
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .byte 2 # DW_AT_comp_dir
+ .quad 0 # DW_AT_low_pc
+ .byte 0 # DW_AT_ranges
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .long .Lrnglists_table_base0 # DW_AT_rnglists_base
+ .byte 2 # Abbrev [2] 0x2b:0x12 DW_TAG_class_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 3 # DW_AT_name
+ .byte 1 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .byte 3 # Abbrev [3] 0x31:0xb DW_TAG_subprogram
+ .byte 3 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ # DW_AT_declaration
+ # DW_AT_external
+ .byte 1 # DW_AT_accessibility
+ # DW_ACCESS_public
+ .byte 4 # Abbrev [4] 0x36:0x5 DW_TAG_formal_parameter
+ .long 61 # DW_AT_type
+ # DW_AT_artificial
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 5 # Abbrev [5] 0x3d:0x5 DW_TAG_pointer_type
+ .long 43 # DW_AT_type
+ .byte 6 # Abbrev [6] 0x42:0x31 DW_TAG_subprogram
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .byte 8 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 9 # DW_AT_decl_line
+ .long 133 # DW_AT_type
+ # DW_AT_external
+ .byte 7 # Abbrev [7] 0x51:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .byte 10 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 9 # DW_AT_decl_line
+ .long 133 # DW_AT_type
+ .byte 7 # Abbrev [7] 0x5c:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 112
+ .byte 11 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 9 # DW_AT_decl_line
+ .long 207 # DW_AT_type
+ .byte 8 # Abbrev [8] 0x67:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 111
+ .byte 13 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 10 # DW_AT_decl_line
+ .long 43 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 9 # Abbrev [9] 0x73:0x12 DW_TAG_subprogram
+ .byte 4 # DW_AT_linkage_name
+ .byte 5 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 133 # DW_AT_type
+ # DW_AT_inline
+ .byte 10 # Abbrev [10] 0x7c:0x8 DW_TAG_formal_parameter
+ .byte 7 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 133 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 11 # Abbrev [11] 0x85:0x4 DW_TAG_base_type
+ .byte 6 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 12 # Abbrev [12] 0x89:0x31 DW_TAG_subprogram
+ .byte 1 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long 154 # DW_AT_object_pointer
+ .byte 9 # DW_AT_linkage_name
+ .long 49 # DW_AT_specification
+ .byte 13 # Abbrev [13] 0x9a:0x9 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 112
+ .byte 14 # DW_AT_name
+ .long 221 # DW_AT_type
+ # DW_AT_artificial
+ .byte 14 # Abbrev [14] 0xa3:0x16 DW_TAG_inlined_subroutine
+ .long 137 # DW_AT_abstract_origin Manually Modified
+ .byte 2 # DW_AT_low_pc
+ .long .Ltmp3-.Ltmp2 # DW_AT_high_pc
+ .byte 0 # DW_AT_call_file
+ .byte 6 # DW_AT_call_line
+ .byte 37 # DW_AT_call_column
+ .byte 15 # Abbrev [15] 0xb0:0x8 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 124
+ .long 124 # DW_AT_abstract_origin
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 16 # Abbrev [16] 0xba:0x15 DW_TAG_subprogram
+ .byte 3 # DW_AT_low_pc
+ .long .Lfunc_end2-.Lfunc_begin2 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long 115 # DW_AT_abstract_origin
+ .byte 15 # Abbrev [15] 0xc6:0x8 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 124
+ .long 124 # DW_AT_abstract_origin
+ .byte 0 # End Of Children Mark
+ .byte 5 # Abbrev [5] 0xcf:0x5 DW_TAG_pointer_type
+ .long 212 # DW_AT_type
+ .byte 5 # Abbrev [5] 0xd4:0x5 DW_TAG_pointer_type
+ .long 217 # DW_AT_type
+ .byte 11 # Abbrev [11] 0xd9:0x4 DW_TAG_base_type
+ .byte 12 # DW_AT_name
+ .byte 6 # DW_AT_encoding
+ .byte 1 # DW_AT_byte_size
+ .byte 5 # Abbrev [5] 0xdd:0x5 DW_TAG_pointer_type
+ .long 43 # DW_AT_type
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_rnglists,"",@progbits
+ .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length
+.Ldebug_list_header_start0:
+ .short 5 # Version
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+ .long 1 # Offset entry count
+.Lrnglists_table_base0:
+ .long .Ldebug_ranges0-.Lrnglists_table_base0
+.Ldebug_ranges0:
+ .byte 1 # DW_RLE_base_addressx
+ .byte 0 # base address index
+ .byte 4 # DW_RLE_offset_pair
+ .uleb128 .Lfunc_begin0-.Lfunc_begin0 # starting offset
+ .uleb128 .Lfunc_end0-.Lfunc_begin0 # ending offset
+ .byte 4 # DW_RLE_offset_pair
+ .uleb128 .Lfunc_begin2-.Lfunc_begin0 # starting offset
+ .uleb128 .Lfunc_end2-.Lfunc_begin0 # ending offset
+ .byte 3 # DW_RLE_startx_length
+ .byte 1 # start index
+ .uleb128 .Lfunc_end1-.Lfunc_begin1 # length
+ .byte 0 # DW_RLE_end_of_list
+.Ldebug_list_header_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 64 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 20.0.0git" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=24
+.Linfo_string2:
+ .asciz "abstractChainTwo" # string offset=33
+.Linfo_string3:
+ .asciz "State" # string offset=88
+.Linfo_string4:
+ .asciz "main" # string offset=94
+.Linfo_string5:
+ .asciz "_ZL3fooi" # string offset=99
+.Linfo_string6:
+ .asciz "foo" # string offset=108
+.Linfo_string7:
+ .asciz "int" # string offset=112
+.Linfo_string8:
+ .asciz "i" # string offset=116
+.Linfo_string9:
+ .asciz "_ZN5StateC2Ev" # string offset=118
+.Linfo_string10:
+ .asciz "argc" # string offset=132
+.Linfo_string11:
+ .asciz "argv" # string offset=137
+.Linfo_string12:
+ .asciz "char" # string offset=142
+.Linfo_string13:
+ .asciz "S" # string offset=147
+.Linfo_string14:
+ .asciz "this" # string offset=149
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string5
+ .long .Linfo_string6
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .long .Linfo_string4
+ .long .Linfo_string9
+ .long .Linfo_string10
+ .long .Linfo_string11
+ .long .Linfo_string12
+ .long .Linfo_string13
+ .long .Linfo_string14
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+ .quad .Lfunc_begin1
+ .quad .Ltmp2
+ .quad .Lfunc_begin2
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 7 # Header: bucket count
+ .long 7 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 1 # Bucket 0
+ .long 2 # Bucket 1
+ .long 0 # Bucket 2
+ .long 3 # Bucket 3
+ .long 0 # Bucket 4
+ .long 5 # Bucket 5
+ .long 0 # Bucket 6
+ .long -685500246 # Hash in Bucket 0
+ .long 274811398 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 3
+ .long 2090499946 # Hash in Bucket 3
+ .long 193491849 # Hash in Bucket 5
+ .long 2090147939 # Hash in Bucket 5
+ .long -71448558 # Hash in Bucket 5
+ .long .Linfo_string5 # String in Bucket 0: _ZL3fooi
+ .long .Linfo_string3 # String in Bucket 1: State
+ .long .Linfo_string7 # String in Bucket 3: int
+ .long .Linfo_string4 # String in Bucket 3: main
+ .long .Linfo_string6 # String in Bucket 5: foo
+ .long .Linfo_string12 # String in Bucket 5: char
+ .long .Linfo_string9 # String in Bucket 5: _ZN5StateC2Ev
+ .long .Lnames5-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 5
+ .long .Lnames6-.Lnames_entries0 # Offset in Bucket 5
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 5
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 29 # DW_TAG_inlined_subroutine
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 2 # DW_TAG_class_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 4 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames5:
+.L1:
+ .byte 1 # Abbreviation code
+ .long 163 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+.L0:
+ .byte 2 # Abbreviation code
+ .long 186 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: _ZL3fooi
+.Lnames0:
+.L5:
+ .byte 3 # Abbreviation code
+ .long 43 # DW_IDX_die_offset
+.L2: # DW_IDX_parent
+ .byte 2 # Abbreviation code
+ .long 137 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: State
+.Lnames2:
+.L4:
+ .byte 4 # Abbreviation code
+ .long 133 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames1:
+.L6:
+ .byte 2 # Abbreviation code
+ .long 66 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: main
+.Lnames4:
+ .byte 1 # Abbreviation code
+ .long 163 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 2 # Abbreviation code
+ .long 186 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: foo
+.Lnames6:
+.L3:
+ .byte 4 # Abbreviation code
+ .long 217 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: char
+.Lnames3:
+ .byte 2 # Abbreviation code
+ .long 137 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: _ZN5StateC2Ev
+ .p2align 2, 0x0
+.Lnames_end0:
+ .ident "clang version 20.0.0git"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf5-debug-names-gnu-push-tls-address.s b/bolt/test/X86/dwarf5-debug-names-gnu-push-tls-address.s
new file mode 100644
index 0000000000000..f84d0b6654e7a
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-names-gnu-push-tls-address.s
@@ -0,0 +1,291 @@
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
+# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe
+# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-names --debug-info %tmain.exe.bolt > %tlog.txt
+# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s
+
+## This test checks that BOLT correctly generates .debug_names section when there is DW_TAG_variable
+## with DW_OP_GNU_push_tls_address in DW_AT_location.
+
+# BOLT: [[DIEOFFSET:0x[0-9a-f]*]]: DW_TAG_variable
+# BOLT-NEXT: DW_AT_name ("x")
+# BOLT-NEXT: DW_AT_type ({{.+}} "int")
+# BOLT-NEXT: DW_AT_external (true)
+# BOLT-NEXT: DW_AT_decl_file ("gnu_tls_push/main.cpp")
+# BOLT-NEXT: DW_AT_decl_line (1)
+# BOLT-NEXT: DW_AT_location (DW_OP_const8u 0x0, DW_OP_GNU_push_tls_address)
+# BOLT: Hash: 0x2B61D
+# BOLT-NEXT: String: {{.+}} "x"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: {{.+}}
+# BOLT-NEXT: Tag: DW_TAG_variable
+# BOLT-NEXT: DW_IDX_die_offset: [[DIEOFFSET]]
+# BOLT-NEXT: DW_IDX_parent:
+
+## thread_local int x = 0;
+## int main() {
+## x = 10;
+## return x;
+## }
+ .file "main.cpp"
+ .file 0 "gnu_tls_push" "main.cpp" md5 0x551db97d5e23dc6a81abdc5ade4d9d71
+ .globl main
+ .type main,@function
+main:
+.Lfunc_begin0:
+ .loc 0 2 0
+ .loc 0 3 3 prologue_end
+ .loc 0 3 5 is_stmt 0
+ .loc 0 4 10 is_stmt 1
+ .loc 0 4 3 epilogue_begin is_stmt 0
+ retq
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
+ .hidden _ZTW1x
+ .weak _ZTW1x
+ .type _ZTW1x,@function
+_ZTW1x:
+.Lfunc_begin1:
+ retq
+.Lfunc_end1:
+ .size _ZTW1x, .Lfunc_end1-_ZTW1x
+
+ .type x,@object
+ .section .tbss,"awT",@nobits
+ .globl x
+x:
+ .long 0
+ .size x, 4
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0x3e DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 1 # DW_AT_name
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .byte 2 # DW_AT_comp_dir
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x23:0x13 DW_TAG_variable
+ .byte 3 # DW_AT_name
+ .long 54 # DW_AT_type
+ # DW_AT_external
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .byte 10 # DW_AT_location
+ .byte 14
+ .quad x@DTPOFF
+ .byte 224
+ .byte 3 # Abbrev [3] 0x36:0x4 DW_TAG_base_type
+ .byte 4 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 4 # Abbrev [4] 0x3a:0xf DW_TAG_subprogram
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .byte 5 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .long 54 # DW_AT_type
+ # DW_AT_external
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 28 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 17.0.4" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=137
+.Linfo_string2:
+ .asciz "gnu_tls_push" # string offset=146
+.Linfo_string3:
+ .asciz "x" # string offset=184
+.Linfo_string4:
+ .asciz "int" # string offset=186
+.Linfo_string5:
+ .asciz "main" # string offset=190
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .long .Linfo_string5
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 3 # Header: bucket count
+ .long 3 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 1 # Bucket 0
+ .long 2 # Bucket 1
+ .long 3 # Bucket 2
+ .long 177693 # Hash in Bucket 0
+ .long 2090499946 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 2
+ .long .Linfo_string3 # String in Bucket 0: x
+ .long .Linfo_string5 # String in Bucket 1: main
+ .long .Linfo_string4 # String in Bucket 2: int
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 2
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 52 # DW_TAG_variable
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames1:
+.L2:
+ .byte 1 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: x
+.Lnames2:
+.L0:
+ .byte 2 # Abbreviation code
+ .long 58 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: main
+.Lnames0:
+.L1:
+ .byte 3 # Abbreviation code
+ .long 54 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+ .p2align 2, 0x0
+.Lnames_end0:
+ .ident "clang version 17.0.4 (https://git.internal.tfbnw.net/repos/git/rw/osmeta/external/llvm-project 8d1fd9f463cb31caf429b83cf7a5baea5f67e54a)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf5-debug-names-union.test b/bolt/test/X86/dwarf5-debug-names-union.test
new file mode 100644
index 0000000000000..c6da1db684ddc
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-names-union.test
@@ -0,0 +1,496 @@
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
+# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe
+# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-names %tmain.exe.bolt > %tlog.txt
+# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s
+
+## This test checks that bolt correctly generates entry for DW_TAG_union_type for .debug_name section.
+
+# BOLT: Abbreviations [
+# BOLT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_union_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_structure_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 0 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 1 [
+# BOLT-NEXT: Name 1 {
+# BOLT-NEXT: Hash: 0x7C9A7F6A
+# BOLT-NEXT: String: {{.+}} "main"
+# BOLT-NEXT: Entry @ [[ENTRY:0x[0-9a-f]*]] {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000024
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 2 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 3 [
+# BOLT-NEXT: Name 2 {
+# BOLT-NEXT: Hash: 0xB888030
+# BOLT-NEXT: String: {{.+}} "int"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV2]]
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000083
+# BOLT-NEXT: DW_IDX_parent:
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 3 {
+# BOLT-NEXT: Hash: 0xED0F01B4
+# BOLT-NEXT: String: {{.+}} "MyUnion"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_union_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000049
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY]]
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 4 [
+# BOLT-NEXT: Name 4 {
+# BOLT-NEXT: Hash: 0x8AB681F0
+# BOLT-NEXT: String: {{.+}} "MyStruct"
+# BOLT-NEXT: Entry @ [[ENTRY2:0x[0-9a-f]*]] {
+# BOLT-NEXT: Abbrev: [[ABBREV4]]
+# BOLT-NEXT: Tag: DW_TAG_structure_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000062
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY]]
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 5 {
+# BOLT-NEXT: Hash: 0x8EEF3866
+# BOLT-NEXT: String: {{.+}} "MyUnion2"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_union_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000071
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY2]]
+
+
+## int main() {
+## union MyUnion {
+## int a;
+## int b;
+## };
+## struct MyStruct {
+## union MyUnion2 {
+## int a;
+## };
+## MyUnion2 myUnion2;
+## };
+## MyUnion myEnum;
+## myEnum.a = 5;
+## MyStruct myStruct;
+## return myEnum.a + myStruct.myUnion2.a;
+## }
+
+ .text
+ .file "main.cpp"
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@function
+main: # @main
+.Lfunc_begin0:
+ .file 0 "union" "main.cpp" md5 0xb75b2512f2daa57bbcfe0c29f56d95f4
+ .loc 0 1 0 # main.cpp:1:0
+ retq
+.Lfunc_end0:
+ .size main, .-main
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 23 # DW_TAG_union_type
+ .byte 1 # DW_CHILDREN_yes
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 13 # DW_TAG_member
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 56 # DW_AT_data_member_location
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 1 # DW_CHILDREN_yes
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 7 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0x7b DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 1 # DW_AT_name
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .byte 2 # DW_AT_comp_dir
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x23:0x5f DW_TAG_subprogram
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .byte 3 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 130 # DW_AT_type
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x32:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .byte 5 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 12 # DW_AT_decl_line
+ .long 72 # DW_AT_type
+ .byte 3 # Abbrev [3] 0x3d:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 116
+ .byte 9 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 14 # DW_AT_decl_line
+ .long 97 # DW_AT_type
+ .byte 4 # Abbrev [4] 0x48:0x19 DW_TAG_union_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 8 # DW_AT_name
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .byte 5 # Abbrev [5] 0x4e:0x9 DW_TAG_member
+ .byte 6 # DW_AT_name
+ .long 130 # DW_AT_type
+ .byte 0 # DW_AT_decl_file
+ .byte 3 # DW_AT_decl_line
+ .byte 0 # DW_AT_data_member_location
+ .byte 5 # Abbrev [5] 0x57:0x9 DW_TAG_member
+ .byte 7 # DW_AT_name
+ .long 130 # DW_AT_type
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .byte 0 # DW_AT_data_member_location
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0x61:0x20 DW_TAG_structure_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 12 # DW_AT_name
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .byte 5 # Abbrev [5] 0x67:0x9 DW_TAG_member
+ .byte 10 # DW_AT_name
+ .long 112 # DW_AT_type
+ .byte 0 # DW_AT_decl_file
+ .byte 10 # DW_AT_decl_line
+ .byte 0 # DW_AT_data_member_location
+ .byte 4 # Abbrev [4] 0x70:0x10 DW_TAG_union_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 11 # DW_AT_name
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 7 # DW_AT_decl_line
+ .byte 5 # Abbrev [5] 0x76:0x9 DW_TAG_member
+ .byte 6 # DW_AT_name
+ .long 130 # DW_AT_type
+ .byte 0 # DW_AT_decl_file
+ .byte 8 # DW_AT_decl_line
+ .byte 0 # DW_AT_data_member_location
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 7 # Abbrev [7] 0x82:0x4 DW_TAG_base_type
+ .byte 4 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 56 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 20.0.0git" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=24
+.Linfo_string2:
+ .asciz "union" # string offset=33
+.Linfo_string3:
+ .asciz "main" # string offset=77
+.Linfo_string4:
+ .asciz "int" # string offset=82
+.Linfo_string5:
+ .asciz "myEnum" # string offset=86
+.Linfo_string6:
+ .asciz "MyUnion" # string offset=93
+.Linfo_string7:
+ .asciz "a" # string offset=101
+.Linfo_string8:
+ .asciz "b" # string offset=103
+.Linfo_string9:
+ .asciz "myStruct" # string offset=105
+.Linfo_string10:
+ .asciz "MyStruct" # string offset=114
+.Linfo_string11:
+ .asciz "myUnion2" # string offset=123
+.Linfo_string12:
+ .asciz "MyUnion2" # string offset=132
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .long .Linfo_string5
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .long .Linfo_string6
+ .long .Linfo_string9
+ .long .Linfo_string11
+ .long .Linfo_string12
+ .long .Linfo_string10
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 5 # Header: bucket count
+ .long 5 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 0 # Bucket 0
+ .long 1 # Bucket 1
+ .long 0 # Bucket 2
+ .long 2 # Bucket 3
+ .long 4 # Bucket 4
+ .long 2090499946 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 3
+ .long -317783628 # Hash in Bucket 3
+ .long -1967750672 # Hash in Bucket 4
+ .long -1896925082 # Hash in Bucket 4
+ .long .Linfo_string3 # String in Bucket 1: main
+ .long .Linfo_string4 # String in Bucket 3: int
+ .long .Linfo_string6 # String in Bucket 3: MyUnion
+ .long .Linfo_string10 # String in Bucket 4: MyStruct
+ .long .Linfo_string12 # String in Bucket 4: MyUnion2
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 4
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 4
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 23 # DW_TAG_union_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 4 # Abbrev code
+ .byte 19 # DW_TAG_structure_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L3:
+ .byte 1 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: main
+.Lnames1:
+.L1:
+ .byte 2 # Abbreviation code
+ .long 130 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames2:
+.L4:
+ .byte 3 # Abbreviation code
+ .long 72 # DW_IDX_die_offset
+ .long .L3-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: MyUnion
+.Lnames3:
+.L2:
+ .byte 4 # Abbreviation code
+ .long 97 # DW_IDX_die_offset
+ .long .L3-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: MyStruct
+.Lnames4:
+.L0:
+ .byte 3 # Abbreviation code
+ .long 112 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: MyUnion2
+ .p2align 2, 0x0
+.Lnames_end0:
+ .ident "clang version 20.0.0git"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/linux-static-keys.s b/bolt/test/X86/linux-static-keys.s
index 0bd17a375d882..d34dd640ef879 100644
--- a/bolt/test/X86/linux-static-keys.s
+++ b/bolt/test/X86/linux-static-keys.s
@@ -35,13 +35,13 @@ _start:
.L0:
jmp L1
# CHECK: jit
-# CHECK-SAME: # ID: 1 {{.*}} # Likely: 0 # InitValue: 1
+# CHECK-SAME: # ID: 1 {{.*}} # Likely: 1 # InitValue: 0
nop
L1:
.nops 5
- jmp .L0
# CHECK: jit
-# CHECK-SAME: # ID: 2 {{.*}} # Likely: 1 # InitValue: 1
+# CHECK-SAME: # ID: 2 {{.*}} # Likely: 0 # InitValue: 0
+ jmp .L0
## Check that a branch profile associated with a NOP is handled properly when
## dynamic branch is created.
@@ -67,18 +67,24 @@ foo:
.type __start___jump_table, %object
__start___jump_table:
- .long .L0 - . # Jump address
- .long L1 - . # Target address
- .quad 1 # Key address
+ .long .L0 - . # Jump address
+ .long L1 - . # Target address
+ .quad fake_static_key + 1 - . # Key address; LSB = 1 : likely
- .long L1 - . # Jump address
- .long L2 - . # Target address
- .quad 0 # Key address
+ .long L1 - . # Jump address
+ .long L2 - . # Target address
+ .quad fake_static_key -. # Key address; LSB = 0 : unlikely
.globl __stop___jump_table
.type __stop___jump_table, %object
__stop___jump_table:
+## Staic keys (we just use the label ignoring the format of the keys).
+ .data
+ .align 8
+fake_static_key:
+ .quad 0
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/binary-analysis/AArch64/Inputs/dummy.txt b/bolt/test/binary-analysis/AArch64/Inputs/dummy.txt
new file mode 100644
index 0000000000000..2995a4d0e7491
--- /dev/null
+++ b/bolt/test/binary-analysis/AArch64/Inputs/dummy.txt
@@ -0,0 +1 @@
+dummy
\ No newline at end of file
diff --git a/bolt/test/binary-analysis/AArch64/cmdline-args.test b/bolt/test/binary-analysis/AArch64/cmdline-args.test
new file mode 100644
index 0000000000000..e414818644a3b
--- /dev/null
+++ b/bolt/test/binary-analysis/AArch64/cmdline-args.test
@@ -0,0 +1,33 @@
+# This file tests error messages produced on invalid command line arguments.
+# It also checks that help messages are generated as expected.
+
+# Verify that an error message is provided if an input file is missing or incorrect
+
+RUN: not llvm-bolt-binary-analysis 2>&1 | FileCheck -check-prefix=NOFILEARG %s
+NOFILEARG: llvm-bolt-binary-analysis: Not enough positional command line arguments specified!
+NOFILEARG-NEXT: Must specify at least 1 positional argument: See: {{.*}}llvm-bolt-binary-analysis --help
+
+RUN: not llvm-bolt-binary-analysis non-existing-file 2>&1 | FileCheck -check-prefix=NONEXISTINGFILEARG %s
+NONEXISTINGFILEARG: llvm-bolt-binary-analysis: 'non-existing-file': No such file or directory.
+
+RUN: not llvm-bolt-binary-analysis %p/Inputs/dummy.txt 2>&1 | FileCheck -check-prefix=NOELFFILEARG %s
+NOELFFILEARG: llvm-bolt-binary-analysis: '{{.*}}/Inputs/dummy.txt': The file was not recognized as a valid object file.
+
+RUN: %clang %cflags %p/../../Inputs/asm_foo.s %p/../../Inputs/asm_main.c -o %t.exe
+RUN: llvm-bolt-binary-analysis %t.exe 2>&1 | FileCheck -check-prefix=VALIDELFFILEARG --allow-empty %s
+# Check that there are no BOLT-WARNING or BOLT-ERROR output lines
+VALIDELFFILEARG: BOLT-INFO:
+VALIDELFFILEARG-NOT: BOLT-WARNING:
+VALIDELFFILEARG-NOT: BOLT-ERROR:
+
+# Check --help output
+
+RUN: llvm-bolt-binary-analysis --help 2>&1 | FileCheck -check-prefix=HELP %s
+
+HELP: OVERVIEW: BinaryAnalysis
+HELP-EMPTY:
+HELP-NEXT: USAGE: llvm-bolt-binary-analysis [options]
+HELP-EMPTY:
+HELP-NEXT: OPTIONS:
+HELP-EMPTY:
+HELP-NEXT: Generic Options:
diff --git a/bolt/test/binary-analysis/AArch64/lit.local.cfg b/bolt/test/binary-analysis/AArch64/lit.local.cfg
new file mode 100644
index 0000000000000..6f247dd52e82f
--- /dev/null
+++ b/bolt/test/binary-analysis/AArch64/lit.local.cfg
@@ -0,0 +1,7 @@
+if "AArch64" not in config.root.targets:
+ config.unsupported = True
+
+flags = "--target=aarch64-linux-gnu -nostartfiles -nostdlib -ffreestanding -Wl,--emit-relocs"
+
+config.substitutions.insert(0, ("%cflags", f"%cflags {flags}"))
+config.substitutions.insert(0, ("%cxxflags", f"%cxxflags {flags}"))
diff --git a/bolt/test/lit.cfg.py b/bolt/test/lit.cfg.py
index da3ae34ba3bdd..0d05229be2bf3 100644
--- a/bolt/test/lit.cfg.py
+++ b/bolt/test/lit.cfg.py
@@ -110,6 +110,7 @@
),
ToolSubst("llvm-boltdiff", unresolved="fatal"),
ToolSubst("llvm-bolt-heatmap", unresolved="fatal"),
+ ToolSubst("llvm-bolt-binary-analysis", unresolved="fatal"),
ToolSubst("llvm-bat-dump", unresolved="fatal"),
ToolSubst("perf2bolt", unresolved="fatal"),
ToolSubst("yaml2obj", unresolved="fatal"),
diff --git a/bolt/test/merge-fdata-bat-no-lbr.test b/bolt/test/merge-fdata-bat-no-lbr.test
new file mode 100644
index 0000000000000..fd5cd16263356
--- /dev/null
+++ b/bolt/test/merge-fdata-bat-no-lbr.test
@@ -0,0 +1,20 @@
+## Check that merge-fdata correctly handles merging two fdata files with both boltedcollection and no_lbr tags.
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: merge-fdata %t/a.fdata %t/b.fdata -o %t/merged.fdata
+# RUN: FileCheck %s --input-file %t/merged.fdata
+
+# CHECK: boltedcollection
+# CHECK: no_lbr
+# CHECK: main 2
+
+#--- a.fdata
+boltedcollection
+no_lbr
+main 1
+#--- b.fdata
+boltedcollection
+no_lbr
+main 1
diff --git a/bolt/test/merge-fdata-lbr-mode.test b/bolt/test/merge-fdata-lbr-mode.test
new file mode 100644
index 0000000000000..2cd3853194288
--- /dev/null
+++ b/bolt/test/merge-fdata-lbr-mode.test
@@ -0,0 +1,15 @@
+## Check that merge-fdata tool doesn't falsely print no_lbr when not in no-lbr mode
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: merge-fdata %t/a.fdata %t/b.fdata -o %t/merged.fdata
+# RUN: FileCheck %s --input-file %t/merged.fdata
+
+# CHECK-NOT: no_lbr
+# CHECK: 1 main 0 1 main 2 1 3
+
+#--- a.fdata
+1 main 0 1 main 2 0 1
+#--- b.fdata
+1 main 0 1 main 2 1 2
diff --git a/bolt/test/merge-fdata-mixed-bat-no-lbr.test b/bolt/test/merge-fdata-mixed-bat-no-lbr.test
new file mode 100644
index 0000000000000..eeb3a0e23b0cc
--- /dev/null
+++ b/bolt/test/merge-fdata-mixed-bat-no-lbr.test
@@ -0,0 +1,16 @@
+## Check that merge-fdata doesn't incorrectly merge two fdata files with boltedcollection and no_lbr tags.
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: not merge-fdata %t/a.fdata %t/b.fdata 2>&1 | FileCheck %s
+
+# CHECK: cannot mix profile with and without boltedcollection
+
+#--- a.fdata
+boltedcollection
+no_lbr
+main 1
+#--- b.fdata
+no_lbr
+main 1
diff --git a/bolt/test/merge-fdata-mixed-mode.test b/bolt/test/merge-fdata-mixed-mode.test
new file mode 100644
index 0000000000000..f897fec5d9db4
--- /dev/null
+++ b/bolt/test/merge-fdata-mixed-mode.test
@@ -0,0 +1,15 @@
+## Check that merge-fdata tool correctly reports error message
+## when trying to merge 'no-lbr' and 'lbr' profiles
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: not merge-fdata %t/a.fdata %t/b.fdata 2>&1 | FileCheck %s
+
+# CHECK: cannot mix profile with and without no_lbr
+
+#--- a.fdata
+no_lbr
+main 1
+#--- b.fdata
+main 1
diff --git a/bolt/test/merge-fdata-no-lbr-mode.test b/bolt/test/merge-fdata-no-lbr-mode.test
new file mode 100644
index 0000000000000..9dfad99f79994
--- /dev/null
+++ b/bolt/test/merge-fdata-no-lbr-mode.test
@@ -0,0 +1,18 @@
+## Check that merge-fdata tool correctly processes fdata files with header
+## string produced by no-lbr mode (no_lbr)
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: merge-fdata %t/a.fdata %t/b.fdata -o %t/merged.fdata
+# RUN: FileCheck %s --input-file %t/merged.fdata
+
+# CHECK: no_lbr
+# CHECK: main 2
+
+#--- a.fdata
+no_lbr
+main 1
+#--- b.fdata
+no_lbr
+main 1
diff --git a/bolt/test/unreadable-profile.test b/bolt/test/unreadable-profile.test
index fe1ca93f3221e..4c1cd8af0a62c 100644
--- a/bolt/test/unreadable-profile.test
+++ b/bolt/test/unreadable-profile.test
@@ -1,4 +1,4 @@
-REQUIRES: system-linux
+REQUIRES: system-linux, non-root-user
RUN: touch %t.profile && chmod 000 %t.profile
RUN: %clang %S/Inputs/hello.c -o %t
diff --git a/bolt/tools/CMakeLists.txt b/bolt/tools/CMakeLists.txt
index 22ea3b9bd805f..3383902cffc40 100644
--- a/bolt/tools/CMakeLists.txt
+++ b/bolt/tools/CMakeLists.txt
@@ -7,3 +7,4 @@ add_subdirectory(llvm-bolt-fuzzer)
add_subdirectory(bat-dump)
add_subdirectory(merge-fdata)
add_subdirectory(heatmap)
+add_subdirectory(binary-analysis)
diff --git a/bolt/tools/binary-analysis/CMakeLists.txt b/bolt/tools/binary-analysis/CMakeLists.txt
new file mode 100644
index 0000000000000..841fc5b371185
--- /dev/null
+++ b/bolt/tools/binary-analysis/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ MC
+ Object
+ Support
+ )
+
+add_bolt_tool(llvm-bolt-binary-analysis
+ binary-analysis.cpp
+ DISABLE_LLVM_LINK_LLVM_DYLIB
+ )
+
+target_link_libraries(llvm-bolt-binary-analysis
+ PRIVATE
+ LLVMBOLTRewrite
+ LLVMBOLTUtils
+ )
+
+add_dependencies(bolt llvm-bolt-binary-analysis)
diff --git a/bolt/tools/binary-analysis/binary-analysis.cpp b/bolt/tools/binary-analysis/binary-analysis.cpp
new file mode 100644
index 0000000000000..b03fee3e025ae
--- /dev/null
+++ b/bolt/tools/binary-analysis/binary-analysis.cpp
@@ -0,0 +1,122 @@
+//===- bolt/tools/binary-analysis/binary-analysis.cpp ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a generic binary analysis tool, where multiple different specific
+// binary analyses can be plugged in to. The binary analyses are mostly built
+// on top of BOLT components.
+//
+//===----------------------------------------------------------------------===//
+
+#include "bolt/Rewrite/RewriteInstance.h"
+#include "bolt/Utils/CommandLineOpts.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+#define DEBUG_TYPE "bolt"
+
+using namespace llvm;
+using namespace object;
+using namespace bolt;
+
+namespace opts {
+
+static cl::OptionCategory *BinaryAnalysisCategories[] = {
+ &BinaryAnalysisCategory};
+
+static cl::opt InputFilename(cl::Positional,
+ cl::desc(""),
+ cl::Required,
+ cl::cat(BinaryAnalysisCategory),
+ cl::sub(cl::SubCommand::getAll()));
+
+} // namespace opts
+
+static StringRef ToolName = "llvm-bolt-binary-analysis";
+
+static void report_error(StringRef Message, std::error_code EC) {
+ assert(EC);
+ errs() << ToolName << ": '" << Message << "': " << EC.message() << ".\n";
+ exit(1);
+}
+
+static void report_error(StringRef Message, Error E) {
+ assert(E);
+ errs() << ToolName << ": '" << Message << "': " << toString(std::move(E))
+ << ".\n";
+ exit(1);
+}
+
+void ParseCommandLine(int argc, char **argv) {
+ cl::HideUnrelatedOptions(ArrayRef(opts::BinaryAnalysisCategories));
+ // Register the target printer for --version.
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
+ cl::ParseCommandLineOptions(argc, argv, "BinaryAnalysis\n");
+}
+
+static std::string GetExecutablePath(const char *Argv0) {
+ SmallString<256> ExecutablePath(Argv0);
+ // Do a PATH lookup if Argv0 isn't a valid path.
+ if (!llvm::sys::fs::exists(ExecutablePath))
+ if (llvm::ErrorOr P =
+ llvm::sys::findProgramByName(ExecutablePath))
+ ExecutablePath = *P;
+ return std::string(ExecutablePath.str());
+}
+
+int main(int argc, char **argv) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+ PrettyStackTraceProgram X(argc, argv);
+
+ std::string ToolPath = GetExecutablePath(argv[0]);
+
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ // Initialize targets and assembly printers/parsers.
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+ llvm::InitializeAllDisassemblers();
+
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+
+ ParseCommandLine(argc, argv);
+
+ opts::BinaryAnalysisMode = true;
+
+ if (!sys::fs::exists(opts::InputFilename))
+ report_error(opts::InputFilename, errc::no_such_file_or_directory);
+
+ Expected> BinaryOrErr =
+ createBinary(opts::InputFilename);
+ if (Error E = BinaryOrErr.takeError())
+ report_error(opts::InputFilename, std::move(E));
+ Binary &Binary = *BinaryOrErr.get().getBinary();
+
+ if (auto *e = dyn_cast(&Binary)) {
+ auto RIOrErr = RewriteInstance::create(e, argc, argv, ToolPath);
+ if (Error E = RIOrErr.takeError())
+ report_error(opts::InputFilename, std::move(E));
+ RewriteInstance &RI = *RIOrErr.get();
+ if (Error E = RI.run())
+ report_error(opts::InputFilename, std::move(E));
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/bolt/tools/merge-fdata/merge-fdata.cpp b/bolt/tools/merge-fdata/merge-fdata.cpp
index 89ca46c1c0a8f..74a5f8ca2d477 100644
--- a/bolt/tools/merge-fdata/merge-fdata.cpp
+++ b/bolt/tools/merge-fdata/merge-fdata.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/ThreadPool.h"
#include
+#include
#include
#include
@@ -265,55 +266,70 @@ bool isYAML(const StringRef Filename) {
void mergeLegacyProfiles(const SmallVectorImpl &Filenames) {
errs() << "Using legacy profile format.\n";
std::optional BoltedCollection;
+ std::optional NoLBRCollection;
std::mutex BoltedCollectionMutex;
- typedef StringMap ProfileTy;
+ struct CounterTy {
+ uint64_t Exec{0};
+ uint64_t Mispred{0};
+ CounterTy &operator+=(const CounterTy &O) {
+ Exec += O.Exec;
+ Mispred += O.Mispred;
+ return *this;
+ }
+ CounterTy operator+(const CounterTy &O) { return *this += O; }
+ };
+ typedef StringMap ProfileTy;
auto ParseProfile = [&](const std::string &Filename, auto &Profiles) {
const llvm::thread::id tid = llvm::this_thread::get_id();
if (isYAML(Filename))
report_error(Filename, "cannot mix YAML and legacy formats");
- ErrorOr> MB =
- MemoryBuffer::getFileOrSTDIN(Filename);
- if (std::error_code EC = MB.getError())
- report_error(Filename, EC);
- StringRef Buf = MB.get()->getBuffer();
+ std::ifstream FdataFile(Filename, std::ios::in);
+ std::string FdataLine;
+ std::getline(FdataFile, FdataLine);
+
+ auto checkMode = [&](const std::string &Key, std::optional &Flag) {
+ const bool KeyIsSet = FdataLine.rfind(Key, 0) == 0;
+
+ if (!Flag.has_value())
+ Flag = KeyIsSet;
+ else if (*Flag != KeyIsSet)
+ report_error(Filename, "cannot mix profile with and without " + Key);
+ if (KeyIsSet)
+ // Advance line
+ std::getline(FdataFile, FdataLine);
+ };
+
ProfileTy *Profile;
{
std::lock_guard Lock(BoltedCollectionMutex);
// Check if the string "boltedcollection" is in the first line
- if (Buf.starts_with("boltedcollection\n")) {
- if (!BoltedCollection.value_or(true))
- report_error(
- Filename,
- "cannot mix profile collected in BOLT and non-BOLT deployments");
- BoltedCollection = true;
- Buf = Buf.drop_front(17);
- } else {
- if (BoltedCollection.value_or(false))
- report_error(
- Filename,
- "cannot mix profile collected in BOLT and non-BOLT deployments");
- BoltedCollection = false;
- }
-
+ checkMode("boltedcollection", BoltedCollection);
+ // Check if the string "no_lbr" is in the first line
+ // (or second line if BoltedCollection is true)
+ checkMode("no_lbr", NoLBRCollection);
Profile = &Profiles[tid];
}
- SmallVector Lines;
- SplitString(Buf, Lines, "\n");
- for (StringRef Line : Lines) {
- size_t Pos = Line.rfind(" ");
- if (Pos == StringRef::npos)
- report_error(Filename, "Malformed / corrupted profile");
- StringRef Signature = Line.substr(0, Pos);
- uint64_t Count;
- if (Line.substr(Pos + 1, Line.size() - Pos).getAsInteger(10, Count))
- report_error(Filename, "Malformed / corrupted profile counter");
+ do {
+ StringRef Line(FdataLine);
+ CounterTy Count;
+ auto [Signature, ExecCount] = Line.rsplit(' ');
+ if (ExecCount.getAsInteger(10, Count.Exec))
+ report_error(Filename, "Malformed / corrupted execution count");
+ // Only LBR profile has misprediction field
+ if (!NoLBRCollection.value_or(false)) {
+ auto [SignatureLBR, MispredCount] = Signature.rsplit(' ');
+ Signature = SignatureLBR;
+ if (MispredCount.getAsInteger(10, Count.Mispred))
+ report_error(Filename, "Malformed / corrupted misprediction count");
+ }
+
Count += Profile->lookup(Signature);
Profile->insert_or_assign(Signature, Count);
- }
+ } while (std::getline(FdataFile, FdataLine));
};
// The final reduction has non-trivial cost, make sure each thread has at
@@ -330,14 +346,20 @@ void mergeLegacyProfiles(const SmallVectorImpl &Filenames) {
ProfileTy MergedProfile;
for (const auto &[Thread, Profile] : ParsedProfiles)
for (const auto &[Key, Value] : Profile) {
- uint64_t Count = MergedProfile.lookup(Key) + Value;
+ CounterTy Count = MergedProfile.lookup(Key) + Value;
MergedProfile.insert_or_assign(Key, Count);
}
if (BoltedCollection.value_or(false))
output() << "boltedcollection\n";
- for (const auto &[Key, Value] : MergedProfile)
- output() << Key << " " << Value << "\n";
+ if (NoLBRCollection.value_or(false))
+ output() << "no_lbr\n";
+ for (const auto &[Key, Value] : MergedProfile) {
+ output() << Key << " ";
+ if (!NoLBRCollection.value_or(false))
+ output() << Value.Mispred << " ";
+ output() << Value.Exec << "\n";
+ }
errs() << "Profile from " << Filenames.size() << " files merged.\n";
}
diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp
index 05b898d34af56..9819a8c2b777b 100644
--- a/bolt/unittests/Core/BinaryContext.cpp
+++ b/bolt/unittests/Core/BinaryContext.cpp
@@ -48,7 +48,8 @@ struct BinaryContextTester : public testing::TestWithParam {
void initializeBOLT() {
Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
- ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true,
+ ObjFile->makeTriple(), std::make_shared(),
+ ObjFile->getFileName(), nullptr, true,
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
ASSERT_FALSE(!BC);
}
@@ -216,4 +217,4 @@ TEST_P(BinaryContextTester, BaseAddressSegmentsSmallerThanAlignment) {
BC->getBaseAddressForMapping(0xaaaaaaab1000, 0x1000);
ASSERT_TRUE(BaseAddress.has_value());
ASSERT_EQ(*BaseAddress, 0xaaaaaaaa0000ULL);
-}
\ No newline at end of file
+}
diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp
index cd6f24c4570a7..5488cae366284 100644
--- a/bolt/unittests/Core/MCPlusBuilder.cpp
+++ b/bolt/unittests/Core/MCPlusBuilder.cpp
@@ -58,7 +58,8 @@ struct MCPlusBuilderTester : public testing::TestWithParam {
void initializeBolt() {
Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
- ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true,
+ ObjFile->makeTriple(), std::make_shared(),
+ ObjFile->getFileName(), nullptr, true,
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
ASSERT_FALSE(!BC);
BC->initializeTarget(std::unique_ptr(
diff --git a/bolt/unittests/Core/MemoryMaps.cpp b/bolt/unittests/Core/MemoryMaps.cpp
index 230fd314142e8..06073d0a82e14 100644
--- a/bolt/unittests/Core/MemoryMaps.cpp
+++ b/bolt/unittests/Core/MemoryMaps.cpp
@@ -59,7 +59,8 @@ struct MemoryMapsTester : public testing::TestWithParam {
void initializeBOLT() {
Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
- ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true,
+ ObjFile->makeTriple(), std::make_shared(),
+ ObjFile->getFileName(), nullptr, true,
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
ASSERT_FALSE(!BC);
}
diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 795eb4b904e3e..28b645cf021dd 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -157,17 +157,17 @@ static void genMarkdown(const ClangDocContext &CDCtx, const FunctionInfo &I,
for (const auto &N : I.Params) {
if (!First)
Stream << ", ";
- Stream << N.Type.Name + " " + N.Name;
+ Stream << N.Type.QualName + " " + N.Name;
First = false;
}
writeHeader(I.Name, 3, OS);
std::string Access = getAccessSpelling(I.Access).str();
if (Access != "")
- writeLine(genItalic(Access + " " + I.ReturnType.Type.Name + " " + I.Name +
- "(" + Stream.str() + ")"),
+ writeLine(genItalic(Access + " " + I.ReturnType.Type.QualName + " " +
+ I.Name + "(" + Stream.str() + ")"),
OS);
else
- writeLine(genItalic(I.ReturnType.Type.Name + " " + I.Name + "(" +
+ writeLine(genItalic(I.ReturnType.Type.QualName + " " + I.Name + "(" +
Stream.str() + ")"),
OS);
if (I.DefLoc)
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index 97e16a12febd0..ff42f96a0477b 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -81,6 +81,9 @@ class ClangTidyContext {
~ClangTidyContext();
+ ClangTidyContext(const ClangTidyContext &) = delete;
+ ClangTidyContext &operator=(const ClangTidyContext &) = delete;
+
/// Report any errors detected using this method.
///
/// This is still under heavy development and will likely change towards using
diff --git a/clang-tools-extra/clang-tidy/NoLintDirectiveHandler.h b/clang-tools-extra/clang-tidy/NoLintDirectiveHandler.h
index e862195abaabb..f66285672d04a 100644
--- a/clang-tools-extra/clang-tidy/NoLintDirectiveHandler.h
+++ b/clang-tools-extra/clang-tidy/NoLintDirectiveHandler.h
@@ -31,6 +31,8 @@ class NoLintDirectiveHandler {
public:
NoLintDirectiveHandler();
~NoLintDirectiveHandler();
+ NoLintDirectiveHandler(const NoLintDirectiveHandler &) = delete;
+ NoLintDirectiveHandler &operator=(const NoLintDirectiveHandler &) = delete;
bool shouldSuppress(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Diag, llvm::StringRef DiagName,
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index b0a2318acc059..13adad7c3dadb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -16,6 +16,7 @@ add_clang_library(clangTidyBugproneModule STATIC
ChainedComparisonCheck.cpp
ComparePointerToMemberVirtualFunctionCheck.cpp
CopyConstructorInitCheck.cpp
+ CrtpConstructorAccessibilityCheck.cpp
DanglingHandleCheck.cpp
DynamicStaticInitializersCheck.cpp
EasilySwappableParametersCheck.cpp
@@ -26,11 +27,8 @@ add_clang_library(clangTidyBugproneModule STATIC
ForwardingReferenceOverloadCheck.cpp
ImplicitWideningOfMultiplicationResultCheck.cpp
InaccurateEraseCheck.cpp
- IncorrectEnableIfCheck.cpp
- ReturnConstRefFromParameterCheck.cpp
- SuspiciousStringviewDataUsageCheck.cpp
- SwitchMissingDefaultCaseCheck.cpp
IncDecInConditionsCheck.cpp
+ IncorrectEnableIfCheck.cpp
IncorrectRoundingsCheck.cpp
InfiniteLoopCheck.cpp
IntegerDivisionCheck.cpp
@@ -45,8 +43,8 @@ add_clang_library(clangTidyBugproneModule STATIC
MultipleNewInOneExpressionCheck.cpp
MultipleStatementMacroCheck.cpp
NoEscapeCheck.cpp
- NondeterministicPointerIterationOrderCheck.cpp
NonZeroEnumToBoolConversionCheck.cpp
+ NondeterministicPointerIterationOrderCheck.cpp
NotNullTerminatedResultCheck.cpp
OptionalValueConversionCheck.cpp
ParentVirtualCallCheck.cpp
@@ -54,6 +52,7 @@ add_clang_library(clangTidyBugproneModule STATIC
PosixReturnCheck.cpp
RedundantBranchConditionCheck.cpp
ReservedIdentifierCheck.cpp
+ ReturnConstRefFromParameterCheck.cpp
SharedPtrArrayMismatchCheck.cpp
SignalHandlerCheck.cpp
SignedCharMisuseCheck.cpp
@@ -74,7 +73,9 @@ add_clang_library(clangTidyBugproneModule STATIC
SuspiciousReallocUsageCheck.cpp
SuspiciousSemicolonCheck.cpp
SuspiciousStringCompareCheck.cpp
+ SuspiciousStringviewDataUsageCheck.cpp
SwappedArgumentsCheck.cpp
+ SwitchMissingDefaultCaseCheck.cpp
TaggedUnionMemberCountCheck.cpp
TerminatingContinueCheck.cpp
ThrowKeywordMissingCheck.cpp
@@ -85,7 +86,6 @@ add_clang_library(clangTidyBugproneModule STATIC
UnhandledExceptionAtNewCheck.cpp
UnhandledSelfAssignmentCheck.cpp
UniquePtrArrayMismatchCheck.cpp
- CrtpConstructorAccessibilityCheck.cpp
UnsafeFunctionsCheck.cpp
UnusedLocalNonTrivialVariableCheck.cpp
UnusedRaiiCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index 2b2d80ea9346b..b7f0c08b2a7d4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -13,13 +13,15 @@
#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
#include "clang/Analysis/CallGraph.h"
#include "llvm/ADT/SCCIterator.h"
-#include "llvm/ADT/SmallVector.h"
using namespace clang::ast_matchers;
+using clang::ast_matchers::internal::Matcher;
using clang::tidy::utils::hasPtrOrReferenceInFunc;
namespace clang {
-namespace ast_matchers {
+namespace tidy::bugprone {
+
+namespace {
/// matches a Decl if it has a "no return" attribute of any kind
AST_MATCHER(Decl, declHasNoReturnAttr) {
return Node.hasAttr() || Node.hasAttr() ||
@@ -30,23 +32,21 @@ AST_MATCHER(Decl, declHasNoReturnAttr) {
AST_MATCHER(FunctionType, typeHasNoReturnAttr) {
return Node.getNoReturnAttr();
}
-} // namespace ast_matchers
-namespace tidy::bugprone {
+} // namespace
-static internal::Matcher
-loopEndingStmt(internal::Matcher Internal) {
- internal::Matcher isNoReturnFunType =
+static Matcher loopEndingStmt(Matcher Internal) {
+ Matcher IsNoReturnFunType =
ignoringParens(functionType(typeHasNoReturnAttr()));
- internal::Matcher isNoReturnDecl =
- anyOf(declHasNoReturnAttr(), functionDecl(hasType(isNoReturnFunType)),
- varDecl(hasType(blockPointerType(pointee(isNoReturnFunType)))));
+ Matcher IsNoReturnDecl =
+ anyOf(declHasNoReturnAttr(), functionDecl(hasType(IsNoReturnFunType)),
+ varDecl(hasType(blockPointerType(pointee(IsNoReturnFunType)))));
return stmt(anyOf(
mapAnyOf(breakStmt, returnStmt, gotoStmt, cxxThrowExpr).with(Internal),
callExpr(Internal,
callee(mapAnyOf(functionDecl, /* block callee */ varDecl)
- .with(isNoReturnDecl))),
- objcMessageExpr(Internal, callee(isNoReturnDecl))));
+ .with(IsNoReturnDecl))),
+ objcMessageExpr(Internal, callee(IsNoReturnDecl))));
}
/// Return whether `Var` was changed in `LoopStmt`.
diff --git a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp
index 600eab3755276..55ca4809f058a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp
@@ -12,20 +12,43 @@
#include "../utils/OptionsUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include
using namespace clang::ast_matchers;
+using clang::ast_matchers::internal::Matcher;
namespace clang::tidy::bugprone {
namespace {
-AST_MATCHER_P(QualType, hasCleanType, ast_matchers::internal::Matcher,
- InnerMatcher) {
+AST_MATCHER_P(QualType, hasCleanType, Matcher, InnerMatcher) {
return InnerMatcher.matches(
Node.getNonReferenceType().getUnqualifiedType().getCanonicalType(),
Finder, Builder);
}
+constexpr std::array NameList{
+ "::std::make_unique",
+ "::std::make_shared",
+};
+
+Matcher constructFrom(Matcher TypeMatcher,
+ Matcher ArgumentMatcher) {
+ return expr(
+ anyOf(
+ // construct optional
+ cxxConstructExpr(argumentCountIs(1U), hasType(TypeMatcher),
+ hasArgument(0U, ArgumentMatcher)),
+ // known template methods in std
+ callExpr(argumentCountIs(1),
+ callee(functionDecl(
+ matchers::matchesAnyListedName(NameList),
+ hasTemplateArgument(0, refersToType(TypeMatcher)))),
+ hasArgument(0, ArgumentMatcher))),
+ unless(anyOf(hasAncestor(typeLoc()),
+ hasAncestor(expr(matchers::hasUnevaluatedContext())))));
+}
+
} // namespace
OptionalValueConversionCheck::OptionalValueConversionCheck(
@@ -43,18 +66,20 @@ OptionalValueConversionCheck::getCheckTraversalKind() const {
}
void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) {
- auto ConstructTypeMatcher =
- qualType(hasCleanType(qualType().bind("optional-type")));
+ auto BindOptionalType = qualType(
+ hasCleanType(qualType(hasDeclaration(namedDecl(
+ matchers::matchesAnyListedName(OptionalTypes))))
+ .bind("optional-type")));
- auto CallTypeMatcher =
+ auto EqualsBoundOptionalType =
qualType(hasCleanType(equalsBoundNode("optional-type")));
auto OptionalDereferenceMatcher = callExpr(
anyOf(
cxxOperatorCallExpr(hasOverloadedOperatorName("*"),
- hasUnaryOperand(hasType(CallTypeMatcher)))
+ hasUnaryOperand(hasType(EqualsBoundOptionalType)))
.bind("op-call"),
- cxxMemberCallExpr(thisPointerType(CallTypeMatcher),
+ cxxMemberCallExpr(thisPointerType(EqualsBoundOptionalType),
callee(cxxMethodDecl(anyOf(
hasOverloadedOperatorName("*"),
matchers::matchesAnyListedName(ValueMethods)))))
@@ -65,15 +90,9 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) {
callExpr(argumentCountIs(1), callee(functionDecl(hasName("::std::move"))),
hasArgument(0, ignoringImpCasts(OptionalDereferenceMatcher)));
Finder->addMatcher(
- cxxConstructExpr(
- argumentCountIs(1U),
- hasDeclaration(cxxConstructorDecl(
- ofClass(matchers::matchesAnyListedName(OptionalTypes)))),
- hasType(ConstructTypeMatcher),
- hasArgument(0U, ignoringImpCasts(anyOf(OptionalDereferenceMatcher,
- StdMoveCallMatcher))),
- unless(anyOf(hasAncestor(typeLoc()),
- hasAncestor(expr(matchers::hasUnevaluatedContext())))))
+ expr(constructFrom(BindOptionalType,
+ ignoringImpCasts(anyOf(OptionalDereferenceMatcher,
+ StdMoveCallMatcher))))
.bind("expr"),
this);
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp
index 1bd7abbad66d2..295955a971d7e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp
@@ -31,21 +31,20 @@ void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) {
qualType(lValueReferenceType(pointee(
qualType(isConstQualified()))))
.bind("type"))),
- hasDeclContext(functionDecl().bind("owner")),
+ hasDeclContext(functionDecl(
+ equalsBoundNode("func"),
+ hasReturnTypeLoc(loc(qualType(
+ hasCanonicalType(equalsBoundNode("type"))))))),
unless(hasLifetimeBoundAttr()))
.bind("param")))
.bind("dref"));
- const auto Func =
- functionDecl(equalsBoundNode("owner"),
- hasReturnTypeLoc(loc(
- qualType(hasCanonicalType(equalsBoundNode("type"))))))
- .bind("func");
- Finder->addMatcher(returnStmt(hasReturnValue(DRef), hasAncestor(Func)), this);
Finder->addMatcher(
- returnStmt(hasReturnValue(ignoringParens(conditionalOperator(
- eachOf(hasTrueExpression(DRef), hasFalseExpression(DRef)),
- hasAncestor(Func))))),
+ returnStmt(
+ hasAncestor(functionDecl().bind("func")),
+ hasReturnValue(anyOf(
+ DRef, ignoringParens(conditionalOperator(eachOf(
+ hasTrueExpression(DRef), hasFalseExpression(DRef))))))),
this);
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.h b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.h
index 2d1570f7df8ab..e2fcccbfefb26 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.h
@@ -12,7 +12,6 @@
#include "../ClangTidyCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h"
-#include
namespace clang::tidy::bugprone {
@@ -26,8 +25,7 @@ class UncheckedOptionalAccessCheck : public ClangTidyCheck {
public:
UncheckedOptionalAccessCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
- ModelOptions{
- Options.getLocalOrGlobal("IgnoreSmartPointerDereference", false)} {}
+ ModelOptions{Options.get("IgnoreSmartPointerDereference", false)} {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
index 225e867c9b24f..d665c47d12bb4 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -277,7 +277,7 @@ ProTypeMemberInitCheck::ProTypeMemberInitCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IgnoreArrays(Options.get("IgnoreArrays", false)),
- UseAssignment(Options.getLocalOrGlobal("UseAssignment", false)) {}
+ UseAssignment(Options.get("UseAssignment", false)) {}
void ProTypeMemberInitCheck::registerMatchers(MatchFinder *Finder) {
auto IsUserProvidedNonDelegatingConstructor =
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp
index 7db9e29e8fd0e..8c386d5bc7945 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp
@@ -119,11 +119,10 @@ void RvalueReferenceParamNotMovedCheck::check(
RvalueReferenceParamNotMovedCheck::RvalueReferenceParamNotMovedCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
- AllowPartialMove(Options.getLocalOrGlobal("AllowPartialMove", false)),
- IgnoreUnnamedParams(
- Options.getLocalOrGlobal("IgnoreUnnamedParams", false)),
+ AllowPartialMove(Options.get("AllowPartialMove", false)),
+ IgnoreUnnamedParams(Options.get("IgnoreUnnamedParams", false)),
IgnoreNonDeducedTemplateTypes(
- Options.getLocalOrGlobal("IgnoreNonDeducedTemplateTypes", false)) {}
+ Options.get("IgnoreNonDeducedTemplateTypes", false)) {}
void RvalueReferenceParamNotMovedCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873..bab1167fb15ff 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -36,6 +36,7 @@ add_clang_library(clangTidyModernizeModule STATIC
UseEmplaceCheck.cpp
UseEqualsDefaultCheck.cpp
UseEqualsDeleteCheck.cpp
+ UseIntegerSignComparisonCheck.cpp
UseNodiscardCheck.cpp
UseNoexceptCheck.cpp
UseNullptrCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 1860759332063..fc46c72982fdc 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -37,6 +37,7 @@
#include "UseEmplaceCheck.h"
#include "UseEqualsDefaultCheck.h"
#include "UseEqualsDeleteCheck.h"
+#include "UseIntegerSignComparisonCheck.h"
#include "UseNodiscardCheck.h"
#include "UseNoexceptCheck.h"
#include "UseNullptrCheck.h"
@@ -76,6 +77,8 @@ class ModernizeModule : public ClangTidyModule {
CheckFactories.registerCheck("modernize-pass-by-value");
CheckFactories.registerCheck(
"modernize-use-designated-initializers");
+ CheckFactories.registerCheck(
+ "modernize-use-integer-sign-comparison");
CheckFactories.registerCheck("modernize-use-ranges");
CheckFactories.registerCheck(
"modernize-use-starts-ends-with");
diff --git a/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp
new file mode 100644
index 0000000000000..8f807bc0a96d5
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.cpp
@@ -0,0 +1,171 @@
+//===--- UseIntegerSignComparisonCheck.cpp - clang-tidy -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseIntegerSignComparisonCheck.h"
+#include "clang/AST/Expr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang::tidy::modernize {
+
+/// Find if the passed type is the actual "char" type,
+/// not applicable to explicit "signed char" or "unsigned char" types.
+static bool isActualCharType(const clang::QualType &Ty) {
+ using namespace clang;
+ const Type *DesugaredType = Ty->getUnqualifiedDesugaredType();
+ if (const auto *BT = llvm::dyn_cast(DesugaredType))
+ return (BT->getKind() == BuiltinType::Char_U ||
+ BT->getKind() == BuiltinType::Char_S);
+ return false;
+}
+
+namespace {
+AST_MATCHER(clang::QualType, isActualChar) {
+ return clang::tidy::modernize::isActualCharType(Node);
+}
+} // namespace
+
+static BindableMatcher
+intCastExpression(bool IsSigned,
+ const std::string &CastBindName = std::string()) {
+ // std::cmp_{} functions trigger a compile-time error if either LHS or RHS
+ // is a non-integer type, char, enum or bool
+ // (unsigned char/ signed char are Ok and can be used).
+ auto IntTypeExpr = expr(hasType(hasCanonicalType(qualType(
+ isInteger(), IsSigned ? isSignedInteger() : isUnsignedInteger(),
+ unless(isActualChar()), unless(booleanType()), unless(enumType())))));
+
+ const auto ImplicitCastExpr =
+ CastBindName.empty() ? implicitCastExpr(hasSourceExpression(IntTypeExpr))
+ : implicitCastExpr(hasSourceExpression(IntTypeExpr))
+ .bind(CastBindName);
+
+ const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
+ const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
+ const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
+
+ return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr,
+ FunctionalCastExpr));
+}
+
+static StringRef parseOpCode(BinaryOperator::Opcode Code) {
+ switch (Code) {
+ case BO_LT:
+ return "cmp_less";
+ case BO_GT:
+ return "cmp_greater";
+ case BO_LE:
+ return "cmp_less_equal";
+ case BO_GE:
+ return "cmp_greater_equal";
+ case BO_EQ:
+ return "cmp_equal";
+ case BO_NE:
+ return "cmp_not_equal";
+ default:
+ return "";
+ }
+}
+
+UseIntegerSignComparisonCheck::UseIntegerSignComparisonCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+ utils::IncludeSorter::IS_LLVM),
+ areDiagsSelfContained()) {}
+
+void UseIntegerSignComparisonCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseIntegerSignComparisonCheck::registerMatchers(MatchFinder *Finder) {
+ const auto SignedIntCastExpr = intCastExpression(true, "sIntCastExpression");
+ const auto UnSignedIntCastExpr = intCastExpression(false);
+
+ // Flag all operators "==", "<=", ">=", "<", ">", "!="
+ // that are used between signed/unsigned
+ const auto CompareOperator =
+ binaryOperator(hasAnyOperatorName("==", "<=", ">=", "<", ">", "!="),
+ hasOperands(SignedIntCastExpr, UnSignedIntCastExpr),
+ unless(isInTemplateInstantiation()))
+ .bind("intComparison");
+
+ Finder->addMatcher(CompareOperator, this);
+}
+
+void UseIntegerSignComparisonCheck::registerPPCallbacks(
+ const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
+ IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseIntegerSignComparisonCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *SignedCastExpression =
+ Result.Nodes.getNodeAs("sIntCastExpression");
+ assert(SignedCastExpression);
+
+ // Ignore the match if we know that the signed int value is not negative.
+ Expr::EvalResult EVResult;
+ if (!SignedCastExpression->isValueDependent() &&
+ SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
+ *Result.Context)) {
+ const llvm::APSInt SValue = EVResult.Val.getInt();
+ if (SValue.isNonNegative())
+ return;
+ }
+
+ const auto *BinaryOp =
+ Result.Nodes.getNodeAs("intComparison");
+ if (BinaryOp == nullptr)
+ return;
+
+ const BinaryOperator::Opcode OpCode = BinaryOp->getOpcode();
+
+ const Expr *LHS = BinaryOp->getLHS()->IgnoreImpCasts();
+ const Expr *RHS = BinaryOp->getRHS()->IgnoreImpCasts();
+ if (LHS == nullptr || RHS == nullptr)
+ return;
+ const Expr *SubExprLHS = nullptr;
+ const Expr *SubExprRHS = nullptr;
+ SourceRange R1 = SourceRange(LHS->getBeginLoc());
+ SourceRange R2 = SourceRange(BinaryOp->getOperatorLoc());
+ SourceRange R3 = SourceRange(Lexer::getLocForEndOfToken(
+ RHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
+ if (const auto *LHSCast = llvm::dyn_cast(LHS)) {
+ SubExprLHS = LHSCast->getSubExpr();
+ R1 = SourceRange(LHS->getBeginLoc(),
+ SubExprLHS->getBeginLoc().getLocWithOffset(-1));
+ R2.setBegin(Lexer::getLocForEndOfToken(
+ SubExprLHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
+ }
+ if (const auto *RHSCast = llvm::dyn_cast(RHS)) {
+ SubExprRHS = RHSCast->getSubExpr();
+ R2.setEnd(SubExprRHS->getBeginLoc().getLocWithOffset(-1));
+ }
+ DiagnosticBuilder Diag =
+ diag(BinaryOp->getBeginLoc(),
+ "comparison between 'signed' and 'unsigned' integers");
+ const std::string CmpNamespace = ("std::" + parseOpCode(OpCode)).str();
+ const std::string CmpHeader = "";
+ // Prefer modernize-use-integer-sign-comparison when C++20 is available!
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange(R1, SubExprLHS != nullptr),
+ llvm::Twine(CmpNamespace + "(").str());
+ Diag << FixItHint::CreateReplacement(R2, ",");
+ Diag << FixItHint::CreateReplacement(CharSourceRange::getCharRange(R3), ")");
+
+ // If there is no include for cmp_{*} functions, we'll add it.
+ Diag << IncludeInserter.createIncludeInsertion(
+ Result.SourceManager->getFileID(BinaryOp->getBeginLoc()), CmpHeader);
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.h b/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.h
new file mode 100644
index 0000000000000..a1074829d6eca
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseIntegerSignComparisonCheck.h
@@ -0,0 +1,42 @@
+//===--- UseIntegerSignComparisonCheck.h - clang-tidy -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEINTEGERSIGNCOMPARISONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEINTEGERSIGNCOMPARISONCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang::tidy::modernize {
+
+/// Replace comparisons between signed and unsigned integers with their safe
+/// C++20 ``std::cmp_*`` alternative, if available.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-integer-sign-comparison.html
+class UseIntegerSignComparisonCheck : public ClangTidyCheck {
+public:
+ UseIntegerSignComparisonCheck(StringRef Name, ClangTidyContext *Context);
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus20;
+ }
+
+private:
+ utils::IncludeInserter IncludeInserter;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEINTEGERSIGNCOMPARISONCHECK_H
diff --git a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
index dc6e0cf9c7d12..94cb7ec38087a 100644
--- a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
@@ -77,7 +77,7 @@ InefficientVectorOperationCheck::InefficientVectorOperationCheck(
: ClangTidyCheck(Name, Context),
VectorLikeClasses(utils::options::parseStringList(
Options.get("VectorLikeClasses", "::std::vector"))),
- EnableProto(Options.getLocalOrGlobal("EnableProto", false)) {}
+ EnableProto(Options.get("EnableProto", false)) {}
void InefficientVectorOperationCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantAccessSpecifiersCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantAccessSpecifiersCheck.h
index a5389d063f6cf..566e5ea637986 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantAccessSpecifiersCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantAccessSpecifiersCheck.h
@@ -21,8 +21,7 @@ class RedundantAccessSpecifiersCheck : public ClangTidyCheck {
public:
RedundantAccessSpecifiersCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
- CheckFirstDeclaration(
- Options.getLocalOrGlobal("CheckFirstDeclaration", false)) {}
+ CheckFirstDeclaration(Options.get("CheckFirstDeclaration", false)) {}
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus;
}
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
index b9ff0e81cbc52..4d5adbe02f525 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
@@ -94,7 +94,7 @@ RedundantCastingCheck::RedundantCastingCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
- IgnoreTypeAliases(Options.getLocalOrGlobal("IgnoreTypeAliases", false)) {}
+ IgnoreTypeAliases(Options.get("IgnoreTypeAliases", false)) {}
void RedundantCastingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoreMacros", IgnoreMacros);
diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
index 88e4886cd0df9..9104723c7f1c0 100644
--- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
@@ -397,7 +397,7 @@ RenamerClangTidyCheck::RenamerClangTidyCheck(StringRef CheckName,
ClangTidyContext *Context)
: ClangTidyCheck(CheckName, Context),
AggressiveDependentMemberLookup(
- Options.getLocalOrGlobal("AggressiveDependentMemberLookup", false)) {}
+ Options.get("AggressiveDependentMemberLookup", false)) {}
RenamerClangTidyCheck::~RenamerClangTidyCheck() = default;
void RenamerClangTidyCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h
index 597fd9de7ff68..f43734ec1ede3 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.h
+++ b/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -73,6 +73,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks,
/// The destructor blocks on any outstanding background tasks.
~ClangdLSPServer();
+ ClangdLSPServer(const ClangdLSPServer &other) = delete;
+ ClangdLSPServer &operator=(const ClangdLSPServer &other) = delete;
+
/// Run LSP server loop, communicating with the Transport provided in the
/// constructor. This method must not be executed more than once.
///
diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp
index fddfffe7523d9..207e4c3e6722c 100644
--- a/clang-tools-extra/clangd/CompileCommands.cpp
+++ b/clang-tools-extra/clangd/CompileCommands.cpp
@@ -458,20 +458,6 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) {
PrevAlias[Self] = T;
NextAlias[T] = Self;
};
- // Also grab prefixes for each option, these are not fully exposed.
- llvm::ArrayRef Prefixes[DriverID::LastOption];
-
-#define PREFIX(NAME, VALUE) \
- static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
- static constexpr llvm::ArrayRef NAME( \
- NAME##_init, std::size(NAME##_init) - 1);
-#define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
- FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \
- METAVAR, VALUES) \
- Prefixes[DriverID::OPT_##ID] = PREFIX;
-#include "clang/Driver/Options.inc"
-#undef OPTION
-#undef PREFIX
struct {
DriverID ID;
@@ -498,7 +484,9 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) {
llvm::SmallVector Rules;
// Iterate over each alias, to add rules for parsing it.
for (unsigned A = ID; A != DriverID::OPT_INVALID; A = NextAlias[A]) {
- if (!Prefixes[A].size()) // option groups.
+ llvm::SmallVector Prefixes;
+ DriverTable.appendOptionPrefixes(A, Prefixes);
+ if (Prefixes.empty()) // option groups.
continue;
auto Opt = DriverTable.getOption(A);
// Exclude - and -foo pseudo-options.
@@ -507,7 +495,7 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) {
auto Modes = getModes(Opt);
std::pair ArgCount = getArgCount(Opt);
// Iterate over each spelling of the alias, e.g. -foo vs --foo.
- for (StringRef Prefix : Prefixes[A]) {
+ for (StringRef Prefix : Prefixes) {
llvm::SmallString<64> Buf(Prefix);
Buf.append(Opt.getName());
llvm::StringRef Spelling = Result->try_emplace(Buf).first->getKey();
diff --git a/clang-tools-extra/clangd/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp
index 26d54200eeffd..9eb892e8e4a8e 100644
--- a/clang-tools-extra/clangd/HeuristicResolver.cpp
+++ b/clang-tools-extra/clangd/HeuristicResolver.cpp
@@ -118,6 +118,16 @@ const Type *resolveDeclsToType(const std::vector &Decls,
return nullptr;
}
+TemplateName getReferencedTemplateName(const Type *T) {
+ if (const auto *TST = T->getAs()) {
+ return TST->getTemplateName();
+ }
+ if (const auto *DTST = T->getAs()) {
+ return DTST->getTemplateName();
+ }
+ return TemplateName();
+}
+
// Helper function for HeuristicResolver::resolveDependentMember()
// which takes a possibly-dependent type `T` and heuristically
// resolves it to a CXXRecordDecl in which we can try name lookup.
@@ -142,12 +152,12 @@ CXXRecordDecl *HeuristicResolverImpl::resolveTypeToRecordDecl(const Type *T) {
if (!T)
return nullptr;
- const auto *TST = T->getAs();
- if (!TST)
+ TemplateName TN = getReferencedTemplateName(T);
+ if (TN.isNull())
return nullptr;
- const ClassTemplateDecl *TD = dyn_cast_or_null(
- TST->getTemplateName().getAsTemplateDecl());
+ const ClassTemplateDecl *TD =
+ dyn_cast_or_null(TN.getAsTemplateDecl());
if (!TD)
return nullptr;
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index 29508901f85bb..bee31fe51555e 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -199,7 +199,7 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
SourceManager SourceMgr(*Diags, FileMgr);
- HeaderSearch HeaderInfo(HSOpts, SourceMgr, *Diags, LangOpts,
+ HeaderSearch HeaderInfo(std::move(HSOpts), SourceMgr, *Diags, LangOpts,
/*Target=*/nullptr);
TrivialModuleLoader ModuleLoader;
diff --git a/clang-tools-extra/clangd/ParsedAST.h b/clang-tools-extra/clangd/ParsedAST.h
index 63e564bd68a78..8d9d1e6456926 100644
--- a/clang-tools-extra/clangd/ParsedAST.h
+++ b/clang-tools-extra/clangd/ParsedAST.h
@@ -59,6 +59,9 @@ class ParsedAST {
~ParsedAST();
+ ParsedAST(const ParsedAST &Other) = delete;
+ ParsedAST &operator=(const ParsedAST &Other) = delete;
+
/// Note that the returned ast will not contain decls from the preamble that
/// were not deserialized during parsing. Clients should expect only decls
/// from the main file to be in the AST.
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp
index 71548b59cc308..035e5e63d8fbb 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -411,6 +411,9 @@ class PreambleThrottlerRequest {
if (Throttler)
Throttler->release(ID);
}
+ PreambleThrottlerRequest(const PreambleThrottlerRequest &) = delete;
+ PreambleThrottlerRequest &
+ operator=(const PreambleThrottlerRequest &) = delete;
private:
PreambleThrottler::RequestID ID;
@@ -621,7 +624,8 @@ class ASTWorker {
AsyncTaskRunner *Tasks, Semaphore &Barrier,
const TUScheduler::Options &Opts, ParsingCallbacks &Callbacks);
~ASTWorker();
-
+ ASTWorker(const ASTWorker &other) = delete;
+ ASTWorker &operator=(const ASTWorker &other) = delete;
void update(ParseInputs Inputs, WantDiagnostics, bool ContentChanged);
void
runWithAST(llvm::StringRef Name,
diff --git a/clang-tools-extra/clangd/TUScheduler.h b/clang-tools-extra/clangd/TUScheduler.h
index fb936d46bbcf7..d0da20310a8b2 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -242,6 +242,9 @@ class TUScheduler {
std::unique_ptr ASTCallbacks = nullptr);
~TUScheduler();
+ TUScheduler(const TUScheduler &other) = delete;
+ TUScheduler &operator=(const TUScheduler &other) = delete;
+
struct FileStats {
std::size_t UsedBytesAST = 0;
std::size_t UsedBytesPreamble = 0;
diff --git a/clang-tools-extra/clangd/index/MemIndex.h b/clang-tools-extra/clangd/index/MemIndex.h
index 8f390c5028dc4..fb1052b0c7ca8 100644
--- a/clang-tools-extra/clangd/index/MemIndex.h
+++ b/clang-tools-extra/clangd/index/MemIndex.h
@@ -97,7 +97,7 @@ class MemIndex : public SymbolIndex {
// Set of files which were used during this index build.
llvm::StringSet<> Files;
// Contents of the index (symbols, references, etc.)
- IndexContents IdxContents;
+ IndexContents IdxContents = IndexContents::None;
std::shared_ptr KeepAlive; // poor man's move-only std::any
// Size of memory retained by KeepAlive.
size_t BackingDataSize = 0;
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index 81125dbb1aeaf..6d0af20e31260 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -550,9 +550,14 @@ bool SymbolCollector::shouldCollectSymbol(const NamedDecl &ND,
// Avoid indexing internal symbols in protobuf generated headers.
if (isPrivateProtoDecl(ND))
return false;
+
+ // System headers that end with `intrin.h` likely contain useful symbols.
if (!Opts.CollectReserved &&
(hasReservedName(ND) || hasReservedScope(*ND.getDeclContext())) &&
- ASTCtx.getSourceManager().isInSystemHeader(ND.getLocation()))
+ ASTCtx.getSourceManager().isInSystemHeader(ND.getLocation()) &&
+ !ASTCtx.getSourceManager()
+ .getFilename(ND.getLocation())
+ .ends_with("intrin.h"))
return false;
return true;
diff --git a/clang-tools-extra/clangd/index/dex/Dex.h b/clang-tools-extra/clangd/index/dex/Dex.h
index 20c0503d19b97..502f597d81ef0 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.h
+++ b/clang-tools-extra/clangd/index/dex/Dex.h
@@ -146,7 +146,9 @@ class Dex : public SymbolIndex {
// Set of files which were used during this index build.
llvm::StringSet<> Files;
// Contents of the index (symbols, references, etc.)
- IndexContents IdxContents;
+ // This is only populated if `Files` is, which applies to some but not all
+ // consumers of this class.
+ IndexContents IdxContents = IndexContents::None;
// Size of memory retained by KeepAlive.
size_t BackingDataSize = 0;
};
diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
index 3b378153eafd5..d84e501b87ce7 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp
@@ -49,7 +49,8 @@ class ExtractionContext {
llvm::StringRef VarName) const;
// Generate Replacement for declaring the selected Expr as a new variable
tooling::Replacement insertDeclaration(llvm::StringRef VarName,
- SourceRange InitChars) const;
+ SourceRange InitChars,
+ bool AddSemicolon) const;
private:
bool Extractable = false;
@@ -252,7 +253,8 @@ ExtractionContext::replaceWithVar(SourceRange Chars,
// returns the Replacement for declaring a new variable storing the extraction
tooling::Replacement
ExtractionContext::insertDeclaration(llvm::StringRef VarName,
- SourceRange InitializerChars) const {
+ SourceRange InitializerChars,
+ bool AddSemicolon) const {
llvm::StringRef ExtractionCode = toSourceCode(SM, InitializerChars);
const SourceLocation InsertionLoc =
toHalfOpenFileRange(SM, Ctx.getLangOpts(),
@@ -260,7 +262,9 @@ ExtractionContext::insertDeclaration(llvm::StringRef VarName,
->getBegin();
std::string ExtractedVarDecl =
printType(VarType, ExprNode->getDeclContext(), VarName) + " = " +
- ExtractionCode.str() + "; ";
+ ExtractionCode.str();
+ if (AddSemicolon)
+ ExtractedVarDecl += "; ";
return tooling::Replacement(SM, InsertionLoc, 0, ExtractedVarDecl);
}
@@ -419,12 +423,10 @@ const SelectionTree::Node *getCallExpr(const SelectionTree::Node *DeclRef) {
// Returns true if Inner (which is a direct child of Outer) is appearing as
// a statement rather than an expression whose value can be used.
-bool childExprIsStmt(const Stmt *Outer, const Expr *Inner) {
+bool childExprIsDisallowedStmt(const Stmt *Outer, const Expr *Inner) {
if (!Outer || !Inner)
return false;
// Exclude the most common places where an expr can appear but be unused.
- if (llvm::isa(Outer))
- return true;
if (llvm::isa(Outer))
return true;
// Control flow statements use condition etc, but not the body.
@@ -476,12 +478,9 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
const auto *Parent = OuterImplicit.Parent;
if (!Parent)
return false;
- // We don't want to extract expressions used as statements, that would leave
- // a `placeholder;` around that has no effect.
- // Unfortunately because the AST doesn't have ExprStmt, we have to check in
- // this roundabout way.
- if (childExprIsStmt(Parent->ASTNode.get(),
- OuterImplicit.ASTNode.get()))
+ // Filter non-applicable expression statements.
+ if (childExprIsDisallowedStmt(Parent->ASTNode.get(),
+ OuterImplicit.ASTNode.get()))
return false;
std::function IsFullySelected =
@@ -516,6 +515,12 @@ bool eligibleForExtraction(const SelectionTree::Node *N) {
return false;
}
+ // If e.g. a capture clause was selected, the target node is the lambda
+ // expression. We only want to offer the extraction if the entire lambda
+ // expression was selected.
+ if (llvm::isa(E))
+ return N->Selected == SelectionTree::Complete;
+
// The same logic as for assignments applies to initializations.
// However, we do allow extracting the RHS of an init capture, as it is
// a valid use case to move non-trivial expressions out of the capture clause.
@@ -599,10 +604,24 @@ Expected ExtractVariable::apply(const Selection &Inputs) {
// FIXME: get variable name from user or suggest based on type
std::string VarName = "placeholder";
SourceRange Range = Target->getExtractionChars();
- // insert new variable declaration
- if (auto Err = Result.add(Target->insertDeclaration(VarName, Range)))
+
+ const SelectionTree::Node &OuterImplicit =
+ Target->getExprNode()->outerImplicit();
+ assert(OuterImplicit.Parent);
+ bool IsExprStmt = llvm::isa_and_nonnull(
+ OuterImplicit.Parent->ASTNode.get());
+
+ // insert new variable declaration. add a semicolon if and only if
+ // we are not dealing with an expression statement, which already has
+ // a semicolon that stays where it is, as it's not part of the range.
+ if (auto Err =
+ Result.add(Target->insertDeclaration(VarName, Range, !IsExprStmt)))
return std::move(Err);
- // replace expression with variable name
+
+ // replace expression with variable name, unless it's an expression statement,
+ // in which case we remove it.
+ if (IsExprStmt)
+ VarName.clear();
if (auto Err = Result.add(Target->replaceWithVar(Range, VarName)))
return std::move(Err);
return Effect::mainFileEdit(Inputs.AST->getSourceManager(),
diff --git a/clang-tools-extra/clangd/support/DirectiveTree.cpp b/clang-tools-extra/clangd/support/DirectiveTree.cpp
index d25da111681af..7ea08add7a107 100644
--- a/clang-tools-extra/clangd/support/DirectiveTree.cpp
+++ b/clang-tools-extra/clangd/support/DirectiveTree.cpp
@@ -328,6 +328,9 @@ class Preprocessor {
Preprocessor(const TokenStream &In, TokenStream &Out) : In(In), Out(Out) {}
~Preprocessor() { Out.finalize(); }
+ Preprocessor(const Preprocessor &other) = delete;
+ Preprocessor &operator=(const Preprocessor &other) = delete;
+
void walk(const DirectiveTree &T) {
for (const auto &C : T.Chunks)
std::visit(*this, C);
diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 3220a5a6a9825..fc54f89f4941e 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -842,6 +842,8 @@ TEST_F(TargetDeclTest, OverloadExpr) {
}
TEST_F(TargetDeclTest, DependentExprs) {
+ Flags.push_back("--std=c++20");
+
// Heuristic resolution of method of dependent field
Code = R"cpp(
struct A { void foo() {} };
@@ -962,6 +964,21 @@ TEST_F(TargetDeclTest, DependentExprs) {
};
)cpp";
EXPECT_DECLS("MemberExpr", "void find()");
+
+ // Base expression is the type of a non-type template parameter
+ // which is deduced using CTAD.
+ Code = R"cpp(
+ template
+ struct Waldo {
+ const int found = N;
+ };
+
+ template
+ int test() {
+ return W.[[found]];
+ }
+ )cpp";
+ EXPECT_DECLS("CXXDependentScopeMemberExpr", "const int found = N");
}
TEST_F(TargetDeclTest, DependentTypes) {
diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
index 30b9b1902aa9c..1ec51d862d0a6 100644
--- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -1092,6 +1092,13 @@ sizeof...($TemplateParameter[[Elements]]);
$Field_dependentName[[waldo]];
}
};
+ )cpp",
+ // Pointer-to-member with nested-name-specifiers
+ R"cpp(
+ struct $Class_def[[Outer]] {
+ struct $Class_def[[Inner]] {};
+ };
+ using $Typedef_decl[[Alias]] = void ($Class[[Outer]]::$Class[[Inner]]:: *)();
)cpp"};
for (const auto &TestCase : TestCases)
// Mask off scope modifiers to keep the tests manageable.
diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
index e8088cb37fa51..7a9703c744e93 100644
--- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
@@ -2111,6 +2111,20 @@ TEST_F(SymbolCollectorTest, Reserved) {
EXPECT_THAT(Symbols, IsEmpty());
}
+TEST_F(SymbolCollectorTest, ReservedSymbolInIntrinsicHeader) {
+ const char *Header = R"cpp(
+ #pragma once
+ void __foo();
+ )cpp";
+
+ TestHeaderName = "xintrin.h";
+ TestHeaderURI = URI::create(testPath(TestHeaderName)).toString();
+ InMemoryFileSystem = new llvm::vfs::InMemoryFileSystem;
+ CollectorOpts.FallbackDir = testRoot();
+ runSymbolCollector("#pragma GCC system_header\n" + std::string(Header), "");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(qName("__foo")));
+}
+
TEST_F(SymbolCollectorTest, Concepts) {
const char *Header = R"cpp(
template
diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index d393c72974d44..7d824d659ad2c 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -1019,6 +1019,15 @@ TEST(LocateSymbol, All) {
void *Value;
void *getPointer() const { return Info::get^Pointer(Value); }
};
+ )cpp",
+ R"cpp(// Deducing this
+ struct S {
+ int bar(this S&);
+ };
+ void foo() {
+ S [[waldo]];
+ int x = wa^ldo.bar();
+ }
)cpp"};
for (const char *Test : Tests) {
Annotations T(Test);
@@ -1035,6 +1044,7 @@ TEST(LocateSymbol, All) {
TU.Code = std::string(T.code());
TU.ExtraArgs.push_back("-xobjective-c++");
+ TU.ExtraArgs.push_back("-std=c++23");
auto AST = TU.build();
auto Results = locateSymbolAt(AST, T.point());
diff --git a/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
index 656b62c9a1f4e..552e693c0363a 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
@@ -151,8 +151,8 @@ TEST_F(ExtractVariableTest, Test) {
// Variable DeclRefExpr
a = [[b]];
a = [[xyz()]];
- // statement expression
- [[xyz()]];
+ // expression statement of type void
+ [[v()]];
while (a)
[[++a]];
// label statement
@@ -493,6 +493,16 @@ TEST_F(ExtractVariableTest, Test) {
a = a + 1;
}
})cpp"},
+ {R"cpp(
+ int func() { return 0; }
+ int main() {
+ [[func()]];
+ })cpp",
+ R"cpp(
+ int func() { return 0; }
+ int main() {
+ auto placeholder = func();
+ })cpp"},
{R"cpp(
template
auto call(T t) { return t(); }
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index e00f86f7d0144..6803842106791 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -136,10 +136,16 @@ New checks
Gives warnings for tagged unions, where the number of tags is
different from the number of data members inside the union.
+- New :doc:`modernize-use-integer-sign-comparison
+ ` check.
+
+ Replace comparisons between signed and unsigned integers with their safe
+ C++20 ``std::cmp_*`` alternative, if available.
+
- New :doc:`portability-template-virtual-member-function
` check.
- Finds cases when an uninstantiated virtual member function in a template class
+ Finds cases when an uninstantiated virtual member function in a template class
causes cross-compiler incompatibility.
New check aliases
@@ -176,6 +182,10 @@ Changes in existing checks
` check by fixing
a crash when determining if an ``enable_if[_t]`` was found.
+- Improved :doc:`bugprone-optional-value-conversion
+ ` to support detecting
+ conversion directly by ``std::make_unique`` and ``std::make_shared``.
+
- Improved :doc:`bugprone-posix-return
` check to support integer literals
as LHS and posix call as RHS of comparison.
@@ -183,8 +193,8 @@ Changes in existing checks
- Improved :doc:`bugprone-return-const-ref-from-parameter
` check to
diagnose potential dangling references when returning a ``const &`` parameter
- by using the conditional operator ``cond ? var1 : var2`` and no longer giving
- false positives for functions which contain lambda and ignore parameters
+ by using the conditional operator ``cond ? var1 : var2`` and fixing false
+ positives for functions which contain lambda and ignore parameters
with ``[[clang::lifetimebound]]`` attribute.
- Improved :doc:`bugprone-sizeof-expression
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/cplusplus.PureVirtualCall.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/cplusplus.PureVirtualCall.rst
deleted file mode 100644
index 9fab628b80d44..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/cplusplus.PureVirtualCall.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. title:: clang-tidy - clang-analyzer-cplusplus.PureVirtualCall
-
-clang-analyzer-cplusplus.PureVirtualCall
-========================================
-
-Check pure virtual function calls during construction/destruction.
-
-The clang-analyzer-cplusplus.PureVirtualCall check is an alias of
-Clang Static Analyzer cplusplus.PureVirtualCall.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/cplusplus.SelfAssignment.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/cplusplus.SelfAssignment.rst
new file mode 100644
index 0000000000000..62e300660828b
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/cplusplus.SelfAssignment.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - clang-analyzer-cplusplus.SelfAssignment
+.. meta::
+ :http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-selfassignment
+
+clang-analyzer-cplusplus.SelfAssignment
+=======================================
+
+Checks C++ copy and move assignment operators for self assignment.
+
+The `clang-analyzer-cplusplus.SelfAssignment` check is an alias, please see
+`Clang Static Analyzer Available Checkers
+`_
+for more information.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/optin.osx.OSObjectCStyleCast.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/optin.osx.OSObjectCStyleCast.rst
deleted file mode 100644
index c2fef59f56894..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/optin.osx.OSObjectCStyleCast.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. title:: clang-tidy - clang-analyzer-optin.osx.OSObjectCStyleCast
-
-clang-analyzer-optin.osx.OSObjectCStyleCast
-===========================================
-
-Checker for C-style casts of OSObjects.
-
-The clang-analyzer-optin.osx.OSObjectCStyleCast check is an alias of
-Clang Static Analyzer optin.osx.OSObjectCStyleCast.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/osx.MIG.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/osx.MIG.rst
deleted file mode 100644
index a7b8a1cfb14cd..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/osx.MIG.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. title:: clang-tidy - clang-analyzer-osx.MIG
-
-clang-analyzer-osx.MIG
-======================
-
-Find violations of the Mach Interface Generator calling convention.
-
-The clang-analyzer-osx.MIG check is an alias of
-Clang Static Analyzer osx.MIG.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/osx.OSObjectRetainCount.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/osx.OSObjectRetainCount.rst
deleted file mode 100644
index c32982d407c28..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/osx.OSObjectRetainCount.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. title:: clang-tidy - clang-analyzer-osx.OSObjectRetainCount
-
-clang-analyzer-osx.OSObjectRetainCount
-======================================
-
-Check for leaks and improper reference count management for OSObject.
-
-The clang-analyzer-osx.OSObjectRetainCount check is an alias of
-Clang Static Analyzer osx.OSObjectRetainCount.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/security.PutenvStackArray.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/security.PutenvStackArray.rst
index 0a5feff8d3ca8..5858078246d9b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/security.PutenvStackArray.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/security.PutenvStackArray.rst
@@ -1,10 +1,17 @@
.. title:: clang-tidy - clang-analyzer-security.PutenvStackArray
+.. meta::
+ :http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#security-putenvstackarray-c
clang-analyzer-security.PutenvStackArray
========================================
-Finds calls to the function 'putenv' which pass a pointer to an automatic
-(stack-allocated) array as the argument.
+Finds calls to the putenv function which pass a pointer to a stack-allocated
+(automatic) array as the argument. Function putenv does not copy the passed
+string, only a pointer to the data is stored and this data can be read even by
+other threads. Content of a stack-allocated array is likely to be overwritten
+after exiting from the function.
-The clang-analyzer-security.PutenvStackArray check is an alias of
-Clang Static Analyzer security.PutenvStackArray.
+The `clang-analyzer-security.PutenvStackArray` check is an alias, please see
+`Clang Static Analyzer Available Checkers
+`_
+for more information.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/security.SetgidSetuidOrder.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/security.SetgidSetuidOrder.rst
index 82f22b11f77fb..b3ba78597a5ba 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/security.SetgidSetuidOrder.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/security.SetgidSetuidOrder.rst
@@ -1,10 +1,18 @@
.. title:: clang-tidy - clang-analyzer-security.SetgidSetuidOrder
+.. meta::
+ :http-equiv=refresh: 5;URL=https://clang.llvm.org/docs/analyzer/checkers.html#security-setgidsetuidorder-c
clang-analyzer-security.SetgidSetuidOrder
=========================================
-Warn on possible reversed order of 'setgid(getgid()))' and 'setuid(getuid())'
-(CERT: POS36-C).
+The checker checks for sequences of ``setuid(getuid())`` and ``setgid(getgid())``
+calls (in this order). If such a sequence is found and there is no other
+privilege-changing function call (``seteuid``, ``setreuid``, ``setresuid`` and
+the GID versions of these) in between, a warning is generated. The checker finds
+only exactly ``setuid(getuid())`` calls (and the GID versions), not for example
+if the result of ``getuid()`` is stored in a variable.
-The clang-analyzer-security.SetgidSetuidOrder check is an alias of
-Clang Static Analyzer security.SetgidSetuidOrder.
+The `clang-analyzer-security.SetgidSetuidOrder` check is an alias, please see
+`Clang Static Analyzer Available Checkers
+`_
+for more information.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.CopyToSelf.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.CopyToSelf.rst
deleted file mode 100644
index d0c82abd81901..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.CopyToSelf.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. title:: clang-tidy - clang-analyzer-valist.CopyToSelf
-
-clang-analyzer-valist.CopyToSelf
-================================
-
-Check for va_lists which are copied onto itself.
-
-The clang-analyzer-valist.CopyToSelf check is an alias of
-Clang Static Analyzer valist.CopyToSelf.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.Uninitialized.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.Uninitialized.rst
deleted file mode 100644
index 98b5dd023254a..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.Uninitialized.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. title:: clang-tidy - clang-analyzer-valist.Uninitialized
-
-clang-analyzer-valist.Uninitialized
-===================================
-
-Check for usages of uninitialized (or already released) va_lists.
-
-The clang-analyzer-valist.Uninitialized check is an alias of
-Clang Static Analyzer valist.Uninitialized.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.Unterminated.rst b/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.Unterminated.rst
deleted file mode 100644
index 85e21c5721063..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/clang-analyzer/valist.Unterminated.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. title:: clang-tidy - clang-analyzer-valist.Unterminated
-
-clang-analyzer-valist.Unterminated
-==================================
-
-Check for va_lists which are not released by a va_end call.
-
-The clang-analyzer-valist.Unterminated check is an alias of
-Clang Static Analyzer valist.Unterminated.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index d731b13fc0df4..4d8853a0f6d86 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -115,8 +115,8 @@ Clang-Tidy Checks
:doc:`bugprone-multiple-new-in-one-expression `,
:doc:`bugprone-multiple-statement-macro `,
:doc:`bugprone-no-escape `,
- :doc:`bugprone-nondeterministic-pointer-iteration-order `,
:doc:`bugprone-non-zero-enum-to-bool-conversion `,
+ :doc:`bugprone-nondeterministic-pointer-iteration-order `,
:doc:`bugprone-not-null-terminated-result `, "Yes"
:doc:`bugprone-optional-value-conversion `, "Yes"
:doc:`bugprone-parent-virtual-call `, "Yes"
@@ -301,6 +301,7 @@ Clang-Tidy Checks
:doc:`modernize-use-emplace `, "Yes"
:doc:`modernize-use-equals-default `, "Yes"
:doc:`modernize-use-equals-delete `, "Yes"
+ :doc:`modernize-use-integer-sign-comparison `, "Yes"
:doc:`modernize-use-nodiscard `, "Yes"
:doc:`modernize-use-noexcept `, "Yes"
:doc:`modernize-use-nullptr `, "Yes"
@@ -458,7 +459,7 @@ Check aliases
:doc:`clang-analyzer-cplusplus.NewDelete `, `Clang Static Analyzer cplusplus.NewDelete `_,
:doc:`clang-analyzer-cplusplus.NewDeleteLeaks `, `Clang Static Analyzer cplusplus.NewDeleteLeaks `_,
:doc:`clang-analyzer-cplusplus.PlacementNew `, `Clang Static Analyzer cplusplus.PlacementNew `_,
- :doc:`clang-analyzer-cplusplus.PureVirtualCall