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/metrics/metrics.py b/.ci/metrics/metrics.py index deb36bc1689a0..55025e50d1081 100644 --- a/.ci/metrics/metrics.py +++ b/.ci/metrics/metrics.py @@ -12,7 +12,7 @@ "https://influx-prod-13-prod-us-east-0.grafana.net/api/v1/push/influx/write" ) GITHUB_PROJECT = "llvm/llvm-project" -WORKFLOWS_TO_TRACK = ["Check code formatting"] +WORKFLOWS_TO_TRACK = ["Check code formatting", "LLVM Premerge Checks"] SCRAPE_INTERVAL_SECONDS = 5 * 60 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..30d9f6b883ceb 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -94,3 +94,9 @@ b6262880b34629e9d7a72b5a42f315a3c9ed8139 39c7dc7207e76e72da21cf4fedda21b5311bf62d e80bc777749331e9519575f416c342f7626dd14d 7e5cd8f1b6c5263ed5e2cc03d60c8779a8d3e9f7 + +# NFC: clang-format test_demangle.pass.cpp but keep test "lines" +d33bf2e9df578ff7e44fd22504d6ad5a122b7ee6 + +# [lldb][NFC] clang-format MainLoopPosix.cpp +66bdbfbaa08fa3d8e64a7fe136a8fb717f5cdbb7 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 098d36f162205..ab8b75f415870 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -129,7 +129,7 @@ /mlir/**/Transforms/SROA.* @moxinilian # BOLT -/bolt/ @aaupov @maksfb @rafaelauler @ayermolo @dcci +/bolt/ @aaupov @maksfb @rafaelauler @ayermolo @dcci @yota9 # Bazel build system. /utils/bazel/ @rupprecht @keith diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index 54290f15419d9..0aa05cd027a47 100644 --- a/.github/new-prs-labeler.yml +++ b/.github/new-prs-labeler.yml @@ -747,6 +747,12 @@ backend:RISC-V: - llvm/**/*riscv* - llvm/**/*RISCV* +backend:Xtensa: + - clang/**/*xtensa* + - clang/**/*Xtensa* + - llvm/**/*xtensa* + - llvm/**/*Xtensa* + lld:coff: - lld/**/COFF/** - lld/Common/** 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/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..b4fa27203236a 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 @@ -104,9 +106,9 @@ jobs: with: python-version: '3.11' cache: 'pip' - cache-dependency-path: 'llvm/docs/requirements.txt' + cache-dependency-path: 'llvm/docs/requirements-hashed.txt' - name: Install python dependencies - run: pip install -r llvm/docs/requirements.txt + run: pip install -r llvm/docs/requirements-hashed.txt - name: Install system dependencies run: | sudo apt-get update @@ -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 index fb73aa392f343..58e15ce29546e 100644 --- a/.github/workflows/libc-fullbuild-tests.yml +++ b/.github/workflows/libc-fullbuild-tests.yml @@ -1,6 +1,7 @@ # 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" ] @@ -22,7 +23,13 @@ jobs: # 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: @@ -30,10 +37,14 @@ jobs: 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-headers-generic linux-libc-dev + 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 @@ -42,7 +53,9 @@ jobs: 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 }} diff --git a/.github/workflows/libc-overlay-tests.yml b/.github/workflows/libc-overlay-tests.yml index d0cdfdef99fe9..8b59d76aed4a8 100644 --- a/.github/workflows/libc-overlay-tests.yml +++ b/.github/workflows/libc-overlay-tests.yml @@ -1,6 +1,7 @@ # 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" ] @@ -32,7 +33,14 @@ jobs: 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: @@ -40,12 +48,15 @@ jobs: 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: | @@ -62,6 +73,9 @@ jobs: 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 }} diff --git a/.github/workflows/premerge.yaml b/.github/workflows/premerge.yaml new file mode 100644 index 0000000000000..7a9762812cc18 --- /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.sha }} + 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/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/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md index 6d3b797da3787..91918d614a90f 100644 --- a/bolt/docs/CommandLineArgumentReference.md +++ b/bolt/docs/CommandLineArgumentReference.md @@ -498,9 +498,12 @@ Automatically put hot code on 2MB page(s) (hugify) at runtime. No manual call to hugify is needed in the binary (which is what --hot-text relies on). -- `--icf` +- `--icf=` Fold functions with identical code + - `all`: Enable identical code folding + - `none`: Disable identical code folding (default) + - `safe`: Enable safe identical code folding - `--icp` diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index 7560908c250c3..e8b2757f7db21 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -428,6 +428,9 @@ class BinaryFunction { /// Function order for streaming into the destination binary. uint32_t Index{-1U}; + /// Function is referenced by a non-control flow instruction. + bool HasAddressTaken{false}; + /// Get basic block index assuming it belongs to this function. unsigned getIndex(const BinaryBasicBlock *BB) const { assert(BB->getIndex() < BasicBlocks.size()); @@ -822,6 +825,14 @@ class BinaryFunction { return nullptr; } + /// Return true if function is referenced in a non-control flow instruction. + /// This flag is set when the code and relocation analyses are being + /// performed, which occurs when safe ICF (Identical Code Folding) is enabled. + bool hasAddressTaken() const { return HasAddressTaken; } + + /// Set whether function is referenced in a non-control flow instruction. + void setHasAddressTaken(bool AddressTaken) { HasAddressTaken = AddressTaken; } + /// Returns the raw binary encoding of this function. ErrorOr> getData() const; @@ -2135,6 +2146,9 @@ class BinaryFunction { // adjustments. void handleAArch64IndirectCall(MCInst &Instruction, const uint64_t Offset); + /// Analyze instruction to identify a function reference. + void analyzeInstructionForFuncReference(const MCInst &Inst); + /// Scan function for references to other functions. In relocation mode, /// add relocations for external references. In non-relocation mode, detect /// and mark new entry points. 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/Passes/IdenticalCodeFolding.h b/bolt/include/bolt/Passes/IdenticalCodeFolding.h index b4206fa360744..f59e75c618605 100644 --- a/bolt/include/bolt/Passes/IdenticalCodeFolding.h +++ b/bolt/include/bolt/Passes/IdenticalCodeFolding.h @@ -11,6 +11,7 @@ #include "bolt/Core/BinaryFunction.h" #include "bolt/Passes/BinaryPasses.h" +#include "llvm/ADT/SparseBitVector.h" namespace llvm { namespace bolt { @@ -20,22 +21,72 @@ namespace bolt { /// class IdenticalCodeFolding : public BinaryFunctionPass { protected: - bool shouldOptimize(const BinaryFunction &BF) const override { - if (BF.hasUnknownControlFlow()) - return false; - if (BF.isFolded()) - return false; - if (BF.hasSDTMarker()) - return false; - return BinaryFunctionPass::shouldOptimize(BF); - } + /// Return true if the function is safe to fold. + bool shouldOptimize(const BinaryFunction &BF) const override; public: + enum class ICFLevel { + None, /// No ICF. (Default) + Safe, /// Safe ICF. + All, /// Aggressive ICF. + }; explicit IdenticalCodeFolding(const cl::opt &PrintPass) : BinaryFunctionPass(PrintPass) {} const char *getName() const override { return "identical-code-folding"; } Error runOnFunctions(BinaryContext &BC) override; + +private: + /// Bit vector of memory addresses of vtables. + llvm::SparseBitVector<> VTableBitVector; + + /// Return true if the memory address is in a vtable. + bool isAddressInVTable(uint64_t Address) const { + return VTableBitVector.test(Address / 8); + } + + /// Mark memory address of a vtable as used. + void setAddressUsedInVTable(uint64_t Address) { + VTableBitVector.set(Address / 8); + } + + /// Scan symbol table and mark memory addresses of + /// vtables. + void initVTableReferences(const BinaryContext &BC); + + /// Analyze code section and relocations and mark functions that are not + /// safe to fold. + void markFunctionsUnsafeToFold(BinaryContext &BC); + + /// Process static and dynamic relocations in the data sections to identify + /// function references, and mark them as unsafe to fold. It filters out + /// symbol references that are in vtables. + void analyzeDataRelocations(BinaryContext &BC); + + /// Process functions that have been disassembled and mark functions that are + /// used in non-control flow instructions as unsafe to fold. + void analyzeFunctions(BinaryContext &BC); +}; + +class DeprecatedICFNumericOptionParser + : public cl::parser { +public: + explicit DeprecatedICFNumericOptionParser(cl::Option &O) + : cl::parser(O) {} + + bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, + IdenticalCodeFolding::ICFLevel &Value) { + if (Arg == "0" || Arg == "1") { + Value = (Arg == "0") ? IdenticalCodeFolding::ICFLevel::None + : IdenticalCodeFolding::ICFLevel::All; + errs() << formatv("BOLT-WARNING: specifying numeric value \"{0}\" " + "for option -{1} is deprecated\n", + Arg, ArgName); + return false; + } + return cl::parser::parse(O, ArgName, Arg, + Value); + } }; } // namespace bolt 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/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/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index a9ccaea3c4385..1c5cd62a095b2 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -1504,6 +1504,20 @@ MCSymbol *BinaryFunction::registerBranch(uint64_t Src, uint64_t Dst) { return Target; } +void BinaryFunction::analyzeInstructionForFuncReference(const MCInst &Inst) { + for (const MCOperand &Op : MCPlus::primeOperands(Inst)) { + if (!Op.isExpr()) + continue; + const MCExpr &Expr = *Op.getExpr(); + if (Expr.getKind() != MCExpr::SymbolRef) + continue; + const MCSymbol &Symbol = cast(Expr).getSymbol(); + // Set HasAddressTaken for a function regardless of the ICF level. + if (BinaryFunction *BF = BC.getFunctionForSymbol(&Symbol)) + BF->setHasAddressTaken(true); + } +} + bool BinaryFunction::scanExternalRefs() { bool Success = true; bool DisassemblyFailed = false; @@ -1624,6 +1638,8 @@ bool BinaryFunction::scanExternalRefs() { [](const MCOperand &Op) { return Op.isExpr(); })) { // Skip assembly if the instruction may not have any symbolic operands. continue; + } else { + analyzeInstructionForFuncReference(Instruction); } // Emit the instruction using temp emitter and generate relocations. 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 280c7c505eeda..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; } @@ -222,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()) { @@ -359,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/IdenticalCodeFolding.cpp b/bolt/lib/Passes/IdenticalCodeFolding.cpp index 38e080c9dd621..8923562776cc4 100644 --- a/bolt/lib/Passes/IdenticalCodeFolding.cpp +++ b/bolt/lib/Passes/IdenticalCodeFolding.cpp @@ -15,6 +15,7 @@ #include "bolt/Core/ParallelUtilities.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Timer.h" #include @@ -42,8 +43,41 @@ TimeICF("time-icf", cl::ReallyHidden, cl::ZeroOrMore, cl::cat(BoltOptCategory)); + +cl::opt + ICF("icf", cl::desc("fold functions with identical code"), + cl::init(bolt::IdenticalCodeFolding::ICFLevel::None), + cl::values(clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::All, "all", + "Enable identical code folding"), + clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::All, "1", + "Enable identical code folding"), + clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::All, "", + "Enable identical code folding"), + clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::None, + "none", + "Disable identical code folding (default)"), + clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::None, "0", + "Disable identical code folding (default)"), + clEnumValN(bolt::IdenticalCodeFolding::ICFLevel::Safe, + "safe", "Enable safe identical code folding")), + cl::ZeroOrMore, cl::ValueOptional, cl::cat(BoltOptCategory)); } // namespace opts +bool IdenticalCodeFolding::shouldOptimize(const BinaryFunction &BF) const { + if (BF.hasUnknownControlFlow()) + return false; + if (BF.isFolded()) + return false; + if (BF.hasSDTMarker()) + return false; + if (BF.isPseudo()) + return false; + if (opts::ICF == ICFLevel::Safe && BF.hasAddressTaken()) + return false; + return BinaryFunctionPass::shouldOptimize(BF); +} + /// Compare two jump tables in 2 functions. The function relies on consistent /// ordering of basic blocks in both binary functions (e.g. DFS). static bool equalJumpTables(const JumpTable &JumpTableA, @@ -340,6 +374,74 @@ typedef std::unordered_map, namespace llvm { namespace bolt { +void IdenticalCodeFolding::initVTableReferences(const BinaryContext &BC) { + for (const auto &[Address, Data] : BC.getBinaryData()) { + // Filter out all symbols that are not vtables. + if (!Data->getName().starts_with("_ZTV")) + continue; + for (uint64_t I = Address, End = I + Data->getSize(); I < End; I += 8) + setAddressUsedInVTable(I); + } +} + +void IdenticalCodeFolding::analyzeDataRelocations(BinaryContext &BC) { + initVTableReferences(BC); + // For static relocations there should be a symbol for function references. + for (const BinarySection &Sec : BC.sections()) { + if (!Sec.hasSectionRef() || !Sec.isData()) + continue; + for (const auto &Rel : Sec.relocations()) { + const uint64_t RelAddr = Rel.Offset + Sec.getAddress(); + if (isAddressInVTable(RelAddr)) + continue; + if (BinaryFunction *BF = BC.getFunctionForSymbol(Rel.Symbol)) + BF->setHasAddressTaken(true); + } + // For dynamic relocations there are two cases: + // 1: No symbol and only addend. + // 2: There is a symbol, but it does not references a function in a binary. + for (const auto &Rel : Sec.dynamicRelocations()) { + const uint64_t RelAddr = Rel.Offset + Sec.getAddress(); + if (isAddressInVTable(RelAddr)) + continue; + if (BinaryFunction *BF = BC.getBinaryFunctionAtAddress(Rel.Addend)) + BF->setHasAddressTaken(true); + } + } +} + +void IdenticalCodeFolding::analyzeFunctions(BinaryContext &BC) { + ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) { + for (const BinaryBasicBlock &BB : BF) + for (const MCInst &Inst : BB) + if (!(BC.MIB->isCall(Inst) || BC.MIB->isBranch(Inst))) + BF.analyzeInstructionForFuncReference(Inst); + }; + ParallelUtilities::PredicateTy SkipFunc = + [&](const BinaryFunction &BF) -> bool { return !BF.hasCFG(); }; + ParallelUtilities::runOnEachFunction( + BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun, + SkipFunc, "markUnsafe"); + + LLVM_DEBUG({ + for (const auto &BFIter : BC.getBinaryFunctions()) { + if (!BFIter.second.hasAddressTaken()) + continue; + dbgs() << "BOLT-DEBUG: skipping function with reference taken " + << BFIter.second.getOneName() << '\n'; + } + }); +} + +void IdenticalCodeFolding::markFunctionsUnsafeToFold(BinaryContext &BC) { + NamedRegionTimer MarkFunctionsUnsafeToFoldTimer( + "markFunctionsUnsafeToFold", "markFunctionsUnsafeToFold", "ICF breakdown", + "ICF breakdown", opts::TimeICF); + if (!BC.isX86()) + BC.outs() << "BOLT-WARNING: safe ICF is only supported for x86\n"; + analyzeDataRelocations(BC); + analyzeFunctions(BC); +} Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) { const size_t OriginalFunctionCount = BC.getBinaryFunctions().size(); @@ -385,7 +487,7 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) { "ICF breakdown", opts::TimeICF); for (auto &BFI : BC.getBinaryFunctions()) { BinaryFunction &BF = BFI.second; - if (!this->shouldOptimize(BF)) + if (!shouldOptimize(BF)) continue; CongruentBuckets[&BF].emplace(&BF); } @@ -475,7 +577,8 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) { LLVM_DEBUG(SinglePass.stopTimer()); }; - + if (opts::ICF == ICFLevel::Safe) + markFunctionsUnsafeToFold(BC); hashFunctions(); createCongruentBuckets(); 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..2d851c751ae10 100644 --- a/bolt/lib/Rewrite/BinaryPassManager.cpp +++ b/bolt/lib/Rewrite/BinaryPassManager.cpp @@ -54,6 +54,9 @@ extern cl::opt PrintDynoStats; extern cl::opt DumpDotAll; extern cl::opt AsmDump; extern cl::opt PLT; +extern cl::opt + ICF; static cl::opt DynoStatsAll("dyno-stats-all", @@ -65,9 +68,6 @@ static cl::opt cl::desc("eliminate unreachable code"), cl::init(true), cl::cat(BoltOptCategory)); -cl::opt ICF("icf", cl::desc("fold functions with identical code"), - cl::cat(BoltOptCategory)); - static cl::opt JTFootprintReductionFlag( "jt-footprint-reduction", cl::desc("make jump tables size smaller at the cost of using more " @@ -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, @@ -398,7 +403,7 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { opts::StripRepRet); Manager.registerPass(std::make_unique(PrintICF), - opts::ICF); + opts::ICF != IdenticalCodeFolding::ICFLevel::None); Manager.registerPass( std::make_unique(NeverPrint, opts::SpecializeMemcpy1), @@ -423,7 +428,7 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { Manager.registerPass(std::make_unique(PrintInline)); Manager.registerPass(std::make_unique(PrintICF), - opts::ICF); + opts::ICF != IdenticalCodeFolding::ICFLevel::None); Manager.registerPass(std::make_unique(PrintPLT)); @@ -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/BoltDiff.cpp b/bolt/lib/Rewrite/BoltDiff.cpp index 74b5ca18abce4..35f6710506646 100644 --- a/bolt/lib/Rewrite/BoltDiff.cpp +++ b/bolt/lib/Rewrite/BoltDiff.cpp @@ -28,7 +28,9 @@ using namespace bolt; namespace opts { extern cl::OptionCategory BoltDiffCategory; extern cl::opt NeverPrint; -extern cl::opt ICF; +extern cl::opt + ICF; static cl::opt IgnoreLTOSuffix( "ignore-lto-suffix", @@ -697,7 +699,7 @@ void RewriteInstance::compare(RewriteInstance &RI2) { } // Pre-pass ICF - if (opts::ICF) { + if (opts::ICF != IdenticalCodeFolding::ICFLevel::None) { IdenticalCodeFolding ICF(opts::NeverPrint); outs() << "BOLT-DIFF: Starting ICF pass for binary 1"; BC->logBOLTErrorsAndQuitOnFatal(ICF.runOnFunctions(*BC)); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 76e1f0156f828..4329235d47049 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -19,6 +19,7 @@ #include "bolt/Core/Relocation.h" #include "bolt/Passes/BinaryPasses.h" #include "bolt/Passes/CacheMetrics.h" +#include "bolt/Passes/IdenticalCodeFolding.h" #include "bolt/Passes/ReorderFunctions.h" #include "bolt/Profile/BoltAddressTranslation.h" #include "bolt/Profile/DataAggregator.h" @@ -78,7 +79,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; @@ -86,6 +86,9 @@ extern cl::opt ReorderFunctions; extern cl::opt TerminalTrap; extern cl::opt TimeBuild; extern cl::opt TimeRewrite; +extern cl::opt + ICF; cl::opt AllowStripped("allow-stripped", cl::desc("allow processing of stripped binaries"), @@ -699,6 +702,11 @@ Error RewriteInstance::run() { if (opts::DiffOnly) return Error::success(); + if (opts::BinaryAnalysisMode) { + runBinaryAnalyses(); + return Error::success(); + } + preregisterSections(); runOptimizationPasses(); @@ -2051,6 +2059,13 @@ void RewriteInstance::adjustCommandLineOptions() { exit(1); } + if (!BC->HasRelocations && + opts::ICF == IdenticalCodeFolding::ICFLevel::Safe) { + BC->errs() << "BOLT-ERROR: binary built without relocations. Safe ICF is " + "not supported\n"; + exit(1); + } + if (opts::Instrument || (opts::ReorderFunctions != ReorderFunctions::RT_NONE && !opts::HotText.getNumOccurrences())) { @@ -3475,6 +3490,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, @@ -3841,20 +3858,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; @@ -5637,26 +5640,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/icf-safe-icp.test b/bolt/test/X86/icf-safe-icp.test new file mode 100644 index 0000000000000..a9227d311edce --- /dev/null +++ b/bolt/test/X86/icf-safe-icp.test @@ -0,0 +1,148 @@ +## Check that BOLT handles correctly folding functions with --icf=safe +## that can be referenced through a non control flow instruction when ICP optimization is enabled. +## This tests also checks that destructors are folded. + +# REQUIRES: system-linux, asserts +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q +# RUN: llvm-bolt --no-threads %t.exe --icf -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s +# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s + +# ICFCHECK: ICF iteration 1 +# ICFCHECK-NEXT: folding Derived3Destructor into Derived2Destructor +# ICFCHECK-NEXT: folding Derived3Func into Derived2Func + +# SAFEICFCHECK: skipping function with reference taken Derived3Func +# SAFEICFCHECK-NEXT: ICF iteration 1 +# SAFEICFCHECK-NEXT: folding Derived3Destructor into Derived2Destructor +# SAFEICFCHECK-NEXT: ===--------- + + +## generate profile +## clang++ -O2 -fprofile-generate=. main.cpp -c -o mainProf.o +## PROF=test.profdata +## clang++ -m64 -fprofile-use=$PROF \ +## -mllvm -disable-icp=true -mllvm -print-after-all \ +## -g0 -flto=thin -fwhole-program-vtables -fno-split-lto-unit -O2 \ +## -fdebug-types-section \ +## main.cpp -c -o mainProfLTO.bc +## PASS='pgo-icall-prom' +## clang++ -m64 -fprofile-use=$PROF \ +## -O3 -Rpass=$PASS \ +## -mllvm -print-before=$PASS \ +## -mllvm -print-after=$PASS \ +## -mllvm -filter-print-funcs=main \ +## -mllvm -debug-only=$PASS \ +## -x ir \ +## mainProfLTO.bc -c -o mainProfFinal.o + +## class Base { +## public: +## virtual int func(int a, int b) const = 0; +## +## virtual ~Base() {}; +## }; +## +## class Derived2 : public Base { +## int c = 5; +## public: +## __attribute__((noinline)) int func(int a, int b)const override { return a * (a - b) + this->c; } +## +## ~Derived2() {} +## }; +## +## class Derived3 : public Base { +## int c = 500; +## public: +## __attribute__((noinline)) int func(int a, int b) const override { return a * (a - b) + this->c; } +## ~Derived3() {} +## }; +## +## __attribute__((noinline)) Base *createType(int a) { +## Base *base = nullptr; +## if (a == 4) +## base = new Derived2(); +## else +## base = new Derived3(); +## return base; +## } +## +## extern int returnFive(); +## extern int returnFourOrFive(int val); +## int main(int argc, char **argv) { +## int sum = 0; +## int a = returnFourOrFive(argc); +## int b = returnFive(); +## Base *ptr = createType(a); +## Base *ptr2 = createType(b); +## sum += ptr->func(b, a) + ptr2->func(b, a); +## return 0; +## } +## clang++ -c helper.cpp -o helper.o +## int FooVar = 1; +## int BarVar = 2; +## +## int fooGlobalFuncHelper(int a, int b) { +## return 5; +## } +## Manually modified to remove "extra" assembly. + .globl main + .type main,@function +main: + leaq Derived3Func(%rip), %rcx + callq Derived3Func + .size main, .-main + + .weak Derived2Func + .type Derived2Func,@function +Derived2Func: + imull %esi, %eax + retq + .size Derived2Func, .-Derived2Func + + .weak Derived2Destructor + .type Derived2Destructor,@function +Derived2Destructor: + jmp _ZdlPvm@PLT + .size Derived2Destructor, .-Derived2Destructor + + .weak Derived3Func + .type Derived3Func,@function +Derived3Func: + imull %esi, %eax + retq + .size Derived3Func, .-Derived3Func + + .weak _ZN4BaseD2Ev + .type _ZN4BaseD2Ev,@function +_ZN4BaseD2Ev: + retq + .size _ZN4BaseD2Ev, .-_ZN4BaseD2Ev + + .weak Derived3Destructor + .type Derived3Destructor,@function +Derived3Destructor: + jmp _ZdlPvm@PLT + .size Derived3Destructor, .-Derived3Destructor + + .type _ZTV8Derived2,@object + .section .data.rel.ro._ZTV8Derived2,"awG",@progbits,_ZTV8Derived2,comdat + .weak _ZTV8Derived2 +_ZTV8Derived2: + .quad 0 + .quad _ZTI8Derived2 + .quad Derived2Func + .quad _ZN4BaseD2Ev + .quad Derived2Destructor + .size _ZTV8Derived2, 40 + + .type _ZTV8Derived3,@object + .section .data.rel.ro._ZTV8Derived3,"awG",@progbits,_ZTV8Derived3,comdat + .weak _ZTV8Derived3 +_ZTV8Derived3: + .quad 0 + .quad _ZTI8Derived3 + .quad Derived3Func + .quad _ZN4BaseD2Ev + .quad Derived3Destructor + .size _ZTV8Derived3, 40 diff --git a/bolt/test/X86/icf-safe-process-rela-data.test b/bolt/test/X86/icf-safe-process-rela-data.test new file mode 100644 index 0000000000000..cf71f55257777 --- /dev/null +++ b/bolt/test/X86/icf-safe-process-rela-data.test @@ -0,0 +1,64 @@ +## Check that BOLT handles correctly folding functions with --icf=safe that are only referenced from a .rela.data section. + +# REQUIRES: system-linux, asserts +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q -no-pie +# RUN: llvm-bolt --no-threads %t.exe --icf -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s +# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s + +# ICFCHECK: ICF iteration 1 +# ICFCHECK-NEXT: folding barAddFunc into fooAddFunc + +# SAFEICFCHECK: skipping function with reference taken fooAddFunc +# SAFEICFCHECK-NEXT: skipping function with reference taken barAddFunc +# SAFEICFCHECK-NEXT: ICF iteration 1 +# SAFEICFCHECK-NEXT: ===--------- + +## clang++ main.cpp +## Other functions removed for brevity. +## int main(int argc, char **argv) { +## const static int (*const funcGlobalBarAdd)(int, int) = barAddHdlper; +## const int (* const funcGlobalBarMul)(int, int) = fooGlobalFuncHelper; +## helper2(funcGlobalBarAdd, funcGlobalFooAdd, 3, 4) +## } +## Extra assembly removed. + + .globl fooAddFunc + .type fooAddFunc,@function +fooAddFunc: + addl -8(%rbp), %eax + retq + .size fooAddFunc, .-fooAddFunc + + .globl barAddFunc + .type barAddFunc,@function +barAddFunc: + addl -8(%rbp), %eax + retq + .size barAddFunc, .-barAddFunc + + .globl helperFunc + .type helperFunc,@function +helperFunc: + retq + .size helperFunc, .-helperFunc + + .globl main + .type main,@function +main: + movq localStaticVarBarAdd, %rdi + movq localStaticVarFooAdd, %rsi + callq helperFunc + retq + .size main, .-main + + .type localStaticVarBarAdd,@object # @localStaticVarBarAdd + .data +localStaticVarBarAdd: + .quad barAddFunc + .size localStaticVarBarAdd, 8 + + .type localStaticVarFooAdd,@object # @localStaticVarFooAdd +localStaticVarFooAdd: + .quad fooAddFunc + .size localStaticVarFooAdd, 8 diff --git a/bolt/test/X86/icf-safe-test1-no-relocs.test b/bolt/test/X86/icf-safe-test1-no-relocs.test new file mode 100644 index 0000000000000..b4e55a6d5504f --- /dev/null +++ b/bolt/test/X86/icf-safe-test1-no-relocs.test @@ -0,0 +1,20 @@ +## Check that BOLT reports an error for a binary with no relocations with the --icf=safe option. + +# REQUIRES: system-linux, asserts +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags %t1.o -o %t.exe +# RUN: not llvm-bolt --no-threads %t.exe --icf=safe -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s + +# SAFEICFCHECK: BOLT-ERROR: binary built without relocations. Safe ICF is not supported + +## int main(int argc, char **argv) { +## return temp; +## } + .globl main + .type main,@function +main: + .cfi_startproc + retq +.Lfunc_end8: + .size main, .-main + .cfi_endproc diff --git a/bolt/test/X86/icf-safe-test1.test b/bolt/test/X86/icf-safe-test1.test new file mode 100644 index 0000000000000..8a8e5ccf38e7c --- /dev/null +++ b/bolt/test/X86/icf-safe-test1.test @@ -0,0 +1,98 @@ +## Check that BOLT handles correctly folding functions with --icf=safe that can be referenced by non-control flow instructions. +## It invokes BOLT twice first testing CFG path, and second when functions have to be disassembled. + +# REQUIRES: system-linux, asserts +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q +# RUN: llvm-bolt --no-threads %t.exe --icf -debug-only=bolt-icf \ +# RUN: -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s +# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf \ +# RUN: -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s +# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf \ +# RUN: --skip-funcs=helper1Func,main -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECKNOCFG %s + +# ICFCHECK: ICF iteration 1 +# ICFCHECK-NEXT: folding barAddFunc into fooAddFunc +# ICFCHECK-NEXT: folding barSubFunc into fooSubFunc + +# SAFEICFCHECK: skipping function with reference taken barAddFunc +# SAFEICFCHECK-NEXT: ICF iteration 1 +# SAFEICFCHECK-NEXT: folding barSubFunc into fooSubFunc +# SAFEICFCHECK-NEXT: ===--------- + +# SAFEICFCHECKNOCFG: skipping function with reference taken barAddFunc +# SAFEICFCHECKNOCFG-NEXT: ICF iteration 1 +# SAFEICFCHECKNOCFG-NEXT: folding barSubFunc into fooSubFunc +# SAFEICFCHECKNOCFG-NEXT: ===--------- + +## clang++ -c main.cpp -o main.o +## extern int FooVar; +## extern int BarVar; +## [[clang::noinline]] +## int fooSub(int a, int b) { +## return a - b; +## } +## [[clang::noinline]] +## int barSub(int a, int b) { +## return a - b; +## } +## [[clang::noinline]] +## int fooAdd(int a, int b) { +## return a + b; +## } +## [[clang::noinline]] +## int barAdd(int a, int b) { +## return a + b; +## } +## int main(int argc, char **argv) { +## int temp = helper1(barAdd, FooVar, BarVar) + +## fooSub(FooVar, BarVar) + +## barSub(FooVar, BarVar) + fooAdd(FooVar, BarVar); +## return temp; +## } + .globl fooSubFunc + .type fooSubFunc,@function +fooSubFunc: + subl -8(%rbp), %eax + retq + .size fooSubFunc, .-fooSubFunc + + .globl barSubFunc + .type barSubFunc,@function +barSubFunc: + subl -8(%rbp), %eax + retq + .size barSubFunc, .-barSubFunc + + .globl fooAddFunc + .type fooAddFunc,@function +fooAddFunc: + addl -8(%rbp), %eax + retq + .size fooAddFunc, .-fooAddFunc + + .globl barAddFunc + .type barAddFunc,@function +barAddFunc: + addl -8(%rbp), %eax + retq + .size barAddFunc, .-barAddFunc + + .globl helper1Func + .type helper1Func,@function +helper1Func: + leaq barAddFunc(%rip), %rax + cmpq %rax, -16(%rbp) + retq + .size helper1Func, .-helper1Func + + .globl main + .type main,@function +main: + leaq barAddFunc(%rip), %rdi + callq helper1Func + callq fooSubFunc + callq barSubFunc + callq fooAddFunc + retq + .size main, .-main diff --git a/bolt/test/X86/icf-safe-test2GlobalConstPtrNoPic.test b/bolt/test/X86/icf-safe-test2GlobalConstPtrNoPic.test new file mode 100644 index 0000000000000..ea2d8a5f11e06 --- /dev/null +++ b/bolt/test/X86/icf-safe-test2GlobalConstPtrNoPic.test @@ -0,0 +1,95 @@ +## Check that BOLT handles correctly folding functions with --icf=safe that can be referenced by non-control flow instructions, +## when binary is built with -fno-PIC/-fno-PIE. + +# REQUIRES: system-linux, asserts +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o +# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q -no-pie +# RUN: llvm-bolt --no-threads %t.exe --icf -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s +# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s + +# ICFCHECK: ICF iteration 1 +# ICFCHECK-NEXT: folding barAddFunc into fooAddFunc +# ICFCHECK-NEXT: folding barMulFunc into fooMulFunc + +# SAFEICFCHECK: skipping function with reference taken fooMulFunc +# SAFEICFCHECK-NEXT: skipping function with reference taken barMulFunc +# SAFEICFCHECK-NEXT: skipping function with reference taken barAddFunc +# SAFEICFCHECK-NEXT: ICF iteration 1 +# SAFEICFCHECK-NEXT: ===--------- + +## clang++ main.cpp -c -o -fno-PIC +## Similar code gets generated for external reference function. +## Other functions removed for brevity. +## const static int (*const funcGlobalBarAdd)(int, int) = barAdd; +## const int (*const funcGlobalBarMul)(int, int) = barMul; +## int main(int argc, char **argv) { +## int temp = helper1(funcGlobalBarAdd, FooVar, BarVar) +## return temp; +## } +## Manually modified to remove "extra" assembly. + .globl fooMulFunc + .type fooMulFunc,@function +fooMulFunc: + imull -8(%rbp), %eax + retq + .size fooMulFunc, .-fooMulFunc + + .globl barMulFunc + .type barMulFunc,@function +barMulFunc: + imull -8(%rbp), %eax + retq + .size barMulFunc, .-barMulFunc + + .globl fooAddFunc + .type fooAddFunc,@function +fooAddFunc: + addl -8(%rbp), %eax + retq + .size fooAddFunc, .-fooAddFunc + + .globl barAddFunc + .type barAddFunc,@function +barAddFunc: + addl -8(%rbp), %eax + retq + .size barAddFunc, .-barAddFunc + + .globl helperFunc + .type helperFunc,@function +helperFunc: + movabsq $barAddFunc, %rax + cmpq %rax, -16(%rbp) + retq + .size helperFunc, .-helperFunc + + .globl main + .type main,@function +main: + movl FooVar, %esi + movl BarVar, %edx + movabsq $barAddFunc, %rdi + callq helperFunc + movabsq $fooMulFunc, %rdi + movabsq $barMulFunc, %rsi + retq + .size main, .-main + + .type FooVar,@object + .data + .globl FooVar +FooVar: + .long 1 + .size FooVar, 4 + + .type BarVar,@object + .globl BarVar +BarVar: + .long 2 + .size BarVar, 4 + + .type .L.str,@object + .section .rodata.str1.1,"aMS",@progbits,1 +.L.str: + .asciz "val: %d\n" + .size .L.str, 9 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/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-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index b9db78cf7d688..93efdd44f4589 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -236,10 +236,10 @@ static RecordDecl *getRecordDeclForType(const QualType &T) { return nullptr; } -TypeInfo getTypeInfoForType(const QualType &T) { +TypeInfo getTypeInfoForType(const QualType &T, const PrintingPolicy &Policy) { const TagDecl *TD = getTagDeclForType(T); if (!TD) - return TypeInfo(Reference(SymbolID(), T.getAsString())); + return TypeInfo(Reference(SymbolID(), T.getAsString(Policy))); InfoType IT; if (dyn_cast(TD)) { @@ -250,7 +250,7 @@ TypeInfo getTypeInfoForType(const QualType &T) { IT = InfoType::IT_default; } return TypeInfo(Reference(getUSRForDecl(TD), TD->getNameAsString(), IT, - T.getAsString(), getInfoRelativePath(TD))); + T.getAsString(Policy), getInfoRelativePath(TD))); } static bool isPublic(const clang::AccessSpecifier AS, @@ -379,10 +379,11 @@ static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly, if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F)) continue; + auto &LO = F->getLangOpts(); // Use getAccessUnsafe so that we just get the default AS_none if it's not // valid, as opposed to an assert. MemberTypeInfo &NewMember = I.Members.emplace_back( - getTypeInfoForType(F->getTypeSourceInfo()->getType()), + getTypeInfoForType(F->getTypeSourceInfo()->getType(), LO), F->getNameAsString(), getFinalAccessSpecifier(Access, F->getAccessUnsafe())); populateMemberTypeInfo(NewMember, F); @@ -412,9 +413,10 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) { } static void parseParameters(FunctionInfo &I, const FunctionDecl *D) { + auto &LO = D->getLangOpts(); for (const ParmVarDecl *P : D->parameters()) { FieldTypeInfo &FieldInfo = I.Params.emplace_back( - getTypeInfoForType(P->getOriginalType()), P->getNameAsString()); + getTypeInfoForType(P->getOriginalType(), LO), P->getNameAsString()); FieldInfo.DefaultValue = getSourceCode(D, P->getDefaultArgRange()); } } @@ -541,7 +543,8 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, bool &IsInAnonymousNamespace) { populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir, IsInAnonymousNamespace); - I.ReturnType = getTypeInfoForType(D->getReturnType()); + auto &LO = D->getLangOpts(); + I.ReturnType = getTypeInfoForType(D->getReturnType(), LO); parseParameters(I, D); PopulateTemplateParameters(I.Template, D); @@ -783,7 +786,8 @@ emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber, return {}; Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir); - Info.Underlying = getTypeInfoForType(D->getUnderlyingType()); + auto &LO = D->getLangOpts(); + Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO); if (Info.Underlying.Type.Name.empty()) { // Typedef for an unnamed type. This is like "typedef struct { } Foo;" // The record serializer explicitly checks for this syntax and constructs @@ -809,7 +813,8 @@ emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber, return {}; Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir); - Info.Underlying = getTypeInfoForType(D->getUnderlyingType()); + auto &LO = D->getLangOpts(); + Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO); Info.IsUsing = true; // Info is wrapped in its parent scope so is returned in the second position. 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/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/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/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 5e7a0e65690b7..7638bbc103d16 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -57,10 +57,9 @@ struct MissingIncludeInfo { IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - IgnoreHeaders(utils::options::parseStringList( - Options.getLocalOrGlobal("IgnoreHeaders", ""))), - DeduplicateFindings( - Options.getLocalOrGlobal("DeduplicateFindings", true)) { + IgnoreHeaders( + utils::options::parseStringList(Options.get("IgnoreHeaders", ""))), + DeduplicateFindings(Options.get("DeduplicateFindings", true)) { for (const auto &Header : IgnoreHeaders) { if (!llvm::Regex{Header}.isValid()) configurationDiag("Invalid ignore headers regex '%0'") << Header; 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/InconsistentDeclarationParameterNameCheck.h b/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h index 1c526577b403f..0c5ead860c161 100644 --- a/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h +++ b/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h @@ -26,7 +26,7 @@ class InconsistentDeclarationParameterNameCheck : public ClangTidyCheck { ClangTidyContext *Context) : ClangTidyCheck(Name, Context), IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)), - Strict(Options.getLocalOrGlobal("Strict", false)) {} + Strict(Options.get("Strict", false)) {} void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; 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/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/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/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/unittests/DumpASTTests.cpp b/clang-tools-extra/clangd/unittests/DumpASTTests.cpp index 304682118c871..cb2c17ad4ef0d 100644 --- a/clang-tools-extra/clangd/unittests/DumpASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/DumpASTTests.cpp @@ -49,7 +49,7 @@ declaration: Function - root )"}, {R"cpp( namespace root { -struct S { static const int x = 0; }; +struct S { static const int x = 0; ~S(); }; int y = S::x + root::S().x; } )cpp", @@ -60,10 +60,12 @@ declaration: Namespace - root type: Qualified - const type: Builtin - int expression: IntegerLiteral - 0 + declaration: CXXDestructor + type: Record - S + type: FunctionProto + type: Builtin - void declaration: CXXConstructor declaration: CXXConstructor - declaration: CXXConstructor - declaration: CXXDestructor declaration: Var - y type: Builtin - int expression: ExprWithCleanups @@ -74,7 +76,7 @@ declaration: Namespace - root type: Record - S expression: ImplicitCast - LValueToRValue expression: Member - x - expression: MaterializeTemporary - rvalue + expression: CXXBindTemporary expression: CXXTemporaryObject - S type: Elaborated specifier: Namespace - root:: @@ -82,6 +84,37 @@ declaration: Namespace - root )"}, {R"cpp( namespace root { +struct S { static const int x = 0; }; +int y = S::x + root::S().x; +} + )cpp", + R"( +declaration: Namespace - root + declaration: CXXRecord - S + declaration: Var - x + type: Qualified - const + type: Builtin - int + expression: IntegerLiteral - 0 + declaration: CXXConstructor + declaration: CXXConstructor + declaration: CXXConstructor + declaration: CXXDestructor + declaration: Var - y + type: Builtin - int + expression: BinaryOperator - + + expression: ImplicitCast - LValueToRValue + expression: DeclRef - x + specifier: TypeSpec + type: Record - S + expression: ImplicitCast - LValueToRValue + expression: Member - x + expression: CXXTemporaryObject - S + type: Elaborated + specifier: Namespace - root:: + type: Record - S + )"}, + {R"cpp( +namespace root { template int tmpl() { (void)tmpl(); return T::value; 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/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 b2b66dca6ccf8..3fd7a4f9da18a 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -115,6 +115,24 @@ Improvements to clang-tidy - Improved :program:`run-clang-tidy.py` script. Fixed minor shutdown noise happening on certain platforms when interrupting the script. +- Removed :program:`clang-tidy`'s global options for most of checks. All options + are changed to local options except `IncludeStyle`, `StrictMode` and + `IgnoreMacros`. + +.. csv-table:: + :header: "Check", "Options removed from global option" + + :doc:`bugprone-reserved-identifier `, AggressiveDependentMemberLookup + :doc:`bugprone-unchecked-optional-access `, IgnoreSmartPointerDereference + :doc:`cppcoreguidelines-pro-type-member-init `, UseAssignment + :doc:`cppcoreguidelines-rvalue-reference-param-not-moved `, AllowPartialMove; IgnoreUnnamedParams; IgnoreNonDeducedTemplateTypes + :doc:`misc-include-cleaner `, IgnoreHeaders; DeduplicateFindings + :doc:`performance-inefficient-vector-operation `, EnableProto + :doc:`readability-identifier-naming `, AggressiveDependentMemberLookup + :doc:`readability-inconsistent-declaration-parameter-name `, Strict + :doc:`readability-redundant-access-specifiers `, CheckFirstDeclaration + :doc:`readability-redundant-casting `, IgnoreTypeAliases + New checks ^^^^^^^^^^ @@ -136,10 +154,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 +200,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. 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 `, Clang Static Analyzer cplusplus.PureVirtualCall, + :doc:`clang-analyzer-cplusplus.SelfAssignment `, `Clang Static Analyzer cplusplus.SelfAssignment `_, :doc:`clang-analyzer-cplusplus.StringChecker `, `Clang Static Analyzer cplusplus.StringChecker `_, :doc:`clang-analyzer-deadcode.DeadStores `, `Clang Static Analyzer deadcode.DeadStores `_, :doc:`clang-analyzer-fuchsia.HandleChecker `, `Clang Static Analyzer fuchsia.HandleChecker `_, @@ -471,7 +472,6 @@ Check aliases :doc:`clang-analyzer-optin.cplusplus.UninitializedObject `, `Clang Static Analyzer optin.cplusplus.UninitializedObject `_, :doc:`clang-analyzer-optin.cplusplus.VirtualCall `, `Clang Static Analyzer optin.cplusplus.VirtualCall `_, :doc:`clang-analyzer-optin.mpi.MPI-Checker `, `Clang Static Analyzer optin.mpi.MPI-Checker `_, - :doc:`clang-analyzer-optin.osx.OSObjectCStyleCast `, Clang Static Analyzer optin.osx.OSObjectCStyleCast, :doc:`clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker `, `Clang Static Analyzer optin.osx.cocoa.localizability.EmptyLocalizationContextChecker `_, :doc:`clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker `, `Clang Static Analyzer optin.osx.cocoa.localizability.NonLocalizedStringChecker `_, :doc:`clang-analyzer-optin.performance.GCDAntipattern `, `Clang Static Analyzer optin.performance.GCDAntipattern `_, @@ -479,9 +479,7 @@ Check aliases :doc:`clang-analyzer-optin.portability.UnixAPI `, `Clang Static Analyzer optin.portability.UnixAPI `_, :doc:`clang-analyzer-optin.taint.TaintedAlloc `, `Clang Static Analyzer optin.taint.TaintedAlloc `_, :doc:`clang-analyzer-osx.API `, `Clang Static Analyzer osx.API `_, - :doc:`clang-analyzer-osx.MIG `, Clang Static Analyzer osx.MIG, :doc:`clang-analyzer-osx.NumberObjectConversion `, `Clang Static Analyzer osx.NumberObjectConversion `_, - :doc:`clang-analyzer-osx.OSObjectRetainCount `, Clang Static Analyzer osx.OSObjectRetainCount, :doc:`clang-analyzer-osx.ObjCProperty `, `Clang Static Analyzer osx.ObjCProperty `_, :doc:`clang-analyzer-osx.SecKeychainAPI `, `Clang Static Analyzer osx.SecKeychainAPI `_, :doc:`clang-analyzer-osx.cocoa.AtSync `, `Clang Static Analyzer osx.cocoa.AtSync `_, @@ -508,8 +506,8 @@ Check aliases :doc:`clang-analyzer-osx.coreFoundation.containers.OutOfBounds `, `Clang Static Analyzer osx.coreFoundation.containers.OutOfBounds `_, :doc:`clang-analyzer-osx.coreFoundation.containers.PointerSizedValues `, `Clang Static Analyzer osx.coreFoundation.containers.PointerSizedValues `_, :doc:`clang-analyzer-security.FloatLoopCounter `, `Clang Static Analyzer security.FloatLoopCounter `_, - :doc:`clang-analyzer-security.PutenvStackArray `, Clang Static Analyzer security.PutenvStackArray, - :doc:`clang-analyzer-security.SetgidSetuidOrder `, Clang Static Analyzer security.SetgidSetuidOrder, + :doc:`clang-analyzer-security.PutenvStackArray `, `Clang Static Analyzer security.PutenvStackArray `_, + :doc:`clang-analyzer-security.SetgidSetuidOrder `, `Clang Static Analyzer security.SetgidSetuidOrder `_, :doc:`clang-analyzer-security.cert.env.InvalidPtr `, `Clang Static Analyzer security.cert.env.InvalidPtr `_, :doc:`clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling `, `Clang Static Analyzer security.insecureAPI.DeprecatedOrUnsafeBufferHandling `_, :doc:`clang-analyzer-security.insecureAPI.UncheckedReturn `, `Clang Static Analyzer security.insecureAPI.UncheckedReturn `_, @@ -535,9 +533,6 @@ Check aliases :doc:`clang-analyzer-unix.Vfork `, `Clang Static Analyzer unix.Vfork `_, :doc:`clang-analyzer-unix.cstring.BadSizeArg `, `Clang Static Analyzer unix.cstring.BadSizeArg `_, :doc:`clang-analyzer-unix.cstring.NullArg `, `Clang Static Analyzer unix.cstring.NullArg `_, - :doc:`clang-analyzer-valist.CopyToSelf `, Clang Static Analyzer valist.CopyToSelf, - :doc:`clang-analyzer-valist.Uninitialized `, Clang Static Analyzer valist.Uninitialized, - :doc:`clang-analyzer-valist.Unterminated `, Clang Static Analyzer valist.Unterminated, :doc:`clang-analyzer-webkit.NoUncountedMemberChecker `, `Clang Static Analyzer webkit.NoUncountedMemberChecker `_, :doc:`clang-analyzer-webkit.RefCntblBaseVirtualDtor `, `Clang Static Analyzer webkit.RefCntblBaseVirtualDtor `_, :doc:`clang-analyzer-webkit.UncountedLambdaCapturesChecker `, `Clang Static Analyzer webkit.UncountedLambdaCapturesChecker `_, diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/unused-parameters.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/unused-parameters.rst index 87b75579d97a7..9321f651fd705 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/misc/unused-parameters.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/unused-parameters.rst @@ -35,13 +35,13 @@ Options .. option:: StrictMode - When `false` (default value), the check will ignore trivially unused parameters, - i.e. when the corresponding function has an empty body (and in case of - constructors - no constructor initializers). When the function body is empty, - an unused parameter is unlikely to be unnoticed by a human reader, and - there's basically no place for a bug to hide. + When `false` (default value), the check will ignore trivially unused parameters, + i.e. when the corresponding function has an empty body (and in case of + constructors - no constructor initializers). When the function body is empty, + an unused parameter is unlikely to be unnoticed by a human reader, and + there's basically no place for a bug to hide. .. option:: IgnoreVirtual - Determines whether virtual method parameters should be inspected. - Set to `true` to ignore them. Default is `false`. + Determines whether virtual method parameters should be inspected. + Set to `true` to ignore them. Default is `false`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-integer-sign-comparison.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-integer-sign-comparison.rst new file mode 100644 index 0000000000000..7e2c13b782694 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-integer-sign-comparison.rst @@ -0,0 +1,36 @@ +.. title:: clang-tidy - modernize-use-integer-sign-comparison + +modernize-use-integer-sign-comparison +===================================== + +Replace comparisons between signed and unsigned integers with their safe +C++20 ``std::cmp_*`` alternative, if available. + +The check provides a replacement only for C++20 or later, otherwise +it highlights the problem and expects the user to fix it manually. + +Examples of fixes created by the check: + +.. code-block:: c++ + + unsigned int func(int a, unsigned int b) { + return a == b; + } + +becomes + +.. code-block:: c++ + + #include + + unsigned int func(int a, unsigned int b) { + return std::cmp_equal(a, b); + } + +Options +------- + +.. option:: IncludeStyle + + A string specifying which include-style is used, `llvm` or `google`. + Default is `llvm`. diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst index a4233d5d8e269..f053e57e8d4c8 100644 --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -9,7 +9,7 @@ See also: .. toctree:: :maxdepth: 1 - The list of clang-tidy checks + List of Clang-Tidy Checks Clang-tidy IDE/Editor Integrations Getting Involved External Clang-Tidy Examples @@ -21,7 +21,7 @@ static analysis. :program:`clang-tidy` is modular and provides a convenient interface for writing new checks. -Using clang-tidy +Using Clang-Tidy ================ :program:`clang-tidy` is a `LibTooling`_-based tool, and it's easier to work diff --git a/clang-tools-extra/test/clang-doc/builtin_types.cpp b/clang-tools-extra/test/clang-doc/builtin_types.cpp new file mode 100644 index 0000000000000..6c1fc8a1d7879 --- /dev/null +++ b/clang-tools-extra/test/clang-doc/builtin_types.cpp @@ -0,0 +1,136 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t/yaml %t/md + +// RUN: clang-doc --doxygen --executor=standalone %s -output=%t/yaml +// RUN: FileCheck %s < %t/yaml/index.yaml --check-prefix=YAML + +// RUN: clang-doc --doxygen --executor=standalone %s -output=%t/md --format=md +// RUN: FileCheck %s < %t/md/GlobalNamespace/index.md --check-prefix=MD + +// YAML: --- +// YAML-NEXT: USR: '0000000000000000000000000000000000000000' +// YAML-NEXT: ChildFunctions: + +// MD: # Global Namespace +// MD: ## Functions + +extern bool b(); + +// YAML-NEXT: - USR: '88A104C263241E354ECF5B55B04AE8CEAD625B71' +// YAML-NEXT: Name: 'b' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE-5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'bool' +// YAML-NEXT: QualName: 'bool' + +// MD: ### b +// MD: *bool b()* + +char c(); + +// YAML-NEXT: - USR: 'EA3287837B3F175C8DB154406B4DAD2924F479B5' +// YAML-NEXT: Name: 'c' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE-5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'char' +// YAML-NEXT: QualName: 'char' + +// MD: ### c +// MD: *char c()* + +double d(); + +// YAML-NEXT: - USR: '60A47E4696CEFC411AB2E1EEFA2DD914E2A7E450' +// YAML-NEXT: Name: 'd' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE-5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'double' +// YAML-NEXT: QualName: 'double' + +// MD: ### d +// MD: *double d()* + +float f(); + +// YAML-NEXT: - USR: 'B3A9EC6BECD5869CF3ACDFB25153CFE6BBDD5EAB' +// YAML-NEXT: Name: 'f' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE-5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'float' +// YAML-NEXT: QualName: 'float' + +// MD: ### f +// MD: *float f()* + +int i(); + +// YAML-NEXT: - USR: '307041280A81EB46F949A94AD52587C659FD801C' +// YAML-NEXT: Name: 'i' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE-5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'int' +// YAML-NEXT: QualName: 'int' + +// MD: ### i +// MD: *int i()* + +long l(); + +// YAML-NEXT: - USR: 'A1CE9AB0064C412F857592E01332C641C1A06F37' +// YAML-NEXT: Name: 'l' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE-5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'long' +// YAML-NEXT: QualName: 'long' + +// MD: ### l +// MD: *long l()* + +long long ll(); + +// YAML-NEXT: - USR: '5C2C44ED4825C066EF6ED796863586F343C8BCA9' +// YAML-NEXT: Name: 'll' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE-5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'long long' +// YAML-NEXT: QualName: 'long long' + +// MD: ### ll +// MD: *long long ll()* + +short s(); + +// YAML-NEXT: - USR: '412341570FD3AD2C3A1E9A1DE7B3C01C07BEACFE' +// YAML-NEXT: Name: 's' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE-5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'short' +// YAML-NEXT: QualName: 'short' +// YAML-NEXT: ... + +// MD: ### s +// MD: *short s()* diff --git a/clang-tools-extra/test/clang-doc/templates.cpp b/clang-tools-extra/test/clang-doc/templates.cpp index 4d4a25b8d3b82..cab5426b7cefc 100644 --- a/clang-tools-extra/test/clang-doc/templates.cpp +++ b/clang-tools-extra/test/clang-doc/templates.cpp @@ -1,76 +1,157 @@ // RUN: rm -rf %t // RUN: mkdir %t -// RUN: echo "" > %t/compile_flags.txt -// RUN: cp "%s" "%t/test.cpp" -// RUN: clang-doc --doxygen --executor=standalone -p %t %t/test.cpp -output=%t/docs -// RUN: cat %t/docs/index.yaml | FileCheck %s --check-prefix=CHECK -// RUN: rm -rf %t + +// RUN: clang-doc --doxygen --executor=standalone %s -output=%t/docs +// RUN: cat %t/docs/index.yaml | FileCheck %s --check-prefix=YAML + +// RUN: clang-doc --doxygen --executor=standalone %s -output=%t/docs --format=md +// RUN: cat %t/docs/GlobalNamespace/index.md | FileCheck %s --check-prefix=MD + +// YAML: --- +// YAML-NEXT: USR: '{{([0-9A-F]{40})}}' +// YAML-NEXT: ChildRecords: +// YAML-NEXT: - Type: Record +// YAML-NEXT: Name: 'tuple' +// YAML-NEXT: QualName: 'tuple' +// YAML-NEXT: USR: '{{([0-9A-F]{40})}}' +// YAML-NEXT: Path: 'GlobalNamespace' + +// MD: # Global Namespace +// MD: ## Functions + +template +void ParamPackFunction(T... args); + +// YAML-NEXT: ChildFunctions: +// YAML-NEXT: - USR: '{{([0-9A-F]{40})}}' +// YAML-NEXT: Name: 'ParamPackFunction' +// YAML-NEXT: Location: +// YAML-NEXT: - LineNumber: [[# @LINE - 6]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: Params: +// YAML-NEXT: - Type: +// YAML-NEXT: Name: 'T...' +// YAML-NEXT: QualName: 'T...' +// YAML-NEXT: Name: 'args' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'void' +// YAML-NEXT: QualName: 'void' +// YAML-NEXT: Template: +// YAML-NEXT: Params: +// YAML-NEXT: - Contents: 'class... T' + +// MD: ### ParamPackFunction +// MD: *void ParamPackFunction(T... args)* template void function(T x) {} +// YAML-NEXT: - USR: '{{([0-9A-F]{40})}}' +// YAML-NEXT: Name: 'function' +// YAML-NEXT: DefLocation: +// YAML-NEXT: LineNumber: [[# @LINE - 5]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: Params: +// YAML-NEXT: - Type: +// YAML-NEXT: Name: 'T' +// YAML-NEXT: QualName: 'T' +// YAML-NEXT: Name: 'x' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'void' +// YAML-NEXT: QualName: 'void' +// YAML-NEXT: Template: +// YAML-NEXT: Params: +// YAML-NEXT: - Contents: 'typename T' +// YAML-NEXT: - Contents: 'int U = 1' + +// MD: ### function +// MD: *void function(T x)* +// MD: *Defined at {{.*}}templates.cpp#[[# @LINE - 23]]* + template<> void function(bool x) {} -template -void ParamPackFunction(T... args); +// YAML-NEXT: - USR: '{{([0-9A-F]{40})}}' +// YAML-NEXT: Name: 'function' +// YAML-NEXT: DefLocation: +// YAML-NEXT: LineNumber: [[# @LINE - 6]] +// YAML-NEXT: Filename: '{{.*}}' +// YAML-NEXT: Params: +// YAML-NEXT: - Type: +// YAML-NEXT: Name: 'bool' +// YAML-NEXT: QualName: 'bool' +// YAML-NEXT: Name: 'x' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Name: 'void' +// YAML-NEXT: QualName: 'void' +// YAML-NEXT: Template: +// YAML-NEXT: Specialization: +// YAML-NEXT: SpecializationOf: '{{([0-9A-F]{40})}}' +// YAML-NEXT: Params: +// YAML-NEXT: - Contents: 'bool' +// YAML-NEXT: - Contents: '0' + +// MD: ### function +// MD: *void function(bool x)* +// MD: *Defined at {{.*}}templates.cpp#[[# @LINE - 26]]* + +/// A Tuple type +/// +/// Does Tuple things. +template +struct tuple{}; + +/// A function with a tuple parameter +/// +/// \param t The input to func_with_tuple_param +tuple func_with_tuple_param(tuple t){ return t;} + +// YAML-NEXT: - USR: '{{([0-9A-F]{40})}}' +// YAML-NEXT: Name: 'func_with_tuple_param' +// YAML-NEXT: Description: +// YAML-NEXT: - Kind: 'FullComment' +// YAML-NEXT: Children: +// YAML-NEXT: - Kind: 'ParagraphComment' +// YAML-NEXT: Children: +// YAML-NEXT: - Kind: 'TextComment' +// YAML-NEXT: Text: ' A function with a tuple parameter' +// YAML-NEXT: - Kind: 'ParagraphComment' +// YAML-NEXT: Children: +// YAML-NEXT: - Kind: 'TextComment' +// YAML-NEXT: - Kind: 'ParamCommandComment' +// YAML-NEXT: Direction: '[in]' +// YAML-NEXT: ParamName: 't' +// YAML-NEXT: Children: +// YAML-NEXT: - Kind: 'ParagraphComment' +// YAML-NEXT: Children: +// YAML-NEXT: - Kind: 'TextComment' +// YAML-NEXT: Text: ' The input to func_with_tuple_param' +// YAML-NEXT: DefLocation: +// YAML-NEXT: LineNumber: [[# @LINE - 23]] +// YAML-NEXT: Filename: +// YAML-NEXT: Params: +// YAML-NEXT: - Type: +// YAML-NEXT: Type: Record +// YAML-NEXT: Name: 'tuple' +// YAML-NEXT: QualName: 'tuple' +// YAML-NEXT: USR: '{{([0-9A-F]{40})}}' +// YAML-NEXT: Path: 'GlobalNamespace' +// YAML-NEXT: Name: 't' +// YAML-NEXT: ReturnType: +// YAML-NEXT: Type: +// YAML-NEXT: Type: Record +// YAML-NEXT: Name: 'tuple' +// YAML-NEXT: QualName: 'tuple' +// YAML-NEXT: USR: '{{([0-9A-F]{40})}}' +// YAML-NEXT: Path: 'GlobalNamespace' +// YAML-NEXT: ... + +// MD: ### func_with_tuple_param +// MD: *tuple func_with_tuple_param(tuple t)* +// MD: *Defined at {{.*}}templates.cpp#[[# @LINE - 44]]* +// MD: A function with a tuple parameter +// MD: **t** The input to func_with_tuple_param -// CHECK: --- -// CHECK-NEXT: USR: '{{([0-9A-F]{40})}}' -// CHECK-NEXT: ChildFunctions: -// CHECK-NEXT: - USR: '{{([0-9A-F]{40})}}' -// CHECK-NEXT: Name: 'ParamPackFunction' -// CHECK-NEXT: Location: -// CHECK-NEXT: - LineNumber: 16 -// CHECK-NEXT: Filename: '{{.*}}' -// CHECK-NEXT: Params: -// CHECK-NEXT: - Type: -// CHECK-NEXT: Name: 'T...' -// CHECK-NEXT: QualName: 'T...' -// CHECK-NEXT: Name: 'args' -// CHECK-NEXT: ReturnType: -// CHECK-NEXT: Type: -// CHECK-NEXT: Name: 'void' -// CHECK-NEXT: QualName: 'void' -// CHECK-NEXT: Template: -// CHECK-NEXT: Params: -// CHECK-NEXT: - Contents: 'class... T' -// CHECK-NEXT: - USR: '{{([0-9A-F]{40})}}' -// CHECK-NEXT: Name: 'function' -// CHECK-NEXT: DefLocation: -// CHECK-NEXT: LineNumber: 10 -// CHECK-NEXT: Filename: '{{.*}}' -// CHECK-NEXT: Params: -// CHECK-NEXT: - Type: -// CHECK-NEXT: Name: 'T' -// CHECK-NEXT: QualName: 'T' -// CHECK-NEXT: Name: 'x' -// CHECK-NEXT: ReturnType: -// CHECK-NEXT: Type: -// CHECK-NEXT: Name: 'void' -// CHECK-NEXT: QualName: 'void' -// CHECK-NEXT: Template: -// CHECK-NEXT: Params: -// CHECK-NEXT: - Contents: 'typename T' -// CHECK-NEXT: - Contents: 'int U = 1' -// CHECK-NEXT: - USR: '{{([0-9A-F]{40})}}' -// CHECK-NEXT: Name: 'function' -// CHECK-NEXT: DefLocation: -// CHECK-NEXT: LineNumber: 12 -// CHECK-NEXT: Filename: '{{.*}}' -// CHECK-NEXT: Params: -// CHECK-NEXT: - Type: -// CHECK-NEXT: Name: '_Bool' -// CHECK-NEXT: QualName: '_Bool' -// CHECK-NEXT: Name: 'x' -// CHECK-NEXT: ReturnType: -// CHECK-NEXT: Type: -// CHECK-NEXT: Name: 'void' -// CHECK-NEXT: QualName: 'void' -// CHECK-NEXT: Template: -// CHECK-NEXT: Specialization: -// CHECK-NEXT: SpecializationOf: '{{([0-9A-F]{40})}}' -// CHECK-NEXT: Params: -// CHECK-NEXT: - Contents: 'bool' -// CHECK-NEXT: - Contents: '0' -// CHECK-NEXT: ... diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-strict.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-strict.cpp index c25d25ac5738f..38d91f3984647 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-strict.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-strict.cpp @@ -1,5 +1,5 @@ // RUN: %check_clang_tidy %s bugprone-argument-comment %t -- \ -// RUN: -config="{CheckOptions: {StrictMode: true}}" -- +// RUN: -config="{CheckOptions: {bugprone-argument-comment.StrictMode: true}}" -- void f(int _with_underscores_); void g(int x_); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion-construct-from-std.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion-construct-from-std.cpp new file mode 100644 index 0000000000000..768ab1ce014ce --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion-construct-from-std.cpp @@ -0,0 +1,53 @@ +// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-optional-value-conversion %t + +namespace std { +template struct optional { + constexpr optional() noexcept; + constexpr optional(T &&) noexcept; + constexpr optional(const T &) noexcept; + template constexpr optional(U &&) noexcept; + const T &operator*() const; + T *operator->(); + const T *operator->() const; + T &operator*(); + const T &value() const; + T &value(); + const T &get() const; + T &get(); + T value_or(T) const; +}; + +template T &&move(T &x) { return static_cast(x); } + +template class default_delete {}; + +template > +class unique_ptr {}; + +template +class shared_ptr {}; + +template unique_ptr make_unique(Args &&...args); +template shared_ptr make_shared(Args &&...args); + +} // namespace std + +struct A { + explicit A (int); +}; +std::optional opt; + +void invalid() { + std::make_unique>(opt.value()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional' into 'int' and back into 'std::optional', remove potentially error-prone optional dereference [bugprone-optional-value-conversion] + using A = std::optional; + std::make_unique(opt.value()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional' into 'int' and back into 'std::optional', remove potentially error-prone optional dereference [bugprone-optional-value-conversion] + std::make_shared>(opt.value()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional' into 'int' and back into 'std::optional', remove potentially error-prone optional dereference [bugprone-optional-value-conversion] +} + +void valid() { + std::make_unique(opt.value()); + std::make_shared(opt.value()); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-const-cast.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-const-cast.cpp index be70e3ba35699..a775334260e35 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-const-cast.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-const-cast.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy -check-suffix=STRICT %s cppcoreguidelines-pro-type-const-cast %t -- -config="{CheckOptions: {StrictMode: true}}" +// RUN: %check_clang_tidy -check-suffix=STRICT %s cppcoreguidelines-pro-type-const-cast %t -- -config="{CheckOptions: {cppcoreguidelines-pro-type-const-cast.StrictMode: true}}" // RUN: %check_clang_tidy -check-suffix=NSTRICT %s cppcoreguidelines-pro-type-const-cast %t namespace Const { diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp index 11179b7d2d19b..a3c73a960974b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp @@ -1,5 +1,5 @@ // RUN: %check_clang_tidy -check-suffixes=NSTRICT,STRICT %s cppcoreguidelines-pro-type-static-cast-downcast %t -// RUN: %check_clang_tidy -check-suffix=NSTRICT %s cppcoreguidelines-pro-type-static-cast-downcast %t -- -config="{CheckOptions: {StrictMode: false}}" +// RUN: %check_clang_tidy -check-suffix=NSTRICT %s cppcoreguidelines-pro-type-static-cast-downcast %t -- -config="{CheckOptions: {cppcoreguidelines-pro-type-static-cast-downcast.StrictMode: false}}" class Base { }; diff --git a/clang-tools-extra/test/clang-tidy/checkers/fuchsia/default-arguments-calls.cpp b/clang-tools-extra/test/clang-tidy/checkers/fuchsia/default-arguments-calls.cpp index ed9079092f6ac..50b6d4c5676c3 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/fuchsia/default-arguments-calls.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/fuchsia/default-arguments-calls.cpp @@ -26,7 +26,7 @@ void S::x(int i = 12) {} int main() { S s; s.x(); - // CHECK-NOTES: [[@LINE-1]]:3: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments-calls] + // CHECK-NOTES: [[@LINE-1]]:5: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments-calls] // CHECK-NOTES: [[@LINE-6]]:11: note: default parameter was declared here // CHECK-NEXT: void S::x(int i = 12) {} x(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters-strict.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters-strict.cpp index f8385c1a17e7b..319cefa1c68f1 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters-strict.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters-strict.cpp @@ -1,5 +1,5 @@ // RUN: %check_clang_tidy %s misc-unused-parameters %t -- \ -// RUN: -config="{CheckOptions: {StrictMode: true}}" -- +// RUN: -config="{CheckOptions: {misc-unused-parameters.StrictMode: true}}" -- // Warn on empty function bodies in StrictMode. namespace strict_mode { diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp new file mode 100644 index 0000000000000..99f00444c2d3f --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-integer-sign-comparison.cpp @@ -0,0 +1,122 @@ +// CHECK-FIXES: #include +// RUN: %check_clang_tidy -std=c++20 %s modernize-use-integer-sign-comparison %t + +// The code that triggers the check +#define MAX_MACRO(a, b) (a < b) ? b : a + +unsigned int FuncParameters(int bla) { + unsigned int result = 0; + if (result == bla) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_equal(result , bla)) + + return 1; +} + +template +void TemplateFuncParameter(T val) { + unsigned long uL = 0; + if (val >= uL) + return; +// CHECK-MESSAGES-NOT: warning: +} + +template +int TemplateFuncParameters(T1 val1, T2 val2) { + if (val1 >= val2) + return 0; +// CHECK-MESSAGES-NOT: warning: + return 1; +} + +int AllComparisons() { + unsigned int uVar = 42; + unsigned short uArray[7] = {0, 1, 2, 3, 9, 7, 9}; + + int sVar = -42; + short sArray[7] = {-1, -2, -8, -94, -5, -4, -6}; + + enum INT_TEST { + VAL1 = 0, + VAL2 = -1 + }; + + char ch = 'a'; + unsigned char uCh = 'a'; + signed char sCh = 'a'; + bool bln = false; + + if (bln == sVar) + return 0; +// CHECK-MESSAGES-NOT: warning: + + if (ch > uCh) + return 0; +// CHECK-MESSAGES-NOT: warning: + + if (sVar <= INT_TEST::VAL2) + return 0; +// CHECK-MESSAGES-NOT: warning: + + if (uCh < sCh) + return -1; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_less(uCh , sCh)) + + if ((int)uVar < sVar) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_less(uVar, sVar)) + + (uVar != sVar) ? uVar = sVar + : sVar = uVar; +// CHECK-MESSAGES: :[[@LINE-2]]:6: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: (std::cmp_not_equal(uVar , sVar)) ? uVar = sVar + + while (uArray[0] <= sArray[0]) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:12: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: while (std::cmp_less_equal(uArray[0] , sArray[0])) + + if (uArray[1] > sArray[1]) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_greater(uArray[1] , sArray[1])) + + MAX_MACRO(uVar, sArray[0]); +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] + + if (static_cast(uArray[2]) < static_cast(sArray[2])) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_less(uArray[2],sArray[2])) + + if ((unsigned int)uArray[3] < (int)sArray[3]) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_less(uArray[3],sArray[3])) + + if ((unsigned int)(uArray[4]) < (int)(sArray[4])) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_less((uArray[4]),(sArray[4]))) + + if (uArray[5] > sArray[5]) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_greater(uArray[5] , sArray[5])) + + #define VALUE sArray[6] + if (uArray[6] > VALUE) + return 0; +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: comparison between 'signed' and 'unsigned' integers [modernize-use-integer-sign-comparison] +// CHECK-FIXES: if (std::cmp_greater(uArray[6] , VALUE)) + + + FuncParameters(uVar); + TemplateFuncParameter(sVar); + TemplateFuncParameters(uVar, sVar); + + return 0; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp index 42fb3382e4a93..0a5a63eba2596 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp @@ -1,12 +1,12 @@ // RUN: %check_clang_tidy \ // RUN: -std=c++20 %s modernize-use-std-format %t -- \ -// RUN: -config="{CheckOptions: {StrictMode: true}}" \ +// RUN: -config="{CheckOptions: {modernize-use-std-format.StrictMode: true}}" \ // RUN: -- -isystem %clang_tidy_headers \ // RUN: -DPRI_CMDLINE_MACRO="\"s\"" \ // RUN: -D__PRI_CMDLINE_MACRO="\"s\"" // RUN: %check_clang_tidy \ // RUN: -std=c++20 %s modernize-use-std-format %t -- \ -// RUN: -config="{CheckOptions: {StrictMode: false}}" \ +// RUN: -config="{CheckOptions: {modernize-use-std-format.StrictMode: false}}" \ // RUN: -- -isystem %clang_tidy_headers \ // RUN: -DPRI_CMDLINE_MACRO="\"s\"" \ // RUN: -D__PRI_CMDLINE_MACRO="\"s\"" diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp index 95c32837e4447..83fbd2e7500c5 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp @@ -1,10 +1,10 @@ // RUN: %check_clang_tidy \ // RUN: -std=c++23 %s modernize-use-std-print %t -- \ -// RUN: -config="{CheckOptions: {StrictMode: true}}" \ +// RUN: -config="{CheckOptions: {modernize-use-std-print.StrictMode: true}}" \ // RUN: -- -isystem %clang_tidy_headers // RUN: %check_clang_tidy \ // RUN: -std=c++23 %s modernize-use-std-print %t -- \ -// RUN: -config="{CheckOptions: {StrictMode: false}}" \ +// RUN: -config="{CheckOptions: {modernize-use-std-print.StrictMode: false}}" \ // RUN: -- -isystem %clang_tidy_headers #include diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp index f11fc408fcb9c..5da995d9d6e83 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print.cpp @@ -1,12 +1,12 @@ // RUN: %check_clang_tidy -check-suffixes=,STRICT \ // RUN: -std=c++23 %s modernize-use-std-print %t -- \ -// RUN: -config="{CheckOptions: {StrictMode: true}}" \ +// RUN: -config="{CheckOptions: {modernize-use-std-print.StrictMode: true}}" \ // RUN: -- -isystem %clang_tidy_headers -fexceptions \ // RUN: -DPRI_CMDLINE_MACRO="\"s\"" \ // RUN: -D__PRI_CMDLINE_MACRO="\"s\"" // RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \ // RUN: -std=c++23 %s modernize-use-std-print %t -- \ -// RUN: -config="{CheckOptions: {StrictMode: false}}" \ +// RUN: -config="{CheckOptions: {modernize-use-std-print.StrictMode: false}}" \ // RUN: -- -isystem %clang_tidy_headers -fexceptions \ // RUN: -DPRI_CMDLINE_MACRO="\"s\"" \ // RUN: -D__PRI_CMDLINE_MACRO="\"s\"" diff --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp index 5df42b9f5bca0..e6168418b58fa 100644 --- a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp @@ -631,8 +631,8 @@ TEST(SerializeTests, emitTypedefs) { TEST(SerializeTests, emitFunctionTemplate) { EmittedInfoList Infos; // A template and a specialization. - ExtractInfosFromCode("template void GetFoo(T);\n" - "template<> void GetFoo(bool);", + ExtractInfosFromCode("template bool GetFoo(T);\n" + "template<> bool GetFoo(bool);", 2, /*Public=*/false, Infos); @@ -666,6 +666,8 @@ TEST(SerializeTests, emitFunctionTemplate) { ASSERT_EQ(1u, Func2.Template->Specialization->Params.size()); EXPECT_EQ("bool", Func2.Template->Specialization->Params[0].Contents); EXPECT_EQ(Func1.USR, Func2.Template->Specialization->SpecializationOf); + + EXPECT_EQ("bool", Func2.ReturnType.Type.Name); } TEST(SerializeTests, emitClassTemplate) { diff --git a/clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp b/clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp index d400cf6fe2d57..3d6ec995e443d 100644 --- a/clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp @@ -71,10 +71,12 @@ TEST(IncludeCleanerCheckTest, SuppressUnusedIncludes) { std::vector Errors; ClangTidyOptions Opts; - Opts.CheckOptions["IgnoreHeaders"] = llvm::StringRef{llvm::formatv( - "bar.h;{0};{1};vector;;", - llvm::Regex::escape(appendPathFileSystemIndependent({"foo", "qux.h"})), - llvm::Regex::escape(appendPathFileSystemIndependent({"baz", "qux"})))}; + Opts.CheckOptions["test-check-0.IgnoreHeaders"] = llvm::StringRef{ + llvm::formatv("bar.h;{0};{1};vector;;", + llvm::Regex::escape( + appendPathFileSystemIndependent({"foo", "qux.h"})), + llvm::Regex::escape( + appendPathFileSystemIndependent({"baz", "qux"})))}; EXPECT_EQ( PostCode, runCheckOnCode( @@ -139,7 +141,7 @@ int BarResult2 = $diag2^bar();)"); { std::vector Errors; ClangTidyOptions Opts; - Opts.CheckOptions.insert({"DeduplicateFindings", "false"}); + Opts.CheckOptions["test-check-0.DeduplicateFindings"] = "false"; runCheckOnCode(Code.code(), &Errors, "file.cpp", {}, Opts, {{"baz.h", R"(#pragma once @@ -170,7 +172,7 @@ std::vector x; )"; ClangTidyOptions Opts; - Opts.CheckOptions["IgnoreHeaders"] = llvm::StringRef{ + Opts.CheckOptions["test-check-0.IgnoreHeaders"] = llvm::StringRef{ "public.h;;baz.h;" + llvm::Regex::escape(appendPathFileSystemIndependent({"foo", "qux.h"}))}; std::vector Errors; diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 27e8095534a65..b79e570667b2c 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -362,7 +362,6 @@ if (APPLE AND NOT CMAKE_LINKER MATCHES ".*lld.*") message(STATUS "Host linker version: ${HOST_LINK_VERSION}") endif() -include(CMakeParseArguments) include(AddClang) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/clang/Maintainers.rst b/clang/Maintainers.rst index 7396211715a80..f9732aade7186 100644 --- a/clang/Maintainers.rst +++ b/clang/Maintainers.rst @@ -320,8 +320,8 @@ OpenMP conformance OpenCL conformance ~~~~~~~~~~~~~~~~~~ -| Anastasia Stulova -| anastasia\@compiler-experts.com (email), Anastasia (Phabricator), AnastasiaStulova (GitHub) +| Sven van Haastregt +| sven.vanhaastregt\@arm.com (email), svenvh (GitHub) OpenACC @@ -365,6 +365,7 @@ Emeritus Lead Maintainers Inactive component maintainers ------------------------------ +| Anastasia Stulova (stulovaa\@gmail.com) -- OpenCL, C++ for OpenCL | Chandler Carruth (chandlerc\@gmail.com, chandlerc\@google.com) -- CMake, library layering | Devin Coughlin (dcoughlin\@apple.com) -- Clang static analyzer | Manuel Klimek (klimek\@google.com (email), klimek (Phabricator), r4nt (GitHub)) -- Tooling, AST matchers diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index 784a883a3bf91..e799900094df3 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -300,19 +300,22 @@ if(FUCHSIA_SDK) set(LLVM_RUNTIME_MULTILIB_hwasan+noexcept_TARGETS "aarch64-unknown-fuchsia;riscv64-unknown-fuchsia" CACHE STRING "") endif() -foreach(target armv6m-none-eabi;armv7m-none-eabi;armv8m.main-none-eabi;armv8.1m.main-none-eabi) +foreach(target armv6m-none-eabi;armv7m-none-eabi;armv8m.main-none-eabi;armv8.1m.main-none-eabi;aarch64-none-elf) list(APPEND BUILTIN_TARGETS "${target}") set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "") set(BUILTINS_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "") set(BUILTINS_${target}_CMAKE_SYSROOT "" CACHE STRING "") set(BUILTINS_${target}_CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "") foreach(lang C;CXX;ASM) - set(BUILTINS_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "--target=${target}") + if(NOT ${target} STREQUAL "aarch64-none-elf") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mthumb") + endif() if(${target} STREQUAL "armv8m.main-none-eabi") - set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33") endif() if(${target} STREQUAL "armv8.1m.main-none-eabi") - set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8.1-m.main+mve.fp+fp.dp -mcpu=cortex-m55" CACHE STRING "") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8.1-m.main+mve.fp+fp.dp -mcpu=cortex-m55") endif() set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "${BUILTINS_${target}_CMAKE_${lang}_local_flags}" CACHE STRING "") endforeach() @@ -330,12 +333,15 @@ foreach(target armv6m-none-eabi;armv7m-none-eabi;armv8m.main-none-eabi;armv8.1m. foreach(lang C;CXX;ASM) # TODO: The preprocessor defines workaround various issues in libc and libc++ integration. # These should be addressed and removed over time. - set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dgettimeofday(tv, tz)\" -D_LIBCPP_PRINT=1") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" -D_LIBCPP_PRINT=1") + if(NOT ${target} STREQUAL "aarch64-none-elf") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mthumb") + endif() if(${target} STREQUAL "armv8m.main-none-eabi") - set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33") endif() if(${target} STREQUAL "armv8.1m.main-none-eabi") - set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8.1-m.main+mve.fp+fp.dp -mcpu=cortex-m55" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8.1-m.main+mve.fp+fp.dp -mcpu=cortex-m55") endif() set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "${RUNTIMES_${target}_CMAKE_${lang}_local_flags}" CACHE STRING "") endforeach() @@ -388,7 +394,7 @@ foreach(target riscv32-unknown-elf) foreach(lang C;CXX;ASM) # TODO: The preprocessor defines workaround various issues in libc and libc++ integration. # These should be addressed and removed over time. - set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dgettimeofday(tv, tz)\" -D_LIBCPP_PRINT=1" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" -D_LIBCPP_PRINT=1" CACHE STRING "") endforeach() foreach(type SHARED;MODULE;EXE) set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "") diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 6a886a49ea076..3d4f68b818bce 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -4526,9 +4526,13 @@ default member initializer, the invocation point is the location of the constructor or aggregate initialization used to create the object. Otherwise the invocation point is the same as the location of the builtin. -When the invocation point of ``__builtin_FUNCTION`` is not a function scope the +When the invocation point of ``__builtin_FUNCTION`` is not a function scope, the empty string is returned. +The builtin ``__builtin_COLUMN`` returns the offset from the start of the line, +beginning from column 1. `This may differ from other implementations. +`_ + The builtin ``__builtin_source_location`` returns a pointer to constant static data of type ``std::source_location::__impl``. This type must have already been defined, and must contain exactly four fields: ``const char *_M_file_name``, @@ -5551,7 +5555,7 @@ The ``#pragma clang section`` directive obeys the following rules: * Global variables that are initialized to zero will be placed in the named bss section, if one is present. -* The ``#pragma clang section`` directive does not does try to infer section-kind +* The ``#pragma clang section`` directive does not try to infer section-kind from the name. For example, naming a section "``.bss.mySec``" does NOT mean it will be a bss section name. diff --git a/clang/docs/MatrixTypes.rst b/clang/docs/MatrixTypes.rst index e32e13b73aba6..32949c6c43529 100644 --- a/clang/docs/MatrixTypes.rst +++ b/clang/docs/MatrixTypes.rst @@ -33,9 +33,10 @@ program is ill-formed. Currently, the element type of a matrix is only permitted to be one of the following types: -* an integer type (as in C23 6.2.5p22), but excluding enumerated types and ``bool`` -* the standard floating types ``float`` or ``double`` -* a half-precision floating point type, if one is supported on the target +* an integer type (as in C23 6.2.5p22), but excluding enumerated types, ``bool``, + and ``_BitInt`` types whose width is not a power of 2; +* the standard floating types ``float`` or ``double``; +* a half-precision floating point type, if one is supported on the target. Other types may be supported in the future. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c040a0d80d0df..29794f27d3005 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -61,6 +61,8 @@ code bases. C/C++ Language Potentially Breaking Changes ------------------------------------------- +- Clang now rejects ``_Complex _BitInt`` types. + C++ Specific Potentially Breaking Changes ----------------------------------------- @@ -270,6 +272,8 @@ C++23 Feature Support - Extend lifetime of temporaries in mem-default-init for P2718R0. Clang now fully supports `P2718R0 Lifetime extension in range-based for loops `_. + +- ``__cpp_explicit_this_parameter`` is now defined. (#GH82780) C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -319,6 +323,11 @@ Resolutions to C++ Defect Reports - Fix name lookup for a dependent base class that is the current instantiation. (`CWG591: When a dependent base class is the current instantiation `_). +- Clang now allows calling explicit object member functions directly with prvalues + instead of always materializing a temporary, meaning by-value explicit object parameters + do not need to move from a temporary. + (`CWG2813: Class member access with prvalues `_). + C Language Changes ------------------ @@ -414,6 +423,12 @@ Non-comprehensive list of changes in this release ``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``, ``__builtin_elementwise_sub_sat``. +- Clang now rejects ``_BitInt`` matrix element types if the bit width is less than ``CHAR_WIDTH`` or + not a power of two, matching preexisting behaviour for vector types. + +- Matrix types (a Clang extension) can now be used in pseudo-destructor expressions, + which allows them to be stored in STL containers. + New Compiler Flags ------------------ @@ -458,6 +473,10 @@ Modified Compiler Flags ``memset`` and similar functions for which it is a documented undefined behavior. It is implied by ``-Wnontrivial-memaccess`` +- Added ``-fmodules-reduced-bmi`` flag corresponding to + ``-fexperimental-modules-reduced-bmi`` flag. The ``-fmodules-reduced-bmi`` flag + is intended to be enabled by default in the future. + Removed Compiler Flags ------------------------- @@ -608,6 +627,8 @@ Improvements to Clang's diagnostics - Clang now diagnoses ``[[deprecated]]`` attribute usage on local variables (#GH90073). +- Fix false positives when `[[gsl::Owner/Pointer]]` and `[[clang::lifetimebound]]` are used together. + - Improved diagnostic message for ``__builtin_bit_cast`` size mismatch (#GH115870). - Clang now omits shadow warnings for enum constants in separate class scopes (#GH62588). @@ -660,6 +681,25 @@ Improvements to Clang's diagnostics bool operator==(const C&) = default; }; +- Clang now emits `-Wdangling-capture` diangostic when a STL container captures a dangling reference. + + .. code-block:: c++ + + void test() { + std::vector views; + views.push_back(std::string("123")); // warning + } + +- Clang now emits a ``-Wtautological-compare`` diagnostic when a check for + pointer addition overflow is always true or false, because overflow would + be undefined behavior. + + .. code-block:: c++ + + bool incorrect_overflow_check(const char *ptr, size_t index) { + return ptr + index < ptr; // warning + } + Improvements to Clang's time-trace ---------------------------------- @@ -698,6 +738,8 @@ Bug Fixes to Compiler Builtins - Fix ``__has_builtin`` incorrectly returning ``false`` for some C++ type traits. (#GH111477) +- Fix ``__builtin_source_location`` incorrectly returning wrong column for method chains. (#GH119129) + Bug Fixes to Attribute Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -797,12 +839,17 @@ Bug Fixes to C++ Support missing placeholder return type. (#GH78694) - Fixed a bug where bounds of partially expanded pack indexing expressions were checked too early. (#GH116105) - Fixed an assertion failure caused by using ``consteval`` in condition in consumed analyses. (#GH117385) +- Fixed an assertion failure caused by invalid default argument substitutions in non-defining + friend declarations. (#GH113324) - Fix a crash caused by incorrect argument position in merging deduced template arguments. (#GH113659) - Fixed a parser crash when using pack indexing as a nested name specifier. (#GH119072) +- Fixed a null pointer dereference issue when heuristically computing ``sizeof...(pack)`` expressions. (#GH81436) - Fixed an assertion failure caused by mangled names with invalid identifiers. (#GH112205) - Fixed an incorrect lambda scope of generic lambdas that caused Clang to crash when computing potential lambda captures at the end of a full expression. (#GH115931) - Clang no longer rejects deleting a pointer of incomplete enumeration type. (#GH99278) +- Fixed recognition of ``std::initializer_list`` when it's surrounded with ``extern "C++"`` and exported + out of a module (which is the case e.g. in MSVC's implementation of ``std`` module). (#GH118218) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1148,6 +1195,10 @@ Sanitizers `_. See that link for examples. +- Introduced an experimental Type Sanitizer, activated by using the + ``-fsanitize=type`` flag. This sanitizer detects violations of C/C++ type-based + aliasing rules. + Python Binding Changes ---------------------- - Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``. diff --git a/clang/docs/StandardCPlusPlusModules.rst b/clang/docs/StandardCPlusPlusModules.rst index 8e22adad15106..93edce0cf90b7 100644 --- a/clang/docs/StandardCPlusPlusModules.rst +++ b/clang/docs/StandardCPlusPlusModules.rst @@ -602,16 +602,16 @@ unnecessary dependencies for the BMI. To mitigate the problem, Clang has a compiler option to reduce the information contained in the BMI. These two formats are known as Full BMI and Reduced BMI, respectively. -Users can use the ``-fexperimental-modules-reduced-bmi`` option to produce a +Users can use the ``-fmodules-reduced-bmi`` option to produce a Reduced BMI. For the one-phase compilation model (CMake implements this model), with -``-fexperimental-modules-reduced-bmi``, the generated BMI will be a Reduced +``-fmodules-reduced-bmi``, the generated BMI will be a Reduced BMI automatically. (The output path of the BMI is specified by ``-fmodule-output=`` as usual with the one-phase compilation model). It is also possible to produce a Reduced BMI with the two-phase compilation -model. When ``-fexperimental-modules-reduced-bmi``, ``--precompile``, and +model. When ``-fmodules-reduced-bmi``, ``--precompile``, and ``-fmodule-output=`` are specified, the generated BMI specified by ``-o`` will be a full BMI and the BMI specified by ``-fmodule-output=`` will be a Reduced BMI. The dependency graph in this case would look like: @@ -625,7 +625,7 @@ BMI. The dependency graph in this case would look like: -> ... -> consumer_n.cpp -Clang does not emit diagnostics when ``-fexperimental-modules-reduced-bmi`` is +Clang does not emit diagnostics when ``-fmodules-reduced-bmi`` is used with a non-module unit. This design permits users of the one-phase compilation model to try using reduced BMIs without needing to modify the build system. The two-phase compilation module requires build system support. @@ -691,11 +691,10 @@ ensure it is reachable, e.g. ``using N::g;``. Support for Reduced BMIs is still experimental, but it may become the default in the future. The expected roadmap for Reduced BMIs as of Clang 19.x is: -1. ``-fexperimental-modules-reduced-bmi`` is opt-in for 1~2 releases. The period depends +1. ``-fexperimental-modules-reduced-bmi`` was introduced in v19.x +2. For v20.x, ``-fmodules-reduced-bmi`` is introduced as an equivalent non-experimental + option. It is expected to stay opt-in for 1~2 releases, though the period depends on user feedback and may be extended. -2. Announce that Reduced BMIs are no longer experimental and introduce - ``-fmodules-reduced-bmi`` as a new option, and recommend use of the new - option. This transition is expected to take 1~2 additional releases as well. 3. Finally, ``-fmodules-reduced-bmi`` will be the default. When that time comes, the term BMI will refer to the Reduced BMI and the Full BMI will only be meaningful to build systems which elect to support two-phase compilation. @@ -814,8 +813,8 @@ With reduced BMI, non-cascading changes can be more powerful. For example, .. code-block:: console - $ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm -fexperimental-modules-reduced-bmi -o A.o - $ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm -fexperimental-modules-reduced-bmi -o B.o -fmodule-file=A=A.pcm + $ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm -fmodules-reduced-bmi -o A.o + $ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm -fmodules-reduced-bmi -o B.o -fmodule-file=A=A.pcm $ md5sum B.pcm 6c2bd452ca32ab418bf35cd141b060b9 B.pcm @@ -831,8 +830,8 @@ and recompile the example: .. code-block:: console - $ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm -fexperimental-modules-reduced-bmi -o A.o - $ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm -fexperimental-modules-reduced-bmi -o B.o -fmodule-file=A=A.pcm + $ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm -fmodules-reduced-bmi -o A.o + $ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm -fmodules-reduced-bmi -o B.o -fmodule-file=A=A.pcm $ md5sum B.pcm 6c2bd452ca32ab418bf35cd141b060b9 B.pcm diff --git a/clang/docs/tools/dump_format_help.py b/clang/docs/tools/dump_format_help.py index baf90048ee135..ba41ed8c02c81 100755 --- a/clang/docs/tools/dump_format_help.py +++ b/clang/docs/tools/dump_format_help.py @@ -72,5 +72,7 @@ def validate(text, columns): contents = substitute(contents, "FORMAT_HELP", help_text) -with open(opts.output if opts.output else DOC_FILE, "wb") as output: - output.write(contents.encode()) +with open( + opts.output if opts.output else DOC_FILE, "w", newline="", encoding="utf-8" +) as f: + f.write(contents) diff --git a/clang/docs/tools/dump_format_style.py b/clang/docs/tools/dump_format_style.py index f00f3ee8b20e8..f035143f6b3d1 100755 --- a/clang/docs/tools/dump_format_style.py +++ b/clang/docs/tools/dump_format_style.py @@ -411,8 +411,8 @@ class State: state = State.InStruct enums[enum.name] = enum else: - # Enum member without documentation. Must be documented where the enum - # is used. + # Enum member without documentation. Must be documented + # where the enum is used. pass elif state == State.InNestedEnum: if line.startswith("///"): @@ -492,5 +492,7 @@ class State: contents = substitute(contents, "FORMAT_STYLE_OPTIONS", options_text) -with open(args.output if args.output else DOC_FILE, "wb") as output: - output.write(contents.encode()) +with open( + args.output if args.output else DOC_FILE, "w", newline="", encoding="utf-8" +) as f: + f.write(contents) diff --git a/clang/include/clang-c/CXString.h b/clang/include/clang-c/CXString.h index f117010c71a46..63dce4d140ce2 100644 --- a/clang/include/clang-c/CXString.h +++ b/clang/include/clang-c/CXString.h @@ -46,6 +46,10 @@ typedef struct { /** * Retrieve the character data associated with the given string. + * + * The returned data is a reference and not owned by the user. This data + * is only valid while the `CXString` is valid. This function is similar + * to `std::string::c_str()`. */ CINDEX_LINKAGE const char *clang_getCString(CXString string); diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 8fc06328f0bce..122118b8f3763 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2166,9 +2166,31 @@ enum CXCursorKind { */ CXCursor_OpenACCLoopConstruct = 321, + /** OpenACC Combined Constructs. + */ CXCursor_OpenACCCombinedConstruct = 322, - CXCursor_LastStmt = CXCursor_OpenACCCombinedConstruct, + /** OpenACC data Construct. + */ + CXCursor_OpenACCDataConstruct = 323, + + /** OpenACC enter data Construct. + */ + CXCursor_OpenACCEnterDataConstruct = 324, + + /** OpenACC exit data Construct. + */ + CXCursor_OpenACCExitDataConstruct = 325, + + /** OpenACC host_data Construct. + */ + CXCursor_OpenACCHostDataConstruct = 326, + + /** OpenACC wait Construct. + */ + CXCursor_OpenACCWaitConstruct = 327, + + CXCursor_LastStmt = CXCursor_OpenACCWaitConstruct, /** * Cursor that represents the translation unit itself. diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index ff374ad3ada06..9c01978fd49ef 100644 --- a/clang/include/clang/APINotes/Types.h +++ b/clang/include/clang/APINotes/Types.h @@ -542,6 +542,9 @@ class FunctionInfo : public CommonEntityInfo { /// The result type of this function, as a C type. std::string ResultType; + /// Ownership convention for return value + std::string SwiftReturnOwnership; + /// The function parameters. std::vector Params; @@ -622,7 +625,8 @@ inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS) { LHS.NumAdjustedNullable == RHS.NumAdjustedNullable && LHS.NullabilityPayload == RHS.NullabilityPayload && LHS.ResultType == RHS.ResultType && LHS.Params == RHS.Params && - LHS.RawRetainCountConvention == RHS.RawRetainCountConvention; + LHS.RawRetainCountConvention == RHS.RawRetainCountConvention && + LHS.SwiftReturnOwnership == RHS.SwiftReturnOwnership; } inline bool operator!=(const FunctionInfo &LHS, const FunctionInfo &RHS) { diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index 7869ee386689d..4401f3a8ff482 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -157,11 +157,9 @@ class APValue { void Profile(llvm::FoldingSetNodeID &ID) const; - template - bool is() const { return Ptr.is(); } + template bool is() const { return isa(Ptr); } - template - T get() const { return Ptr.get(); } + template T get() const { return cast(Ptr); } template T dyn_cast() const { return Ptr.dyn_cast(); } diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 89fcb6789d880..1e89a6805ce9c 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -245,7 +245,11 @@ class ASTContext : public RefCountedBase { mutable llvm::FoldingSet ObjCObjectPointerTypes; mutable llvm::FoldingSet DependentUnaryTransformTypes; - mutable llvm::ContextualFoldingSet AutoTypes; + // An AutoType can have a dependency on another AutoType via its template + // arguments. Since both dependent and dependency are on the same set, + // we can end up in an infinite recursion when looking for a node if we used + // a `FoldingSet`, since both could end up in the same bucket. + mutable llvm::DenseMap AutoTypes; mutable llvm::FoldingSet DeducedTemplateSpecializationTypes; mutable llvm::FoldingSet AtomicTypes; diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 3d63d581a9be6..f5652b295de16 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -159,7 +159,7 @@ class ASTNodeTraverser // Some statements have custom mechanisms for dumping their children. if (isa(S) || isa(S) || - isa(S)) + isa(S) || isa(S)) return; if (Traversal == TK_IgnoreUnlessSpelledInSource && @@ -825,6 +825,16 @@ class ASTNodeTraverser Visit(C); } + void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *Node) { + // Needs custom child checking to put clauses AFTER the children, which are + // the expressions in the 'wait' construct. Others likely need this as well, + // and might need to do the associated statement after it. + for (const Stmt *S : Node->children()) + Visit(S); + for (const auto *C : Node->clauses()) + Visit(C); + } + void VisitInitListExpr(const InitListExpr *ILE) { if (auto *Filler = ILE->getArrayFiller()) { Visit(Filler, "array_filler"); diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 725498e132fc2..3365ebe4d9012 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -24,6 +24,7 @@ #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/Sanitizers.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Support/Compiler.h" #include "llvm/Frontend/HLSL/HLSLResource.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 8c39ef3d5a9fa..67ee0bb412692 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -747,9 +747,9 @@ class DeclaratorDecl : public ValueDecl { /// ignoring outer template declarations. SourceLocation InnerLocStart; - bool hasExtInfo() const { return DeclInfo.is(); } - ExtInfo *getExtInfo() { return DeclInfo.get(); } - const ExtInfo *getExtInfo() const { return DeclInfo.get(); } + bool hasExtInfo() const { return isa(DeclInfo); } + ExtInfo *getExtInfo() { return cast(DeclInfo); } + const ExtInfo *getExtInfo() const { return cast(DeclInfo); } protected: DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L, @@ -762,9 +762,8 @@ class DeclaratorDecl : public ValueDecl { friend class ASTDeclWriter; TypeSourceInfo *getTypeSourceInfo() const { - return hasExtInfo() - ? getExtInfo()->TInfo - : DeclInfo.get(); + return hasExtInfo() ? getExtInfo()->TInfo + : cast(DeclInfo); } void setTypeSourceInfo(TypeSourceInfo *TI) { @@ -3458,18 +3457,17 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable { using redeclarable_base::isFirstDecl; bool isModed() const { - return MaybeModedTInfo.getPointer().is(); + return isa(MaybeModedTInfo.getPointer()); } TypeSourceInfo *getTypeSourceInfo() const { - return isModed() ? MaybeModedTInfo.getPointer().get()->first - : MaybeModedTInfo.getPointer().get(); + return isModed() ? cast(MaybeModedTInfo.getPointer())->first + : cast(MaybeModedTInfo.getPointer()); } QualType getUnderlyingType() const { - return isModed() ? MaybeModedTInfo.getPointer().get()->second - : MaybeModedTInfo.getPointer() - .get() + return isModed() ? cast(MaybeModedTInfo.getPointer())->second + : cast(MaybeModedTInfo.getPointer()) ->getType(); } @@ -3587,10 +3585,10 @@ class TagDecl : public TypeDecl, /// otherwise, it is a null (TypedefNameDecl) pointer. llvm::PointerUnion TypedefNameDeclOrQualifier; - bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is(); } - ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get(); } + bool hasExtInfo() const { return isa(TypedefNameDeclOrQualifier); } + ExtInfo *getExtInfo() { return cast(TypedefNameDeclOrQualifier); } const ExtInfo *getExtInfo() const { - return TypedefNameDeclOrQualifier.get(); + return cast(TypedefNameDeclOrQualifier); } protected: @@ -3793,7 +3791,7 @@ class TagDecl : public TypeDecl, TypedefNameDecl *getTypedefNameForAnonDecl() const { return hasExtInfo() ? nullptr - : TypedefNameDeclOrQualifier.get(); + : cast(TypedefNameDeclOrQualifier); } void setTypedefNameForAnonDecl(TypedefNameDecl *TDD); @@ -4011,7 +4009,7 @@ class EnumDecl : public TagDecl { return QualType(); if (const Type *T = IntegerType.dyn_cast()) return QualType(T, 0); - return IntegerType.get()->getType().getUnqualifiedType(); + return cast(IntegerType)->getType().getUnqualifiedType(); } /// Set the underlying integer type. diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index a3447d1990975..82932e098c86f 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -271,16 +271,12 @@ class alignas(8) Decl { /// // LexicalDC == global namespace llvm::PointerUnion DeclCtx; - bool isInSemaDC() const { return DeclCtx.is(); } - bool isOutOfSemaDC() const { return DeclCtx.is(); } + bool isInSemaDC() const { return isa(DeclCtx); } + bool isOutOfSemaDC() const { return isa(DeclCtx); } - MultipleDC *getMultipleDC() const { - return DeclCtx.get(); - } + MultipleDC *getMultipleDC() const { return cast(DeclCtx); } - DeclContext *getSemanticDC() const { - return DeclCtx.get(); - } + DeclContext *getSemanticDC() const { return cast(DeclCtx); } /// Loc - The location of this decl. SourceLocation Loc; @@ -1340,7 +1336,7 @@ class DeclListNode { assert(Ptr && "dereferencing end() iterator"); if (DeclListNode *CurNode = Ptr.dyn_cast()) return CurNode->D; - return Ptr.get(); + return cast(Ptr); } void operator->() const { } // Unsupported. bool operator==(const iterator &X) const { return Ptr == X.Ptr; } diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index e389b5cd6df5b..c232556edeff7 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2388,19 +2388,19 @@ class CXXCtorInitializer final { /// Determine whether this initializer is initializing a base class. bool isBaseInitializer() const { - return Initializee.is() && !IsDelegating; + return isa(Initializee) && !IsDelegating; } /// Determine whether this initializer is initializing a non-static /// data member. - bool isMemberInitializer() const { return Initializee.is(); } + bool isMemberInitializer() const { return isa(Initializee); } bool isAnyMemberInitializer() const { return isMemberInitializer() || isIndirectMemberInitializer(); } bool isIndirectMemberInitializer() const { - return Initializee.is(); + return isa(Initializee); } /// Determine whether this initializer is an implicit initializer @@ -2416,7 +2416,7 @@ class CXXCtorInitializer final { /// Determine whether this initializer is creating a delegating /// constructor. bool isDelegatingInitializer() const { - return Initializee.is() && IsDelegating; + return isa(Initializee) && IsDelegating; } /// Determine whether this initializer is a pack expansion. @@ -2457,21 +2457,21 @@ class CXXCtorInitializer final { /// non-static data member being initialized. Otherwise, returns null. FieldDecl *getMember() const { if (isMemberInitializer()) - return Initializee.get(); + return cast(Initializee); return nullptr; } FieldDecl *getAnyMember() const { if (isMemberInitializer()) - return Initializee.get(); + return cast(Initializee); if (isIndirectMemberInitializer()) - return Initializee.get()->getAnonField(); + return cast(Initializee)->getAnonField(); return nullptr; } IndirectFieldDecl *getIndirectMember() const { if (isIndirectMemberInitializer()) - return Initializee.get(); + return cast(Initializee); return nullptr; } diff --git a/clang/include/clang/AST/DeclContextInternals.h b/clang/include/clang/AST/DeclContextInternals.h index e169c48592192..b17b7627ac90c 100644 --- a/clang/include/clang/AST/DeclContextInternals.h +++ b/clang/include/clang/AST/DeclContextInternals.h @@ -70,7 +70,7 @@ class StoredDeclsList { // want to keep (if any) will be of the form DeclListNode(D, ); // replace it with just D. if (NewLast) { - DeclListNode *Node = NewLast->get(); + DeclListNode *Node = cast(*NewLast); *NewLast = Node->D; C.DeallocateDeclListNode(Node); } @@ -84,11 +84,11 @@ class StoredDeclsList { if (!Data.getPointer()) // All declarations are erased. return nullptr; - else if (NewHead.is()) + else if (isa(NewHead)) // The list only contains a declaration, the header itself. return (DeclListNode::Decls *)&Data; else { - assert(NewLast && NewLast->is() && "Not the tail?"); + assert(NewLast && isa(*NewLast) && "Not the tail?"); return NewLast; } } @@ -207,7 +207,7 @@ class StoredDeclsList { } // Append the Decls. - DeclListNode *Node = C.AllocateDeclListNode(Tail->get()); + DeclListNode *Node = C.AllocateDeclListNode(cast(*Tail)); Node->Rest = DeclsAsList; *Tail = Node; } @@ -293,7 +293,7 @@ class StoredDeclsList { llvm::errs() << '[' << Node->D << "] -> "; D = Node->Rest; } else { - llvm::errs() << '[' << D.get() << "]\n"; + llvm::errs() << '[' << cast(D) << "]\n"; return; } } diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index e4bf54c3d77b7..d3a466a8617bb 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -319,8 +319,7 @@ class DefaultArgStorage { const DefaultArgStorage &Storage = Parm->getDefaultArgStorage(); if (auto *Prev = Storage.ValueOrInherited.template dyn_cast()) Parm = Prev; - assert(!Parm->getDefaultArgStorage() - .ValueOrInherited.template is() && + assert(!isa(Parm->getDefaultArgStorage().ValueOrInherited) && "should only be one level of indirection"); return Parm; } @@ -333,7 +332,7 @@ class DefaultArgStorage { /// Determine whether the default argument for this parameter was inherited /// from a previous declaration of the same entity. - bool isInherited() const { return ValueOrInherited.template is(); } + bool isInherited() const { return isa(ValueOrInherited); } /// Get the default argument's value. This does not consider whether the /// default argument is visible. @@ -343,7 +342,7 @@ class DefaultArgStorage { Storage = &Prev->getDefaultArgStorage(); if (const auto *C = Storage->ValueOrInherited.template dyn_cast()) return C->Value; - return Storage->ValueOrInherited.template get(); + return cast(Storage->ValueOrInherited); } /// Get the parameter from which we inherit the default argument, if any. @@ -379,7 +378,7 @@ class DefaultArgStorage { Inherited->PrevDeclWithDefaultArg = InheritedFrom; } else ValueOrInherited = new (allocateDefaultArgStorageChain(C)) - Chain{InheritedFrom, ValueOrInherited.template get()}; + Chain{InheritedFrom, cast(ValueOrInherited)}; } /// Remove the default argument, even if it was inherited. @@ -735,6 +734,7 @@ class RedeclarableTemplateDecl : public TemplateDecl, } void anchor() override; + protected: template struct SpecEntryTraits { using DeclType = EntryType; @@ -775,13 +775,22 @@ class RedeclarableTemplateDecl : public TemplateDecl, return SpecIterator(isEnd ? Specs.end() : Specs.begin()); } - void loadLazySpecializationsImpl() const; + void loadLazySpecializationsImpl(bool OnlyPartial = false) const; + + bool loadLazySpecializationsImpl(llvm::ArrayRef Args, + TemplateParameterList *TPL = nullptr) const; template typename SpecEntryTraits::DeclType* findSpecializationImpl(llvm::FoldingSetVector &Specs, void *&InsertPos, ProfileArguments &&...ProfileArgs); + template + typename SpecEntryTraits::DeclType * + findSpecializationLocally(llvm::FoldingSetVector &Specs, + void *&InsertPos, + ProfileArguments &&...ProfileArgs); + template void addSpecializationImpl(llvm::FoldingSetVector &Specs, EntryType *Entry, void *InsertPos); @@ -796,13 +805,6 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// was explicitly specialized. llvm::PointerIntPair InstantiatedFromMember; - - /// If non-null, points to an array of specializations (including - /// partial specializations) known only by their external declaration IDs. - /// - /// The first value in the array is the number of specializations/partial - /// specializations that follow. - GlobalDeclID *LazySpecializations = nullptr; }; /// Pointer to the common data shared by all declarations of this @@ -1962,7 +1964,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, SpecializedTemplate.dyn_cast()) return PartialSpec->PartialSpecialization; - return SpecializedTemplate.get(); + return cast(SpecializedTemplate); } /// Retrieve the set of template arguments that should be used @@ -1989,7 +1991,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// template arguments have been deduced. void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgumentList *TemplateArgs) { - assert(!SpecializedTemplate.is() && + assert(!isa(SpecializedTemplate) && "Already set to a class template partial specialization!"); auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); PS->PartialSpecialization = PartialSpec; @@ -2000,7 +2002,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// Note that this class template specialization is an instantiation /// of the given class template. void setInstantiationOf(ClassTemplateDecl *TemplDecl) { - assert(!SpecializedTemplate.is() && + assert(!isa(SpecializedTemplate) && "Previously set to a class template partial specialization!"); SpecializedTemplate = TemplDecl; } @@ -2010,7 +2012,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { if (auto *Info = ExplicitInfo.dyn_cast()) return Info->TemplateArgsAsWritten; - return ExplicitInfo.get(); + return cast(ExplicitInfo); } /// Set the template argument list as written in the sources. @@ -2283,7 +2285,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { friend class TemplateDeclInstantiator; /// Load any lazily-loaded specializations from the external source. - void LoadLazySpecializations() const; + void LoadLazySpecializations(bool OnlyPartial = false) const; /// Get the underlying class declarations of the template. CXXRecordDecl *getTemplatedDecl() const { @@ -2731,7 +2733,7 @@ class VarTemplateSpecializationDecl : public VarDecl, SpecializedTemplate.dyn_cast()) return PartialSpec->PartialSpecialization; - return SpecializedTemplate.get(); + return cast(SpecializedTemplate); } /// Retrieve the set of template arguments that should be used @@ -2758,7 +2760,7 @@ class VarTemplateSpecializationDecl : public VarDecl, /// template arguments have been deduced. void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgumentList *TemplateArgs) { - assert(!SpecializedTemplate.is() && + assert(!isa(SpecializedTemplate) && "Already set to a variable template partial specialization!"); auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); PS->PartialSpecialization = PartialSpec; @@ -2769,7 +2771,7 @@ class VarTemplateSpecializationDecl : public VarDecl, /// Note that this variable template specialization is an instantiation /// of the given variable template. void setInstantiationOf(VarTemplateDecl *TemplDecl) { - assert(!SpecializedTemplate.is() && + assert(!isa(SpecializedTemplate) && "Previously set to a variable template partial specialization!"); SpecializedTemplate = TemplDecl; } @@ -2779,7 +2781,7 @@ class VarTemplateSpecializationDecl : public VarDecl, const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { if (auto *Info = ExplicitInfo.dyn_cast()) return Info->TemplateArgsAsWritten; - return ExplicitInfo.get(); + return cast(ExplicitInfo); } /// Set the template argument list as written in the sources. @@ -3033,7 +3035,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl { friend class ASTDeclWriter; /// Load any lazily-loaded specializations from the external source. - void LoadLazySpecializations() const; + void LoadLazySpecializations(bool OnlyPartial = false) const; /// Get the underlying variable declarations of the template. VarDecl *getTemplatedDecl() const { @@ -3306,7 +3308,7 @@ inline NamedDecl *getAsNamedDecl(TemplateParameter P) { return PD; if (auto *PD = P.dyn_cast()) return PD; - return P.get(); + return cast(P); } inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) { diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 1a24b8857674c..4cec89c979f77 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -878,7 +878,7 @@ class CXXTypeidExpr : public Expr { /// object. This is not a strong guarantee. bool isMostDerived(const ASTContext &Context) const; - bool isTypeOperand() const { return Operand.is(); } + bool isTypeOperand() const { return isa(Operand); } /// Retrieves the type operand of this typeid() expression after /// various required adjustments (removing reference types, cv-qualifiers). @@ -887,11 +887,11 @@ class CXXTypeidExpr : public Expr { /// Retrieve source information for the type operand. TypeSourceInfo *getTypeOperandSourceInfo() const { assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); - return Operand.get(); + return cast(Operand); } Expr *getExprOperand() const { assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); - return static_cast(Operand.get()); + return static_cast(cast(Operand)); } SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } @@ -1093,7 +1093,7 @@ class CXXUuidofExpr : public Expr { Operand = (TypeSourceInfo*)nullptr; } - bool isTypeOperand() const { return Operand.is(); } + bool isTypeOperand() const { return isa(Operand); } /// Retrieves the type operand of this __uuidof() expression after /// various required adjustments (removing reference types, cv-qualifiers). @@ -1102,11 +1102,11 @@ class CXXUuidofExpr : public Expr { /// Retrieve source information for the type operand. TypeSourceInfo *getTypeOperandSourceInfo() const { assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); - return Operand.get(); + return cast(Operand); } Expr *getExprOperand() const { assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); - return static_cast(Operand.get()); + return static_cast(cast(Operand)); } MSGuidDecl *getGuidDecl() const { return Guid; } @@ -4750,24 +4750,24 @@ class MaterializeTemporaryExpr : public Expr { /// be materialized into a glvalue. Expr *getSubExpr() const { return cast( - State.is() - ? State.get() - : State.get()->getTemporaryExpr()); + isa(State) + ? cast(State) + : cast(State)->getTemporaryExpr()); } /// Retrieve the storage duration for the materialized temporary. StorageDuration getStorageDuration() const { - return State.is() ? SD_FullExpression - : State.get() + return isa(State) ? SD_FullExpression + : cast(State) ->getStorageDuration(); } /// Get the storage for the constant value of a materialized temporary /// of static storage duration. APValue *getOrCreateValue(bool MayCreate) const { - assert(State.is() && + assert(isa(State) && "the temporary has not been lifetime extended"); - return State.get()->getOrCreateValue( + return cast(State)->getOrCreateValue( MayCreate); } @@ -4782,8 +4782,8 @@ class MaterializeTemporaryExpr : public Expr { /// Get the declaration which triggered the lifetime-extension of this /// temporary, if any. ValueDecl *getExtendingDecl() { - return State.is() ? nullptr - : State.get() + return isa(State) ? nullptr + : cast(State) ->getExtendingDecl(); } const ValueDecl *getExtendingDecl() const { @@ -4793,8 +4793,8 @@ class MaterializeTemporaryExpr : public Expr { void setExtendingDecl(ValueDecl *ExtendedBy, unsigned ManglingNumber); unsigned getManglingNumber() const { - return State.is() ? 0 - : State.get() + return isa(State) ? 0 + : cast(State) ->getManglingNumber(); } @@ -4820,17 +4820,17 @@ class MaterializeTemporaryExpr : public Expr { // Iterators child_range children() { - return State.is() + return isa(State) ? child_range(State.getAddrOfPtr1(), State.getAddrOfPtr1() + 1) - : State.get()->childrenExpr(); + : cast(State)->childrenExpr(); } const_child_range children() const { - return State.is() + return isa(State) ? const_child_range(State.getAddrOfPtr1(), State.getAddrOfPtr1() + 1) : const_cast( - State.get()) + cast(State)) ->childrenExpr(); } }; diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h index f3e32ce396198..f988d40cf73c3 100644 --- a/clang/include/clang/AST/ExprConcepts.h +++ b/clang/include/clang/AST/ExprConcepts.h @@ -261,13 +261,13 @@ class TypeRequirement : public Requirement { assert(Status == SS_SubstitutionFailure && "Attempted to get substitution diagnostic when there has been no " "substitution failure."); - return Value.get(); + return cast(Value); } TypeSourceInfo *getType() const { assert(!isSubstitutionFailure() && "Attempted to get type when there has been a substitution failure."); - return Value.get(); + return cast(Value); } static bool classof(const Requirement *R) { @@ -329,24 +329,24 @@ class ExprRequirement : public Requirement { bool isSubstitutionFailure() const { return !isEmpty() && - TypeConstraintInfo.getPointer().is(); + isa(TypeConstraintInfo.getPointer()); } bool isTypeConstraint() const { return !isEmpty() && - TypeConstraintInfo.getPointer().is(); + isa(TypeConstraintInfo.getPointer()); } SubstitutionDiagnostic *getSubstitutionDiagnostic() const { assert(isSubstitutionFailure()); - return TypeConstraintInfo.getPointer().get(); + return cast(TypeConstraintInfo.getPointer()); } const TypeConstraint *getTypeConstraint() const; TemplateParameterList *getTypeConstraintTemplateParameterList() const { assert(isTypeConstraint()); - return TypeConstraintInfo.getPointer().get(); + return cast(TypeConstraintInfo.getPointer()); } }; private: @@ -409,14 +409,14 @@ class ExprRequirement : public Requirement { assert(isExprSubstitutionFailure() && "Attempted to get expression substitution diagnostic when there has " "been no expression substitution failure"); - return Value.get(); + return cast(Value); } Expr *getExpr() const { assert(!isExprSubstitutionFailure() && "ExprRequirement has no expression because there has been a " "substitution failure."); - return Value.get(); + return cast(Value); } static bool classof(const Requirement *R) { diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index f833916c91aa5..1fccc26069582 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -752,28 +752,24 @@ class ObjCPropertyRefExpr : public Expr { setMethodRefFlag(MethodRef_Setter, val); } - const Expr *getBase() const { - return cast(Receiver.get()); - } - Expr *getBase() { - return cast(Receiver.get()); - } + const Expr *getBase() const { return cast(cast(Receiver)); } + Expr *getBase() { return cast(cast(Receiver)); } SourceLocation getLocation() const { return IdLoc; } SourceLocation getReceiverLocation() const { return ReceiverLoc; } QualType getSuperReceiverType() const { - return QualType(Receiver.get(), 0); + return QualType(cast(Receiver), 0); } ObjCInterfaceDecl *getClassReceiver() const { - return Receiver.get(); + return cast(Receiver); } - bool isObjectReceiver() const { return Receiver.is(); } - bool isSuperReceiver() const { return Receiver.is(); } - bool isClassReceiver() const { return Receiver.is(); } + bool isObjectReceiver() const { return isa(Receiver); } + bool isSuperReceiver() const { return isa(Receiver); } + bool isClassReceiver() const { return isa(Receiver); } /// Determine the type of the base, regardless of the kind of receiver. QualType getReceiverType(const ASTContext &ctx) const; @@ -787,7 +783,7 @@ class ObjCPropertyRefExpr : public Expr { // Iterators child_range children() { - if (Receiver.is()) { + if (isa(Receiver)) { Stmt **begin = reinterpret_cast(&Receiver); // hack! return child_range(begin, begin+1); } diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 582ed7c65f58c..4d7ff822fceb7 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -152,6 +152,21 @@ class ExternalASTSource : public RefCountedBase { virtual bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); + /// Load all the external specializations for the Decl \param D if \param + /// OnlyPartial is false. Otherwise, load all the external **partial** + /// specializations for the \param D. + /// + /// Return true if any new specializations get loaded. Return false otherwise. + virtual bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial); + + /// Load all the specializations for the Decl \param D with the same template + /// args specified by \param TemplateArgs. + /// + /// Return true if any new specializations get loaded. Return false otherwise. + virtual bool + LoadExternalSpecializations(const Decl *D, + ArrayRef TemplateArgs); + /// Ensures that the table of all visible declarations inside this /// context is up to date. /// @@ -447,9 +462,7 @@ struct LazyGenerationalUpdatePtr { : Value(Value) {} /// Forcibly set this pointer (which must be lazy) as needing updates. - void markIncomplete() { - Value.template get()->LastGeneration = 0; - } + void markIncomplete() { cast(Value)->LastGeneration = 0; } /// Set the value of this pointer, in the current generation. void set(T NewValue) { @@ -472,14 +485,14 @@ struct LazyGenerationalUpdatePtr { } return LazyVal->LastValue; } - return Value.template get(); + return cast(Value); } /// Get the most recently computed value of this pointer without updating it. T getNotUpdated() const { if (auto *LazyVal = Value.template dyn_cast()) return LazyVal->LastValue; - return Value.template get(); + return cast(Value); } void *getOpaqueValue() { return Value.getOpaqueValue(); } diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 2588c3f645c02..51db58d484a25 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -38,7 +38,7 @@ class OpenACCClause { SourceLocation getBeginLoc() const { return Location.getBegin(); } SourceLocation getEndLoc() const { return Location.getEnd(); } - static bool classof(const OpenACCClause *) { return false; } + static bool classof(const OpenACCClause *) { return true; } using child_iterator = StmtIterator; using const_child_iterator = ConstStmtIterator; @@ -76,6 +76,50 @@ class OpenACCAutoClause : public OpenACCClause { } }; +// Represents the 'finalize' clause. +class OpenACCFinalizeClause : public OpenACCClause { +protected: + OpenACCFinalizeClause(SourceLocation BeginLoc, SourceLocation EndLoc) + : OpenACCClause(OpenACCClauseKind::Finalize, BeginLoc, EndLoc) {} + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Finalize; + } + + static OpenACCFinalizeClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +// Represents the 'if_present' clause. +class OpenACCIfPresentClause : public OpenACCClause { +protected: + OpenACCIfPresentClause(SourceLocation BeginLoc, SourceLocation EndLoc) + : OpenACCClause(OpenACCClauseKind::IfPresent, BeginLoc, EndLoc) {} + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::IfPresent; + } + + static OpenACCIfPresentClause * + Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc); + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + // Represents the 'independent' clause. class OpenACCIndependentClause : public OpenACCClause { protected: @@ -147,8 +191,9 @@ using DeviceTypeArgument = std::pair; /// an identifier. The 'asterisk' means 'the rest'. class OpenACCDeviceTypeClause final : public OpenACCClauseWithParams, - public llvm::TrailingObjects { + friend TrailingObjects; // Data stored in trailing objects as IdentifierInfo* /SourceLocation pairs. A // nullptr IdentifierInfo* represents an asterisk. unsigned NumArchs; @@ -333,7 +378,8 @@ class OpenACCClauseWithExprs : public OpenACCClauseWithParams { // Represents the 'devnum' and expressions lists for the 'wait' clause. class OpenACCWaitClause final : public OpenACCClauseWithExprs, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; SourceLocation QueuesLoc; OpenACCWaitClause(SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, @@ -375,7 +421,8 @@ class OpenACCWaitClause final class OpenACCNumGangsClause final : public OpenACCClauseWithExprs, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCNumGangsClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef IntExprs, SourceLocation EndLoc) @@ -405,7 +452,8 @@ class OpenACCNumGangsClause final class OpenACCTileClause final : public OpenACCClauseWithExprs, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCTileClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef SizeExprs, SourceLocation EndLoc) : OpenACCClauseWithExprs(OpenACCClauseKind::Tile, BeginLoc, LParenLoc, @@ -459,7 +507,8 @@ class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs { class OpenACCGangClause final : public OpenACCClauseWithExprs, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; protected: OpenACCGangClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef GangKinds, @@ -614,7 +663,8 @@ class OpenACCClauseWithVarList : public OpenACCClauseWithExprs { class OpenACCPrivateClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, SourceLocation EndLoc) @@ -636,7 +686,8 @@ class OpenACCPrivateClause final class OpenACCFirstPrivateClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCFirstPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, SourceLocation EndLoc) @@ -658,7 +709,8 @@ class OpenACCFirstPrivateClause final class OpenACCDevicePtrClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCDevicePtrClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, SourceLocation EndLoc) @@ -680,7 +732,8 @@ class OpenACCDevicePtrClause final class OpenACCAttachClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCAttachClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, SourceLocation EndLoc) @@ -700,9 +753,79 @@ class OpenACCAttachClause final ArrayRef VarList, SourceLocation EndLoc); }; +class OpenACCDetachClause final + : public OpenACCClauseWithVarList, + private llvm::TrailingObjects { + friend TrailingObjects; + + OpenACCDetachClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef VarList, SourceLocation EndLoc) + : OpenACCClauseWithVarList(OpenACCClauseKind::Detach, BeginLoc, LParenLoc, + EndLoc) { + std::uninitialized_copy(VarList.begin(), VarList.end(), + getTrailingObjects()); + setExprs(MutableArrayRef(getTrailingObjects(), VarList.size())); + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Detach; + } + static OpenACCDetachClause * + Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef VarList, SourceLocation EndLoc); +}; + +class OpenACCDeleteClause final + : public OpenACCClauseWithVarList, + private llvm::TrailingObjects { + friend TrailingObjects; + + OpenACCDeleteClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef VarList, SourceLocation EndLoc) + : OpenACCClauseWithVarList(OpenACCClauseKind::Delete, BeginLoc, LParenLoc, + EndLoc) { + std::uninitialized_copy(VarList.begin(), VarList.end(), + getTrailingObjects()); + setExprs(MutableArrayRef(getTrailingObjects(), VarList.size())); + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Delete; + } + static OpenACCDeleteClause * + Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef VarList, SourceLocation EndLoc); +}; + +class OpenACCUseDeviceClause final + : public OpenACCClauseWithVarList, + private llvm::TrailingObjects { + friend TrailingObjects; + + OpenACCUseDeviceClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef VarList, SourceLocation EndLoc) + : OpenACCClauseWithVarList(OpenACCClauseKind::UseDevice, BeginLoc, + LParenLoc, EndLoc) { + std::uninitialized_copy(VarList.begin(), VarList.end(), + getTrailingObjects()); + setExprs(MutableArrayRef(getTrailingObjects(), VarList.size())); + } + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::UseDevice; + } + static OpenACCUseDeviceClause * + Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, + ArrayRef VarList, SourceLocation EndLoc); +}; + class OpenACCNoCreateClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCNoCreateClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, SourceLocation EndLoc) @@ -724,7 +847,8 @@ class OpenACCNoCreateClause final class OpenACCPresentClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCPresentClause(SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, SourceLocation EndLoc) @@ -746,7 +870,8 @@ class OpenACCPresentClause final class OpenACCCopyClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCCopyClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef VarList, @@ -775,7 +900,8 @@ class OpenACCCopyClause final class OpenACCCopyInClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; bool IsReadOnly; OpenACCCopyInClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc, @@ -807,7 +933,8 @@ class OpenACCCopyInClause final class OpenACCCopyOutClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; bool IsZero; OpenACCCopyOutClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc, @@ -839,7 +966,8 @@ class OpenACCCopyOutClause final class OpenACCCreateClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; bool IsZero; OpenACCCreateClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc, @@ -871,7 +999,8 @@ class OpenACCCreateClause final class OpenACCReductionClause final : public OpenACCClauseWithVarList, - public llvm::TrailingObjects { + private llvm::TrailingObjects { + friend TrailingObjects; OpenACCReductionOperator Op; OpenACCReductionClause(SourceLocation BeginLoc, SourceLocation LParenLoc, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 76b598a5db238..d9a87b30062df 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2151,8 +2151,11 @@ DEF_TRAVERSE_DECL(DecompositionDecl, { }) DEF_TRAVERSE_DECL(BindingDecl, { - if (getDerived().shouldVisitImplicitCode()) + if (getDerived().shouldVisitImplicitCode()) { TRY_TO(TraverseStmt(D->getBinding())); + if (const auto HoldingVar = D->getHoldingVar()) + TRY_TO(TraverseDecl(HoldingVar)); + } }) DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); }) @@ -4058,6 +4061,21 @@ DEF_TRAVERSE_STMT(OpenACCLoopConstruct, { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) DEF_TRAVERSE_STMT(OpenACCCombinedConstruct, { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) +DEF_TRAVERSE_STMT(OpenACCDataConstruct, + { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) +DEF_TRAVERSE_STMT(OpenACCEnterDataConstruct, + { TRY_TO(VisitOpenACCClauseList(S->clauses())); }) +DEF_TRAVERSE_STMT(OpenACCExitDataConstruct, + { TRY_TO(VisitOpenACCClauseList(S->clauses())); }) +DEF_TRAVERSE_STMT(OpenACCHostDataConstruct, + { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) +DEF_TRAVERSE_STMT(OpenACCWaitConstruct, { + if (S->hasDevNumExpr()) + TRY_TO(TraverseStmt(S->getDevNumExpr())); + for (auto *E : S->getQueueIdExprs()) + TRY_TO(TraverseStmt(E)); + TRY_TO(VisitOpenACCClauseList(S->clauses())); +}) // Traverse HLSL: Out argument expression DEF_TRAVERSE_STMT(HLSLOutArgExpr, {}) diff --git a/clang/include/clang/AST/Redeclarable.h b/clang/include/clang/AST/Redeclarable.h index 8d320a9ced279..ee21f11e5f707 100644 --- a/clang/include/clang/AST/Redeclarable.h +++ b/clang/include/clang/AST/Redeclarable.h @@ -113,25 +113,24 @@ class Redeclarable { DeclLink(PreviousTag, decl_type *D) : Link(NotKnownLatest(Previous(D))) {} bool isFirst() const { - return Link.is() || + return isa(Link) || // FIXME: 'template' is required on the next line due to an // apparent clang bug. - Link.get().template is(); + isa(cast(Link)); } decl_type *getPrevious(const decl_type *D) const { - if (Link.is()) { - NotKnownLatest NKL = Link.get(); - if (NKL.is()) - return static_cast(NKL.get()); + if (NotKnownLatest NKL = dyn_cast(Link)) { + if (auto *Prev = dyn_cast(NKL)) + return static_cast(Prev); // Allocate the generational 'most recent' cache now, if needed. Link = KnownLatest(*reinterpret_cast( - NKL.get()), + cast(NKL)), const_cast(D)); } - return static_cast(Link.get().get(D)); + return static_cast(cast(Link).get(D)); } void setPrevious(decl_type *D) { @@ -141,25 +140,24 @@ class Redeclarable { void setLatest(decl_type *D) { assert(isFirst() && "decl became canonical unexpectedly"); - if (Link.is()) { - NotKnownLatest NKL = Link.get(); + if (NotKnownLatest NKL = dyn_cast(Link)) { Link = KnownLatest(*reinterpret_cast( - NKL.get()), + cast(NKL)), D); } else { - auto Latest = Link.get(); + auto Latest = cast(Link); Latest.set(D); Link = Latest; } } - void markIncomplete() { Link.get().markIncomplete(); } + void markIncomplete() { cast(Link).markIncomplete(); } Decl *getLatestNotUpdated() const { assert(isFirst() && "expected a canonical decl"); - if (Link.is()) + if (isa(Link)) return nullptr; - return Link.get().getNotUpdated(); + return cast(Link).getNotUpdated(); } }; diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h index fa8793e740822..093393a81be9c 100644 --- a/clang/include/clang/AST/StmtOpenACC.h +++ b/clang/include/clang/AST/StmtOpenACC.h @@ -127,11 +127,12 @@ class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt { /// the 'Kind'. class OpenACCComputeConstruct final : public OpenACCAssociatedStmtConstruct, - public llvm::TrailingObjects { + private llvm::TrailingObjects { friend class ASTStmtWriter; friend class ASTStmtReader; friend class ASTContext; + friend TrailingObjects; OpenACCComputeConstruct(unsigned NumClauses) : OpenACCAssociatedStmtConstruct( OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid, @@ -189,7 +190,7 @@ class OpenACCComputeConstruct final /// Construct. class OpenACCLoopConstruct final : public OpenACCAssociatedStmtConstruct, - public llvm::TrailingObjects { // The compute/combined construct kind this loop is associated with, or // invalid if this is an orphaned loop construct. @@ -202,6 +203,7 @@ class OpenACCLoopConstruct final friend class OpenACCAssociatedStmtConstruct; friend class OpenACCCombinedConstruct; friend class OpenACCComputeConstruct; + friend TrailingObjects; OpenACCLoopConstruct(unsigned NumClauses); @@ -245,8 +247,9 @@ class OpenACCLoopConstruct final // shared with both loop and compute constructs. class OpenACCCombinedConstruct final : public OpenACCAssociatedStmtConstruct, - public llvm::TrailingObjects { + friend TrailingObjects; OpenACCCombinedConstruct(unsigned NumClauses) : OpenACCAssociatedStmtConstruct( OpenACCCombinedConstructClass, OpenACCDirectiveKind::Invalid, @@ -292,5 +295,302 @@ class OpenACCCombinedConstruct final return const_cast(this)->getLoop(); } }; + +// This class represents a 'data' construct, which has an associated statement +// and clauses, but is otherwise pretty simple. +class OpenACCDataConstruct final + : public OpenACCAssociatedStmtConstruct, + private llvm::TrailingObjects { + friend TrailingObjects; + OpenACCDataConstruct(unsigned NumClauses) + : OpenACCAssociatedStmtConstruct( + OpenACCDataConstructClass, OpenACCDirectiveKind::Data, + SourceLocation{}, SourceLocation{}, SourceLocation{}, + /*AssociatedStmt=*/nullptr) { + std::uninitialized_value_construct( + getTrailingObjects(), + getTrailingObjects() + NumClauses); + setClauseList(MutableArrayRef(getTrailingObjects(), + NumClauses)); + } + + OpenACCDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, + ArrayRef Clauses, + Stmt *StructuredBlock) + : OpenACCAssociatedStmtConstruct(OpenACCDataConstructClass, + OpenACCDirectiveKind::Data, Start, + DirectiveLoc, End, StructuredBlock) { + std::uninitialized_copy(Clauses.begin(), Clauses.end(), + getTrailingObjects()); + setClauseList(MutableArrayRef(getTrailingObjects(), + Clauses.size())); + } + void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); } + +public: + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpenACCDataConstructClass; + } + + static OpenACCDataConstruct *CreateEmpty(const ASTContext &C, + unsigned NumClauses); + static OpenACCDataConstruct *Create(const ASTContext &C, SourceLocation Start, + SourceLocation DirectiveLoc, + SourceLocation End, + ArrayRef Clauses, + Stmt *StructuredBlock); + Stmt *getStructuredBlock() { return getAssociatedStmt(); } + const Stmt *getStructuredBlock() const { + return const_cast(this)->getStructuredBlock(); + } +}; +// This class represents a 'enter data' construct, which JUST has clauses. +class OpenACCEnterDataConstruct final + : public OpenACCConstructStmt, + private llvm::TrailingObjects { + friend TrailingObjects; + OpenACCEnterDataConstruct(unsigned NumClauses) + : OpenACCConstructStmt(OpenACCEnterDataConstructClass, + OpenACCDirectiveKind::EnterData, SourceLocation{}, + SourceLocation{}, SourceLocation{}) { + std::uninitialized_value_construct( + getTrailingObjects(), + getTrailingObjects() + NumClauses); + setClauseList(MutableArrayRef(getTrailingObjects(), + NumClauses)); + } + OpenACCEnterDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, + ArrayRef Clauses) + : OpenACCConstructStmt(OpenACCEnterDataConstructClass, + OpenACCDirectiveKind::EnterData, Start, + DirectiveLoc, End) { + std::uninitialized_copy(Clauses.begin(), Clauses.end(), + getTrailingObjects()); + setClauseList(MutableArrayRef(getTrailingObjects(), + Clauses.size())); + } + +public: + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpenACCEnterDataConstructClass; + } + static OpenACCEnterDataConstruct *CreateEmpty(const ASTContext &C, + unsigned NumClauses); + static OpenACCEnterDataConstruct * + Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, ArrayRef Clauses); +}; +// This class represents a 'exit data' construct, which JUST has clauses. +class OpenACCExitDataConstruct final + : public OpenACCConstructStmt, + private llvm::TrailingObjects { + friend TrailingObjects; + OpenACCExitDataConstruct(unsigned NumClauses) + : OpenACCConstructStmt(OpenACCExitDataConstructClass, + OpenACCDirectiveKind::ExitData, SourceLocation{}, + SourceLocation{}, SourceLocation{}) { + std::uninitialized_value_construct( + getTrailingObjects(), + getTrailingObjects() + NumClauses); + setClauseList(MutableArrayRef(getTrailingObjects(), + NumClauses)); + } + OpenACCExitDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, + ArrayRef Clauses) + : OpenACCConstructStmt(OpenACCExitDataConstructClass, + OpenACCDirectiveKind::ExitData, Start, + DirectiveLoc, End) { + std::uninitialized_copy(Clauses.begin(), Clauses.end(), + getTrailingObjects()); + setClauseList(MutableArrayRef(getTrailingObjects(), + Clauses.size())); + } + +public: + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpenACCExitDataConstructClass; + } + static OpenACCExitDataConstruct *CreateEmpty(const ASTContext &C, + unsigned NumClauses); + static OpenACCExitDataConstruct * + Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, ArrayRef Clauses); +}; +// This class represents a 'host_data' construct, which has an associated +// statement and clauses, but is otherwise pretty simple. +class OpenACCHostDataConstruct final + : public OpenACCAssociatedStmtConstruct, + private llvm::TrailingObjects { + friend TrailingObjects; + OpenACCHostDataConstruct(unsigned NumClauses) + : OpenACCAssociatedStmtConstruct( + OpenACCHostDataConstructClass, OpenACCDirectiveKind::HostData, + SourceLocation{}, SourceLocation{}, SourceLocation{}, + /*AssociatedStmt=*/nullptr) { + std::uninitialized_value_construct( + getTrailingObjects(), + getTrailingObjects() + NumClauses); + setClauseList(MutableArrayRef(getTrailingObjects(), + NumClauses)); + } + OpenACCHostDataConstruct(SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, + ArrayRef Clauses, + Stmt *StructuredBlock) + : OpenACCAssociatedStmtConstruct(OpenACCHostDataConstructClass, + OpenACCDirectiveKind::HostData, Start, + DirectiveLoc, End, StructuredBlock) { + std::uninitialized_copy(Clauses.begin(), Clauses.end(), + getTrailingObjects()); + setClauseList(MutableArrayRef(getTrailingObjects(), + Clauses.size())); + } + void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); } + +public: + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpenACCHostDataConstructClass; + } + static OpenACCHostDataConstruct *CreateEmpty(const ASTContext &C, + unsigned NumClauses); + static OpenACCHostDataConstruct * + Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, ArrayRef Clauses, + Stmt *StructuredBlock); + Stmt *getStructuredBlock() { return getAssociatedStmt(); } + const Stmt *getStructuredBlock() const { + return const_cast(this)->getStructuredBlock(); + } +}; + +// This class represents a 'wait' construct, which has some expressions plus a +// clause list. +class OpenACCWaitConstruct final + : public OpenACCConstructStmt, + private llvm::TrailingObjects { + // FIXME: We should be storing a `const OpenACCClause *` to be consistent with + // the rest of the constructs, but TrailingObjects doesn't allow for mixing + // constness in its implementation of `getTrailingObjects`. + + friend TrailingObjects; + friend class ASTStmtWriter; + friend class ASTStmtReader; + // Locations of the left and right parens of the 'wait-argument' + // expression-list. + SourceLocation LParenLoc, RParenLoc; + // Location of the 'queues' keyword, if present. + SourceLocation QueuesLoc; + + // Number of the expressions being represented. Index '0' is always the + // 'devnum' expression, even if it not present. + unsigned NumExprs = 0; + + OpenACCWaitConstruct(unsigned NumExprs, unsigned NumClauses) + : OpenACCConstructStmt(OpenACCWaitConstructClass, + OpenACCDirectiveKind::Wait, SourceLocation{}, + SourceLocation{}, SourceLocation{}), + NumExprs(NumExprs) { + assert(NumExprs >= 1 && + "NumExprs should always be >= 1 because the 'devnum' " + "expr is represented by a null if necessary"); + std::uninitialized_value_construct(getExprPtr(), + getExprPtr() + NumExprs); + std::uninitialized_value_construct(getTrailingObjects(), + getTrailingObjects() + + NumClauses); + setClauseList(MutableArrayRef(const_cast( + getTrailingObjects()), + NumClauses)); + } + + OpenACCWaitConstruct(SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation LParenLoc, Expr *DevNumExpr, + SourceLocation QueuesLoc, ArrayRef QueueIdExprs, + SourceLocation RParenLoc, SourceLocation End, + ArrayRef Clauses) + : OpenACCConstructStmt(OpenACCWaitConstructClass, + OpenACCDirectiveKind::Wait, Start, DirectiveLoc, + End), + LParenLoc(LParenLoc), RParenLoc(RParenLoc), QueuesLoc(QueuesLoc), + NumExprs(QueueIdExprs.size() + 1) { + assert(NumExprs >= 1 && + "NumExprs should always be >= 1 because the 'devnum' " + "expr is represented by a null if necessary"); + + std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1, + getExprPtr()); + std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(), + getExprPtr() + 1); + + std::uninitialized_copy(const_cast(Clauses.begin()), + const_cast(Clauses.end()), + getTrailingObjects()); + setClauseList(MutableArrayRef(const_cast( + getTrailingObjects()), + Clauses.size())); + } + + size_t numTrailingObjects(OverloadToken) const { return NumExprs; } + size_t numTrailingObjects(OverloadToken) const { + return clauses().size(); + } + + Expr **getExprPtr() const { + return const_cast(getTrailingObjects()); + } + + llvm::ArrayRef getExprs() const { + return llvm::ArrayRef(getExprPtr(), NumExprs); + } + + llvm::ArrayRef getExprs() { + return llvm::ArrayRef(getExprPtr(), NumExprs); + } + +public: + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpenACCWaitConstructClass; + } + + static OpenACCWaitConstruct * + CreateEmpty(const ASTContext &C, unsigned NumExprs, unsigned NumClauses); + + static OpenACCWaitConstruct * + Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, + ArrayRef QueueIdExprs, SourceLocation RParenLoc, + SourceLocation End, ArrayRef Clauses); + + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); } + SourceLocation getQueuesLoc() const { return QueuesLoc; } + + bool hasDevNumExpr() const { return getExprs()[0]; } + Expr *getDevNumExpr() const { return getExprs()[0]; } + llvm::ArrayRef getQueueIdExprs() { return getExprs().drop_front(); } + llvm::ArrayRef getQueueIdExprs() const { + return getExprs().drop_front(); + } + + child_range children() { + Stmt **Begin = reinterpret_cast(getExprPtr()); + return child_range(Begin, Begin + NumExprs); + } + + const_child_range children() const { + Stmt *const *Begin = + reinterpret_cast(getExprPtr()); + return const_child_range(Begin, Begin + NumExprs); + } +}; } // namespace clang #endif // LLVM_CLANG_AST_STMTOPENACC_H diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index a8f0263d5505a..9d0ee24a4f5e3 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -484,7 +484,7 @@ struct TemplateArgumentLocInfo { Pointer; TemplateTemplateArgLocInfo *getTemplate() const { - return Pointer.get(); + return cast(Pointer); } public: @@ -499,10 +499,10 @@ struct TemplateArgumentLocInfo { SourceLocation EllipsisLoc); TypeSourceInfo *getAsTypeSourceInfo() const { - return Pointer.get(); + return cast(Pointer); } - Expr *getAsExpr() const { return Pointer.get(); } + Expr *getAsExpr() const { return cast(Pointer); } NestedNameSpecifierLoc getTemplateQualifierLoc() const { const auto *Template = getTemplate(); diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 988b142a7672a..b6f16be7a5b98 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -411,6 +411,11 @@ class TextNodeDumper void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S); void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S); void VisitOpenACCCombinedConstruct(const OpenACCCombinedConstruct *S); + void VisitOpenACCDataConstruct(const OpenACCDataConstruct *S); + void VisitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct *S); + void VisitOpenACCExitDataConstruct(const OpenACCExitDataConstruct *S); + void VisitOpenACCHostDataConstruct(const OpenACCHostDataConstruct *S); + void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S); void VisitOpenACCAsteriskSizeExpr(const OpenACCAsteriskSizeExpr *S); void VisitEmbedExpr(const EmbedExpr *S); void VisitAtomicExpr(const AtomicExpr *AE); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 6fd6c73a516f0..09c98f642852f 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -934,11 +934,11 @@ class QualType { Qualifiers::FastWidth> Value; const ExtQuals *getExtQualsUnsafe() const { - return Value.getPointer().get(); + return cast(Value.getPointer()); } const Type *getTypePtrUnsafe() const { - return Value.getPointer().get(); + return cast(Value.getPointer()); } const ExtQualsTypeCommonBase *getCommonPtr() const { @@ -1064,7 +1064,7 @@ class QualType { /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType /// instance. bool hasLocalNonFastQualifiers() const { - return Value.getPointer().is(); + return isa(Value.getPointer()); } /// Retrieve the set of qualifiers local to this particular QualType @@ -6553,7 +6553,7 @@ class DeducedType : public Type { /// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained /// by a type-constraint. -class AutoType : public DeducedType, public llvm::FoldingSetNode { +class AutoType : public DeducedType { friend class ASTContext; // ASTContext creates these ConceptDecl *TypeConstraintConcept; diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 17fc36fbe2ac8..90d2a2056fe1b 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4651,6 +4651,13 @@ def HLSLNumThreads: InheritableAttr { let Documentation = [NumThreadsDocs]; } +def HLSLSV_GroupThreadID: HLSLAnnotationAttr { + let Spellings = [HLSLAnnotation<"SV_GroupThreadID">]; + let Subjects = SubjectList<[ParmVar, Field]>; + let LangOpts = [HLSL]; + let Documentation = [HLSLSV_GroupThreadIDDocs]; +} + def HLSLSV_GroupID: HLSLAnnotationAttr { let Spellings = [HLSLAnnotation<"SV_GroupID">]; let Subjects = SubjectList<[ParmVar, Field]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 7a82b8fa32059..fdad4c9a3ea19 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7941,6 +7941,17 @@ randomized. }]; } +def HLSLSV_GroupThreadIDDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``SV_GroupThreadID`` semantic, when applied to an input parameter, specifies which +individual thread within a thread group is executing in. This attribute is +only supported in compute shaders. + +The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-groupthreadid + }]; +} + def HLSLSV_GroupIDDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h index a9bb6efe850cc..e27d8ccce7366 100644 --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -55,7 +55,6 @@ struct HeaderDesc { #undef HEADER } ID; - constexpr HeaderDesc() : ID() {} constexpr HeaderDesc(HeaderID ID) : ID(ID) {} const char *getName() const; @@ -69,140 +68,14 @@ enum ID { FirstTSBuiltin }; -// The info used to represent each builtin. struct Info { - // Rather than store pointers to the string literals describing these four - // aspects of builtins, we store offsets into a common string table. - struct StrOffsets { - int Name; - int Type; - int Attributes; - int Features; - } Offsets; - + llvm::StringLiteral Name; + const char *Type, *Attributes; + const char *Features; HeaderDesc Header; LanguageID Langs; }; -// The storage for `N` builtins. This contains a single pointer to the string -// table used for these builtins and an array of metadata for each builtin. -template struct Storage { - const char *StringTable; - - std::array Infos; - - // A constexpr function to construct the storage for a a given string table in - // the first argument and an array in the second argument. This is *only* - // expected to be used at compile time, we should mark it `consteval` when - // available. - // - // The `Infos` array is particularly special. This function expects an array - // of `Info` structs, where the string offsets of each entry refer to the - // *sizes* of those strings rather than their offsets, and for the target - // string to be in the provided string table at an offset the sum of all - // previous string sizes. This function walks the `Infos` array computing the - // running sum and replacing the sizes with the actual offsets in the string - // table that should be used. This arrangement is designed to make it easy to - // expand `.def` and `.inc` files with X-macros to construct both the string - // table and the `Info` structs in the arguments to this function. - static constexpr Storage Make(const char *Strings, - std::array Infos) { - // Translate lengths to offsets. - int Offset = 0; - for (auto &I : Infos) { - Info::StrOffsets NewOffsets = {}; - NewOffsets.Name = Offset; - Offset += I.Offsets.Name; - NewOffsets.Type = Offset; - Offset += I.Offsets.Type; - NewOffsets.Attributes = Offset; - Offset += I.Offsets.Attributes; - NewOffsets.Features = Offset; - Offset += I.Offsets.Features; - I.Offsets = NewOffsets; - } - return {Strings, Infos}; - } -}; - -// A detail macro used below to emit a string literal that, after string literal -// concatenation, ends up triggering the `-Woverlength-strings` warning. While -// the warning is useful in general to catch accidentally excessive strings, -// here we are creating them intentionally. -// -// This relies on a subtle aspect of `_Pragma`: that the *diagnostic* ones don't -// turn into actual tokens that would disrupt string literal concatenation. -#ifdef __clang__ -#define CLANG_BUILTIN_DETAIL_STR_TABLE(S) \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Woverlength-strings\"") \ - S _Pragma("clang diagnostic pop") -#else -#define CLANG_BUILTIN_DETAIL_STR_TABLE(S) S -#endif - -// A macro that can be used with `Builtins.def` and similar files as an X-macro -// to add the string arguments to a builtin string table. This is typically the -// target for the `BUILTIN`, `LANGBUILTIN`, or `LIBBUILTIN` macros in those -// files. -#define CLANG_BUILTIN_STR_TABLE(ID, TYPE, ATTRS) \ - CLANG_BUILTIN_DETAIL_STR_TABLE(#ID "\0" TYPE "\0" ATTRS "\0" /*FEATURE*/ "\0") - -// A macro that can be used with target builtin `.def` and `.inc` files as an -// X-macro to add the string arguments to a builtin string table. this is -// typically the target for the `TARGET_BUILTIN` macro. -#define CLANG_TARGET_BUILTIN_STR_TABLE(ID, TYPE, ATTRS, FEATURE) \ - CLANG_BUILTIN_DETAIL_STR_TABLE(#ID "\0" TYPE "\0" ATTRS "\0" FEATURE "\0") - -// A macro that can be used with target builtin `.def` and `.inc` files as an -// X-macro to add the string arguments to a builtin string table. this is -// typically the target for the `TARGET_HEADER_BUILTIN` macro. We can't delegate -// to `TARGET_BUILTIN` because the `FEATURE` string changes position. -#define CLANG_TARGET_HEADER_BUILTIN_STR_TABLE(ID, TYPE, ATTRS, HEADER, LANGS, \ - FEATURE) \ - CLANG_BUILTIN_DETAIL_STR_TABLE(#ID "\0" TYPE "\0" ATTRS "\0" FEATURE "\0") - -// A detail macro used internally to compute the desired string table -// `StrOffsets` struct for arguments to `Storage::Make`. -#define CLANG_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS) \ - Builtin::Info::StrOffsets { \ - sizeof(#ID), sizeof(TYPE), sizeof(ATTRS), sizeof("") \ - } - -// A detail macro used internally to compute the desired string table -// `StrOffsets` struct for arguments to `Storage::Make`. -#define CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS, FEATURE) \ - Builtin::Info::StrOffsets { \ - sizeof(#ID), sizeof(TYPE), sizeof(ATTRS), sizeof(FEATURE) \ - } - -// A set of macros that can be used with builtin `.def' files as an X-macro to -// create an `Info` struct for a particular builtin. It both computes the -// `StrOffsets` value for the string table (the lengths here, translated to -// offsets by the Storage::Make function), and the other metadata for each -// builtin. -// -// There is a corresponding macro for each of `BUILTIN`, `LANGBUILTIN`, -// `LIBBUILTIN`, `TARGET_BUILTIN`, and `TARGET_HEADER_BUILTIN`. -#define CLANG_BUILTIN_ENTRY(ID, TYPE, ATTRS) \ - Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS), \ - HeaderDesc::NO_HEADER, ALL_LANGUAGES}, -#define CLANG_LANGBUILTIN_ENTRY(ID, TYPE, ATTRS, LANG) \ - Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS), \ - HeaderDesc::NO_HEADER, LANG}, -#define CLANG_LIBBUILTIN_ENTRY(ID, TYPE, ATTRS, HEADER, LANG) \ - Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS), \ - HeaderDesc::HEADER, LANG}, -#define CLANG_TARGET_BUILTIN_ENTRY(ID, TYPE, ATTRS, FEATURE) \ - Builtin::Info{ \ - CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS, FEATURE), \ - HeaderDesc::NO_HEADER, ALL_LANGUAGES}, -#define CLANG_TARGET_HEADER_BUILTIN_ENTRY(ID, TYPE, ATTRS, HEADER, LANG, \ - FEATURE) \ - Builtin::Info{ \ - CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS, FEATURE), \ - HeaderDesc::HEADER, LANG}, - /// Holds information about both target-independent and /// target-specific builtins, allowing easy queries by clients. /// @@ -210,11 +83,8 @@ template struct Storage { /// AuxTSRecords. Their IDs are shifted up by TSRecords.size() and need to /// be translated back with getAuxBuiltinID() before use. class Context { - const char *TSStrTable = nullptr; - const char *AuxTSStrTable = nullptr; - - llvm::ArrayRef TSInfos; - llvm::ArrayRef AuxTSInfos; + llvm::ArrayRef TSRecords; + llvm::ArrayRef AuxTSRecords; public: Context() = default; @@ -230,13 +100,10 @@ class Context { /// Return the identifier name for the specified builtin, /// e.g. "__builtin_abs". - llvm::StringRef getName(unsigned ID) const; + llvm::StringRef getName(unsigned ID) const { return getRecord(ID).Name; } /// Get the type descriptor string for the specified builtin. - const char *getTypeString(unsigned ID) const; - - /// Get the attributes descriptor string for the specified builtin. - const char *getAttributesString(unsigned ID) const; + const char *getTypeString(unsigned ID) const { return getRecord(ID).Type; } /// Return true if this function is a target-specific builtin. bool isTSBuiltin(unsigned ID) const { @@ -245,40 +112,40 @@ class Context { /// Return true if this function has no side effects. bool isPure(unsigned ID) const { - return strchr(getAttributesString(ID), 'U') != nullptr; + return strchr(getRecord(ID).Attributes, 'U') != nullptr; } /// Return true if this function has no side effects and doesn't /// read memory. bool isConst(unsigned ID) const { - return strchr(getAttributesString(ID), 'c') != nullptr; + return strchr(getRecord(ID).Attributes, 'c') != nullptr; } /// Return true if we know this builtin never throws an exception. bool isNoThrow(unsigned ID) const { - return strchr(getAttributesString(ID), 'n') != nullptr; + return strchr(getRecord(ID).Attributes, 'n') != nullptr; } /// Return true if we know this builtin never returns. bool isNoReturn(unsigned ID) const { - return strchr(getAttributesString(ID), 'r') != nullptr; + return strchr(getRecord(ID).Attributes, 'r') != nullptr; } /// Return true if we know this builtin can return twice. bool isReturnsTwice(unsigned ID) const { - return strchr(getAttributesString(ID), 'j') != nullptr; + return strchr(getRecord(ID).Attributes, 'j') != nullptr; } /// Returns true if this builtin does not perform the side-effects /// of its arguments. bool isUnevaluated(unsigned ID) const { - return strchr(getAttributesString(ID), 'u') != nullptr; + return strchr(getRecord(ID).Attributes, 'u') != nullptr; } /// Return true if this is a builtin for a libc/libm function, /// with a "__builtin_" prefix (e.g. __builtin_abs). bool isLibFunction(unsigned ID) const { - return strchr(getAttributesString(ID), 'F') != nullptr; + return strchr(getRecord(ID).Attributes, 'F') != nullptr; } /// Determines whether this builtin is a predefined libc/libm @@ -289,21 +156,21 @@ class Context { /// they do not, but they are recognized as builtins once we see /// a declaration. bool isPredefinedLibFunction(unsigned ID) const { - return strchr(getAttributesString(ID), 'f') != nullptr; + return strchr(getRecord(ID).Attributes, 'f') != nullptr; } /// Returns true if this builtin requires appropriate header in other /// compilers. In Clang it will work even without including it, but we can emit /// a warning about missing header. bool isHeaderDependentFunction(unsigned ID) const { - return strchr(getAttributesString(ID), 'h') != nullptr; + return strchr(getRecord(ID).Attributes, 'h') != nullptr; } /// Determines whether this builtin is a predefined compiler-rt/libgcc /// function, such as "__clear_cache", where we know the signature a /// priori. bool isPredefinedRuntimeFunction(unsigned ID) const { - return strchr(getAttributesString(ID), 'i') != nullptr; + return strchr(getRecord(ID).Attributes, 'i') != nullptr; } /// Determines whether this builtin is a C++ standard library function @@ -311,7 +178,7 @@ class Context { /// specialization, where the signature is determined by the standard library /// declaration. bool isInStdNamespace(unsigned ID) const { - return strchr(getAttributesString(ID), 'z') != nullptr; + return strchr(getRecord(ID).Attributes, 'z') != nullptr; } /// Determines whether this builtin can have its address taken with no @@ -325,33 +192,33 @@ class Context { /// Determines whether this builtin has custom typechecking. bool hasCustomTypechecking(unsigned ID) const { - return strchr(getAttributesString(ID), 't') != nullptr; + return strchr(getRecord(ID).Attributes, 't') != nullptr; } /// Determines whether a declaration of this builtin should be recognized /// even if the type doesn't match the specified signature. bool allowTypeMismatch(unsigned ID) const { - return strchr(getAttributesString(ID), 'T') != nullptr || + return strchr(getRecord(ID).Attributes, 'T') != nullptr || hasCustomTypechecking(ID); } /// Determines whether this builtin has a result or any arguments which /// are pointer types. bool hasPtrArgsOrResult(unsigned ID) const { - return strchr(getTypeString(ID), '*') != nullptr; + return strchr(getRecord(ID).Type, '*') != nullptr; } /// Return true if this builtin has a result or any arguments which are /// reference types. bool hasReferenceArgsOrResult(unsigned ID) const { - return strchr(getTypeString(ID), '&') != nullptr || - strchr(getTypeString(ID), 'A') != nullptr; + return strchr(getRecord(ID).Type, '&') != nullptr || + strchr(getRecord(ID).Type, 'A') != nullptr; } /// If this is a library function that comes from a specific /// header, retrieve that header name. const char *getHeaderName(unsigned ID) const { - return getInfo(ID).Header.getName(); + return getRecord(ID).Header.getName(); } /// Determine whether this builtin is like printf in its @@ -376,25 +243,27 @@ class Context { /// Such functions can be const when the MathErrno lang option and FP /// exceptions are disabled. bool isConstWithoutErrnoAndExceptions(unsigned ID) const { - return strchr(getAttributesString(ID), 'e') != nullptr; + return strchr(getRecord(ID).Attributes, 'e') != nullptr; } bool isConstWithoutExceptions(unsigned ID) const { - return strchr(getAttributesString(ID), 'g') != nullptr; + return strchr(getRecord(ID).Attributes, 'g') != nullptr; } - const char *getRequiredFeatures(unsigned ID) const; + const char *getRequiredFeatures(unsigned ID) const { + return getRecord(ID).Features; + } unsigned getRequiredVectorWidth(unsigned ID) const; /// Return true if builtin ID belongs to AuxTarget. bool isAuxBuiltinID(unsigned ID) const { - return ID >= (Builtin::FirstTSBuiltin + TSInfos.size()); + return ID >= (Builtin::FirstTSBuiltin + TSRecords.size()); } /// Return real builtin ID (i.e. ID it would have during compilation /// for AuxTarget). - unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSInfos.size(); } + unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSRecords.size(); } /// Returns true if this is a libc/libm function without the '__builtin_' /// prefix. @@ -406,20 +275,16 @@ class Context { /// Return true if this function can be constant evaluated by Clang frontend. bool isConstantEvaluated(unsigned ID) const { - return strchr(getAttributesString(ID), 'E') != nullptr; + return strchr(getRecord(ID).Attributes, 'E') != nullptr; } /// Returns true if this is an immediate (consteval) function bool isImmediate(unsigned ID) const { - return strchr(getAttributesString(ID), 'G') != nullptr; + return strchr(getRecord(ID).Attributes, 'G') != nullptr; } private: - std::pair getStrTableAndInfo(unsigned ID) const; - - const Info &getInfo(unsigned ID) const { - return getStrTableAndInfo(ID).second; - } + const Info &getRecord(unsigned ID) const; /// Helper function for isPrintfLike and isScanfLike. bool isLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg, diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 32a09e2ceb385..d64a66fc9d9cf 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4762,6 +4762,12 @@ def HLSLAsDouble : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLWaveActiveAllTrue : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_active_all_true"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(bool)"; +} + def HLSLWaveActiveAnyTrue : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_wave_active_any_true"]; let Attributes = [NoThrow, Const]; diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def index bb7d54bbb793e..161df386f00f0 100644 --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -1138,6 +1138,5 @@ UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2nn, "vW512*VVi15i15i3", true, // FIXME: Obviously incomplete. #undef BUILTIN -#undef TARGET_BUILTIN #undef CUSTOM_BUILTIN #undef UNALIASED_CUSTOM_BUILTIN diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 2dcf98b465661..8097c9ef772bc 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -380,6 +380,10 @@ class CodeGenOptions : public CodeGenOptionsBase { /// Set of sanitizer checks that trap rather than diagnose. SanitizerSet SanitizeTrap; + /// Set of sanitizer checks that can merge handlers (smaller code size at + /// the expense of debuggability). + SanitizerSet SanitizeMergeHandlers; + /// List of backend command-line options for -fembed-bitcode. std::vector CmdArgs; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 9fa8d5901bd0a..86fcae209c40d 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -721,6 +721,9 @@ def warn_empty_init_statement : Warning< "has no effect">, InGroup, DefaultIgnore; def err_keyword_as_parameter : Error < "invalid parameter name: '%0' is a keyword">; +def warn_pre_cxx26_ambiguous_pack_indexing_type : Warning< + "%0 is no longer a pack expansion but a pack " + "indexing type; add a name to specify a pack expansion">, InGroup; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f185a98720f5b..d67a81f8564a8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3233,8 +3233,8 @@ def err_attribute_too_few_arguments : Error< "%0 attribute takes at least %1 argument%s1">; def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">; def err_attribute_invalid_bitint_vector_type : Error< - "'_BitInt' vector element width must be %select{a power of 2|" - "at least as wide as 'CHAR_BIT'}0">; + "'_BitInt' %select{vector|matrix}0 element width must be %select{a power of 2|" + "at least as wide as 'CHAR_BIT'}1">; def err_attribute_invalid_matrix_type : Error<"invalid matrix element type %0">; def err_attribute_bad_neon_vector_size : Error< "Neon vector size must be 64 or 128 bits">; @@ -10237,16 +10237,16 @@ def warn_dangling_pointer_assignment : Warning< InGroup; def warn_dangling_reference_captured : Warning< "object whose reference is captured by '%0' will be destroyed at the end of " - "the full-expression">, InGroup, DefaultIgnore; + "the full-expression">, InGroup; def warn_dangling_reference_captured_by_unknown : Warning< "object whose reference is captured will be destroyed at the end of " - "the full-expression">, InGroup, DefaultIgnore; + "the full-expression">, InGroup; // For non-floating point, expressions of the form x == x or x != x // should result in a warning, since these always evaluate to a constant. // Array comparisons have similar warnings def warn_comparison_always : Warning< - "%select{self-|array }0comparison always evaluates to " + "%select{self-|array |pointer }0comparison always evaluates to " "%select{a constant|true|false|'std::strong_ordering::equal'}1">, InGroup; def warn_comparison_bitwise_always : Warning< @@ -12682,6 +12682,9 @@ def err_acc_not_a_var_ref : Error<"OpenACC variable is not a valid variable name, sub-array, array " "element,%select{| member of a composite variable,}0 or composite " "variable member">; +def err_acc_not_a_var_ref_use_device + : Error<"OpenACC variable in 'use_device' clause is not a valid variable " + "name or array name">; def err_acc_typecheck_subarray_value : Error<"OpenACC sub-array subscripted value is not an array or pointer">; def err_acc_subarray_function_type @@ -12716,9 +12719,9 @@ def err_acc_clause_cannot_combine : Error<"OpenACC clause '%0' may not appear on the same construct as a " "'%1' clause on a '%2' construct">; def err_acc_reduction_num_gangs_conflict - : Error< - "OpenACC 'reduction' clause may not appear on a 'parallel' construct " - "with a 'num_gangs' clause with more than 1 argument, have %0">; + : Error<"OpenACC '%1' clause %select{|with more than 1 argument }0may not " + "appear on a '%2' construct " + "with a '%3' clause%select{ with more than 1 argument|}0">; def err_acc_reduction_type : Error<"OpenACC 'reduction' variable must be of scalar type, sub-array, or a " "composite of scalar types;%select{| sub-array base}1 type is %0">; @@ -12779,13 +12782,14 @@ def err_acc_clause_in_clause_region def err_acc_gang_reduction_conflict : Error<"%select{OpenACC 'gang' clause with a 'dim' value greater than " "1|OpenACC 'reduction' clause}0 cannot " - "appear on the same 'loop' construct as a %select{'reduction' " + "appear on the same '%1' construct as a %select{'reduction' " "clause|'gang' clause with a 'dim' value greater than 1}0">; def err_acc_gang_reduction_numgangs_conflict - : Error<"OpenACC '%0' clause cannot appear on the same 'loop' construct " - "as a '%1' clause inside a compute construct with a " + : Error<"OpenACC '%0' clause cannot appear on the same '%2' construct as a " + "'%1' clause %select{inside a compute construct with a|and a}3 " "'num_gangs' clause with more than one argument">; -def err_reduction_op_mismatch + + def err_reduction_op_mismatch : Error<"OpenACC 'reduction' variable must have the same operator in all " "nested constructs (%0 vs %1)">; def err_acc_loop_variable_type @@ -12800,6 +12804,8 @@ def err_acc_loop_terminating_condition def err_acc_loop_not_monotonic : Error<"OpenACC '%0' variable must monotonically increase or decrease " "('++', '--', or compound assignment)">; +def err_acc_construct_one_clause_of + : Error<"OpenACC '%0' construct must have at least one %1 clause">; // AMDGCN builtins diagnostics def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">; diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 15c59c6bcdf29..c82b6d9b5f6c1 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -102,6 +102,7 @@ FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Nume FEATURE(memory_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory)) +FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type)) FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) diff --git a/clang/include/clang/Basic/FileEntry.h b/clang/include/clang/Basic/FileEntry.h index 68d4bf6093003..da5ba90974293 100644 --- a/clang/include/clang/Basic/FileEntry.h +++ b/clang/include/clang/Basic/FileEntry.h @@ -68,8 +68,13 @@ class FileEntryRef { StringRef getNameAsRequested() const { return ME->first(); } const FileEntry &getFileEntry() const { - return *getBaseMapEntry().second->V.get(); + return *cast(getBaseMapEntry().second->V); } + + // This function is used if the buffer size needs to be increased + // due to potential z/OS EBCDIC -> UTF-8 conversion + inline void updateFileEntryBufferSize(unsigned BufferSize); + DirectoryEntryRef getDir() const { return ME->second->Dir; } inline off_t getSize() const; @@ -323,6 +328,8 @@ class FileEntry { StringRef tryGetRealPathName() const { return RealPathName; } off_t getSize() const { return Size; } + // Size may increase due to potential z/OS EBCDIC -> UTF-8 conversion. + void setSize(off_t NewSize) { Size = NewSize; } unsigned getUID() const { return UID; } const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; } time_t getModificationTime() const { return ModTime; } @@ -353,6 +360,10 @@ bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); } void FileEntryRef::closeFile() const { getFileEntry().closeFile(); } +void FileEntryRef::updateFileEntryBufferSize(unsigned BufferSize) { + cast(getBaseMapEntry().second->V)->setSize(BufferSize); +} + } // end namespace clang #endif // LLVM_CLANG_BASIC_FILEENTRY_H diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index ae9ebd9f59154..33d1cdb46f108 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -1012,7 +1012,7 @@ class Selector { } MultiKeywordSelector *getMultiKeywordSelector() const { - return InfoPtr.getPointer().get(); + return cast(InfoPtr.getPointer()); } unsigned getIdentifierInfoFlag() const { @@ -1020,7 +1020,7 @@ class Selector { // IMPORTANT NOTE: We have to reconstitute this data rather than use the // value directly from the PointerIntPair. See the comments in `InfoPtr` // for more details. - if (InfoPtr.getPointer().is()) + if (isa(InfoPtr.getPointer())) new_flags |= MultiArg; return new_flags; } diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def index c65ebed751cf1..c7ffac391e202 100644 --- a/clang/include/clang/Basic/OpenACCClauses.def +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -38,12 +38,16 @@ VISIT_CLAUSE(Create) CLAUSE_ALIAS(PCreate, Create, true) CLAUSE_ALIAS(PresentOrCreate, Create, true) VISIT_CLAUSE(Default) +VISIT_CLAUSE(Delete) +VISIT_CLAUSE(Detach) VISIT_CLAUSE(DevicePtr) VISIT_CLAUSE(DeviceType) CLAUSE_ALIAS(DType, DeviceType, false) +VISIT_CLAUSE(Finalize) VISIT_CLAUSE(FirstPrivate) VISIT_CLAUSE(Gang) VISIT_CLAUSE(If) +VISIT_CLAUSE(IfPresent) VISIT_CLAUSE(Independent) VISIT_CLAUSE(NoCreate) VISIT_CLAUSE(NumGangs) @@ -54,6 +58,7 @@ VISIT_CLAUSE(Reduction) VISIT_CLAUSE(Self) VISIT_CLAUSE(Seq) VISIT_CLAUSE(Tile) +VISIT_CLAUSE(UseDevice) VISIT_CLAUSE(Vector) VISIT_CLAUSE(VectorLength) VISIT_CLAUSE(Wait) diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index ea0bf23468cb8..7fb76271826a6 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -158,6 +158,14 @@ inline bool isOpenACCCombinedDirectiveKind(OpenACCDirectiveKind K) { K == OpenACCDirectiveKind::KernelsLoop; } +// Tests 'K' to see if it is 'data', 'host_data', 'enter data', or 'exit data'. +inline bool isOpenACCDataDirectiveKind(OpenACCDirectiveKind K) { + return K == OpenACCDirectiveKind::Data || + K == OpenACCDirectiveKind::EnterData || + K == OpenACCDirectiveKind::ExitData || + K == OpenACCDirectiveKind::HostData; +} + enum class OpenACCAtomicKind : uint8_t { Read, Write, diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index 9223f62b3639a..f234488eaa80c 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -73,6 +73,9 @@ SANITIZER("fuzzer", Fuzzer) // libFuzzer-required instrumentation, no linking. SANITIZER("fuzzer-no-link", FuzzerNoLink) +// TypeSanitizer +SANITIZER("type", Type) + // ThreadSanitizer SANITIZER("thread", Thread) diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 89f5a76eb1131..6c7314b06d858 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -308,6 +308,11 @@ def OpenACCAssociatedStmtConstruct def OpenACCComputeConstruct : StmtNode; def OpenACCLoopConstruct : StmtNode; def OpenACCCombinedConstruct : StmtNode; +def OpenACCDataConstruct : StmtNode; +def OpenACCEnterDataConstruct : StmtNode; +def OpenACCExitDataConstruct : StmtNode; +def OpenACCHostDataConstruct : StmtNode; +def OpenACCWaitConstruct : StmtNode; // OpenACC Additional Expressions. def OpenACCAsteriskSizeExpr : StmtNode; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 52a1ac9781395..82bd537b242c1 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -16,7 +16,6 @@ #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/BitmaskEnum.h" -#include "clang/Basic/Builtins.h" #include "clang/Basic/CFProtectionOptions.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LLVM.h" @@ -1010,11 +1009,10 @@ class TargetInfo : public TransferrableTargetInfo, virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const = 0; - /// Return information about target-specific builtins for the current primary - /// target, and info about which builtins are non-portable across the current - /// set of primary and secondary targets. - virtual std::pair> - getTargetBuiltinStorage() const = 0; + /// Return information about target-specific builtins for + /// the current primary target, and info about which builtins are non-portable + /// across the current set of primary and secondary targets. + virtual ArrayRef getTargetBuiltins() const = 0; /// Returns target-specific min and max values VScale_Range. virtual std::optional> diff --git a/clang/include/clang/Basic/arm_sme.td b/clang/include/clang/Basic/arm_sme.td index 71b2c7cdd04f9..6b31dec004a1e 100644 --- a/clang/include/clang/Basic/arm_sme.td +++ b/clang/include/clang/Basic/arm_sme.td @@ -740,6 +740,38 @@ let SMETargetGuard = "sme2" in { def SVLUTI4_LANE_ZT_X2 : Inst<"svluti4_lane_zt_{d}_x2", "2.di[i", "cUcsUsiUibhf", MergeNone, "aarch64_sme_luti4_lane_zt_x2", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_3>]>; } +// +// SME2 FP8 instructions +// + +// FDOT +let SMETargetGuard = "sme-f8f32" in { + def SVDOT_LANE_FP8_ZA32_VG1x2 : Inst<"svdot_lane_za32[_mf8]_vg1x2_fpm", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fdot_lane_za32_vg1x2", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_3>]>; + def SVDOT_LANE_FP8_ZA32_VG1x4 : Inst<"svdot_lane_za32[_mf8]_vg1x4_fpm", "vm4di>", "m", MergeNone, "aarch64_sme_fp8_fdot_lane_za32_vg1x4", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_3>]>; + + def SVVDOTB_LANE_FP8_ZA32_VG1x4 : Inst<"svvdotb_lane_za32[_mf8]_vg1x4_fpm", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fvdotb_lane_za32_vg1x4", [IsOverloadNone, IsStreaming, IsInOutZA, SetsFPMR], [ImmCheck<3, ImmCheck0_3>]>; + def SVVDOTT_LANE_FP8_ZA32_VG1x4 : Inst<"svvdott_lane_za32[_mf8]_vg1x4_fpm", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fvdott_lane_za32_vg1x4", [IsOverloadNone, IsStreaming, IsInOutZA, SetsFPMR], [ImmCheck<3, ImmCheck0_3>]>; + + def SVDOT_SINGLE_FP8_ZA32_VG1x2 : Inst<"svdot[_single]_za32[_mf8]_vg1x2_fpm", "vm2d>", "m", MergeNone, "aarch64_sme_fp8_fdot_single_za32_vg1x2", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVDOT_SINGLE_FP8_ZA32_VG1x4 : Inst<"svdot[_single]_za32[_mf8]_vg1x4_fpm", "vm4d>", "m", MergeNone, "aarch64_sme_fp8_fdot_single_za32_vg1x4", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + + def SVDOT_MULTI_FP8_ZA32_VG1x2 : Inst<"svdot_za32[_mf8]_vg1x2_fpm", "vm22>", "m", MergeNone, "aarch64_sme_fp8_fdot_multi_za32_vg1x2", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVDOT_MULTI_FP8_ZA32_VG1x4 : Inst<"svdot_za32[_mf8]_vg1x4_fpm", "vm44>", "m", MergeNone, "aarch64_sme_fp8_fdot_multi_za32_vg1x4", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; +} + +let SMETargetGuard = "sme-f8f16" in { + def SVDOT_LANE_FP8_ZA16_VG1x2 : Inst<"svdot_lane_za16[_mf8]_vg1x2_fpm", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fdot_lane_za16_vg1x2", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_7>]>; + def SVDOT_LANE_FP8_ZA16_VG1x4 : Inst<"svdot_lane_za16[_mf8]_vg1x4_fpm", "vm4di>", "m", MergeNone, "aarch64_sme_fp8_fdot_lane_za16_vg1x4", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_7>]>; + + def SVVDOT_LANE_FP8_ZA16_VG1x2 : Inst<"svvdot_lane_za16[_mf8]_vg1x2_fpm", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fvdot_lane_za16_vg1x2", [IsOverloadNone, IsStreaming, IsInOutZA, SetsFPMR], [ImmCheck<3, ImmCheck0_7>]>; + + def SVDOT_SINGLE_FP8_ZA16_VG1x2 : Inst<"svdot[_single]_za16[_mf8]_vg1x2_fpm", "vm2d>", "m", MergeNone, "aarch64_sme_fp8_fdot_single_za16_vg1x2", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVDOT_SINGLE_FP8_ZA16_VG1x4 : Inst<"svdot[_single]_za16[_mf8]_vg1x4_fpm", "vm4d>", "m", MergeNone, "aarch64_sme_fp8_fdot_single_za16_vg1x4", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + + def SVDOT_MULTI_FP8_ZA16_VG1x2 : Inst<"svdot_za16[_mf8]_vg1x2_fpm", "vm22>", "m", MergeNone, "aarch64_sme_fp8_fdot_multi_za16_vg1x2", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVDOT_MULTI_FP8_ZA16_VG1x4 : Inst<"svdot_za16[_mf8]_vg1x4_fpm", "vm44>", "m", MergeNone, "aarch64_sme_fp8_fdot_multi_za16_vg1x4", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; +} + //////////////////////////////////////////////////////////////////////////////// // SME2p1 - FMOPA, FMOPS (non-widening) let SMETargetGuard = "sme-b16b16" in { @@ -827,11 +859,49 @@ let SMETargetGuard = "sme-lutv2" in { let SMETargetGuard = "sme-f8f32" in { def SVMOPA_FP8_ZA32 : Inst<"svmopa_za32[_mf8]_m_fpm", "viPPdd>", "m", MergeNone, "aarch64_sme_fp8_fmopa_za32", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<0, ImmCheck0_3>]>; + // FMLALL (indexed) + def SVMLA_FP8_LANE_ZA32_VG4x1 : Inst<"svmla_lane_za32[_mf8]_vg4x1_fpm", "vmddi>", "m", MergeNone, "aarch64_sme_fp8_fmlall_lane_za32_vg4x1", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; + def SVMLA_FP8_LANE_ZA32_VG4x2 : Inst<"svmla_lane_za32[_mf8]_vg4x2_fpm", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fmlall_lane_za32_vg4x2", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; + def SVMLA_FP8_LANE_ZA16_VG4x4 : Inst<"svmla_lane_za32[_mf8]_vg4x4_fpm", "vm4di>", "m", MergeNone, "aarch64_sme_fp8_fmlall_lane_za32_vg4x4", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; + // FMLALL (single) + def SVMLA_FP8_SINGLE_ZA32_VG4x1 : Inst<"svmla[_single]_za32[_mf8]_vg4x1_fpm", "vmdd>", "m", MergeNone, "aarch64_sme_fp8_fmlall_single_za32_vg4x1", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVMLA_FP8_SINGLE_ZA32_VG4x2 : Inst<"svmla[_single]_za32[_mf8]_vg4x2_fpm", "vm2d>", "m", MergeNone, "aarch64_sme_fp8_fmlall_single_za32_vg4x2", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVMLA_FP8_SINGLE_ZA32_VG4x4 : Inst<"svmla[_single]_za32[_mf8]_vg4x4_fpm", "vm4d>", "m", MergeNone, "aarch64_sme_fp8_fmlall_single_za32_vg4x4", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + // FMLALL (multiple) + def SVMLA_FP8_MULTI_ZA32_VG4x2 : Inst<"svmla_za32[_mf8]_vg4x2_fpm", "vm22>", "m", MergeNone, "aarch64_sme_fp8_fmlall_multi_za32_vg4x2", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVMLA_FP8_MULTI_ZA32_VG4x4 : Inst<"svmla_za32[_mf8]_vg4x4_fpm", "vm44>", "m", MergeNone, "aarch64_sme_fp8_fmlall_multi_za32_vg4x4", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; } let SMETargetGuard = "sme-f8f16" in { def SVMOPA_FP8_ZA16 : Inst<"svmopa_za16[_mf8]_m_fpm", "viPPdd>", "m", MergeNone, "aarch64_sme_fp8_fmopa_za16", [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<0, ImmCheck0_1>]>; + // FMLAL (indexed) + def SVMLA_FP8_LANE_ZA16_VG2x1 : Inst<"svmla_lane_za16[_mf8]_vg2x1_fpm", "vmddi>", "m", MergeNone, "aarch64_sme_fp8_fmlal_lane_za16_vg2x1", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; + def SVMLA_FP8_LANE_ZA16_VG2x2 : Inst<"svmla_lane_za16[_mf8]_vg2x2_fpm", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fmlal_lane_za16_vg2x2", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; + def SVMLA_FP8_LANE_ZA16_VG2x4 : Inst<"svmla_lane_za16[_mf8]_vg2x4_fpm", "vm4di>", "m", MergeNone, "aarch64_sme_fp8_fmlal_lane_za16_vg2x4", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; + // FMLAL (single) + def SVMLA_FP8_SINGLE_ZA16_VG2x1 : Inst<"svmla[_single]_za16[_mf8]_vg2x1_fpm", "vmdd>", "m", MergeNone, "aarch64_sme_fp8_fmlal_single_za16_vg2x1", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVMLA_FP8_SINGLE_ZA16_VG2x2 : Inst<"svmla[_single]_za16[_mf8]_vg2x2_fpm", "vm2d>", "m", MergeNone, "aarch64_sme_fp8_fmlal_single_za16_vg2x2", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVMLA_FP8_SINGLE_ZA16_VG2x4 : Inst<"svmla[_single]_za16[_mf8]_vg2x4_fpm", "vm4d>", "m", MergeNone, "aarch64_sme_fp8_fmlal_single_za16_vg2x4", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + // FMLAL (multiple) + def SVMLA_FP8_MULTI_ZA16_VG2x2 : Inst<"svmla_za16[_mf8]_vg2x2_fpm", "vm22>", "m", MergeNone, "aarch64_sme_fp8_fmlal_multi_za16_vg2x2", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; + def SVMLA_FP8_MULTI_ZA16_VG2x4 : Inst<"svmla_za16[_mf8]_vg2x4_fpm", "vm44>", "m", MergeNone, "aarch64_sme_fp8_fmlal_multi_za16_vg2x4", + [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], []>; } } // let SVETargetGuard = InvalidMode diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index 9b8a8546b072c..e9396e34adad8 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -2430,12 +2430,18 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in { def FSCALE_X4 : Inst<"svscale[_{d}_x4]", "444.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x4", [IsStreaming],[]>; // Convert from FP8 to half-precision/BFloat16 multi-vector - def SVF1CVT : Inst<"svcvt1_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvt1_x2", [IsStreaming, SetsFPMR], []>; - def SVF2CVT : Inst<"svcvt2_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvt2_x2", [IsStreaming, SetsFPMR], []>; + def SVF1CVT_X2 : Inst<"svcvt1_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvt1_x2", [IsStreaming, SetsFPMR], []>; + def SVF2CVT_X2 : Inst<"svcvt2_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvt2_x2", [IsStreaming, SetsFPMR], []>; // Convert from FP8 to deinterleaved half-precision/BFloat16 multi-vector - def SVF1CVTL : Inst<"svcvtl1_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl1_x2", [IsStreaming, SetsFPMR], []>; - def SVF2CVTL : Inst<"svcvtl2_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl2_x2", [IsStreaming, SetsFPMR], []>; + def SVF1CVTL_X2 : Inst<"svcvtl1_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl1_x2", [IsStreaming, SetsFPMR], []>; + def SVF2CVTL_X2 : Inst<"svcvtl2_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl2_x2", [IsStreaming, SetsFPMR], []>; + + // Convert from single/half/bfloat multivector to FP8 + def SVFCVT_X2 : Inst<"svcvt_mf8[_{d}_x2]_fpm", "~2>", "bh", MergeNone, "aarch64_sve_fp8_cvt_x2", [IsStreaming, SetsFPMR], []>; + def SVFCVT_X4 : Inst<"svcvt_mf8[_{d}_x4]_fpm", "~4>", "f", MergeNone, "aarch64_sve_fp8_cvt_x4", [IsOverloadNone, IsStreaming, SetsFPMR], []>; + // interleaved + def SVFCVTN_X4 : Inst<"svcvtn_mf8[_{d}_x4]_fpm", "~4>", "f", MergeNone, "aarch64_sve_fp8_cvtn_x4", [IsOverloadNone, IsStreaming, SetsFPMR], []>; } let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { @@ -2451,3 +2457,72 @@ let SVETargetGuard = "sve2,faminmax", SMETargetGuard = "sme2,faminmax" in { defm SVAMIN : SInstZPZZ<"svamin", "hfd", "aarch64_sve_famin", "aarch64_sve_famin_u">; defm SVAMAX : SInstZPZZ<"svamax", "hfd", "aarch64_sve_famax", "aarch64_sve_famax_u">; } + +let SVETargetGuard = "sve2,fp8", SMETargetGuard = "sme2,fp8" in { + // SVE FP8 widening conversions + + // 8-bit floating-point convert to BFloat16/Float16 + def SVF1CVT : SInst<"svcvt1_{d}[_mf8]_fpm", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvt1", [VerifyRuntimeMode, SetsFPMR]>; + def SVF2CVT : SInst<"svcvt2_{d}[_mf8]_fpm", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvt2", [VerifyRuntimeMode, SetsFPMR]>; + + // 8-bit floating-point convert to BFloat16/Float16 (top) + def SVF1CVTLT : SInst<"svcvtlt1_{d}[_mf8]_fpm", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvtlt1", [VerifyRuntimeMode, SetsFPMR]>; + def SVF2CVTLT : SInst<"svcvtlt2_{d}[_mf8]_fpm", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvtlt2", [VerifyRuntimeMode, SetsFPMR]>; + + // BFloat16/Float16 convert, narrow and interleave to 8-bit floating-point + def SVFCVTN : SInst<"svcvtn_mf8[_{d}_x2]_fpm", "~2>", "bh", MergeNone, "aarch64_sve_fp8_cvtn", [VerifyRuntimeMode, SetsFPMR]>; + + // Single-precision convert, narrow and interleave to 8-bit floating-point (top and bottom) + def SVFCVTNB : SInst<"svcvtnb_mf8[_f32_x2]_fpm", "~2>", "f", MergeNone, "aarch64_sve_fp8_cvtnb", [VerifyRuntimeMode, SetsFPMR]>; + def SVFCVTNT : SInst<"svcvtnt_mf8[_f32_x2]_fpm", "~~2>", "f", MergeNone, "aarch64_sve_fp8_cvtnt", [VerifyRuntimeMode, SetsFPMR]>; +} + +let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="sme,ssve-fp8dot2" in { + // 8-bit floating-point dot product to half-precision (vectors) + def SVFDOT_2WAY : SInst<"svdot[_f16_mf8]_fpm", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode, SetsFPMR]>; + def SVFDOT_N_2WAY : SInst<"svdot[_n_f16_mf8]_fpm", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode, SetsFPMR]>; + + // 8-bit floating-point dot product to half-precision (indexed) + def SVFDOT_LANE_2WAY : SInst<"svdot_lane[_f16_mf8]_fpm", "dd~~i>", "h", MergeNone, "aarch64_sve_fp8_fdot_lane", [VerifyRuntimeMode, SetsFPMR], [ImmCheck<3, ImmCheck0_7>]>; +} + +let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="sme,ssve-fp8dot4" in { + // 8-bit floating-point dot product to single-precision (vectors) + def SVFDOT_4WAY : SInst<"svdot[_f32_mf8]_fpm", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode, SetsFPMR]>; + def SVFDOT_N_4WAY : SInst<"svdot[_n_f32_mf8]_fpm", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode, SetsFPMR]>; + + // 8-bit floating-point dot product to single-precision (indexed) + def SVFDOT_LANE_4WAY : SInst<"svdot_lane[_f32_mf8]_fpm", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fdot_lane", [VerifyRuntimeMode, SetsFPMR], [ImmCheck<3, ImmCheck0_3>]>; +} + +let SVETargetGuard = "sve2,fp8fma", SMETargetGuard = "sme,ssve-fp8fma" in { + // 8-bit floating-point multiply-add long to half-precision (bottom) + def SVFMLALB : SInst<"svmlalb[_f16_mf8]_fpm", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fmlalb", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALB_N : SInst<"svmlalb[_n_f16_mf8]_fpm", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fmlalb", [VerifyRuntimeMode, SetsFPMR]>; + + // 8-bit floating-point multiply-add long to ha_fpmlf-precision (bottom, indexed) + def SVFMLALB_LANE : SInst<"svmlalb_lane[_f16_mf8]_fpm", "dd~~i>", "h", MergeNone, "aarch64_sve_fp8_fmlalb_lane", [VerifyRuntimeMode, SetsFPMR], [ImmCheck<3, ImmCheck0_15>]>; + + // 8-bit floating-point multiply-add long to half-precision (top) + def SVFMLALT : SInst<"svmlalt[_f16_mf8]_fpm", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fmlalt", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALT_N : SInst<"svmlalt[_n_f16_mf8]_fpm", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fmlalt", [VerifyRuntimeMode, SetsFPMR]>; + + // 8-bit floating-point multiply-add long to half-precision (top, indexed) + def SVFMLALT_LANE : SInst<"svmlalt_lane[_f16_mf8]_fpm", "dd~~i>", "h", MergeNone, "aarch64_sve_fp8_fmlalt_lane", [VerifyRuntimeMode, SetsFPMR], [ImmCheck<3, ImmCheck0_15>]>; + + // 8-bit floating-point multiply-add long long to single-precision (all top/bottom variants) + def SVFMLALLBB : SInst<"svmlallbb[_f32_mf8]_fpm", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fmlallbb", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALLBB_N : SInst<"svmlallbb[_n_f32_mf8]_fpm", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fmlallbb", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALLBT : SInst<"svmlallbt[_f32_mf8]_fpm", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fmlallbt", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALLBT_N : SInst<"svmlallbt[_n_f32_mf8]_fpm", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fmlallbt", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALLTB : SInst<"svmlalltb[_f32_mf8]_fpm", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fmlalltb", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALLTB_N : SInst<"svmlalltb[_n_f32_mf8]_fpm", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fmlalltb", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALLTT : SInst<"svmlalltt[_f32_mf8]_fpm", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fmlalltt", [VerifyRuntimeMode, SetsFPMR]>; + def SVFMLALLTT_N : SInst<"svmlalltt[_n_f32_mf8]_fpm", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fmlalltt", [VerifyRuntimeMode, SetsFPMR]>; + + // 8-bit floating-point multiply-add long long to single-precision (indexed, all top/bottom variants) + def SVFMLALLBB_LANE : SInst<"svmlallbb_lane[_f32_mf8]_fpm", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fmlallbb_lane", [VerifyRuntimeMode, SetsFPMR], [ImmCheck<3, ImmCheck0_7>]>; + def SVFMLALLBT_LANE : SInst<"svmlallbt_lane[_f32_mf8]_fpm", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fmlallbt_lane", [VerifyRuntimeMode, SetsFPMR], [ImmCheck<3, ImmCheck0_7>]>; + def SVFMLALLTB_LANE : SInst<"svmlalltb_lane[_f32_mf8]_fpm", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fmlalltb_lane", [VerifyRuntimeMode, SetsFPMR], [ImmCheck<3, ImmCheck0_7>]>; + def SVFMLALLTT_LANE : SInst<"svmlalltt_lane[_f32_mf8]_fpm", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fmlalltt_lane", [VerifyRuntimeMode, SetsFPMR], [ImmCheck<3, ImmCheck0_7>]>; +} diff --git a/clang/include/clang/Basic/arm_sve_sme_incl.td b/clang/include/clang/Basic/arm_sve_sme_incl.td index de10be7bdce0d..ee899209ad832 100644 --- a/clang/include/clang/Basic/arm_sve_sme_incl.td +++ b/clang/include/clang/Basic/arm_sve_sme_incl.td @@ -52,6 +52,7 @@ include "arm_immcheck_incl.td" // h: half-float // d: double // b: bfloat +// m: mfloat8 // Typespec modifiers // ------------------ @@ -88,6 +89,7 @@ include "arm_immcheck_incl.td" // j: element type promoted to 64bits (splat to vector type) // K: element type bitcast to a signed integer (splat to vector type) // L: element type bitcast to an unsigned integer (splat to vector type) +// !: mfloat8_t (splat to svmfloat8_t) // // i: constant uint64_t // k: int32_t diff --git a/clang/include/clang/CIR/CIRGenerator.h b/clang/include/clang/CIR/CIRGenerator.h index c8ca7e4bfa728..414eba80b88b8 100644 --- a/clang/include/clang/CIR/CIRGenerator.h +++ b/clang/include/clang/CIR/CIRGenerator.h @@ -37,14 +37,14 @@ namespace cir { class CIRGenerator : public clang::ASTConsumer { virtual void anchor(); clang::DiagnosticsEngine &diags; - clang::ASTContext *astCtx; + clang::ASTContext *astContext; // Only used for debug info. llvm::IntrusiveRefCntPtr fs; const clang::CodeGenOptions &codeGenOpts; protected: - std::unique_ptr mlirCtx; + std::unique_ptr mlirContext; std::unique_ptr cgm; public: @@ -52,7 +52,7 @@ class CIRGenerator : public clang::ASTConsumer { llvm::IntrusiveRefCntPtr fs, const clang::CodeGenOptions &cgo); ~CIRGenerator() override; - void Initialize(clang::ASTContext &astCtx) override; + void Initialize(clang::ASTContext &astContext) override; bool HandleTopLevelDecl(clang::DeclGroupRef group) override; mlir::ModuleOp getModule() const; }; diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h new file mode 100644 index 0000000000000..75ae74e926fbc --- /dev/null +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H +#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H + +#include "mlir/IR/Builders.h" + +namespace cir { + +class CIRBaseBuilderTy : public mlir::OpBuilder { + +public: + CIRBaseBuilderTy(mlir::MLIRContext &mlirContext) + : mlir::OpBuilder(&mlirContext) {} +}; + +} // namespace cir + +#endif diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index bd5e35c677b44..638f8c52053ec 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1056,11 +1056,11 @@ def z : Separate<["-"], "z">, Flags<[LinkerInput]>, def offload_link : Flag<["--"], "offload-link">, Group, HelpText<"Use the new offloading linker to perform the link job.">; def Xlinker : Separate<["-"], "Xlinker">, Flags<[LinkerInput, RenderAsInput]>, - Visibility<[ClangOption, CLOption, FlangOption, DXCOption]>, + Visibility<[ClangOption, CLOption, FlangOption]>, HelpText<"Pass to the linker">, MetaVarName<"">, Group; def Xoffload_linker : JoinedAndSeparate<["-"], "Xoffload-linker">, - Visibility<[ClangOption, CLOption, FlangOption, DXCOption]>, + Visibility<[ClangOption, FlangOption]>, HelpText<"Pass to the offload linkers or the ones identified by -">, MetaVarName<" ">, Group; def Xpreprocessor : Separate<["-"], "Xpreprocessor">, Group, @@ -1176,7 +1176,7 @@ def compatibility__version : JoinedOrSeparate<["-"], "compatibility_version">; def config : Joined<["--"], "config=">, Flags<[NoXarchOption]>, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, MetaVarName<"">, HelpText<"Specify configuration file">; -def : Separate<["--"], "config">, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, Alias; +def : Separate<["--"], "config">, Visibility<[ClangOption, FlangOption]>, Alias; def no_default_config : Flag<["--"], "no-default-config">, Flags<[NoXarchOption]>, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, HelpText<"Disable loading default configuration files">; @@ -1990,7 +1990,7 @@ def : Flag<["-"], "fno-diagnostics-color">, Group, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, Alias; def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, + Visibility<[ClangOption, FlangOption]>, Values<"auto,always,never">, HelpText<"When to use colors in diagnostics">; def fansi_escape_codes : Flag<["-"], "fansi-escape-codes">, Group, @@ -2016,10 +2016,10 @@ argument are escaped with backslashes. This format differs from the format of the equivalent section produced by GCC with the -frecord-gcc-switches flag. This option is currently only supported on ELF targets.}]>, Group, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; + Visibility<[ClangOption, FlangOption]>; def fno_record_command_line : Flag<["-"], "fno-record-command-line">, Group, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; + Visibility<[ClangOption, FlangOption]>; def : Flag<["-"], "frecord-gcc-switches">, Alias; def : Flag<["-"], "fno-record-gcc-switches">, Alias; def fcommon : Flag<["-"], "fcommon">, Group, @@ -2555,6 +2555,21 @@ def fno_sanitize_trap : Flag<["-"], "fno-sanitize-trap">, Group, Alias, AliasArgs<["all"]>, Visibility<[ClangOption, CLOption]>, HelpText<"Disable trapping for all sanitizers">; +def fsanitize_merge_handlers_EQ + : CommaJoined<["-"], "fsanitize-merge=">, + Group, + HelpText<"Allow compiler to merge handlers for specified sanitizers">; +def fno_sanitize_merge_handlers_EQ + : CommaJoined<["-"], "fno-sanitize-merge=">, + Group, + HelpText<"Do not allow compiler to merge handlers for specified sanitizers">; +def fsanitize_merge_handlers : Flag<["-"], "fsanitize-merge">, Group, + Alias, AliasArgs<["all"]>, + HelpText<"Allow compiler to merge handlers for all sanitizers">; +def fno_sanitize_merge_handlers : Flag<["-"], "fno-sanitize-merge">, Group, + Alias, AliasArgs<["all"]>, + Visibility<[ClangOption, CLOption]>, + HelpText<"Do not allow compiler to merge handlers for any sanitizers">; def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">, Group, Alias, AliasArgs<["undefined"]>; @@ -3195,11 +3210,14 @@ defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf", "Perform ODR checks for decls in the global module fragment.">>, Group; -def modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">, +def modules_reduced_bmi : Flag<["-"], "fmodules-reduced-bmi">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Generate the reduced BMI">, MarshallingInfoFlag>; +def experimental_modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">, + Group, Visibility<[ClangOption, CC1Option]>, Alias; + def fmodules_embed_all_files : Joined<["-"], "fmodules-embed-all-files">, Visibility<[ClangOption, CC1Option, CLOption]>, HelpText<"Embed the contents of all files read by this compilation into " @@ -3460,6 +3478,9 @@ defm diagnostics_show_line_numbers : BoolFOption<"diagnostics-show-line-numbers" NegFlag, PosFlag>; +def fno_realloc_lhs : Flag<["-"], "fno-realloc-lhs">, Group, + HelpText<"An allocatable left-hand side of an intrinsic assignment is assumed to be allocated and match the shape/type of the right-hand side">, + Visibility<[FlangOption, FC1Option]>; def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group, HelpText<"Disable the use of stack protectors">; def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group, @@ -4293,6 +4314,9 @@ defm stack_size_section : BoolFOption<"stack-size-section", PosFlag, NegFlag>; +def frealloc_lhs : Flag<["-"], "frealloc-lhs">, Group, + Visibility<[FlangOption, FC1Option]>, + HelpText<"If an allocatable left-hand side of an intrinsic assignment is unallocated or its shape/type does not match the right-hand side, then it is automatically (re)allocated">; def fstack_usage : Flag<["-"], "fstack-usage">, Group, HelpText<"Emit .su file containing information on function stack sizes">; def stack_usage_file : Separate<["-"], "stack-usage-file">, @@ -5645,7 +5669,7 @@ def gpulibc : Flag<["-"], "gpulibc">, Visibility<[ClangOption, CC1Option, FlangO HelpText<"Link the LLVM C Library for GPUs">; def nogpulibc : Flag<["-"], "nogpulibc">, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>; def nodefaultlibs : Flag<["-"], "nodefaultlibs">, - Visibility<[ClangOption, FlangOption, CLOption, DXCOption]>; + Visibility<[ClangOption, FlangOption]>; def nodriverkitlib : Flag<["-"], "nodriverkitlib">; def nofixprebinding : Flag<["-"], "nofixprebinding">; def nolibc : Flag<["-"], "nolibc">; @@ -5667,10 +5691,10 @@ def nostdincxx : Flag<["-"], "nostdinc++">, Visibility<[ClangOption, CC1Option]> HelpText<"Disable standard #include directories for the C++ standard library">, MarshallingInfoNegativeFlag>; def nostdlib : Flag<["-"], "nostdlib">, - Visibility<[ClangOption, CLOption, FlangOption, DXCOption]>, + Visibility<[ClangOption, FlangOption]>, Group; def stdlib : Flag<["-"], "stdlib">, - Visibility<[ClangOption, CLOption, FlangOption, DXCOption]>, + Visibility<[ClangOption, FlangOption]>, Group; def nostdlibxx : Flag<["-"], "nostdlib++">; def object : Flag<["-"], "object">; @@ -5784,7 +5808,7 @@ def resource_dir_EQ : Joined<["-"], "resource-dir=">, Flags<[NoXarchOption]>, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, Alias; def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>, Group, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; + Visibility<[ClangOption, FlangOption]>; def rtlib_EQ : Joined<["-", "--"], "rtlib=">, Visibility<[ClangOption, CLOption, FlangOption]>, HelpText<"Compiler runtime library to use">; def frtlib_add_rpath: Flag<["-"], "frtlib-add-rpath">, Flags<[NoArgumentUnused]>, @@ -5848,7 +5872,7 @@ def segs__read__write__addr : Separate<["-"], "segs_read_write_addr">; def segs__read__ : Joined<["-"], "segs_read_">; def shared_libgcc : Flag<["-"], "shared-libgcc">; def shared : Flag<["-", "--"], "shared">, Group, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; + Visibility<[ClangOption, FlangOption]>; def single__module : Flag<["-"], "single_module">; def specs_EQ : Joined<["-", "--"], "specs=">, Group; def specs : Separate<["-", "--"], "specs">, Flags<[Unsupported]>; @@ -5858,7 +5882,7 @@ def start_no_unused_arguments : Flag<["--"], "start-no-unused-arguments">, def static_libgcc : Flag<["-"], "static-libgcc">; def static_libstdcxx : Flag<["-"], "static-libstdc++">; def static : Flag<["-", "--"], "static">, Group, - Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, + Visibility<[ClangOption, FlangOption]>, Flags<[NoArgumentUnused]>; def std_default_EQ : Joined<["-"], "std-default=">; def std_EQ : Joined<["-", "--"], "std=">, @@ -6772,7 +6796,6 @@ defm real_4_real_8 : BooleanFFlag<"real-4-real-8">, Group; defm real_8_real_10 : BooleanFFlag<"real-8-real-10">, Group; defm real_8_real_16 : BooleanFFlag<"real-8-real-16">, Group; defm real_8_real_4 : BooleanFFlag<"real-8-real-4">, Group; -defm realloc_lhs : BooleanFFlag<"realloc-lhs">, Group; defm recursive : BooleanFFlag<"recursive">, Group; defm repack_arrays : BooleanFFlag<"repack-arrays">, Group; defm second_underscore : BooleanFFlag<"second-underscore">, Group; @@ -6837,10 +6860,6 @@ def flang_deprecated_no_hlfir : Flag<["-"], "flang-deprecated-no-hlfir">, Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>, HelpText<"Do not use HLFIR lowering (deprecated)">; -def flang_experimental_integer_overflow : Flag<["-"], "flang-experimental-integer-overflow">, - Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>, - HelpText<"Add nsw flag to internal operations such as do-variable increment (experimental)">; - //===----------------------------------------------------------------------===// // FLangOption + CoreOption + NoXarchOption //===----------------------------------------------------------------------===// @@ -6909,6 +6928,7 @@ defm underscoring : OptInFC1FFlag<"underscoring", "Appends one trailing undersco defm ppc_native_vec_elem_order: BoolOptionWithoutMarshalling<"f", "ppc-native-vector-element-order", PosFlag, NegFlag>; +defm unsigned : OptInFC1FFlag<"unsigned", "Enables UNSIGNED type">; def fno_automatic : Flag<["-"], "fno-automatic">, Group, HelpText<"Implies the SAVE attribute for non-automatic local objects in subprograms unless RECURSIVE">; diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 0c6f3869549ef..7410ad4303011 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -25,6 +25,7 @@ class SanitizerArgs { SanitizerSet Sanitizers; SanitizerSet RecoverableSanitizers; SanitizerSet TrapSanitizers; + SanitizerSet MergeHandlers; std::vector UserIgnorelistFiles; std::vector SystemIgnorelistFiles; @@ -87,6 +88,7 @@ class SanitizerArgs { bool needsHwasanAliasesRt() const { return needsHwasanRt() && HwasanUseAliases; } + bool needsTysanRt() const { return Sanitizers.has(SanitizerKind::Type); } bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); } bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); } bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); } diff --git a/clang/include/clang/Lex/PreprocessingRecord.h b/clang/include/clang/Lex/PreprocessingRecord.h index 437d8e4cc174e..7886aef7f0c7f 100644 --- a/clang/include/clang/Lex/PreprocessingRecord.h +++ b/clang/include/clang/Lex/PreprocessingRecord.h @@ -180,13 +180,13 @@ class Token; } /// True if it is a builtin macro. - bool isBuiltinMacro() const { return NameOrDef.is(); } + bool isBuiltinMacro() const { return isa(NameOrDef); } /// The name of the macro being expanded. const IdentifierInfo *getName() const { if (MacroDefinitionRecord *Def = getDefinition()) return Def->getName(); - return NameOrDef.get(); + return cast(NameOrDef); } /// The definition of the macro being expanded. May return null if diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 3312d4ed1d798..3d223c345ea15 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -859,7 +859,7 @@ class Preprocessor { auto *Info = State.dyn_cast(); if (!Info) { Info = new (PP.getPreprocessorAllocator()) - ModuleMacroInfo(State.get()); + ModuleMacroInfo(cast(State)); State = Info; } @@ -892,7 +892,7 @@ class Preprocessor { MacroDirective *getLatest() const { if (auto *Info = State.dyn_cast()) return Info->MD; - return State.get(); + return cast(State); } void setLatest(MacroDirective *MD) { @@ -945,7 +945,7 @@ class Preprocessor { if (Overrides.empty()) return; Info = new (PP.getPreprocessorAllocator()) - ModuleMacroInfo(State.get()); + ModuleMacroInfo(cast(State)); State = Info; } Info->OverriddenMacros.clear(); diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index d3838a4cc8418..e99d2cf2eaa40 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3706,10 +3706,14 @@ class Parser : public CodeCompletionHandler { OpenACCDirectiveKind DirKind; SourceLocation StartLoc; SourceLocation DirLoc; + SourceLocation LParenLoc; + SourceLocation RParenLoc; SourceLocation EndLoc; + SourceLocation MiscLoc; + SmallVector Exprs; SmallVector Clauses; - // TODO OpenACC: As we implement support for the Atomic, Routine, Cache, and - // Wait constructs, we likely want to put that information in here as well. + // TODO OpenACC: As we implement support for the Atomic, Routine, and Cache + // constructs, we likely want to put that information in here as well. }; struct OpenACCWaitParseInfo { @@ -3717,6 +3721,13 @@ class Parser : public CodeCompletionHandler { Expr *DevNumExpr = nullptr; SourceLocation QueuesLoc; SmallVector QueueIdExprs; + + SmallVector getAllExprs() { + SmallVector Out; + Out.push_back(DevNumExpr); + Out.insert(Out.end(), QueueIdExprs.begin(), QueueIdExprs.end()); + return Out; + } }; /// Represents the 'error' state of parsing an OpenACC Clause, and stores diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 3d1906d869926..0c92c52854c9e 100644 --- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -97,6 +97,12 @@ class MultiplexExternalSemaSource : public ExternalSemaSource { bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override; + bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override; + + bool + LoadExternalSpecializations(const Decl *D, + ArrayRef TemplateArgs) override; + /// Ensures that the table of all visible declarations inside this /// context is up to date. void completeVisibleDeclsMap(const DeclContext *DC) override; diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 22cbd0d90ee43..4fa5fbdb5a7f6 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -392,19 +392,17 @@ class ParsedAttr final } bool isArgExpr(unsigned Arg) const { - return Arg < NumArgs && getArg(Arg).is(); + return Arg < NumArgs && isa(getArg(Arg)); } - Expr *getArgAsExpr(unsigned Arg) const { - return getArg(Arg).get(); - } + Expr *getArgAsExpr(unsigned Arg) const { return cast(getArg(Arg)); } bool isArgIdent(unsigned Arg) const { - return Arg < NumArgs && getArg(Arg).is(); + return Arg < NumArgs && isa(getArg(Arg)); } IdentifierLoc *getArgAsIdent(unsigned Arg) const { - return getArg(Arg).get(); + return cast(getArg(Arg)); } const AvailabilityChange &getAvailabilityIntroduced() const { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b8684d11460ed..5ee7ea48cc983 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5314,7 +5314,7 @@ class Sema final : public SemaBase { /// is complete. void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc, - Expr *Init); + ExprResult Init); /// Handle a C++ member initializer using parentheses syntax. MemInitResult @@ -10659,6 +10659,11 @@ class Sema final : public SemaBase { SourceLocation EndLoc); void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); + /// DiagnoseDiscardedExprMarkedNodiscard - Given an expression that is + /// semantically a discarded-value expression, diagnose if any [[nodiscard]] + /// value has been discarded. + void DiagnoseDiscardedExprMarkedNodiscard(const Expr *E); + /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID); diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h index 4b1abccb7741a..fa5309a597b3a 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -210,17 +210,17 @@ bool subsumes(const NormalForm &PDNF, const NormalForm &QCNF, bool Found = false; for (NormalFormConstraint Pia : Pi) { for (NormalFormConstraint Qjb : Qj) { - if (Pia.is() && - Qjb.is()) { - if (Pia.get()->subsumes( - *Qjb.get(), E)) { + if (isa(Pia) && + isa(Qjb)) { + if (cast(Pia)->subsumes( + *cast(Qjb), E)) { Found = true; break; } - } else if (Pia.is() && - Qjb.is()) { - if (E(*Pia.get(), - *Qjb.get())) { + } else if (isa(Pia) && + isa(Qjb)) { + if (E(*cast(Pia), + *cast(Qjb))) { Found = true; break; } diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index ee685d95c9615..f4cd11f423a84 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -119,6 +119,7 @@ class SemaHLSL : public SemaBase { void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL); void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL); void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); + void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL); void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL); void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL); void handleShaderAttr(Decl *D, const ParsedAttr &AL); diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index 41d05b2bfb078..27cda71989726 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -75,7 +75,7 @@ getDepthAndIndex(UnexpandedParameterPack UPP) { if (const auto *TTP = UPP.first.dyn_cast()) return std::make_pair(TTP->getDepth(), TTP->getIndex()); - return getDepthAndIndex(UPP.first.get()); + return getDepthAndIndex(cast(UPP.first)); } class TypoCorrectionConsumer : public VisibleDeclConsumer { diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index a4132534686a8..04ab1ac429a2d 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -399,6 +399,9 @@ class SemaOpenACC : public SemaBase { ClauseKind == OpenACCClauseKind::PCreate || ClauseKind == OpenACCClauseKind::PresentOrCreate || ClauseKind == OpenACCClauseKind::Attach || + ClauseKind == OpenACCClauseKind::Delete || + ClauseKind == OpenACCClauseKind::UseDevice || + ClauseKind == OpenACCClauseKind::Detach || ClauseKind == OpenACCClauseKind::DevicePtr || ClauseKind == OpenACCClauseKind::Reduction || ClauseKind == OpenACCClauseKind::FirstPrivate) && @@ -535,6 +538,9 @@ class SemaOpenACC : public SemaBase { ClauseKind == OpenACCClauseKind::PCreate || ClauseKind == OpenACCClauseKind::PresentOrCreate || ClauseKind == OpenACCClauseKind::Attach || + ClauseKind == OpenACCClauseKind::Delete || + ClauseKind == OpenACCClauseKind::UseDevice || + ClauseKind == OpenACCClauseKind::Detach || ClauseKind == OpenACCClauseKind::DevicePtr || ClauseKind == OpenACCClauseKind::FirstPrivate) && "Parsed clause kind does not have a var-list"); @@ -571,6 +577,9 @@ class SemaOpenACC : public SemaBase { ClauseKind == OpenACCClauseKind::PCreate || ClauseKind == OpenACCClauseKind::PresentOrCreate || ClauseKind == OpenACCClauseKind::Attach || + ClauseKind == OpenACCClauseKind::Delete || + ClauseKind == OpenACCClauseKind::UseDevice || + ClauseKind == OpenACCClauseKind::Detach || ClauseKind == OpenACCClauseKind::DevicePtr || ClauseKind == OpenACCClauseKind::FirstPrivate) && "Parsed clause kind does not have a var-list"); @@ -653,7 +662,8 @@ class SemaOpenACC : public SemaBase { /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES /// happen before any associated declarations or statements have been parsed. /// This function is only called when we are parsing a 'statement' context. - bool ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); + bool ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, + ArrayRef Clauses); /// Called after the directive, including its clauses, have been parsed and /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES @@ -669,12 +679,18 @@ class SemaOpenACC : public SemaBase { /// Called after the directive has been completely parsed, including the /// declaration group or associated statement. - StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc, - SourceLocation DirLoc, - SourceLocation EndLoc, - ArrayRef Clauses, - StmtResult AssocStmt); + /// LParenLoc: Location of the left paren, if it exists (not on all + /// constructs). + /// MiscLoc: First misc location, if necessary (not all constructs). + /// Exprs: List of expressions on the construct itself, if necessary (not all + /// constructs). + /// RParenLoc: Location of the right paren, if it exists (not on all + /// constructs). + StmtResult ActOnEndStmtDirective( + OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc, + SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef Exprs, + SourceLocation RParenLoc, SourceLocation EndLoc, + ArrayRef Clauses, StmtResult AssocStmt); /// Called after the directive has been completely parsed, including the /// declaration group or associated statement. @@ -717,7 +733,8 @@ class SemaOpenACC : public SemaBase { // Does the checking for a 'gang' clause that needs to be done in dependent // and not dependent cases. OpenACCClause * - CheckGangClause(ArrayRef ExistingClauses, + CheckGangClause(OpenACCDirectiveKind DirKind, + ArrayRef ExistingClauses, SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef GangKinds, ArrayRef IntExprs, SourceLocation EndLoc); diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 6872d04cc4dfb..9800f75f676aa 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -486,10 +486,10 @@ enum class TemplateSubstitutionKind : char { const Decl *D = I->first; llvm::PointerUnion &Stored = newScope->LocalDecls[D]; - if (I->second.is()) { - Stored = I->second.get(); + if (auto *D2 = dyn_cast(I->second)) { + Stored = D2; } else { - DeclArgumentPack *OldPack = I->second.get(); + DeclArgumentPack *OldPack = cast(I->second); DeclArgumentPack *NewPack = new DeclArgumentPack(*OldPack); Stored = NewPack; newScope->ArgumentPacks.push_back(NewPack); diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index fd834c14ce790..57e27c373bffa 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -724,15 +724,20 @@ enum ASTRecordTypes { /// Record code for vtables to emit. VTABLES_TO_EMIT = 70, - /// Record code for the FunctionDecl to lambdas mapping. These lambdas have to - /// be loaded right after the function they belong to. It is required to have - /// canonical declaration for the lambda class from the same module as - /// enclosing function. - FUNCTION_DECL_TO_LAMBDAS_MAP = 71, + /// Record code for related declarations that have to be deserialized together + /// from the same module. + RELATED_DECLS_MAP = 71, /// Record code for Sema's vector of functions/blocks with effects to /// be verified. DECLS_WITH_EFFECTS_TO_VERIFY = 72, + + /// Record code for updated specialization + UPDATE_SPECIALIZATION = 73, + + CXX_ADDED_TEMPLATE_SPECIALIZATION = 74, + + CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION = 75, }; /// Record types used within a source manager block. @@ -1502,6 +1507,12 @@ enum DeclCode { /// An ImplicitConceptSpecializationDecl record. DECL_IMPLICIT_CONCEPT_SPECIALIZATION, + // A decls specilization record. + DECL_SPECIALIZATIONS, + + // A decls specilization record. + DECL_PARTIAL_SPECIALIZATIONS, + DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION }; @@ -2006,6 +2017,11 @@ enum StmtCode { STMT_OPENACC_LOOP_CONSTRUCT, STMT_OPENACC_COMBINED_CONSTRUCT, EXPR_OPENACC_ASTERISK_SIZE, + STMT_OPENACC_DATA_CONSTRUCT, + STMT_OPENACC_ENTER_DATA_CONSTRUCT, + STMT_OPENACC_EXIT_DATA_CONSTRUCT, + STMT_OPENACC_HOST_DATA_CONSTRUCT, + STMT_OPENACC_WAIT_CONSTRUCT, // HLSL Constructs EXPR_HLSL_OUT_ARG, diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index f739fe688c110..9f978762a6fb6 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -354,6 +354,9 @@ class ASTIdentifierLookupTrait; /// The on-disk hash table(s) used for DeclContext name lookup. struct DeclContextLookupTable; +/// The on-disk hash table(s) used for specialization decls. +struct LazySpecializationInfoLookupTable; + } // namespace reader } // namespace serialization @@ -534,17 +537,14 @@ class ASTReader /// namespace as if it is not delayed. DelayedNamespaceOffsetMapTy DelayedNamespaceOffsetMap; - /// Mapping from FunctionDecl IDs to the corresponding lambda IDs. + /// Mapping from main decl ID to the related decls IDs. /// - /// These lambdas have to be loaded right after the function they belong to. - /// It is required to have canonical declaration for lambda class from the - /// same module as enclosing function. This is required to correctly resolve - /// captured variables in the lambda. Without this, due to lazy - /// deserialization, canonical declarations for the function and lambdas can - /// be selected from different modules and DeclRefExprs may refer to the AST - /// nodes that don't exist in the function. - llvm::DenseMap> - FunctionToLambdasMap; + /// These related decls have to be loaded right after the main decl. + /// It is required to have canonical declaration for related decls from the + /// same module as the enclosing main decl. Without this, due to lazy + /// deserialization, canonical declarations for the main decl and related can + /// be selected from different modules. + llvm::DenseMap> RelatedDeclsMap; struct PendingUpdateRecord { Decl *D; @@ -632,20 +632,40 @@ class ASTReader llvm::DenseMap Lookups; + using SpecLookupTableTy = + llvm::DenseMap; + /// Map from decls to specialized decls. + SpecLookupTableTy SpecializationsLookups; + /// Split partial specialization from specialization to speed up lookups. + SpecLookupTableTy PartialSpecializationsLookups; + + bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, + const Decl *D); + bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, + const Decl *D, + ArrayRef TemplateArgs); + // Updates for visible decls can occur for other contexts than just the // TU, and when we read those update records, the actual context may not // be available yet, so have this pending map using the ID as a key. It - // will be realized when the context is actually loaded. - struct PendingVisibleUpdate { + // will be realized when the data is actually loaded. + struct UpdateData { ModuleFile *Mod; const unsigned char *Data; }; - using DeclContextVisibleUpdates = SmallVector; + using DeclContextVisibleUpdates = SmallVector; /// Updates to the visible declarations of declaration contexts that /// haven't been loaded yet. llvm::DenseMap PendingVisibleUpdates; + using SpecializationsUpdate = SmallVector; + using SpecializationsUpdateMap = + llvm::DenseMap; + SpecializationsUpdateMap PendingSpecializationsUpdates; + SpecializationsUpdateMap PendingPartialSpecializationsUpdates; + /// The set of C++ or Objective-C classes that have forward /// declarations that have not yet been linked to their definitions. llvm::SmallPtrSet PendingDefinitions; @@ -678,6 +698,11 @@ class ASTReader llvm::BitstreamCursor &Cursor, uint64_t Offset, GlobalDeclID ID); + bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor, + uint64_t Offset, Decl *D, bool IsPartial); + void AddSpecializations(const Decl *D, const unsigned char *Data, + ModuleFile &M, bool IsPartial); + /// A vector containing identifiers that have already been /// loaded. /// @@ -1419,6 +1444,14 @@ class ASTReader const serialization::reader::DeclContextLookupTable * getLoadedLookupTables(DeclContext *Primary) const; + /// Get the loaded specializations lookup tables for \p D, + /// if any. + serialization::reader::LazySpecializationInfoLookupTable * + getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial); + + /// If we have any unloaded specialization for \p D + bool haveUnloadedSpecializations(const Decl *D) const; + private: struct ImportedModule { ModuleFile *Mod; @@ -2076,6 +2109,12 @@ class ASTReader unsigned BlockID, uint64_t *StartOfBlockOffset = nullptr); + bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override; + + bool + LoadExternalSpecializations(const Decl *D, + ArrayRef TemplateArgs) override; + /// Finds all the visible declarations with a given name. /// The current implementation of this method just loads the entire /// lookup table as unmaterialized references. diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index e418fdea44a0a..cb972f0106402 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -230,13 +230,12 @@ class ASTWriter : public ASTDeserializationListener, /// instead of comparing the result of `getDeclID()` or `GetDeclRef()`. llvm::SmallPtrSet PredefinedDecls; - /// Mapping from FunctionDecl ID to the list of lambda IDs inside the - /// function. + /// Mapping from the main decl to related decls inside the main decls. /// - /// These lambdas have to be loaded right after the function they belong to. - /// In order to have canonical declaration for lambda class from the same - /// module as enclosing function during deserialization. - llvm::DenseMap> FunctionToLambdasMap; + /// These related decls have to be loaded right after the main decl they + /// belong to. In order to have canonical declaration for related decls from + /// the same module as the main decl during deserialization. + llvm::DenseMap> RelatedDeclsMap; /// Offset of each declaration in the bitstream, indexed by /// the declaration's ID. @@ -423,6 +422,13 @@ class ASTWriter : public ASTDeserializationListener, /// Only meaningful for reduced BMI. DeclUpdateMap DeclUpdatesFromGMF; + /// Mapping from decl templates and its new specialization in the + /// current TU. + using SpecializationUpdateMap = + llvm::MapVector>; + SpecializationUpdateMap SpecializationsUpdates; + SpecializationUpdateMap PartialSpecializationsUpdates; + using FirstLatestDeclMap = llvm::DenseMap; /// Map of first declarations from a chained PCH that point to the @@ -575,6 +581,12 @@ class ASTWriter : public ASTDeserializationListener, bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC); + void GenerateSpecializationInfoLookupTable( + const NamedDecl *D, llvm::SmallVectorImpl &Specializations, + llvm::SmallVectorImpl &LookupTable, bool IsPartial); + uint64_t WriteSpecializationInfoLookupTable( + const NamedDecl *D, llvm::SmallVectorImpl &Specializations, + bool IsPartial); void GenerateNameLookupTable(ASTContext &Context, const DeclContext *DC, llvm::SmallVectorImpl &LookupTable); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, @@ -590,6 +602,7 @@ class ASTWriter : public ASTDeserializationListener, void WriteDeclAndTypes(ASTContext &Context); void PrepareWritingSpecialDecls(Sema &SemaRef); void WriteSpecialDeclRecords(Sema &SemaRef); + void WriteSpecializationsUpdates(bool IsPartial); void WriteDeclUpdatesBlocks(ASTContext &Context, RecordDataImpl &OffsetsRecord); void WriteDeclContextVisibleUpdate(ASTContext &Context, @@ -619,6 +632,9 @@ class ASTWriter : public ASTDeserializationListener, unsigned DeclEnumAbbrev = 0; unsigned DeclObjCIvarAbbrev = 0; unsigned DeclCXXMethodAbbrev = 0; + unsigned DeclSpecializationsAbbrev = 0; + unsigned DeclPartialSpecializationsAbbrev = 0; + unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0; unsigned DeclTemplateCXXMethodAbbrev = 0; unsigned DeclMemberSpecializedCXXMethodAbbrev = 0; diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def index ad2dbffe88326..d8a7c755c9596 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -189,20 +189,29 @@ ANALYZER_OPTION( "crosscheck-with-z3-eqclass-timeout-threshold", "Set a timeout for bug report equivalence classes in milliseconds. " "If we exhaust this threshold, we will drop the bug report eqclass " - "instead of doing more Z3 queries. Set 0 for no timeout.", 700) + "instead of doing more Z3 queries. Setting this to 700 ms in conjunction " + "with \"crosscheck-with-z3-timeout-threshold\" of 300 ms, would nicely " + "guarantee that no bug report equivalence class can take longer than " + "1 second, effectively mitigating Z3 hangs during refutation. " + "Set 0 for no timeout.", 0) ANALYZER_OPTION( unsigned, Z3CrosscheckTimeoutThreshold, "crosscheck-with-z3-timeout-threshold", "Set a timeout for individual Z3 queries in milliseconds. " - "Set 0 for no timeout.", 300) + "On fast machines, 300 worked well in some cases. " + "The lower it is, the higher the chances of having flaky issues. " + "Having no timeout may hang the analyzer indefinitely. " + "Set 0 for no timeout.", 15'000) ANALYZER_OPTION( unsigned, Z3CrosscheckRLimitThreshold, "crosscheck-with-z3-rlimit-threshold", - "Set the Z3 resource limit threshold. This sets a deterministic cutoff " - "point for Z3 queries, as longer queries usually consume more resources. " - "Set 0 for unlimited.", 400'000) + "Set the Z3 resource limit threshold. This sets a supposedly deterministic " + "cutoff point for Z3 queries, as longer queries usually consume more " + "resources. " + "400'000 should on average make Z3 queries run for up to 100ms on modern " + "hardware. Set 0 for unlimited.", 0) ANALYZER_OPTION(bool, ShouldReportIssuesInMainSourceFile, "report-in-main-source-file", diff --git a/clang/include/module.modulemap b/clang/include/module.modulemap index b399f0beee59a..5bb9f6b7a91f6 100644 --- a/clang/include/module.modulemap +++ b/clang/include/module.modulemap @@ -115,7 +115,7 @@ module Clang_Diagnostics { module Driver { header "clang/Driver/DriverDiagnostic.h" export * } module Frontend { header "clang/Frontend/FrontendDiagnostic.h" export * } module Lex { header "clang/Lex/LexDiagnostic.h" export * } - module Parse { header "clang/Parse/ParseDiagnostic.h" export * } + module Parse { header "clang/Basic/DiagnosticParse.h" export * } module Serialization { header "clang/Serialization/SerializationDiagnostic.h" export * } module Refactoring { header "clang/Tooling/Refactoring/RefactoringDiagnostic.h" export * } } @@ -183,9 +183,14 @@ module Clang_StaticAnalyzer_Frontend { module * { export * } } +module Clang_Support { requires cplusplus umbrella "clang/Support" module * { export * } } + module Clang_Testing { requires cplusplus umbrella "clang/Testing" + + textual header "clang/Testing/TestLanguage.def" + module * { export * } } diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index a03cef36294db..939235179c363 100644 --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0; /// API notes file minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t VERSION_MINOR = 33; // SwiftEscapable +const uint16_t VERSION_MINOR = 34; // SwiftReturnOwnership const uint8_t kSwiftConforms = 1; const uint8_t kSwiftDoesNotConform = 2; diff --git a/clang/lib/APINotes/APINotesManager.cpp b/clang/lib/APINotes/APINotesManager.cpp index 039d09fa7cf57..70d96c735503f 100644 --- a/clang/lib/APINotes/APINotesManager.cpp +++ b/clang/lib/APINotes/APINotesManager.cpp @@ -374,9 +374,9 @@ APINotesManager::findAPINotes(SourceLocation Loc) { ++NumDirectoryCacheHits; // We've been redirected to another directory for answers. Follow it. - if (Known->second && Known->second.is()) { + if (Known->second && isa(Known->second)) { DirsVisited.insert(*Dir); - Dir = Known->second.get(); + Dir = cast(Known->second); continue; } diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index 45a344c13f470..646eabd2a5ecd 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -373,6 +373,13 @@ void ReadFunctionInfo(const uint8_t *&Data, FunctionInfo &Info) { endian::readNext(Data); Info.ResultType = std::string(Data, Data + ResultTypeLen); Data += ResultTypeLen; + + unsigned SwiftReturnOwnershipLength = + endian::readNext(Data); + Info.SwiftReturnOwnership = std::string(reinterpret_cast(Data), + reinterpret_cast(Data) + + SwiftReturnOwnershipLength); + Data += SwiftReturnOwnershipLength; } /// Used to deserialize the on-disk Objective-C method table. @@ -2038,7 +2045,12 @@ APINotesReader::VersionedInfo::VersionedInfo( Results.begin(), Results.end(), [](const std::pair &left, const std::pair &right) -> bool { - assert(left.first != right.first && "two entries for the same version"); + // The comparison function should be reflective, and with expensive + // checks we can get callbacks basically checking that lambda(a,a) is + // false. We could still check that we do not find equal elements when + // left!=right. + assert((&left == &right || left.first != right.first) && + "two entries for the same version"); return left.first < right.first; })); diff --git a/clang/lib/APINotes/APINotesTypes.cpp b/clang/lib/APINotes/APINotesTypes.cpp index d06277fa36727..f726faa832bcc 100644 --- a/clang/lib/APINotes/APINotesTypes.cpp +++ b/clang/lib/APINotes/APINotesTypes.cpp @@ -77,6 +77,8 @@ LLVM_DUMP_METHOD void FunctionInfo::dump(llvm::raw_ostream &OS) const { << "RawRetainCountConvention: " << RawRetainCountConvention << ' '; if (!ResultType.empty()) OS << "Result Type: " << ResultType << ' '; + if (!SwiftReturnOwnership.empty()) + OS << "SwiftReturnOwnership: " << SwiftReturnOwnership << ' '; if (!Params.empty()) OS << '\n'; for (auto &PI : Params) diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 480e1190358d4..1aae07bbdd30e 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -1093,6 +1093,7 @@ unsigned getFunctionInfoSize(const FunctionInfo &FI) { for (const auto &P : FI.Params) size += getParamInfoSize(P); size += sizeof(uint16_t) + FI.ResultType.size(); + size += sizeof(uint16_t) + FI.SwiftReturnOwnership.size(); return size; } @@ -1118,6 +1119,9 @@ void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) { writer.write(FI.ResultType.size()); writer.write(ArrayRef{FI.ResultType.data(), FI.ResultType.size()}); + writer.write(FI.SwiftReturnOwnership.size()); + writer.write(ArrayRef{FI.SwiftReturnOwnership.data(), + FI.SwiftReturnOwnership.size()}); } /// Used to serialize the on-disk global function table. diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp index 0668dda910f2a..414a59a4f12d0 100644 --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -162,6 +162,7 @@ struct Method { bool DesignatedInit = false; bool Required = false; StringRef ResultType; + StringRef SwiftReturnOwnership; }; typedef std::vector MethodsSeq; @@ -196,6 +197,8 @@ template <> struct MappingTraits { IO.mapOptional("DesignatedInit", M.DesignatedInit, false); IO.mapOptional("Required", M.Required, false); IO.mapOptional("ResultType", M.ResultType, StringRef("")); + IO.mapOptional("SwiftReturnOwnership", M.SwiftReturnOwnership, + StringRef("")); } }; } // namespace yaml @@ -291,6 +294,7 @@ struct Function { StringRef SwiftName; StringRef Type; StringRef ResultType; + StringRef SwiftReturnOwnership; }; typedef std::vector FunctionsSeq; @@ -313,6 +317,8 @@ template <> struct MappingTraits { IO.mapOptional("SwiftPrivate", F.SwiftPrivate); IO.mapOptional("SwiftName", F.SwiftName, StringRef("")); IO.mapOptional("ResultType", F.ResultType, StringRef("")); + IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership, + StringRef("")); } }; } // namespace yaml @@ -825,6 +831,7 @@ class YAMLConverter { emitError("'FactoryAsInit' is no longer valid; use 'SwiftName' instead"); MI.ResultType = std::string(M.ResultType); + MI.SwiftReturnOwnership = std::string(M.SwiftReturnOwnership); // Translate parameter information. convertParams(M.Params, MI, MI.Self); @@ -950,6 +957,7 @@ class YAMLConverter { convertNullability(Function.Nullability, Function.NullabilityOfRet, FI, Function.Name); FI.ResultType = std::string(Function.ResultType); + FI.SwiftReturnOwnership = std::string(Function.SwiftReturnOwnership); FI.setRetainCountConvention(Function.RetainCountConvention); } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 80e8c5b9df58e..6ec927e13a755 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -112,6 +112,27 @@ enum FloatingRank { Ibm128Rank }; +template <> struct llvm::DenseMapInfo { + static FoldingSetNodeID getEmptyKey() { return FoldingSetNodeID{}; } + + static FoldingSetNodeID getTombstoneKey() { + FoldingSetNodeID id; + for (size_t i = 0; i < sizeof(id) / sizeof(unsigned); ++i) { + id.AddInteger(std::numeric_limits::max()); + } + return id; + } + + static unsigned getHashValue(const FoldingSetNodeID &Val) { + return Val.ComputeHash(); + } + + static bool isEqual(const FoldingSetNodeID &LHS, + const FoldingSetNodeID &RHS) { + return LHS == RHS; + } +}; + /// \returns The locations that are relevant when searching for Doc comments /// related to \p D. static SmallVector @@ -899,7 +920,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, FunctionProtoTypes(this_(), FunctionProtoTypesLog2InitSize), DependentTypeOfExprTypes(this_()), DependentDecltypeTypes(this_()), TemplateSpecializationTypes(this_()), - DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()), + DependentTemplateSpecializationTypes(this_()), DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()), DeducedTemplates(this_()), ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), @@ -6294,12 +6315,14 @@ QualType ASTContext::getAutoTypeInternal( return getAutoDeductType(); // Look in the folding set for an existing type. - void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent, - TypeConstraintConcept, TypeConstraintArgs); - if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(AT, 0); + bool IsDeducedDependent = + !DeducedType.isNull() && DeducedType->isDependentType(); + AutoType::Profile(ID, *this, DeducedType, Keyword, + IsDependent || IsDeducedDependent, TypeConstraintConcept, + TypeConstraintArgs); + if (auto const AT_iter = AutoTypes.find(ID); AT_iter != AutoTypes.end()) + return QualType(AT_iter->getSecond(), 0); QualType Canon; if (!IsCanon) { @@ -6314,10 +6337,6 @@ QualType ASTContext::getAutoTypeInternal( Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, CanonicalConcept, CanonicalConceptArgs, true); - // Find the insert position again. - [[maybe_unused]] auto *Nothing = - AutoTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!Nothing && "canonical type broken"); } } } @@ -6331,8 +6350,13 @@ QualType ASTContext::getAutoTypeInternal( : TypeDependence::None) | (IsPack ? TypeDependence::UnexpandedPack : TypeDependence::None), Canon, TypeConstraintConcept, TypeConstraintArgs); +#ifndef NDEBUG + llvm::FoldingSetNodeID InsertedID; + AT->Profile(InsertedID, *this); + assert(InsertedID == ID && "ID does not match"); +#endif Types.push_back(AT); - AutoTypes.InsertNode(AT, InsertPos); + AutoTypes.try_emplace(ID, AT); return QualType(AT, 0); } diff --git a/clang/lib/AST/ByteCode/BitcastBuffer.h b/clang/lib/AST/ByteCode/BitcastBuffer.h index b1b6b9e5173a7..d1d6ee39ad17b 100644 --- a/clang/lib/AST/ByteCode/BitcastBuffer.h +++ b/clang/lib/AST/ByteCode/BitcastBuffer.h @@ -18,6 +18,8 @@ namespace interp { enum class Endian { Little, Big }; +struct Bytes; + /// A quantity in bits. struct Bits { size_t N = 0; @@ -30,6 +32,7 @@ struct Bits { bool isFullByte() const { return N % 8 == 0; } bool nonZero() const { return N != 0; } bool isZero() const { return N == 0; } + Bytes toBytes() const; Bits operator-(Bits Other) const { return Bits(N - Other.N); } Bits operator+(Bits Other) const { return Bits(N + Other.N); } @@ -56,6 +59,11 @@ struct Bytes { Bits toBits() const { return Bits(N * 8); } }; +inline Bytes Bits::toBytes() const { + assert(isFullByte()); + return Bytes(N / 8); +} + /// A bit range. Both Start and End are inclusive. struct BitRange { Bits Start; @@ -83,6 +91,7 @@ struct BitcastBuffer { /// Returns the buffer size in bits. Bits size() const { return FinalBitSize; } + Bytes byteSize() const { return FinalBitSize.toBytes(); } /// Returns \c true if all bits in the buffer have been initialized. bool allInitialized() const; diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 7f6295e126dcf..59c77f0ce78d2 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6483,14 +6483,6 @@ bool Compiler::emitBuiltinBitCast(const CastExpr *E) { QualType ToType = E->getType(); std::optional ToT = classify(ToType); - // Bitcasting TO nullptr_t is always fine. - if (ToType->isNullPtrType()) { - if (!this->discard(SubExpr)) - return false; - - return this->emitNullPtr(0, nullptr, E); - } - assert(!ToType->isReferenceType()); // Prepare storage for the result in case we discard. @@ -6523,8 +6515,8 @@ bool Compiler::emitBuiltinBitCast(const CastExpr *E) { return false; } - if (!ToT || ToT == PT_Ptr) { - if (!this->emitBitCastPtr(E)) + if (!ToT) { + if (!this->emitBitCast(E)) return false; return DiscardResult ? this->emitPopPtr(E) : true; } @@ -6540,8 +6532,8 @@ bool Compiler::emitBuiltinBitCast(const CastExpr *E) { ToType->isSpecificBuiltinType(BuiltinType::Char_U)); uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u); - if (!this->emitBitCast(*ToT, ToTypeIsUChar || ToType->isStdByteType(), - ResultBitWidth, TargetSemantics, E)) + if (!this->emitBitCastPrim(*ToT, ToTypeIsUChar || ToType->isStdByteType(), + ResultBitWidth, TargetSemantics, E)) return false; if (DiscardResult) diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h index 26585799e5ead..13fdb5369f2b7 100644 --- a/clang/lib/AST/ByteCode/Integral.h +++ b/clang/lib/AST/ByteCode/Integral.h @@ -179,7 +179,10 @@ template class Integral final { unsigned countLeadingZeros() const { if constexpr (!Signed) return llvm::countl_zero(V); - llvm_unreachable("Don't call countLeadingZeros() on signed types."); + if (isPositive()) + return llvm::countl_zero( + static_cast(V)); + llvm_unreachable("Don't call countLeadingZeros() on negative values."); } Integral truncate(unsigned TruncBits) const { @@ -210,7 +213,7 @@ template class Integral final { return Integral(Value.V); } - static Integral zero() { return from(0); } + static Integral zero(unsigned BitWidth = 0) { return from(0); } template static Integral from(T Value, unsigned NumBits) { return Integral(Value); diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 435af1201890c..7c7752080746e 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1360,7 +1360,10 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func, const CallExpr *CE, uint32_t BuiltinID) { - if (S.checkingPotentialConstantExpression()) + // A little arbitrary, but the current interpreter allows evaluation + // of builtin functions in this mode, with some exceptions. + if (BuiltinID == Builtin::BI__builtin_operator_new && + S.checkingPotentialConstantExpression()) return false; auto NewFrame = std::make_unique(S, Func, OpPC); diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index cdf05e36304ac..8461d1e98f977 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -318,18 +318,6 @@ template ::T> bool Ret(InterpState &S, CodePtr &PC) { const T &Ret = S.Stk.pop(); - // Make sure returned pointers are live. We might be trying to return a - // pointer or reference to a local variable. - // Just return false, since a diagnostic has already been emitted in Sema. - if constexpr (std::is_same_v) { - // FIXME: We could be calling isLive() here, but the emitted diagnostics - // seem a little weird, at least if the returned expression is of - // pointer type. - // Null pointers are considered live here. - if (!Ret.isZero() && !Ret.isLive()) - return false; - } - assert(S.Current); assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); if (!S.checkingPotentialConstantExpression() || S.Current->Caller) @@ -2511,50 +2499,52 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { S, OpPC, LHS, RHS); } - if constexpr (Dir == ShiftDir::Left) { - if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) { - // C++11 [expr.shift]p2: A signed left shift must have a non-negative - // operand, and must not overflow the corresponding unsigned type. - // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to - // E1 x 2^E2 module 2^N. - const SourceInfo &Loc = S.Current->getSource(OpPC); - S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt(); - if (!S.noteUndefinedBehavior()) - return false; - } - } - if (!CheckShift(S, OpPC, LHS, RHS, Bits)) return false; // Limit the shift amount to Bits - 1. If this happened, // it has already been diagnosed by CheckShift() above, // but we still need to handle it. + // Note that we have to be extra careful here since we're doing the shift in + // any case, but we need to adjust the shift amount or the way we do the shift + // for the potential error cases. typename LT::AsUnsigned R; + unsigned MaxShiftAmount = LHS.bitWidth() - 1; if constexpr (Dir == ShiftDir::Left) { - if (RHS > RT::from(Bits - 1, RHS.bitWidth())) - LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(Bits - 1), Bits, &R); - else + if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) == + ComparisonCategoryResult::Greater) { + if (LHS.isNegative()) + R = LT::AsUnsigned::zero(LHS.bitWidth()); + else { + RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth()); + LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), + LT::AsUnsigned::from(RHS, Bits), Bits, &R); + } + } else if (LHS.isNegative()) { + if (LHS.isMin()) { + R = LT::AsUnsigned::zero(LHS.bitWidth()); + } else { + // If the LHS is negative, perform the cast and invert the result. + typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS); + LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits, + &R); + R = -R; + } + } else { + // The good case, a simple left shift. LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), LT::AsUnsigned::from(RHS, Bits), Bits, &R); + } } else { - if (RHS > RT::from(Bits - 1, RHS.bitWidth())) - LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(Bits - 1), Bits, &R); - else - LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), - LT::AsUnsigned::from(RHS, Bits), Bits, &R); - } - - // We did the shift above as unsigned. Restore the sign bit if we need to. - if constexpr (Dir == ShiftDir::Right) { - if (LHS.isSigned() && LHS.isNegative()) { - typename LT::AsUnsigned SignBit; - LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(1, Bits), - LT::AsUnsigned::from(Bits - 1, Bits), Bits, - &SignBit); - LT::AsUnsigned::bitOr(R, SignBit, Bits, &R); + // Right shift. + if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) == + ComparisonCategoryResult::Greater) { + R = LT::AsUnsigned::from(-1); + } else { + // Do the shift on potentially signed LT, then convert to unsigned type. + LT A; + LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A); + R = LT::AsUnsigned::from(A); } } @@ -3040,43 +3030,51 @@ bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) { bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E); template ::T> -inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, - uint32_t ResultBitWidth, const llvm::fltSemantics *Sem) { +inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, + uint32_t ResultBitWidth, + const llvm::fltSemantics *Sem) { const Pointer &FromPtr = S.Stk.pop(); if (!CheckLoad(S, OpPC, FromPtr)) return false; - size_t BuffSize = ResultBitWidth / 8; - llvm::SmallVector Buff(BuffSize); - bool HasIndeterminateBits = false; + if constexpr (std::is_same_v) { + // The only pointer type we can validly bitcast to is nullptr_t. + S.Stk.push(); + return true; + } else { - Bits FullBitWidth(ResultBitWidth); - Bits BitWidth = FullBitWidth; + size_t BuffSize = ResultBitWidth / 8; + llvm::SmallVector Buff(BuffSize); + bool HasIndeterminateBits = false; - if constexpr (std::is_same_v) { - assert(Sem); - BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem)); - } + Bits FullBitWidth(ResultBitWidth); + Bits BitWidth = FullBitWidth; - if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth, - HasIndeterminateBits)) - return false; + if constexpr (std::is_same_v) { + assert(Sem); + BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem)); + } - if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte)) - return false; + if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth, + HasIndeterminateBits)) + return false; - if constexpr (std::is_same_v) { - assert(Sem); - S.Stk.push(T::bitcastFromMemory(Buff.data(), *Sem)); - } else { - assert(!Sem); - S.Stk.push(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); + if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte)) + return false; + + if constexpr (std::is_same_v) { + assert(Sem); + S.Stk.push(T::bitcastFromMemory(Buff.data(), *Sem)); + } else { + assert(!Sem); + S.Stk.push(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); + } + return true; } - return true; } -inline bool BitCastPtr(InterpState &S, CodePtr OpPC) { +inline bool BitCast(InterpState &S, CodePtr OpPC) { const Pointer &FromPtr = S.Stk.pop(); Pointer &ToPtr = S.Stk.peek(); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index a0de193ec32a2..d6b33c8aeeaac 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -1830,6 +1830,7 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC, return true; } + static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call) { @@ -1875,6 +1876,20 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, return false; } + // Check for overlapping memory regions. + if (!Move && Pointer::pointToSameBlock(SrcPtr, DestPtr)) { + unsigned SrcIndex = SrcPtr.getIndex() * SrcPtr.elemSize(); + unsigned DstIndex = DestPtr.getIndex() * DestPtr.elemSize(); + unsigned N = Size.getZExtValue(); + + if ((SrcIndex <= DstIndex && (SrcIndex + N) > DstIndex) || + (DstIndex <= SrcIndex && (DstIndex + N) > SrcIndex)) { + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_overlap) + << /*IsWChar=*/false; + return false; + } + } + // As a last resort, reject dummy pointers. if (DestPtr.isDummy() || SrcPtr.isDummy()) return false; @@ -1886,6 +1901,120 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, return true; } +/// Determine if T is a character type for which we guarantee that +/// sizeof(T) == 1. +static bool isOneByteCharacterType(QualType T) { + return T->isCharType() || T->isChar8Type(); +} + +static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, const CallExpr *Call) { + assert(Call->getNumArgs() == 3); + unsigned ID = Func->getBuiltinID(); + const Pointer &PtrA = getParam(Frame, 0); + const Pointer &PtrB = getParam(Frame, 1); + const APSInt &Size = + peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2))); + + if (ID == Builtin::BImemcmp || ID == Builtin::BIbcmp || + ID == Builtin::BIwmemcmp) + diagnoseNonConstexprBuiltin(S, OpPC, ID); + + if (Size.isZero()) { + pushInteger(S, 0, Call->getType()); + return true; + } + + bool IsWide = + (ID == Builtin::BIwmemcmp || ID == Builtin::BI__builtin_wmemcmp); + + const ASTContext &ASTCtx = S.getASTContext(); + // FIXME: This is an arbitrary limitation the current constant interpreter + // had. We could remove this. + if (!IsWide && (!isOneByteCharacterType(PtrA.getType()) || + !isOneByteCharacterType(PtrB.getType()))) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_memcmp_unsupported) + << ("'" + ASTCtx.BuiltinInfo.getName(ID) + "'").str() << PtrA.getType() + << PtrB.getType(); + return false; + } + + if (PtrA.isDummy() || PtrB.isDummy()) + return false; + + // Now, read both pointers to a buffer and compare those. + BitcastBuffer BufferA( + Bits(ASTCtx.getTypeSize(PtrA.getFieldDesc()->getType()))); + readPointerToBuffer(S.getContext(), PtrA, BufferA, false); + // FIXME: The swapping here is UNDOING something we do when reading the + // data into the buffer. + if (ASTCtx.getTargetInfo().isBigEndian()) + swapBytes(BufferA.Data.get(), BufferA.byteSize().getQuantity()); + + BitcastBuffer BufferB( + Bits(ASTCtx.getTypeSize(PtrB.getFieldDesc()->getType()))); + readPointerToBuffer(S.getContext(), PtrB, BufferB, false); + // FIXME: The swapping here is UNDOING something we do when reading the + // data into the buffer. + if (ASTCtx.getTargetInfo().isBigEndian()) + swapBytes(BufferB.Data.get(), BufferB.byteSize().getQuantity()); + + size_t MinBufferSize = std::min(BufferA.byteSize().getQuantity(), + BufferB.byteSize().getQuantity()); + + unsigned ElemSize = 1; + if (IsWide) + ElemSize = ASTCtx.getTypeSizeInChars(ASTCtx.getWCharType()).getQuantity(); + // The Size given for the wide variants is in wide-char units. Convert it + // to bytes. + size_t ByteSize = Size.getZExtValue() * ElemSize; + size_t CmpSize = std::min(MinBufferSize, ByteSize); + + for (size_t I = 0; I != CmpSize; I += ElemSize) { + if (IsWide) { + INT_TYPE_SWITCH(*S.getContext().classify(ASTCtx.getWCharType()), { + T A = *reinterpret_cast(BufferA.Data.get() + I); + T B = *reinterpret_cast(BufferB.Data.get() + I); + if (A < B) { + pushInteger(S, -1, Call->getType()); + return true; + } else if (A > B) { + pushInteger(S, 1, Call->getType()); + return true; + } + }); + } else { + std::byte A = BufferA.Data[I]; + std::byte B = BufferB.Data[I]; + + if (A < B) { + pushInteger(S, -1, Call->getType()); + return true; + } else if (A > B) { + pushInteger(S, 1, Call->getType()); + return true; + } + } + } + + // We compared CmpSize bytes above. If the limiting factor was the Size + // passed, we're done and the result is equality (0). + if (ByteSize <= CmpSize) { + pushInteger(S, 0, Call->getType()); + return true; + } + + // However, if we read all the available bytes but were instructed to read + // even more, diagnose this as a "read of dereferenced one-past-the-end + // pointer". This is what would happen if we called CheckRead() on every array + // element. + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_past_end) + << AK_Read << S.Current->getRange(OpPC); + return false; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call, uint32_t BuiltinID) { const InterpFrame *Frame = S.Current; @@ -2359,6 +2488,16 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BI__builtin_memcmp: + case Builtin::BImemcmp: + case Builtin::BI__builtin_bcmp: + case Builtin::BIbcmp: + case Builtin::BI__builtin_wmemcmp: + case Builtin::BIwmemcmp: + if (!interp__builtin_memcmp(S, OpPC, Frame, F, Call)) + return false; + break; + default: S.FFDiag(S.Current->getLocation(OpPC), diag::note_invalid_subexpr_in_const_expr) diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp index c9cd113287557..07f7694370821 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp @@ -33,8 +33,9 @@ using namespace clang::interp; // bytes to/from the buffer. /// Used to iterate over pointer fields. -using DataFunc = llvm::function_ref; +using DataFunc = + llvm::function_ref; #define BITCAST_TYPE_SWITCH(Expr, B) \ do { \ @@ -72,11 +73,6 @@ using DataFunc = llvm::function_refisPrimitive()) - return F(P, FieldDesc->getPrimType(), Offset, /*PackedBools=*/false); + if (FieldDesc->isPrimitive()) { + Bits FullBitWidth = + Bits(Ctx.getASTContext().getTypeSize(FieldDesc->getType())); + return F(P, FieldDesc->getPrimType(), Offset, FullBitWidth, + /*PackedBools=*/false); + } // Primitive arrays. if (FieldDesc->isPrimitiveArray()) { QualType ElemType = FieldDesc->getElemQualType(); - size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType); + Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); PrimType ElemT = *Ctx.classify(ElemType); // Special case, since the bools here are packed. bool PackedBools = FieldDesc->getType()->isExtVectorBoolType(); unsigned NumElems = FieldDesc->getNumElems(); bool Ok = true; for (unsigned I = P.getIndex(); I != NumElems; ++I) { - Ok = Ok && F(P.atIndex(I), ElemT, Offset, PackedBools); - Offset += PackedBools ? 1 : ElemSizeInBits; + Ok = Ok && F(P.atIndex(I), ElemT, Offset, ElemSize, PackedBools); + Offset += PackedBools ? Bits(1) : ElemSize; if (Offset >= BitsToRead) break; } @@ -109,10 +109,10 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, // Composite arrays. if (FieldDesc->isCompositeArray()) { QualType ElemType = FieldDesc->getElemQualType(); - size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType); + Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType)); for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) { enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F); - Offset += ElemSizeInBits; + Offset += ElemSize; if (Offset >= BitsToRead) break; } @@ -222,27 +222,56 @@ static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, IsToType)) return false; + if (const auto *VT = T->getAs()) { + const ASTContext &ASTCtx = S.getASTContext(); + QualType EltTy = VT->getElementType(); + unsigned NElts = VT->getNumElements(); + unsigned EltSize = + VT->isExtVectorBoolType() ? 1 : ASTCtx.getTypeSize(EltTy); + + if ((NElts * EltSize) % ASTCtx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + const Expr *E = S.Current->getExpr(OpPC); + S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_vector) + << QualType(VT, 0) << EltSize << NElts << ASTCtx.getCharWidth(); + return false; + } + + if (EltTy->isRealFloatingType() && + &ASTCtx.getFloatTypeSemantics(EltTy) == &APFloat::x87DoubleExtended()) { + // The layout for x86_fp80 vectors seems to be handled very inconsistently + // by both clang and LLVM, so for now we won't allow bit_casts involving + // it in a constexpr context. + const Expr *E = S.Current->getExpr(OpPC); + S.FFDiag(E, diag::note_constexpr_bit_cast_unsupported_type) << EltTy; + return false; + } + } + return true; } -static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, - BitcastBuffer &Buffer, bool ReturnOnUninit) { +bool clang::interp::readPointerToBuffer(const Context &Ctx, + const Pointer &FromPtr, + BitcastBuffer &Buffer, + bool ReturnOnUninit) { const ASTContext &ASTCtx = Ctx.getASTContext(); Endian TargetEndianness = ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; return enumeratePointerFields( FromPtr, Ctx, Buffer.size(), - [&](const Pointer &P, PrimType T, Bits BitOffset, + [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, bool PackedBools) -> bool { - CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType()); - Bits BitWidth = Bits(ASTCtx.toBits(ObjectReprChars)); - Bits FullBitWidth = BitWidth; + Bits BitWidth = FullBitWidth; - if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) { + if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx), (unsigned)FullBitWidth.getQuantity())); - } else if (T == PT_Bool && PackedBools) + else if (T == PT_Bool && PackedBools) BitWidth = Bits(1); if (BitWidth.isZero()) @@ -261,8 +290,7 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, } assert(P.isInitialized()); - auto Buff = - std::make_unique(ObjectReprChars.getQuantity()); + auto Buff = std::make_unique(FullBitWidth.roundToBytes()); // Work around floating point types that contain unused padding bytes. // This is really just `long double` on x86, which is the only // fundamental type with padding bytes. @@ -357,11 +385,9 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big; bool Success = enumeratePointerFields( ToPtr, S.getContext(), Buffer.size(), - [&](const Pointer &P, PrimType T, Bits BitOffset, + [&](const Pointer &P, PrimType T, Bits BitOffset, Bits FullBitWidth, bool PackedBools) -> bool { QualType PtrType = P.getType(); - CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(PtrType); - Bits FullBitWidth = Bits(ASTCtx.toBits(ObjectReprChars)); if (T == PT_Float) { const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType); Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics)); diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h index 92e6ffc79fc4f..b45613b2f21e2 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_INTERP_BUILITN_BIT_CAST_H -#define LLVM_CLANG_AST_INTERP_BUILITN_BIT_CAST_H +#ifndef LLVM_CLANG_AST_INTERP_BUILTIN_BIT_CAST_H +#define LLVM_CLANG_AST_INTERP_BUILTIN_BIT_CAST_H #include "BitcastBuffer.h" #include @@ -17,6 +17,12 @@ namespace interp { class Pointer; class InterpState; class CodePtr; +class Context; + +inline static void swapBytes(std::byte *M, size_t N) { + for (size_t I = 0; I != (N / 2); ++I) + std::swap(M[I], M[N - 1 - I]); +} bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, @@ -25,7 +31,8 @@ bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr); bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr, size_t Size); - +bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, + BitcastBuffer &Buffer, bool ReturnOnUninit); } // namespace interp } // namespace clang diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 0638f8249805f..123c21fa43ece 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -839,13 +839,14 @@ def IsConstantContext: Opcode; def CheckAllocations : Opcode; def BitCastTypeClass : TypeClass { - let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, IntAP, IntAPS, Bool, Float]; + let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, + IntAP, IntAPS, Bool, Float, Ptr]; } -def BitCast : Opcode { +def BitCastPrim : Opcode { let Types = [BitCastTypeClass]; let Args = [ArgBool, ArgUint32, ArgFltSemantics]; let HasGroup = 1; } -def BitCastPtr : Opcode; +def BitCast : Opcode; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 1da3f26bf23cd..40ee3753c2422 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -16,7 +16,9 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/ODRHash.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -348,26 +350,39 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c return Common; } -void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { - // Grab the most recent declaration to ensure we've loaded any lazy - // redeclarations of this template. - CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr(); - if (CommonBasePtr->LazySpecializations) { - ASTContext &Context = getASTContext(); - GlobalDeclID *Specs = CommonBasePtr->LazySpecializations; - CommonBasePtr->LazySpecializations = nullptr; - unsigned SpecSize = (*Specs++).getRawValue(); - for (unsigned I = 0; I != SpecSize; ++I) - (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); - } +void RedeclarableTemplateDecl::loadLazySpecializationsImpl( + bool OnlyPartial /*=false*/) const { + auto *ExternalSource = getASTContext().getExternalSource(); + if (!ExternalSource) + return; + + ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), + OnlyPartial); + return; } -template +bool RedeclarableTemplateDecl::loadLazySpecializationsImpl( + ArrayRef Args, TemplateParameterList *TPL) const { + auto *ExternalSource = getASTContext().getExternalSource(); + if (!ExternalSource) + return false; + + // If TPL is not null, it implies that we're loading specializations for + // partial templates. We need to load all specializations in such cases. + if (TPL) + return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), + /*OnlyPartial=*/false); + + return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), + Args); +} + +template typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType * -RedeclarableTemplateDecl::findSpecializationImpl( +RedeclarableTemplateDecl::findSpecializationLocally( llvm::FoldingSetVector &Specs, void *&InsertPos, - ProfileArguments&&... ProfileArgs) { - using SETraits = SpecEntryTraits; + ProfileArguments &&...ProfileArgs) { + using SETraits = RedeclarableTemplateDecl::SpecEntryTraits; llvm::FoldingSetNodeID ID; EntryType::Profile(ID, std::forward(ProfileArgs)..., @@ -376,6 +391,24 @@ RedeclarableTemplateDecl::findSpecializationImpl( return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr; } +template +typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType * +RedeclarableTemplateDecl::findSpecializationImpl( + llvm::FoldingSetVector &Specs, void *&InsertPos, + ProfileArguments &&...ProfileArgs) { + + if (auto *Found = findSpecializationLocally( + Specs, InsertPos, std::forward(ProfileArgs)...)) + return Found; + + if (!loadLazySpecializationsImpl( + std::forward(ProfileArgs)...)) + return nullptr; + + return findSpecializationLocally( + Specs, InsertPos, std::forward(ProfileArgs)...); +} + template void RedeclarableTemplateDecl::addSpecializationImpl( llvm::FoldingSetVector &Specializations, EntryType *Entry, @@ -384,10 +417,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl( if (InsertPos) { #ifndef NDEBUG + auto Args = SETraits::getTemplateArgs(Entry); + // Due to hash collisions, it can happen that we load another template + // specialization with the same hash. This is fine, as long as the next + // call to findSpecializationImpl does not find a matching Decl for the + // template arguments. + loadLazySpecializationsImpl(Args); void *CorrectInsertPos; - assert(!findSpecializationImpl(Specializations, - CorrectInsertPos, - SETraits::getTemplateArgs(Entry)) && + assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) && InsertPos == CorrectInsertPos && "given incorrect InsertPos for specialization"); #endif @@ -445,12 +482,14 @@ FunctionTemplateDecl::getSpecializations() const { FunctionDecl * FunctionTemplateDecl::findSpecialization(ArrayRef Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void FunctionTemplateDecl::addSpecialization( FunctionTemplateSpecializationInfo *Info, void *InsertPos) { - addSpecializationImpl(getSpecializations(), Info, + auto *Common = getCommonPtr(); + addSpecializationImpl(Common->Specializations, Info, InsertPos); } @@ -510,8 +549,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -void ClassTemplateDecl::LoadLazySpecializations() const { - loadLazySpecializationsImpl(); +void ClassTemplateDecl::LoadLazySpecializations( + bool OnlyPartial /*=false*/) const { + loadLazySpecializationsImpl(OnlyPartial); } llvm::FoldingSetVector & @@ -522,7 +562,7 @@ ClassTemplateDecl::getSpecializations() const { llvm::FoldingSetVector & ClassTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(); + LoadLazySpecializations(/*PartialOnly = */ true); return getCommonPtr()->PartialSpecializations; } @@ -536,12 +576,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const { ClassTemplateSpecializationDecl * ClassTemplateDecl::findSpecialization(ArrayRef Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos) { - addSpecializationImpl(getSpecializations(), D, InsertPos); + auto *Common = getCommonPtr(); + addSpecializationImpl(Common->Specializations, D, + InsertPos); } ClassTemplatePartialSpecializationDecl * @@ -1259,8 +1302,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, DeclarationName(), nullptr, nullptr); } -void VarTemplateDecl::LoadLazySpecializations() const { - loadLazySpecializationsImpl(); +void VarTemplateDecl::LoadLazySpecializations( + bool OnlyPartial /*=false*/) const { + loadLazySpecializationsImpl(OnlyPartial); } llvm::FoldingSetVector & @@ -1271,7 +1315,7 @@ VarTemplateDecl::getSpecializations() const { llvm::FoldingSetVector & VarTemplateDecl::getPartialSpecializations() const { - LoadLazySpecializations(); + LoadLazySpecializations(/*PartialOnly = */ true); return getCommonPtr()->PartialSpecializations; } @@ -1285,12 +1329,14 @@ VarTemplateDecl::newCommon(ASTContext &C) const { VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + auto *Common = getCommonPtr(); + return findSpecializationImpl(Common->Specializations, InsertPos, Args); } void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos) { - addSpecializationImpl(getSpecializations(), D, InsertPos); + auto *Common = getCommonPtr(); + addSpecializationImpl(Common->Specializations, D, InsertPos); } VarTemplatePartialSpecializationDecl * diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 5a6738196d289..8c8ccdb61dc01 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2990,6 +2990,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case ExprWithCleanupsClass: return cast(this)->getSubExpr() ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); + case OpaqueValueExprClass: + return cast(this)->getSourceExpr()->isUnusedResultAWarning( + WarnE, Loc, R1, R2, Ctx); } } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index eed277deb4ac1..89c515e639276 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7352,31 +7352,6 @@ class APValueToBufferConverter { const VectorType *VTy = Ty->castAs(); QualType EltTy = VTy->getElementType(); unsigned NElts = VTy->getNumElements(); - unsigned EltSize = - VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); - - if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { - // The vector's size in bits is not a multiple of the target's byte size, - // so its layout is unspecified. For now, we'll simply treat these cases - // as unsupported (this should only be possible with OpenCL bool vectors - // whose element count isn't a multiple of the byte size). - Info.FFDiag(BCE->getBeginLoc(), - diag::note_constexpr_bit_cast_invalid_vector) - << Ty.getCanonicalType() << EltSize << NElts - << Info.Ctx.getCharWidth(); - return false; - } - - if (EltTy->isRealFloatingType() && &Info.Ctx.getFloatTypeSemantics(EltTy) == - &APFloat::x87DoubleExtended()) { - // The layout for x86_fp80 vectors seems to be handled very inconsistently - // by both clang and LLVM, so for now we won't allow bit_casts involving - // it in a constexpr context. - Info.FFDiag(BCE->getBeginLoc(), - diag::note_constexpr_bit_cast_unsupported_type) - << EltTy; - return false; - } if (VTy->isExtVectorBoolType()) { // Special handling for OpenCL bool vectors: @@ -7643,28 +7618,6 @@ class BufferToAPValueConverter { unsigned EltSize = VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); - if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { - // The vector's size in bits is not a multiple of the target's byte size, - // so its layout is unspecified. For now, we'll simply treat these cases - // as unsupported (this should only be possible with OpenCL bool vectors - // whose element count isn't a multiple of the byte size). - Info.FFDiag(BCE->getBeginLoc(), - diag::note_constexpr_bit_cast_invalid_vector) - << QualType(VTy, 0) << EltSize << NElts << Info.Ctx.getCharWidth(); - return std::nullopt; - } - - if (EltTy->isRealFloatingType() && &Info.Ctx.getFloatTypeSemantics(EltTy) == - &APFloat::x87DoubleExtended()) { - // The layout for x86_fp80 vectors seems to be handled very inconsistently - // by both clang and LLVM, so for now we won't allow bit_casts involving - // it in a constexpr context. - Info.FFDiag(BCE->getBeginLoc(), - diag::note_constexpr_bit_cast_unsupported_type) - << EltTy; - return std::nullopt; - } - SmallVector Elts; Elts.reserve(NElts); if (VTy->isExtVectorBoolType()) { @@ -7793,6 +7746,32 @@ static bool checkBitCastConstexprEligibilityType(SourceLocation Loc, Info, Ctx, CheckingDest)) return false; + if (const auto *VTy = Ty->getAs()) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = VTy->isExtVectorBoolType() ? 1 : Ctx.getTypeSize(EltTy); + + if ((NElts * EltSize) % Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases + // as unsupported (this should only be possible with OpenCL bool vectors + // whose element count isn't a multiple of the byte size). + Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_vector) + << QualType(VTy, 0) << EltSize << NElts << Ctx.getCharWidth(); + return false; + } + + if (EltTy->isRealFloatingType() && + &Ctx.getFloatTypeSemantics(EltTy) == &APFloat::x87DoubleExtended()) { + // The layout for x86_fp80 vectors seems to be handled very inconsistently + // by both clang and LLVM, so for now we won't allow bit_casts involving + // it in a constexpr context. + Info->FFDiag(Loc, diag::note_constexpr_bit_cast_unsupported_type) + << EltTy; + return false; + } + } + return true; } @@ -16536,7 +16515,7 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, const ASTContext &Ctx, bool &IsConst) { // Fast-path evaluations of integer literals, since we sometimes see files // containing vast quantities of these. - if (const IntegerLiteral *L = dyn_cast(Exp)) { + if (const auto *L = dyn_cast(Exp)) { Result.Val = APValue(APSInt(L->getValue(), L->getType()->isUnsignedIntegerType())); IsConst = true; @@ -16549,6 +16528,18 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, return true; } + if (const auto *FL = dyn_cast(Exp)) { + Result.Val = APValue(FL->getValue()); + IsConst = true; + return true; + } + + if (const auto *L = dyn_cast(Exp)) { + Result.Val = APValue(Ctx.MakeIntValue(L->getValue(), L->getType())); + IsConst = true; + return true; + } + if (const auto *CE = dyn_cast(Exp)) { if (CE->hasAPValueResult()) { APValue APV = CE->getAPValueResult(); diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index 7a14cc7d50ed0..543846c0093af 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -96,6 +96,15 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, return false; } +bool ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) { + return false; +} + +bool ExternalASTSource::LoadExternalSpecializations( + const Decl *D, ArrayRef) { + return false; +} + void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {} void ExternalASTSource::FindExternalLexicalDecls( diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 645ca6f0e7b71..7c5c287e6c15b 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -818,15 +818,20 @@ void ODRHash::AddDecl(const Decl *D) { AddDeclarationName(ND->getDeclName()); - const auto *Specialization = - dyn_cast(D); - AddBoolean(Specialization); - if (Specialization) { - const TemplateArgumentList &List = Specialization->getTemplateArgs(); - ID.AddInteger(List.size()); - for (const TemplateArgument &TA : List.asArray()) - AddTemplateArgument(TA); - } + // If this was a specialization we should take into account its template + // arguments. This helps to reduce collisions coming when visiting template + // specialization types (eg. when processing type template arguments). + ArrayRef Args; + if (auto *CTSD = dyn_cast(D)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast(D)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast(D)) + if (FD->getTemplateSpecializationArgs()) + Args = FD->getTemplateSpecializationArgs()->asArray(); + + for (auto &TA : Args) + AddTemplateArgument(TA); } namespace { diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 1299e4f807ceb..fbc9f6d15fa7b 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -32,8 +32,10 @@ bool OpenACCClauseWithVarList::classof(const OpenACCClause *C) { return OpenACCPrivateClause::classof(C) || OpenACCFirstPrivateClause::classof(C) || OpenACCDevicePtrClause::classof(C) || - OpenACCDevicePtrClause::classof(C) || - OpenACCAttachClause::classof(C) || OpenACCNoCreateClause::classof(C) || + OpenACCDeleteClause::classof(C) || + OpenACCUseDeviceClause::classof(C) || + OpenACCDetachClause::classof(C) || OpenACCAttachClause::classof(C) || + OpenACCNoCreateClause::classof(C) || OpenACCPresentClause::classof(C) || OpenACCCopyClause::classof(C) || OpenACCCopyInClause::classof(C) || OpenACCCopyOutClause::classof(C) || OpenACCReductionClause::classof(C) || OpenACCCreateClause::classof(C); @@ -277,6 +279,36 @@ OpenACCAttachClause *OpenACCAttachClause::Create(const ASTContext &C, return new (Mem) OpenACCAttachClause(BeginLoc, LParenLoc, VarList, EndLoc); } +OpenACCDetachClause *OpenACCDetachClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef VarList, + SourceLocation EndLoc) { + void *Mem = + C.Allocate(OpenACCDetachClause::totalSizeToAlloc(VarList.size())); + return new (Mem) OpenACCDetachClause(BeginLoc, LParenLoc, VarList, EndLoc); +} + +OpenACCDeleteClause *OpenACCDeleteClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef VarList, + SourceLocation EndLoc) { + void *Mem = + C.Allocate(OpenACCDeleteClause::totalSizeToAlloc(VarList.size())); + return new (Mem) OpenACCDeleteClause(BeginLoc, LParenLoc, VarList, EndLoc); +} + +OpenACCUseDeviceClause *OpenACCUseDeviceClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + ArrayRef VarList, + SourceLocation EndLoc) { + void *Mem = C.Allocate( + OpenACCUseDeviceClause::totalSizeToAlloc(VarList.size())); + return new (Mem) OpenACCUseDeviceClause(BeginLoc, LParenLoc, VarList, EndLoc); +} + OpenACCDevicePtrClause *OpenACCDevicePtrClause::Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, @@ -444,6 +476,22 @@ OpenACCVectorClause *OpenACCVectorClause::Create(const ASTContext &C, return new (Mem) OpenACCVectorClause(BeginLoc, LParenLoc, IntExpr, EndLoc); } +OpenACCFinalizeClause *OpenACCFinalizeClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation EndLoc) { + void *Mem = + C.Allocate(sizeof(OpenACCFinalizeClause), alignof(OpenACCFinalizeClause)); + return new (Mem) OpenACCFinalizeClause(BeginLoc, EndLoc); +} + +OpenACCIfPresentClause *OpenACCIfPresentClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCIfPresentClause), + alignof(OpenACCIfPresentClause)); + return new (Mem) OpenACCIfPresentClause(BeginLoc, EndLoc); +} + //===----------------------------------------------------------------------===// // OpenACC clauses printing methods //===----------------------------------------------------------------------===// @@ -530,6 +578,28 @@ void OpenACCClausePrinter::VisitAttachClause(const OpenACCAttachClause &C) { OS << ")"; } +void OpenACCClausePrinter::VisitDetachClause(const OpenACCDetachClause &C) { + OS << "detach("; + llvm::interleaveComma(C.getVarList(), OS, + [&](const Expr *E) { printExpr(E); }); + OS << ")"; +} + +void OpenACCClausePrinter::VisitDeleteClause(const OpenACCDeleteClause &C) { + OS << "delete("; + llvm::interleaveComma(C.getVarList(), OS, + [&](const Expr *E) { printExpr(E); }); + OS << ")"; +} + +void OpenACCClausePrinter::VisitUseDeviceClause( + const OpenACCUseDeviceClause &C) { + OS << "use_device("; + llvm::interleaveComma(C.getVarList(), OS, + [&](const Expr *E) { printExpr(E); }); + OS << ")"; +} + void OpenACCClausePrinter::VisitDevicePtrClause( const OpenACCDevicePtrClause &C) { OS << "deviceptr("; @@ -685,3 +755,12 @@ void OpenACCClausePrinter::VisitVectorClause(const OpenACCVectorClause &C) { OS << ")"; } } + +void OpenACCClausePrinter::VisitFinalizeClause(const OpenACCFinalizeClause &C) { + OS << "finalize"; +} + +void OpenACCClausePrinter::VisitIfPresentClause( + const OpenACCIfPresentClause &C) { + OS << "if_present"; +} diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index b1b13b66a5e50..f749d3a705fc9 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -818,7 +818,7 @@ class ItaniumRecordLayoutBuilder { void setSize(CharUnits NewSize) { Size = Context.toBits(NewSize); } void setSize(uint64_t NewSize) { Size = NewSize; } - CharUnits getAligment() const { return Alignment; } + CharUnits getAlignment() const { return Alignment; } CharUnits getDataSize() const { assert(DataSize % Context.getCharWidth() == 0); diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp index 23dd57d235813..6d9f267702e37 100644 --- a/clang/lib/AST/StmtOpenACC.cpp +++ b/clang/lib/AST/StmtOpenACC.cpp @@ -110,3 +110,118 @@ OpenACCCombinedConstruct *OpenACCCombinedConstruct::Create( OpenACCCombinedConstruct(DK, BeginLoc, DirLoc, EndLoc, Clauses, Loop); return Inst; } + +OpenACCDataConstruct *OpenACCDataConstruct::CreateEmpty(const ASTContext &C, + unsigned NumClauses) { + void *Mem = + C.Allocate(OpenACCDataConstruct::totalSizeToAlloc( + NumClauses)); + auto *Inst = new (Mem) OpenACCDataConstruct(NumClauses); + return Inst; +} + +OpenACCDataConstruct * +OpenACCDataConstruct::Create(const ASTContext &C, SourceLocation Start, + SourceLocation DirectiveLoc, SourceLocation End, + ArrayRef Clauses, + Stmt *StructuredBlock) { + void *Mem = + C.Allocate(OpenACCDataConstruct::totalSizeToAlloc( + Clauses.size())); + auto *Inst = new (Mem) + OpenACCDataConstruct(Start, DirectiveLoc, End, Clauses, StructuredBlock); + return Inst; +} + +OpenACCEnterDataConstruct * +OpenACCEnterDataConstruct::CreateEmpty(const ASTContext &C, + unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCEnterDataConstruct::totalSizeToAlloc( + NumClauses)); + auto *Inst = new (Mem) OpenACCEnterDataConstruct(NumClauses); + return Inst; +} + +OpenACCEnterDataConstruct *OpenACCEnterDataConstruct::Create( + const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, ArrayRef Clauses) { + void *Mem = C.Allocate( + OpenACCEnterDataConstruct::totalSizeToAlloc( + Clauses.size())); + auto *Inst = + new (Mem) OpenACCEnterDataConstruct(Start, DirectiveLoc, End, Clauses); + return Inst; +} + +OpenACCExitDataConstruct * +OpenACCExitDataConstruct::CreateEmpty(const ASTContext &C, + unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCExitDataConstruct::totalSizeToAlloc( + NumClauses)); + auto *Inst = new (Mem) OpenACCExitDataConstruct(NumClauses); + return Inst; +} + +OpenACCExitDataConstruct *OpenACCExitDataConstruct::Create( + const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, ArrayRef Clauses) { + void *Mem = C.Allocate( + OpenACCExitDataConstruct::totalSizeToAlloc( + Clauses.size())); + auto *Inst = + new (Mem) OpenACCExitDataConstruct(Start, DirectiveLoc, End, Clauses); + return Inst; +} + +OpenACCHostDataConstruct * +OpenACCHostDataConstruct::CreateEmpty(const ASTContext &C, + unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCHostDataConstruct::totalSizeToAlloc( + NumClauses)); + auto *Inst = new (Mem) OpenACCHostDataConstruct(NumClauses); + return Inst; +} + +OpenACCHostDataConstruct *OpenACCHostDataConstruct::Create( + const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, ArrayRef Clauses, + Stmt *StructuredBlock) { + void *Mem = C.Allocate( + OpenACCHostDataConstruct::totalSizeToAlloc( + Clauses.size())); + auto *Inst = new (Mem) OpenACCHostDataConstruct(Start, DirectiveLoc, End, + Clauses, StructuredBlock); + return Inst; +} + +OpenACCWaitConstruct *OpenACCWaitConstruct::CreateEmpty(const ASTContext &C, + unsigned NumExprs, + unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCWaitConstruct::totalSizeToAlloc( + NumExprs, NumClauses)); + + auto *Inst = new (Mem) OpenACCWaitConstruct(NumExprs, NumClauses); + return Inst; +} + +OpenACCWaitConstruct *OpenACCWaitConstruct::Create( + const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, + ArrayRef QueueIdExprs, SourceLocation RParenLoc, SourceLocation End, + ArrayRef Clauses) { + + assert(llvm::all_of(QueueIdExprs, [](Expr *E) { return E != nullptr; })); + + void *Mem = C.Allocate( + OpenACCWaitConstruct::totalSizeToAlloc( + QueueIdExprs.size() + 1, Clauses.size())); + + auto *Inst = new (Mem) + OpenACCWaitConstruct(Start, DirectiveLoc, LParenLoc, DevNumExpr, + QueuesLoc, QueueIdExprs, RParenLoc, End, Clauses); + return Inst; +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 7507c9d14327a..ecc9b6e35db72 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1193,6 +1193,79 @@ void StmtPrinter::VisitOpenACCCombinedConstruct(OpenACCCombinedConstruct *S) { PrintStmt(S->getLoop()); } +void StmtPrinter::VisitOpenACCDataConstruct(OpenACCDataConstruct *S) { + Indent() << "#pragma acc data"; + + if (!S->clauses().empty()) { + OS << ' '; + OpenACCClausePrinter Printer(OS, Policy); + Printer.VisitClauseList(S->clauses()); + } + OS << '\n'; + + PrintStmt(S->getStructuredBlock()); +} +void StmtPrinter::VisitOpenACCEnterDataConstruct(OpenACCEnterDataConstruct *S) { + Indent() << "#pragma acc enter data"; + + if (!S->clauses().empty()) { + OS << ' '; + OpenACCClausePrinter Printer(OS, Policy); + Printer.VisitClauseList(S->clauses()); + } + OS << '\n'; +} +void StmtPrinter::VisitOpenACCExitDataConstruct(OpenACCExitDataConstruct *S) { + Indent() << "#pragma acc exit data"; + + if (!S->clauses().empty()) { + OS << ' '; + OpenACCClausePrinter Printer(OS, Policy); + Printer.VisitClauseList(S->clauses()); + } + OS << '\n'; +} +void StmtPrinter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { + Indent() << "#pragma acc host_data"; + + if (!S->clauses().empty()) { + OS << ' '; + OpenACCClausePrinter Printer(OS, Policy); + Printer.VisitClauseList(S->clauses()); + } + OS << '\n'; + + PrintStmt(S->getStructuredBlock()); +} + +void StmtPrinter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) { + Indent() << "#pragma acc wait"; + if (!S->getLParenLoc().isInvalid()) { + OS << "("; + if (S->hasDevNumExpr()) { + OS << "devnum: "; + S->getDevNumExpr()->printPretty(OS, nullptr, Policy); + OS << " : "; + } + + if (S->hasQueuesTag()) + OS << "queues: "; + + llvm::interleaveComma(S->getQueueIdExprs(), OS, [&](const Expr *E) { + E->printPretty(OS, nullptr, Policy); + }); + + OS << ")"; + } + + if (!S->clauses().empty()) { + OS << ' '; + OpenACCClausePrinter Printer(OS, Policy); + Printer.VisitClauseList(S->clauses()); + } + OS << '\n'; +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 3dfbef1cdb712..fccd97dca23af 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2515,6 +2515,11 @@ class OpenACCClauseProfiler } } + void VisitClauseWithVarList(const OpenACCClauseWithVarList &Clause) { + for (auto *E : Clause.getVarList()) + Profiler.VisitStmt(E); + } + #define VISIT_CLAUSE(CLAUSE_NAME) \ void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause); @@ -2532,25 +2537,21 @@ void OpenACCClauseProfiler::VisitIfClause(const OpenACCIfClause &Clause) { } void OpenACCClauseProfiler::VisitCopyClause(const OpenACCCopyClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitCopyInClause( const OpenACCCopyInClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitCopyOutClause( const OpenACCCopyOutClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitCreateClause( const OpenACCCreateClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitSelfClause(const OpenACCSelfClause &Clause) { @@ -2558,6 +2559,12 @@ void OpenACCClauseProfiler::VisitSelfClause(const OpenACCSelfClause &Clause) { Profiler.VisitStmt(Clause.getConditionExpr()); } +void OpenACCClauseProfiler::VisitFinalizeClause( + const OpenACCFinalizeClause &Clause) {} + +void OpenACCClauseProfiler::VisitIfPresentClause( + const OpenACCIfPresentClause &Clause) {} + void OpenACCClauseProfiler::VisitNumGangsClause( const OpenACCNumGangsClause &Clause) { for (auto *E : Clause.getIntExprs()) @@ -2583,38 +2590,47 @@ void OpenACCClauseProfiler::VisitCollapseClause( void OpenACCClauseProfiler::VisitPrivateClause( const OpenACCPrivateClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitFirstPrivateClause( const OpenACCFirstPrivateClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitAttachClause( const OpenACCAttachClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); +} + +void OpenACCClauseProfiler::VisitDetachClause( + const OpenACCDetachClause &Clause) { + VisitClauseWithVarList(Clause); +} + +void OpenACCClauseProfiler::VisitDeleteClause( + const OpenACCDeleteClause &Clause) { + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitDevicePtrClause( const OpenACCDevicePtrClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitNoCreateClause( const OpenACCNoCreateClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitPresentClause( const OpenACCPresentClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); +} + +void OpenACCClauseProfiler::VisitUseDeviceClause( + const OpenACCUseDeviceClause &Clause) { + VisitClauseWithVarList(Clause); } void OpenACCClauseProfiler::VisitVectorLengthClause( @@ -2666,8 +2682,7 @@ void OpenACCClauseProfiler::VisitGangClause(const OpenACCGangClause &Clause) { void OpenACCClauseProfiler::VisitReductionClause( const OpenACCReductionClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } } // namespace @@ -2697,6 +2712,45 @@ void StmtProfiler::VisitOpenACCCombinedConstruct( P.VisitOpenACCClauseList(S->clauses()); } +void StmtProfiler::VisitOpenACCDataConstruct(const OpenACCDataConstruct *S) { + VisitStmt(S); + + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + +void StmtProfiler::VisitOpenACCEnterDataConstruct( + const OpenACCEnterDataConstruct *S) { + VisitStmt(S); + + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + +void StmtProfiler::VisitOpenACCExitDataConstruct( + const OpenACCExitDataConstruct *S) { + VisitStmt(S); + + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + +void StmtProfiler::VisitOpenACCHostDataConstruct( + const OpenACCHostDataConstruct *S) { + VisitStmt(S); + + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + +void StmtProfiler::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) { + // VisitStmt covers 'children', so the exprs inside of it are covered. + VisitStmt(S); + + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + void StmtProfiler::VisitHLSLOutArgExpr(const HLSLOutArgExpr *S) { VisitStmt(S); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 2552c11a39532..7cdffbe20e575 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -409,8 +409,12 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { case OpenACCClauseKind::PCopy: case OpenACCClauseKind::PresentOrCopy: case OpenACCClauseKind::If: + case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Independent: + case OpenACCClauseKind::Detach: + case OpenACCClauseKind::Delete: case OpenACCClauseKind::DevicePtr: + case OpenACCClauseKind::Finalize: case OpenACCClauseKind::FirstPrivate: case OpenACCClauseKind::NoCreate: case OpenACCClauseKind::NumGangs: @@ -421,6 +425,7 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { case OpenACCClauseKind::Seq: case OpenACCClauseKind::Tile: case OpenACCClauseKind::Worker: + case OpenACCClauseKind::UseDevice: case OpenACCClauseKind::Vector: case OpenACCClauseKind::VectorLength: // The condition expression will be printed as a part of the 'children', @@ -2936,6 +2941,29 @@ void TextNodeDumper::VisitOpenACCCombinedConstruct( OS << " " << S->getDirectiveKind(); } +void TextNodeDumper::VisitOpenACCDataConstruct(const OpenACCDataConstruct *S) { + OS << " " << S->getDirectiveKind(); +} + +void TextNodeDumper::VisitOpenACCEnterDataConstruct( + const OpenACCEnterDataConstruct *S) { + OS << " " << S->getDirectiveKind(); +} + +void TextNodeDumper::VisitOpenACCExitDataConstruct( + const OpenACCExitDataConstruct *S) { + OS << " " << S->getDirectiveKind(); +} + +void TextNodeDumper::VisitOpenACCHostDataConstruct( + const OpenACCHostDataConstruct *S) { + OS << " " << S->getDirectiveKind(); +} + +void TextNodeDumper::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *S) { + OS << " " << S->getDirectiveKind(); +} + void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) { AddChild("begin", [=] { OS << S->getStartingElementPos(); }); AddChild("number of elements", [=] { OS << S->getDataElementCount(); }); diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp index 35472e705cfd8..5b14d138b6e28 100644 --- a/clang/lib/Analysis/PathDiagnostic.cpp +++ b/clang/lib/Analysis/PathDiagnostic.cpp @@ -484,10 +484,10 @@ SourceLocation PathDiagnosticLocation::getValidSourceLocation( // source code, so find an enclosing statement and use its location. if (!L.isValid()) { AnalysisDeclContext *ADC; - if (LAC.is()) - ADC = LAC.get()->getAnalysisDeclContext(); + if (auto *LC = dyn_cast(LAC)) + ADC = LC->getAnalysisDeclContext(); else - ADC = LAC.get(); + ADC = cast(LAC); ParentMap &PM = ADC->getParentMap(); diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp index cbcfefdc52549..050daee1168d4 100644 --- a/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp @@ -135,14 +135,30 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp, Ctx.NumArgs = CE->getNumArgs(); Ctx.FunArgs = CE->getArgs(); } else if (const auto *CE = dyn_cast(DeclExp)) { - Ctx.NumArgs = CE->getNumArgs(); - Ctx.FunArgs = CE->getArgs(); + // Calls to operators that are members need to be treated like member calls. + if (isa(CE) && isa(D)) { + Ctx.SelfArg = CE->getArg(0); + Ctx.SelfArrow = false; + Ctx.NumArgs = CE->getNumArgs() - 1; + Ctx.FunArgs = CE->getArgs() + 1; + } else { + Ctx.NumArgs = CE->getNumArgs(); + Ctx.FunArgs = CE->getArgs(); + } } else if (const auto *CE = dyn_cast(DeclExp)) { Ctx.SelfArg = nullptr; // Will be set below Ctx.NumArgs = CE->getNumArgs(); Ctx.FunArgs = CE->getArgs(); } + // Usually we want to substitute the self-argument for "this", but lambdas + // are an exception: "this" on or in a lambda call operator doesn't refer + // to the lambda, but to captured "this" in the context it was created in. + // This can happen for operator calls and member calls, so fix it up here. + if (const auto *CMD = dyn_cast(D)) + if (CMD->getParent()->isLambda()) + Ctx.SelfArg = nullptr; + if (Self) { assert(!Ctx.SelfArg && "Ambiguous self argument"); assert(isa(D) && "Self argument requires function"); @@ -326,7 +342,7 @@ til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE, } assert(I == 0); - return Ctx->FunArgs.get(); + return cast(Ctx->FunArgs); } } // Map the param back to the param of the original function declaration diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 40f529e52b44a..a9aff39df6474 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -439,36 +439,25 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { // already duplicated // - call both from Sema and from here - const auto *BaseDRE = - dyn_cast(Node.getBase()->IgnoreParenImpCasts()); - const auto *SLiteral = - dyn_cast(Node.getBase()->IgnoreParenImpCasts()); - uint64_t size; - - if (!BaseDRE && !SLiteral) + uint64_t limit; + if (const auto *CATy = + dyn_cast(Node.getBase() + ->IgnoreParenImpCasts() + ->getType() + ->getUnqualifiedDesugaredType())) { + limit = CATy->getLimitedSize(); + } else if (const auto *SLiteral = dyn_cast( + Node.getBase()->IgnoreParenImpCasts())) { + limit = SLiteral->getLength() + 1; + } else { return false; - - if (BaseDRE) { - if (!BaseDRE->getDecl()) - return false; - const auto *CATy = Finder->getASTContext().getAsConstantArrayType( - BaseDRE->getDecl()->getType()); - if (!CATy) { - return false; - } - size = CATy->getLimitedSize(); - } else if (SLiteral) { - size = SLiteral->getLength() + 1; } if (const auto *IdxLit = dyn_cast(Node.getIdx())) { const APInt ArrIdx = IdxLit->getValue(); - // FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a - // bug - if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < size) + if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < limit) return true; } - return false; } diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp index c991139b8d5ad..8dd1888db2988 100644 --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -29,93 +29,54 @@ const char *HeaderDesc::getName() const { llvm_unreachable("Unknown HeaderDesc::HeaderID enum"); } -static constexpr auto BuiltinStorage = - Builtin::Storage::Make( - CLANG_BUILTIN_STR_TABLE("not a builtin function", "", "") -#define BUILTIN CLANG_BUILTIN_STR_TABLE +static constexpr Builtin::Info BuiltinInfo[] = { + {"not a builtin function", nullptr, nullptr, nullptr, HeaderDesc::NO_HEADER, + ALL_LANGUAGES}, +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANGS}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, LANGS}, #include "clang/Basic/Builtins.inc" - , - {CLANG_BUILTIN_ENTRY("not a builtin function", "", "") -#define BUILTIN CLANG_BUILTIN_ENTRY -#define LANGBUILTIN CLANG_LANGBUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY -#include "clang/Basic/Builtins.inc" - }); +}; -std::pair -Builtin::Context::getStrTableAndInfo(unsigned ID) const { +const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const { if (ID < Builtin::FirstTSBuiltin) - return {BuiltinStorage.StringTable, BuiltinStorage.Infos[ID]}; - assert( - ((ID - Builtin::FirstTSBuiltin) < (TSInfos.size() + AuxTSInfos.size())) && - "Invalid builtin ID!"); + return BuiltinInfo[ID]; + assert(((ID - Builtin::FirstTSBuiltin) < + (TSRecords.size() + AuxTSRecords.size())) && + "Invalid builtin ID!"); if (isAuxBuiltinID(ID)) - return {AuxTSStrTable, - AuxTSInfos[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]}; - return {TSStrTable, TSInfos[ID - Builtin::FirstTSBuiltin]}; -} - -static llvm::StringRef getStrFromTable(const char *StrTable, int Offset) { - return &StrTable[Offset]; -} - -/// Return the identifier name for the specified builtin, -/// e.g. "__builtin_abs". -llvm::StringRef Builtin::Context::getName(unsigned ID) const { - const auto &[StrTable, I] = getStrTableAndInfo(ID); - return getStrFromTable(StrTable, I.Offsets.Name); -} - -const char *Builtin::Context::getTypeString(unsigned ID) const { - const auto &[StrTable, I] = getStrTableAndInfo(ID); - return getStrFromTable(StrTable, I.Offsets.Type).data(); -} - -const char *Builtin::Context::getAttributesString(unsigned ID) const { - const auto &[StrTable, I] = getStrTableAndInfo(ID); - return getStrFromTable(StrTable, I.Offsets.Attributes).data(); -} - -const char *Builtin::Context::getRequiredFeatures(unsigned ID) const { - const auto &[StrTable, I] = getStrTableAndInfo(ID); - return getStrFromTable(StrTable, I.Offsets.Features).data(); + return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]; + return TSRecords[ID - Builtin::FirstTSBuiltin]; } void Builtin::Context::InitializeTarget(const TargetInfo &Target, const TargetInfo *AuxTarget) { - assert(TSStrTable == nullptr && "Already initialized target?"); - assert(TSInfos.empty() && "Already initialized target?"); - std::tie(TSStrTable, TSInfos) = Target.getTargetBuiltinStorage(); - if (AuxTarget) { - std::tie(AuxTSStrTable, AuxTSInfos) = AuxTarget->getTargetBuiltinStorage(); - } + assert(TSRecords.empty() && "Already initialized target?"); + TSRecords = Target.getTargetBuiltins(); + if (AuxTarget) + AuxTSRecords = AuxTarget->getTargetBuiltins(); } bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) { bool InStdNamespace = FuncName.consume_front("std-"); - const char *StrTable = BuiltinStorage.StringTable; for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i) { - const auto &I = BuiltinStorage.Infos[i]; - if (FuncName == getStrFromTable(StrTable, I.Offsets.Name) && - (bool)strchr(getStrFromTable(StrTable, I.Offsets.Attributes).data(), - 'z') == InStdNamespace) - return strchr(getStrFromTable(StrTable, I.Offsets.Attributes).data(), - 'f') != nullptr; + if (FuncName == BuiltinInfo[i].Name && + (bool)strchr(BuiltinInfo[i].Attributes, 'z') == InStdNamespace) + return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr; } return false; } /// Is this builtin supported according to the given language options? -static bool builtinIsSupported(const char *StrTable, - const Builtin::Info &BuiltinInfo, +static bool builtinIsSupported(const Builtin::Info &BuiltinInfo, const LangOptions &LangOpts) { - auto AttributesStr = - getStrFromTable(StrTable, BuiltinInfo.Offsets.Attributes); - /* Builtins Unsupported */ - if (LangOpts.NoBuiltin && strchr(AttributesStr.data(), 'f') != nullptr) + if (LangOpts.NoBuiltin && strchr(BuiltinInfo.Attributes, 'f') != nullptr) return false; /* CorBuiltins Unsupported */ if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG)) @@ -162,7 +123,7 @@ static bool builtinIsSupported(const char *StrTable, if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG) return false; /* consteval Unsupported */ - if (!LangOpts.CPlusPlus20 && strchr(AttributesStr.data(), 'G') != nullptr) + if (!LangOpts.CPlusPlus20 && strchr(BuiltinInfo.Attributes, 'G') != nullptr) return false; return true; } @@ -173,23 +134,20 @@ static bool builtinIsSupported(const char *StrTable, void Builtin::Context::initializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts) { // Step #1: mark all target-independent builtins with their ID's. - for (const auto &&[Index, I] : - llvm::enumerate(llvm::ArrayRef(BuiltinStorage.Infos).drop_front())) - if (builtinIsSupported(BuiltinStorage.StringTable, I, LangOpts)) { - Table.get(getStrFromTable(BuiltinStorage.StringTable, I.Offsets.Name)) - .setBuiltinID(Index + 1); + for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i) + if (builtinIsSupported(BuiltinInfo[i], LangOpts)) { + Table.get(BuiltinInfo[i].Name).setBuiltinID(i); } // Step #2: Register target-specific builtins. - for (const auto &&[Index, I] : llvm::enumerate(TSInfos)) - if (builtinIsSupported(TSStrTable, I, LangOpts)) - Table.get(getStrFromTable(TSStrTable, I.Offsets.Name)) - .setBuiltinID(Index + Builtin::FirstTSBuiltin); + for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) + if (builtinIsSupported(TSRecords[i], LangOpts)) + Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); // Step #3: Register target-specific builtins for AuxTarget. - for (const auto &&[Index, I] : llvm::enumerate(AuxTSInfos)) - Table.get(getStrFromTable(AuxTSStrTable, I.Offsets.Name)) - .setBuiltinID(Index + Builtin::FirstTSBuiltin + TSInfos.size()); + for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i) + Table.get(AuxTSRecords[i].Name) + .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size()); // Step #4: Unregister any builtins specified by -fno-builtin-foo. for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) { @@ -206,7 +164,7 @@ void Builtin::Context::initializeBuiltins(IdentifierTable &Table, } unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const { - const char *WidthPos = ::strchr(getAttributesString(ID), 'V'); + const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V'); if (!WidthPos) return 0; @@ -229,7 +187,7 @@ bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, assert(::toupper(Fmt[0]) == Fmt[1] && "Format string is not in the form \"xX\""); - const char *Like = ::strpbrk(getAttributesString(ID), Fmt); + const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt); if (!Like) return false; @@ -256,7 +214,7 @@ bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx, bool Builtin::Context::performsCallback(unsigned ID, SmallVectorImpl &Encoding) const { - const char *CalleePos = ::strchr(getAttributesString(ID), 'C'); + const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C'); if (!CalleePos) return false; diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index 2876c290a26b1..f0b6f7be6c84f 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -324,9 +324,9 @@ llvm::Expected FileManager::getFileRef(StringRef Filename, *SeenFileEntries .insert({Status.getName(), FileEntryRef::MapValue(*UFE, DirInfo)}) .first; - assert(Redirection.second->V.is() && + assert(isa(Redirection.second->V) && "filename redirected to a non-canonical filename?"); - assert(Redirection.second->V.get() == UFE && + assert(cast(Redirection.second->V) == UFE && "filename from getStatValue() refers to wrong file"); // Cache the redirection in the previously-inserted entry, still available @@ -398,9 +398,9 @@ FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size, {Filename, std::errc::no_such_file_or_directory}).first; if (NamedFileEnt.second) { FileEntryRef::MapValue Value = *NamedFileEnt.second; - if (LLVM_LIKELY(Value.V.is())) + if (LLVM_LIKELY(isa(Value.V))) return FileEntryRef(NamedFileEnt); - return FileEntryRef(*Value.V.get()); + return FileEntryRef(*cast(Value.V)); } // We've not seen this before, or the file is cached as non-existent. @@ -620,7 +620,7 @@ void FileManager::GetUniqueIDMapping( for (const auto &Entry : SeenFileEntries) { // Only return files that exist and are not redirected. - if (!Entry.getValue() || !Entry.getValue()->V.is()) + if (!Entry.getValue() || !isa(Entry.getValue()->V)) continue; FileEntryRef FE(Entry); // Add this file if it's the first one with the UID, or if its name is diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index 6e588ce63d813..44e982d3ee67f 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/AutoConvert.h" #include "llvm/Support/Capacity.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Endian.h" @@ -156,8 +157,11 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM, // Unless this is a named pipe (in which case we can handle a mismatch), // check that the file's size is the same as in the file entry (which may // have come from a stat cache). + // The buffer will always be larger than the file size on z/OS in the presence + // of characters outside the base character set. + assert(Buffer->getBufferSize() >= (size_t)ContentsEntry->getSize()); if (!ContentsEntry->isNamedPipe() && - Buffer->getBufferSize() != (size_t)ContentsEntry->getSize()) { + Buffer->getBufferSize() < (size_t)ContentsEntry->getSize()) { Diag.Report(Loc, diag::err_file_modified) << ContentsEntry->getName(); return std::nullopt; @@ -583,6 +587,17 @@ SourceManager::getOrCreateFileID(FileEntryRef SourceFile, FileCharacter); } +/// Helper function to determine if an input file requires conversion +bool needConversion(StringRef Filename) { +#ifdef __MVS__ + llvm::ErrorOr NeedConversion = + llvm::needzOSConversion(Filename.str().c_str()); + return NeedConversion && *NeedConversion; +#else + return false; +#endif +} + /// createFileID - Create a new FileID for the specified ContentCache and /// include position. This works regardless of whether the ContentCache /// corresponds to a file or some other input source. @@ -602,6 +617,20 @@ FileID SourceManager::createFileIDImpl(ContentCache &File, StringRef Filename, return FileID::get(LoadedID); } unsigned FileSize = File.getSize(); + bool NeedConversion = needConversion(Filename); + if (NeedConversion) { + // Buffer size may increase due to potential z/OS EBCDIC to UTF-8 + // conversion. + if (std::optional Buffer = + File.getBufferOrNone(Diag, getFileManager())) { + unsigned BufSize = Buffer->getBufferSize(); + if (BufSize > FileSize) { + if (File.ContentsEntry.has_value()) + File.ContentsEntry->updateFileEntryBufferSize(BufSize); + FileSize = BufSize; + } + } + } if (!(NextLocalOffset + FileSize + 1 > NextLocalOffset && NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset)) { Diag.Report(IncludePos, diag::err_sloc_space_too_large); diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 0021d33c45d7c..706a391023b3a 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -726,6 +726,9 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::Linux: return std::make_unique>(Triple, Opts); + case llvm::Triple::FreeBSD: + return std::make_unique>(Triple, + Opts); default: return std::make_unique(Triple, Opts); } @@ -734,6 +737,9 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::Linux: return std::make_unique>(Triple, Opts); + case llvm::Triple::FreeBSD: + return std::make_unique>(Triple, + Opts); default: return std::make_unique(Triple, Opts); } diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 858f83d090d7a..53e102bbe4468 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -26,39 +26,35 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsNEON.def" -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsSVE.def" -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsSME.def" -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsAArch64.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsNEON.def" -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsSVE.def" -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsSME.def" -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY -#define LANGBUILTIN CLANG_LANGBUILTIN_ENTRY -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_ENTRY + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANG}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, #include "clang/Basic/BuiltinsAArch64.def" - }); +}; void AArch64TargetInfo::setArchFeatures() { if (*ArchInfo == llvm::AArch64::ARMV8R) { @@ -701,9 +697,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, } } -std::pair> -AArch64TargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef AArch64TargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin - + Builtin::FirstTSBuiltin); } std::optional> diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index a3ce04e249e30..68a8b1ebad8cd 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -180,8 +180,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; std::optional> getVScaleRange(const LangOptions &LangOpts) const override; diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index 21281e7201b02..99f8f2944e279 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -88,18 +88,13 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = { } // namespace targets } // namespace clang -static constexpr int NumBuiltins = - clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsAMDGPU.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsAMDGPU.def" - }); +}; const char *const AMDGPUTargetInfo::GCCRegNames[] = { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", @@ -271,9 +266,9 @@ void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { !isAMDGCN(getTriple())); } -std::pair> -AMDGPUTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef AMDGPUTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin); } void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index 8068184a0d411..ea4189cdea47d 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -257,8 +257,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { StringRef CPU, const std::vector &FeatureVec) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool useFP16ConversionIntrinsics() const override { return false; } diff --git a/clang/lib/Basic/Targets/ARC.h b/clang/lib/Basic/Targets/ARC.h index d84daf2e527ca..7f3d0aa15ab81 100644 --- a/clang/lib/Basic/Targets/ARC.h +++ b/clang/lib/Basic/Targets/ARC.h @@ -40,10 +40,7 @@ class LLVM_LIBRARY_VISIBILITY ARCTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override { - return {nullptr, {}}; - } + ArrayRef getTargetBuiltins() const override { return {}; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index fb10bc8249e98..370444057b429 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -1071,34 +1071,31 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, } } -static constexpr int NumBuiltins = - clang::ARM::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsNEON.def" -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsARM.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY -#include "clang/Basic/BuiltinsNEON.def" -#define BUILTIN CLANG_BUILTIN_ENTRY -#define LANGBUILTIN CLANG_LANGBUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_ENTRY +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANG}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, #include "clang/Basic/BuiltinsARM.def" - }); +}; -std::pair> -ARMTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef ARMTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::ARM::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool ARMTargetInfo::isCLZForZeroUndef() const { return false; } diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index 71f44f7248f68..55ecb99d82d8f 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -196,8 +196,7 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool isCLZForZeroUndef() const override; BuiltinVaListKind getBuiltinVaListKind() const override; diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h index f19dee3a88231..df1f8d171efba 100644 --- a/clang/lib/Basic/Targets/AVR.h +++ b/clang/lib/Basic/Targets/AVR.h @@ -63,10 +63,7 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override { - return {nullptr, {}}; - } + ArrayRef getTargetBuiltins() const override { return {}; } bool allowsLargerPreferedTypeAlignment() const override { return false; } diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp index b62e792590185..f4684765b7ffb 100644 --- a/clang/lib/Basic/Targets/BPF.cpp +++ b/clang/lib/Basic/Targets/BPF.cpp @@ -19,16 +19,11 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - clang::BPF::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsBPF.inc" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsBPF.inc" - }); +}; void BPFTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -86,9 +81,9 @@ void BPFTargetInfo::fillValidCPUList(SmallVectorImpl &Values) const { Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); } -std::pair> -BPFTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef BPFTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::BPF::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool BPFTargetInfo::handleTargetFeatures(std::vector &Features, diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index 8f5c0e31aa87c..27a4b5f314970 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -58,8 +58,7 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; std::string_view getClobbers() const override { return ""; } diff --git a/clang/lib/Basic/Targets/CSKY.cpp b/clang/lib/Basic/Targets/CSKY.cpp index e698508a2370c..c8bf8b9234d24 100644 --- a/clang/lib/Basic/Targets/CSKY.cpp +++ b/clang/lib/Basic/Targets/CSKY.cpp @@ -139,6 +139,10 @@ bool CSKYTargetInfo::handleTargetFeatures(std::vector &Features, return true; } +ArrayRef CSKYTargetInfo::getTargetBuiltins() const { + return ArrayRef(); +} + ArrayRef CSKYTargetInfo::getGCCRegNames() const { static const char *const GCCRegNames[] = { // Integer registers diff --git a/clang/lib/Basic/Targets/CSKY.h b/clang/lib/Basic/Targets/CSKY.h index 59c83340b8c31..94d4eeb9a1fff 100644 --- a/clang/lib/Basic/Targets/CSKY.h +++ b/clang/lib/Basic/Targets/CSKY.h @@ -73,10 +73,7 @@ class LLVM_LIBRARY_VISIBILITY CSKYTargetInfo : public TargetInfo { unsigned getMinGlobalAlign(uint64_t, bool HasNonWeakDef) const override; - std::pair> - getTargetBuiltinStorage() const override { - return {nullptr, {}}; - } + ArrayRef getTargetBuiltins() const override; BuiltinVaListKind getBuiltinVaListKind() const override { return VoidPtrBuiltinVaList; diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h index 3e6e84b0d9e6f..ab22d1281a4df 100644 --- a/clang/lib/Basic/Targets/DirectX.h +++ b/clang/lib/Basic/Targets/DirectX.h @@ -72,10 +72,7 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo { return Feature == "directx"; } - std::pair> - getTargetBuiltinStorage() const override { - return {nullptr, {}}; - } + ArrayRef getTargetBuiltins() const override { return {}; } std::string_view getClobbers() const override { return ""; } diff --git a/clang/lib/Basic/Targets/Hexagon.cpp b/clang/lib/Basic/Targets/Hexagon.cpp index 70059d68c562b..0282ac812c306 100644 --- a/clang/lib/Basic/Targets/Hexagon.cpp +++ b/clang/lib/Basic/Targets/Hexagon.cpp @@ -198,19 +198,15 @@ ArrayRef HexagonTargetInfo::getGCCRegAliases() const { return llvm::ArrayRef(GCCRegAliases); } -static constexpr int NumBuiltins = - clang::Hexagon::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsHexagon.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, nullptr, HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsHexagon.def" - }); +}; bool HexagonTargetInfo::hasFeature(StringRef Feature) const { std::string VS = "hvxv" + HVXVersion; @@ -268,7 +264,7 @@ void HexagonTargetInfo::fillValidCPUList( Values.push_back(Suffix.Name); } -std::pair> -HexagonTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef HexagonTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin - + Builtin::FirstTSBuiltin); } diff --git a/clang/lib/Basic/Targets/Hexagon.h b/clang/lib/Basic/Targets/Hexagon.h index 2230735b8971b..7f053ab7e4888 100644 --- a/clang/lib/Basic/Targets/Hexagon.h +++ b/clang/lib/Basic/Targets/Hexagon.h @@ -66,8 +66,7 @@ class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo { BoolWidth = BoolAlign = 8; } - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { diff --git a/clang/lib/Basic/Targets/Lanai.h b/clang/lib/Basic/Targets/Lanai.h index f37b0fdb08731..f7e439c7c9e1c 100644 --- a/clang/lib/Basic/Targets/Lanai.h +++ b/clang/lib/Basic/Targets/Lanai.h @@ -78,10 +78,7 @@ class LLVM_LIBRARY_VISIBILITY LanaiTargetInfo : public TargetInfo { return TargetInfo::VoidPtrBuiltinVaList; } - std::pair> - getTargetBuiltinStorage() const override { - return {nullptr, {}}; - } + ArrayRef getTargetBuiltins() const override { return {}; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp index 7c714000af42f..d36186aa9c2fb 100644 --- a/clang/lib/Basic/Targets/LoongArch.cpp +++ b/clang/lib/Basic/Targets/LoongArch.cpp @@ -270,18 +270,13 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } -static constexpr int NumBuiltins = - clang::LoongArch::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsLoongArch.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsLoongArch.def" - }); +}; bool LoongArchTargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, @@ -308,9 +303,9 @@ bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { .Default(false); } -std::pair> -LoongArchTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef LoongArchTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin - + Builtin::FirstTSBuiltin); } bool LoongArchTargetInfo::handleTargetFeatures( diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h index 1bb82667cb512..abaa05aa42d43 100644 --- a/clang/lib/Basic/Targets/LoongArch.h +++ b/clang/lib/Basic/Targets/LoongArch.h @@ -70,8 +70,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp index 5670c6309e717..b5b29fd867563 100644 --- a/clang/lib/Basic/Targets/M68k.cpp +++ b/clang/lib/Basic/Targets/M68k.cpp @@ -115,10 +115,9 @@ void M68kTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__HAVE_68881__"); } -std::pair> -M68kTargetInfo::getTargetBuiltinStorage() const { +ArrayRef M68kTargetInfo::getTargetBuiltins() const { // FIXME: Implement. - return {nullptr, {}}; + return {}; } bool M68kTargetInfo::hasFeature(StringRef Feature) const { diff --git a/clang/lib/Basic/Targets/M68k.h b/clang/lib/Basic/Targets/M68k.h index c68b2ab132ea0..b732add77e034 100644 --- a/clang/lib/Basic/Targets/M68k.h +++ b/clang/lib/Basic/Targets/M68k.h @@ -44,8 +44,7 @@ class LLVM_LIBRARY_VISIBILITY M68kTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool hasFeature(StringRef Feature) const override; ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; diff --git a/clang/lib/Basic/Targets/MSP430.h b/clang/lib/Basic/Targets/MSP430.h index 462bcdfaa9b21..2266ada25c1dd 100644 --- a/clang/lib/Basic/Targets/MSP430.h +++ b/clang/lib/Basic/Targets/MSP430.h @@ -50,10 +50,9 @@ class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override { + ArrayRef getTargetBuiltins() const override { // FIXME: Implement. - return {nullptr, {}}; + return {}; } bool allowsLargerPreferedTypeAlignment() const override { return false; } diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp index b4f137b2c1950..174bc9d2ab996 100644 --- a/clang/lib/Basic/Targets/Mips.cpp +++ b/clang/lib/Basic/Targets/Mips.cpp @@ -20,17 +20,13 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsMips.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsMips.def" - }); +}; bool MipsTargetInfo::processorSupportsGPR64() const { return llvm::StringSwitch(CPU) @@ -227,9 +223,9 @@ bool MipsTargetInfo::hasFeature(StringRef Feature) const { .Default(false); } -std::pair> -MipsTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef MipsTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin); } unsigned MipsTargetInfo::getUnwindWordWidth() const { diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h index 2749b5d43a45d..8acaf56523b21 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -197,8 +197,7 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool hasFeature(StringRef Feature) const override; diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index 1d490d9f12992..dbc3fec365761 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -20,19 +20,15 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsNVPTX.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsNVPTX.def" - }); +}; const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; @@ -299,7 +295,7 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, } } -std::pair> -NVPTXTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef NVPTXTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin); } diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index 6520f441b4167..d81b89a7f24ac 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -74,8 +74,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool useFP16ConversionIntrinsics() const override { return false; } diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index 75f53e96ce28f..cd9b3760ca587 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -231,6 +231,9 @@ class LLVM_LIBRARY_VISIBILITY FreeBSDTargetInfo : public OSTargetInfo { case llvm::Triple::riscv32: case llvm::Triple::riscv64: break; + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + break; } } }; @@ -473,7 +476,7 @@ class LLVM_LIBRARY_VISIBILITY PS3PPUTargetInfo : public OSTargetInfo { this->IntMaxType = TargetInfo::SignedLongLong; this->Int64Type = TargetInfo::SignedLongLong; this->SizeType = TargetInfo::UnsignedInt; - this->resetDataLayout("E-m:e-p:32:32-Fi64-i64:64-n32:64"); + this->resetDataLayout("E-m:e-p:32:32-Fi64-i64:64-i128:128-n32:64"); } }; diff --git a/clang/lib/Basic/Targets/PNaCl.h b/clang/lib/Basic/Targets/PNaCl.h index 20c0892fbf8c8..7e0e10aa362d8 100644 --- a/clang/lib/Basic/Targets/PNaCl.h +++ b/clang/lib/Basic/Targets/PNaCl.h @@ -52,10 +52,7 @@ class LLVM_LIBRARY_VISIBILITY PNaClTargetInfo : public TargetInfo { return Feature == "pnacl"; } - std::pair> - getTargetBuiltinStorage() const override { - return {nullptr, {}}; - } + ArrayRef getTargetBuiltins() const override { return {}; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::PNaClABIBuiltinVaList; diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 6aa36839afa81..1448069173b5f 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -19,19 +19,15 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - clang::PPC::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsPPC.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsPPC.def" - }); +}; /// handleTargetFeatures - Perform initialization based on the user /// configured set of features. @@ -931,9 +927,9 @@ void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { MaxAtomicInlineWidth = 128; } -std::pair> -PPCTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef PPCTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::PPC::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool PPCTargetInfo::validateCpuSupports(StringRef FeatureStr) const { diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 4e8da8406116e..3cd0fcad17293 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -187,8 +187,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { StringRef getABI() const override { return ABI; } - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool isCLZForZeroUndef() const override { return false; } @@ -463,12 +462,12 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo { if (Triple.isOSAIX()) { // TODO: Set appropriate ABI for AIX platform. - DataLayout = "E-m:a-Fi64-i64:64-n32:64"; + DataLayout = "E-m:a-Fi64-i64:64-i128:128-n32:64"; LongDoubleWidth = 64; LongDoubleAlign = DoubleAlign = 32; LongDoubleFormat = &llvm::APFloat::IEEEdouble(); } else if ((Triple.getArch() == llvm::Triple::ppc64le)) { - DataLayout = "e-m:e-Fn32-i64:64-n32:64"; + DataLayout = "e-m:e-Fn32-i64:64-i128:128-n32:64"; ABI = "elfv2"; } else { DataLayout = "E-m:e"; @@ -479,7 +478,7 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo { ABI = "elfv1"; DataLayout += "-Fi64"; } - DataLayout += "-i64:64-n32:64"; + DataLayout += "-i64:64-i128:128-n32:64"; } if (Triple.isOSFreeBSD() || Triple.isOSOpenBSD() || Triple.isMusl()) { diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 0add1dfdb2f57..a541dfedc9b8e 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -240,28 +240,22 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, } } -static constexpr int NumBuiltins = - clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsRISCVVector.def" -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsRISCV.inc" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsRISCVVector.def" -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsRISCV.inc" - }); +}; -std::pair> -RISCVTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef RISCVTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool RISCVTargetInfo::initFeatureMap( diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index a168952e6c6f5..68f10e74ba98c 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -62,8 +62,7 @@ class RISCVTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; diff --git a/clang/lib/Basic/Targets/SPIR.cpp b/clang/lib/Basic/Targets/SPIR.cpp index b0e1fa35cca69..040303983594f 100644 --- a/clang/lib/Basic/Targets/SPIR.cpp +++ b/clang/lib/Basic/Targets/SPIR.cpp @@ -81,9 +81,8 @@ SPIRV64AMDGCNTargetInfo::convertConstraint(const char *&Constraint) const { return AMDGPUTI.convertConstraint(Constraint); } -std::pair> -SPIRV64AMDGCNTargetInfo::getTargetBuiltinStorage() const { - return AMDGPUTI.getTargetBuiltinStorage(); +ArrayRef SPIRV64AMDGCNTargetInfo::getTargetBuiltins() const { + return AMDGPUTI.getTargetBuiltins(); } void SPIRV64AMDGCNTargetInfo::getTargetDefines(const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index f25c0cb93e657..85e4bd920d853 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -159,10 +159,7 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { // memcpy as per section 3 of the SPIR spec. bool useFP16ConversionIntrinsics() const override { return false; } - std::pair> - getTargetBuiltinStorage() const override { - return {nullptr, {}}; - } + ArrayRef getTargetBuiltins() const override { return {}; } std::string_view getClobbers() const override { return ""; } @@ -411,8 +408,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64AMDGCNTargetInfo final std::string convertConstraint(const char *&Constraint) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h index 480073fae35c5..9c529a5bc5e7f 100644 --- a/clang/lib/Basic/Targets/Sparc.h +++ b/clang/lib/Basic/Targets/Sparc.h @@ -48,10 +48,9 @@ class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo { bool hasFeature(StringRef Feature) const override; - std::pair> - getTargetBuiltinStorage() const override { + ArrayRef getTargetBuiltins() const override { // FIXME: Implement! - return {nullptr, {}}; + return {}; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp index ffc55a80db9d9..06f08db2eadd4 100644 --- a/clang/lib/Basic/Targets/SystemZ.cpp +++ b/clang/lib/Basic/Targets/SystemZ.cpp @@ -20,18 +20,13 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - clang::SystemZ::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsSystemZ.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsSystemZ.def" - }); +}; const char *const SystemZTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", @@ -175,7 +170,7 @@ void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__VEC__", "10304"); } -std::pair> -SystemZTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef SystemZTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin - + Builtin::FirstTSBuiltin); } diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index 98637f230b69c..e6405f174f660 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -99,8 +99,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; ArrayRef getGCCRegNames() const override; @@ -248,6 +247,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { return RegNo < 4 ? 6 + RegNo : -1; } + bool hasSjLjLowering() const override { return true; } + std::pair hardwareInterferenceSizes() const override { return std::make_pair(256, 256); } diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h index 52a2b13fe2805..d6280b02f07b2 100644 --- a/clang/lib/Basic/Targets/TCE.h +++ b/clang/lib/Basic/Targets/TCE.h @@ -95,10 +95,7 @@ class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo { bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } - std::pair> - getTargetBuiltinStorage() const override { - return {nullptr, {}}; - } + ArrayRef getTargetBuiltins() const override { return {}; } std::string_view getClobbers() const override { return ""; } diff --git a/clang/lib/Basic/Targets/VE.cpp b/clang/lib/Basic/Targets/VE.cpp index f54ddc00f6f68..67cae8faf6052 100644 --- a/clang/lib/Basic/Targets/VE.cpp +++ b/clang/lib/Basic/Targets/VE.cpp @@ -18,16 +18,11 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - clang::VE::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsVE.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsVE.def" - }); +}; void VETargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -44,7 +39,7 @@ void VETargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } -std::pair> -VETargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef VETargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::VE::LastTSBuiltin - Builtin::FirstTSBuiltin); } diff --git a/clang/lib/Basic/Targets/VE.h b/clang/lib/Basic/Targets/VE.h index d2b0cd6de4d51..7e8fdf6096ef2 100644 --- a/clang/lib/Basic/Targets/VE.h +++ b/clang/lib/Basic/Targets/VE.h @@ -55,8 +55,7 @@ class LLVM_LIBRARY_VISIBILITY VETargetInfo : public TargetInfo { bool hasSjLjLowering() const override { return true; } - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index a837c3df99217..7b0fd0c841ba2 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -20,22 +20,18 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsWebAssembly.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsWebAssembly.def" - }); +}; static constexpr llvm::StringLiteral ValidCPUNames[] = { - {"mvp"}, {"bleeding-edge"}, {"generic"}, {"lime"}}; + {"mvp"}, {"bleeding-edge"}, {"generic"}, {"lime1"}}; StringRef WebAssemblyTargetInfo::getABI() const { return ABI; } @@ -364,9 +360,9 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( return true; } -std::pair> -WebAssemblyTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef WebAssemblyTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - + Builtin::FirstTSBuiltin); } void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 1cae72e58e08b..0a14da6a277b8 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -120,8 +120,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { bool setCPU(const std::string &Name) final { return isValidCPUName(Name); } - std::pair> - getTargetBuiltinStorage() const final; + ArrayRef getTargetBuiltins() const final; BuiltinVaListKind getBuiltinVaListKind() const final { return VoidPtrBuiltinVaList; @@ -183,11 +182,12 @@ class LLVM_LIBRARY_VISIBILITY WebAssembly32TargetInfo const TargetOptions &Opts) : WebAssemblyTargetInfo(T, Opts) { if (T.isOSEmscripten()) - resetDataLayout("e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-" - "S128-ni:1:10:20"); - else resetDataLayout( - "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"); + "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-" + "S128-ni:1:10:20"); + else + resetDataLayout("e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-" + "S128-ni:1:10:20"); } protected: @@ -207,11 +207,12 @@ class LLVM_LIBRARY_VISIBILITY WebAssembly64TargetInfo PtrDiffType = SignedLong; IntPtrType = SignedLong; if (T.isOSEmscripten()) - resetDataLayout("e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-" - "S128-ni:1:10:20"); - else resetDataLayout( - "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"); + "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-" + "S128-ni:1:10:20"); + else + resetDataLayout("e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-" + "S128-ni:1:10:20"); } protected: diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 0b071573aa1e0..1b16888a0711b 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -23,45 +23,31 @@ namespace clang { namespace targets { -// The x86-32 builtins are a subset and prefix of the x86-64 builtins. -static constexpr int NumX86Builtins = - X86::LastX86CommonBuiltin - Builtin::FirstTSBuiltin + 1; -static constexpr int NumX86_64Builtins = - X86::LastTSBuiltin - Builtin::FirstTSBuiltin; -static_assert(NumX86Builtins < NumX86_64Builtins); - -static constexpr auto BuiltinStorage = - Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_STR_TABLE +static constexpr Builtin::Info BuiltinInfoX86[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, #include "clang/Basic/BuiltinsX86.def" -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_STR_TABLE +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, #include "clang/Basic/BuiltinsX86.inc" -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_STR_TABLE +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, #include "clang/Basic/BuiltinsX86_64.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_ENTRY -#include "clang/Basic/BuiltinsX86.def" - -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_ENTRY -#include "clang/Basic/BuiltinsX86.inc" - -#define BUILTIN CLANG_BUILTIN_ENTRY -#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY -#define TARGET_HEADER_BUILTIN CLANG_TARGET_HEADER_BUILTIN_ENTRY -#include "clang/Basic/BuiltinsX86_64.def" - }); +}; static const char *const GCCRegNames[] = { "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", @@ -1878,14 +1864,12 @@ ArrayRef X86TargetInfo::getGCCAddlRegNames() const { return llvm::ArrayRef(AddlRegNames); } -std::pair> -X86_32TargetInfo::getTargetBuiltinStorage() const { - // Only use the relevant prefix of the infos, the string table base is common. - return {BuiltinStorage.StringTable, - llvm::ArrayRef(BuiltinStorage.Infos).take_front(NumX86Builtins)}; +ArrayRef X86_32TargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin - + Builtin::FirstTSBuiltin + 1); } -std::pair> -X86_64TargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef X86_64TargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfoX86, + X86::LastTSBuiltin - Builtin::FirstTSBuiltin); } diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 385d9e87a4e37..3ed36c8fa724b 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -508,8 +508,7 @@ class LLVM_LIBRARY_VISIBILITY X86_32TargetInfo : public X86TargetInfo { MaxAtomicInlineWidth = 64; } - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool hasBitIntType() const override { return true; } size_t getMaxBitIntWidth() const override { @@ -813,8 +812,7 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo { MaxAtomicInlineWidth = 128; } - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; bool hasBitIntType() const override { return true; } size_t getMaxBitIntWidth() const override { diff --git a/clang/lib/Basic/Targets/XCore.cpp b/clang/lib/Basic/Targets/XCore.cpp index 403d421d0c067..fd377bbfb90e1 100644 --- a/clang/lib/Basic/Targets/XCore.cpp +++ b/clang/lib/Basic/Targets/XCore.cpp @@ -18,17 +18,13 @@ using namespace clang; using namespace clang::targets; -static constexpr int NumBuiltins = - XCore::LastTSBuiltin - Builtin::FirstTSBuiltin; - -static constexpr auto BuiltinStorage = Builtin::Storage::Make( -#define BUILTIN CLANG_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsXCore.def" - , { -#define BUILTIN CLANG_BUILTIN_ENTRY -#define LIBBUILTIN CLANG_LIBBUILTIN_ENTRY +static constexpr Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, #include "clang/Basic/BuiltinsXCore.def" - }); +}; void XCoreTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -36,7 +32,7 @@ void XCoreTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__XS1B__"); } -std::pair> -XCoreTargetInfo::getTargetBuiltinStorage() const { - return {BuiltinStorage.StringTable, BuiltinStorage.Infos}; +ArrayRef XCoreTargetInfo::getTargetBuiltins() const { + return llvm::ArrayRef(BuiltinInfo, + clang::XCore::LastTSBuiltin - Builtin::FirstTSBuiltin); } diff --git a/clang/lib/Basic/Targets/XCore.h b/clang/lib/Basic/Targets/XCore.h index 1082990d74b2b..84fd59d1a71e4 100644 --- a/clang/lib/Basic/Targets/XCore.h +++ b/clang/lib/Basic/Targets/XCore.h @@ -43,8 +43,7 @@ class LLVM_LIBRARY_VISIBILITY XCoreTargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - std::pair> - getTargetBuiltinStorage() const override; + ArrayRef getTargetBuiltins() const override; BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h new file mode 100644 index 0000000000000..92115778518d4 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// 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_LIB_CIR_CODEGEN_CIRGENBUILDER_H +#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H + +#include "CIRGenTypeCache.h" + +#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" + +namespace clang::CIRGen { + +class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { + const CIRGenTypeCache &typeCache; + +public: + CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc) + : CIRBaseBuilderTy(mlirContext), typeCache(tc) {} +}; + +} // namespace clang::CIRGen + +#endif diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index b44f66493254f..0db24c3b41d18 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -25,17 +25,31 @@ using namespace clang; using namespace clang::CIRGen; -CIRGenModule::CIRGenModule(mlir::MLIRContext &context, - clang::ASTContext &astctx, +CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, + clang::ASTContext &astContext, const clang::CodeGenOptions &cgo, DiagnosticsEngine &diags) - : builder(&context), astCtx(astctx), langOpts(astctx.getLangOpts()), - theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))}, - diags(diags), target(astCtx.getTargetInfo()), genTypes(*this) {} + : builder(mlirContext, *this), astContext(astContext), + langOpts(astContext.getLangOpts()), + theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&mlirContext))}, + diags(diags), target(astContext.getTargetInfo()), genTypes(*this) { + + // Initialize cached types + SInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/true); + SInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/true); + SInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/true); + SInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/true); + SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true); + UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false); + UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false); + UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false); + UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false); + UInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/false); +} mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) { assert(cLoc.isValid() && "expected valid source location"); - const SourceManager &sm = astCtx.getSourceManager(); + const SourceManager &sm = astContext.getSourceManager(); PresumedLoc pLoc = sm.getPresumedLoc(cLoc); StringRef filename = pLoc.getFilename(); return mlir::FileLineColLoc::get(builder.getStringAttr(filename), diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 7a84c942af491..1c7ed63773900 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H #define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H +#include "CIRGenBuilder.h" #include "CIRGenTypeCache.h" #include "CIRGenTypes.h" @@ -40,19 +41,17 @@ class CIRGenModule : public CIRGenTypeCache { CIRGenModule &operator=(CIRGenModule &) = delete; public: - CIRGenModule(mlir::MLIRContext &context, clang::ASTContext &astctx, + CIRGenModule(mlir::MLIRContext &mlirContext, clang::ASTContext &astContext, const clang::CodeGenOptions &cgo, clang::DiagnosticsEngine &diags); ~CIRGenModule() = default; private: - // TODO(CIR) 'builder' will change to CIRGenBuilderTy once that type is - // defined - mlir::OpBuilder builder; + CIRGenBuilderTy builder; /// Hold Clang AST information. - clang::ASTContext &astCtx; + clang::ASTContext &astContext; const clang::LangOptions &langOpts; @@ -67,9 +66,10 @@ class CIRGenModule : public CIRGenTypeCache { public: mlir::ModuleOp getModule() const { return theModule; } - mlir::OpBuilder &getBuilder() { return builder; } - clang::ASTContext &getASTContext() const { return astCtx; } + CIRGenBuilderTy &getBuilder() { return builder; } + clang::ASTContext &getASTContext() const { return astContext; } CIRGenTypes &getTypes() { return genTypes; } + mlir::MLIRContext &getMLIRContext() { return *builder.getContext(); } /// Helpers to convert the presumed location of Clang's SourceLocation to an /// MLIR Location. diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h index fde9a355f5241..a357663c33e0f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h @@ -13,6 +13,8 @@ #ifndef LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H #define LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H +#include "clang/CIR/Dialect/IR/CIRTypes.h" + namespace clang::CIRGen { /// This structure provides a set of types that are commonly used @@ -20,6 +22,20 @@ namespace clang::CIRGen { /// constructor and then copied around into new CIRGenFunction's. struct CIRGenTypeCache { CIRGenTypeCache() = default; + + // ClangIR signed integral types of common sizes + cir::IntType SInt8Ty; + cir::IntType SInt16Ty; + cir::IntType SInt32Ty; + cir::IntType SInt64Ty; + cir::IntType SInt128Ty; + + // ClangIR unsigned integral type of common sizes + cir::IntType UInt8Ty; + cir::IntType UInt16Ty; + cir::IntType UInt32Ty; + cir::IntType UInt64Ty; + cir::IntType UInt128Ty; }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index e3fcbacf5f810..181af1898baff 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -9,14 +9,24 @@ using namespace clang; using namespace clang::CIRGen; CIRGenTypes::CIRGenTypes(CIRGenModule &genModule) - : cgm(genModule), context(genModule.getASTContext()) {} + : cgm(genModule), astContext(genModule.getASTContext()), + builder(cgm.getBuilder()) {} CIRGenTypes::~CIRGenTypes() {} +mlir::MLIRContext &CIRGenTypes::getMLIRContext() const { + return *builder.getContext(); +} + mlir::Type CIRGenTypes::convertType(QualType type) { - type = context.getCanonicalType(type); + type = astContext.getCanonicalType(type); const Type *ty = type.getTypePtr(); + // Has the type already been processed? + TypeCacheTy::iterator tci = typeCache.find(ty); + if (tci != typeCache.end()) + return tci->second; + // For types that haven't been implemented yet or are otherwise unsupported, // report an error and return 'int'. @@ -24,7 +34,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) { switch (ty->getTypeClass()) { case Type::Builtin: { switch (cast(ty)->getKind()) { - // Signed types. + // Signed integral types. case BuiltinType::Char_S: case BuiltinType::Int: case BuiltinType::Int128: @@ -33,11 +43,11 @@ mlir::Type CIRGenTypes::convertType(QualType type) { case BuiltinType::SChar: case BuiltinType::Short: case BuiltinType::WChar_S: - resultType = cir::IntType::get(cgm.getBuilder().getContext(), - context.getTypeSize(ty), - /*isSigned=*/true); + resultType = + cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty), + /*isSigned=*/true); break; - // Unsigned types. + // Unsigned integral types. case BuiltinType::Char8: case BuiltinType::Char16: case BuiltinType::Char32: @@ -49,14 +59,13 @@ mlir::Type CIRGenTypes::convertType(QualType type) { case BuiltinType::ULongLong: case BuiltinType::UShort: case BuiltinType::WChar_U: - resultType = cir::IntType::get(cgm.getBuilder().getContext(), - context.getTypeSize(ty), - /*isSigned=*/false); + resultType = + cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty), + /*isSigned=*/false); break; default: cgm.errorNYI(SourceLocation(), "processing of built-in type", type); - resultType = cir::IntType::get(cgm.getBuilder().getContext(), 32, - /*isSigned=*/true); + resultType = cgm.SInt32Ty; break; } break; @@ -65,23 +74,21 @@ mlir::Type CIRGenTypes::convertType(QualType type) { const auto *bitIntTy = cast(type); if (bitIntTy->getNumBits() > cir::IntType::maxBitwidth()) { cgm.errorNYI(SourceLocation(), "large _BitInt type", type); - resultType = cir::IntType::get(cgm.getBuilder().getContext(), 32, - /*isSigned=*/true); + resultType = cgm.SInt32Ty; } else { - resultType = - cir::IntType::get(cgm.getBuilder().getContext(), - bitIntTy->getNumBits(), bitIntTy->isSigned()); + resultType = cir::IntType::get(&getMLIRContext(), bitIntTy->getNumBits(), + bitIntTy->isSigned()); } break; } default: cgm.errorNYI(SourceLocation(), "processing of type", type); - resultType = - cir::IntType::get(cgm.getBuilder().getContext(), 32, /*isSigned=*/true); + resultType = cgm.SInt32Ty; break; } assert(resultType && "Type conversion not yet implemented"); + typeCache[ty] = resultType; return resultType; } diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index b37738c770de1..563d7759831fa 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -15,9 +15,12 @@ #include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "llvm/ADT/SmallPtrSet.h" + namespace clang { class ASTContext; class QualType; +class Type; } // namespace clang namespace mlir { @@ -26,18 +29,27 @@ class Type; namespace clang::CIRGen { +class CIRGenBuilderTy; class CIRGenModule; /// This class organizes the cross-module state that is used while lowering /// AST types to CIR types. class CIRGenTypes { CIRGenModule &cgm; - clang::ASTContext &context; + clang::ASTContext &astContext; + CIRGenBuilderTy &builder; public: CIRGenTypes(CIRGenModule &cgm); ~CIRGenTypes(); + /// This map of clang::Type to mlir::Type (which includes CIR type) is a + /// cache of types that have already been processed. + using TypeCacheTy = llvm::DenseMap; + TypeCacheTy typeCache; + + mlir::MLIRContext &getMLIRContext() const; + /// Convert a Clang type into a mlir::Type. mlir::Type convertType(clang::QualType type); }; diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index 8f3370c0041af..91070eda7d45a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -29,15 +29,15 @@ CIRGenerator::CIRGenerator(clang::DiagnosticsEngine &diags, : diags(diags), fs(std::move(vfs)), codeGenOpts{cgo} {} CIRGenerator::~CIRGenerator() = default; -void CIRGenerator::Initialize(ASTContext &astCtx) { +void CIRGenerator::Initialize(ASTContext &astContext) { using namespace llvm; - this->astCtx = &astCtx; + this->astContext = &astContext; - mlirCtx = std::make_unique(); - mlirCtx->loadDialect(); - cgm = std::make_unique(*mlirCtx.get(), astCtx, - codeGenOpts, diags); + mlirContext = std::make_unique(); + mlirContext->loadDialect(); + cgm = std::make_unique( + *mlirContext.get(), astContext, codeGenOpts, diags); } mlir::ModuleOp CIRGenerator::getModule() const { return cgm->getModule(); } diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 8cf44592a1747..b1003f2ce5032 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -77,6 +77,7 @@ #include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h" #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" +#include "llvm/Transforms/Instrumentation/TypeSanitizer.h" #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Scalar/EarlyCSE.h" #include "llvm/Transforms/Scalar/GVN.h" @@ -735,9 +736,17 @@ static void addSanitizers(const Triple &TargetTriple, MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); } + if (LangOpts.Sanitize.has(SanitizerKind::Type)) { + MPM.addPass(ModuleTypeSanitizerPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass())); + } + if (LangOpts.Sanitize.has(SanitizerKind::NumericalStability)) MPM.addPass(NumericalStabilitySanitizerPass()); + if (LangOpts.Sanitize.has(SanitizerKind::Realtime)) + MPM.addPass(RealtimeSanitizerPass()); + auto ASanPass = [&](SanitizerMask Mask, bool CompileKernel) { if (LangOpts.Sanitize.has(Mask)) { bool UseGlobalGC = asanUseGlobalsGC(TargetTriple, CodeGenOpts); @@ -1020,17 +1029,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) PB.registerScalarOptimizerLateEPCallback( [](FunctionPassManager &FPM, OptimizationLevel Level) { - FPM.addPass(BoundsCheckingPass()); - }); - - if (LangOpts.Sanitize.has(SanitizerKind::Realtime)) { - PB.registerScalarOptimizerLateEPCallback( - [](FunctionPassManager &FPM, OptimizationLevel Level) { - RealtimeSanitizerOptions Opts; - FPM.addPass(RealtimeSanitizerPass(Opts)); + FPM.addPass( + BoundsCheckingPass(BoundsCheckingPass::ReportingMode::Trap)); }); - MPM.addPass(ModuleRealtimeSanitizerPass()); - } // Don't add sanitizers if we are here from ThinLTO PostLink. That already // done on PreLink stage. diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c2e983eebebc1..4d4b7428abd50 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4860,6 +4860,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // Buffer is a void**. Address Buf = EmitPointerWithAlignment(E->getArg(0)); + if (getTarget().getTriple().getArch() == llvm::Triple::systemz) { + // On this target, the back end fills in the context buffer completely. + // It doesn't really matter if the frontend stores to the buffer before + // calling setjmp, the back-end is going to overwrite them anyway. + Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp); + return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this))); + } + // Store the frame pointer to the setjmp buffer. Value *FrameAddr = Builder.CreateCall( CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy), @@ -10711,7 +10719,16 @@ Value *CodeGenFunction::EmitSVEDupX(Value *Scalar, llvm::Type *Ty) { cast(Ty)->getElementCount(), Scalar); } -Value *CodeGenFunction::EmitSVEDupX(Value* Scalar) { +Value *CodeGenFunction::EmitSVEDupX(Value *Scalar) { + if (auto *Ty = Scalar->getType(); Ty->isVectorTy()) { +#ifndef NDEBUG + auto *VecTy = cast(Ty); + ElementCount EC = VecTy->getElementCount(); + assert(EC.isScalar() && VecTy->getElementType() == Int8Ty && + "Only <1 x i8> expected"); +#endif + Scalar = Builder.CreateExtractElement(Scalar, uint64_t(0)); + } return EmitSVEDupX(Scalar, getSVEVectorForElementType(Scalar->getType())); } @@ -19419,6 +19436,15 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(), ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } + case Builtin::BI__builtin_hlsl_wave_active_all_true: { + Value *Op = EmitScalarExpr(E->getArg(0)); + assert(Op->getType()->isIntegerTy(1) && + "Intrinsic WaveActiveAllTrue operand must be a bool"); + + Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllTrueIntrinsic(); + return EmitRuntimeCall( + Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID), {Op}); + } case Builtin::BI__builtin_hlsl_wave_active_any_true: { Value *Op = EmitScalarExpr(E->getArg(0)); assert(Op->getType()->isIntegerTy(1) && diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 3cefc9da66ddb..50b9dfbbab083 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4379,7 +4379,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, llvm::PHINode *phiToUse = CGF.Builder.CreatePHI(valueToUse->getType(), 2, "icr.to-use"); phiToUse->addIncoming(valueToUse, copyBB); - phiToUse->addIncoming(llvm::UndefValue::get(valueToUse->getType()), + phiToUse->addIncoming(llvm::PoisonValue::get(valueToUse->getType()), originBB); valueToUse = phiToUse; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 60f32f76109e9..f29ddece5dbc9 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2021,28 +2021,10 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType( // ThisPtr may be null if the member function has an explicit 'this' // parameter. if (!ThisPtr.isNull()) { - const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl(); - if (isa(RD)) { - // Create pointer type directly in this case. - const PointerType *ThisPtrTy = cast(ThisPtr); - uint64_t Size = CGM.getContext().getTypeSize(ThisPtrTy); - auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext()); - llvm::DIType *PointeeType = - getOrCreateType(ThisPtrTy->getPointeeType(), Unit); - llvm::DIType *ThisPtrType = - DBuilder.createPointerType(PointeeType, Size, Align); - TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); - // TODO: This and the artificial type below are misleading, the - // types aren't artificial the argument is, but the current - // metadata doesn't represent that. - ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); - Elts.push_back(ThisPtrType); - } else { - llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit); - TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); - ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); - Elts.push_back(ThisPtrType); - } + llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit); + TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); + ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); + Elts.push_back(ThisPtrType); } // Copy rest of the arguments. @@ -2995,20 +2977,21 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (!ID) return nullptr; + auto RuntimeLang = + static_cast(TheCU->getSourceLanguage()); + // Return a forward declaration if this type was imported from a clang module, // and this is not the compile unit with the implementation of the type (which // may contain hidden ivars). if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition() && !ID->getImplementation()) - return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - ID->getName(), - getDeclContextDescriptor(ID), Unit, 0); + return DBuilder.createForwardDecl( + llvm::dwarf::DW_TAG_structure_type, ID->getName(), + getDeclContextDescriptor(ID), Unit, 0, RuntimeLang); // Get overall information about the record type for the debug info. llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation()); unsigned Line = getLineNumber(ID->getLocation()); - auto RuntimeLang = - static_cast(TheCU->getSourceLanguage()); // If this is just a forward declaration return a special forward-declaration // debug type since we won't be able to lay out the entire type. diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 2c3054605ee75..96517511b2111 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -479,6 +479,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction( !isInNoSanitizeList(SanitizerKind::MemtagStack, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeMemTag); + if (getLangOpts().Sanitize.has(SanitizerKind::Type) && + !isInNoSanitizeList(SanitizerKind::Type, Fn, Loc)) + Fn->addFnAttr(llvm::Attribute::SanitizeType); + if (getLangOpts().Sanitize.has(SanitizerKind::Thread) && !isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 5fccc9cbb37ec..d3fa5be6777ef 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1172,7 +1172,7 @@ llvm::Value *CodeGenFunction::GetCountedByFieldExprGEP( Indices.push_back(Builder.getInt32(0)); return Builder.CreateInBoundsGEP( ConvertType(QualType(RD->getTypeForDecl(), 0)), Res, - RecIndicesTy(llvm::reverse(Indices)), "..counted_by.gep"); + RecIndicesTy(llvm::reverse(Indices)), "counted_by.gep"); } /// This method is typically called in contexts where we can't generate @@ -1187,7 +1187,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfCountedByField( const Expr *Base, const FieldDecl *FAMDecl, const FieldDecl *CountDecl) { if (llvm::Value *GEP = GetCountedByFieldExprGEP(Base, FAMDecl, CountDecl)) return Builder.CreateAlignedLoad(ConvertType(CountDecl->getType()), GEP, - getIntAlign(), "..counted_by.load"); + getIntAlign(), "counted_by.load"); return nullptr; } @@ -3546,7 +3546,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF, ArrayRef FnArgs, SanitizerHandler CheckHandler, CheckRecoverableKind RecoverKind, bool IsFatal, - llvm::BasicBlock *ContBB) { + llvm::BasicBlock *ContBB, bool NoMerge) { assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable); std::optional DL; if (!CGF.Builder.getCurrentDebugLocation()) { @@ -3581,6 +3581,11 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF, llvm::AttributeList::FunctionIndex, B), /*Local=*/true); llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs); + NoMerge = NoMerge || ClSanitizeDebugDeoptimization || + !CGF.CGM.getCodeGenOpts().OptimizationLevel || + (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr()); + if (NoMerge) + HandlerCall->addFnAttr(llvm::Attribute::NoMerge); if (!MayReturn) { HandlerCall->setDoesNotReturn(); CGF.Builder.CreateUnreachable(); @@ -3602,6 +3607,7 @@ void CodeGenFunction::EmitCheck( llvm::Value *FatalCond = nullptr; llvm::Value *RecoverableCond = nullptr; llvm::Value *TrapCond = nullptr; + bool NoMerge = false; for (int i = 0, n = Checked.size(); i < n; ++i) { llvm::Value *Check = Checked[i].first; // -fsanitize-trap= overrides -fsanitize-recover=. @@ -3612,6 +3618,9 @@ void CodeGenFunction::EmitCheck( ? RecoverableCond : FatalCond; Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check; + + if (!CGM.getCodeGenOpts().SanitizeMergeHandlers.has(Checked[i].second)) + NoMerge = true; } if (ClSanitizeGuardChecks) { @@ -3626,7 +3635,7 @@ void CodeGenFunction::EmitCheck( } if (TrapCond) - EmitTrapCheck(TrapCond, CheckHandler); + EmitTrapCheck(TrapCond, CheckHandler, NoMerge); if (!FatalCond && !RecoverableCond) return; @@ -3692,7 +3701,7 @@ void CodeGenFunction::EmitCheck( // Simple case: we need to generate a single handler call, either // fatal, or non-fatal. emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, - (FatalCond != nullptr), Cont); + (FatalCond != nullptr), Cont, NoMerge); } else { // Emit two handler calls: first one for set of unrecoverable checks, // another one for recoverable. @@ -3702,10 +3711,10 @@ void CodeGenFunction::EmitCheck( Builder.CreateCondBr(FatalCond, NonFatalHandlerBB, FatalHandlerBB); EmitBlock(FatalHandlerBB); emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, true, - NonFatalHandlerBB); + NonFatalHandlerBB, NoMerge); EmitBlock(NonFatalHandlerBB); emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, false, - Cont); + Cont, NoMerge); } EmitBlock(Cont); @@ -3895,7 +3904,8 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) { } void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, - SanitizerHandler CheckHandlerID) { + SanitizerHandler CheckHandlerID, + bool NoMerge) { llvm::BasicBlock *Cont = createBasicBlock("cont"); // If we're optimizing, collapse all calls to trap down to just one per @@ -3905,9 +3915,9 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID]; - bool NoMerge = ClSanitizeDebugDeoptimization || - !CGM.getCodeGenOpts().OptimizationLevel || - (CurCodeDecl && CurCodeDecl->hasAttr()); + NoMerge = NoMerge || ClSanitizeDebugDeoptimization || + !CGM.getCodeGenOpts().OptimizationLevel || + (CurCodeDecl && CurCodeDecl->hasAttr()); if (TrapBB && !NoMerge) { auto Call = TrapBB->begin(); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index bbf68a4c66192..4b71bd730ce12 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2370,10 +2370,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { ScalableDstTy->getElementCount().getKnownMinValue() / 8); } if (FixedSrcTy->getElementType() == ScalableDstTy->getElementType()) { - llvm::Value *UndefVec = llvm::UndefValue::get(ScalableDstTy); + llvm::Value *PoisonVec = llvm::PoisonValue::get(ScalableDstTy); llvm::Value *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty); llvm::Value *Result = Builder.CreateInsertVector( - ScalableDstTy, UndefVec, Src, Zero, "cast.scalable"); + ScalableDstTy, PoisonVec, Src, Zero, "cast.scalable"); if (Result->getType() != DstTy) Result = Builder.CreateBitCast(Result, DstTy); return Result; diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 2c293523fca8c..c354e58e15f4b 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -389,6 +389,11 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, CGM.getIntrinsic(getThreadIdIntrinsic()); return buildVectorInput(B, ThreadIDIntrinsic, Ty); } + if (D.hasAttr()) { + llvm::Function *GroupThreadIDIntrinsic = + CGM.getIntrinsic(getGroupThreadIdIntrinsic()); + return buildVectorInput(B, GroupThreadIDIntrinsic, Ty); + } if (D.hasAttr()) { llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_group_id); return buildVectorInput(B, GroupIDIntrinsic, Ty); @@ -507,13 +512,17 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() { IP = Token->getNextNode(); } IRBuilder<> B(IP); - for (auto *Fn : CtorFns) - B.CreateCall(FunctionCallee(Fn), {}, OB); + for (auto *Fn : CtorFns) { + auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB); + CI->setCallingConv(Fn->getCallingConv()); + } // Insert global dtors before the terminator of the last instruction B.SetInsertPoint(F.back().getTerminator()); - for (auto *Fn : DtorFns) - B.CreateCall(FunctionCallee(Fn), {}, OB); + for (auto *Fn : DtorFns) { + auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB); + CI->setCallingConv(Fn->getCallingConv()); + } } // No need to keep global ctors/dtors for non-lib profile after call to diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index bb120c8b5e9e6..85238ee34b447 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -86,11 +86,13 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(Step, step) GENERATE_HLSL_INTRINSIC_FUNCTION(Radians, radians) GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id) + GENERATE_HLSL_INTRINSIC_FUNCTION(GroupThreadId, thread_id_in_group) GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot) GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot) GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot) GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddI8Packed, dot4add_i8packed) GENERATE_HLSL_INTRINSIC_FUNCTION(Dot4AddU8Packed, dot4add_u8packed) + GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAllTrue, wave_all) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveAnyTrue, wave_any) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveActiveCountBits, wave_active_countbits) GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 2deb91f27e37b..30c3834de139c 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -4085,7 +4085,7 @@ static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy, CGF.Builder.CreateConstGEP(DependenciesArray, *P), KmpDependInfoTy); } else { assert(E && "Expected a non-null expression"); - LValue &PosLVal = *Pos.get(); + LValue &PosLVal = *cast(Pos); llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc()); Base = CGF.MakeAddrLValue( CGF.Builder.CreateGEP(CGF, DependenciesArray, Idx), KmpDependInfoTy); @@ -4113,7 +4113,7 @@ static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy, if (unsigned *P = Pos.dyn_cast()) { ++(*P); } else { - LValue &PosLVal = *Pos.get(); + LValue &PosLVal = *cast(Pos); llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc()); Idx = CGF.Builder.CreateNUWAdd(Idx, llvm::ConstantInt::get(Idx->getType(), 1)); @@ -9042,337 +9042,69 @@ void CGOpenMPRuntime::emitUserDefinedMapper(const OMPDeclareMapperDecl *D, return; ASTContext &C = CGM.getContext(); QualType Ty = D->getType(); - QualType PtrTy = C.getPointerType(Ty).withRestrict(); - QualType Int64Ty = C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/true); auto *MapperVarDecl = cast(cast(D->getMapperVarRef())->getDecl()); - SourceLocation Loc = D->getLocation(); CharUnits ElementSize = C.getTypeSizeInChars(Ty); llvm::Type *ElemTy = CGM.getTypes().ConvertTypeForMem(Ty); - // Prepare mapper function arguments and attributes. - ImplicitParamDecl HandleArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - ImplicitParamDecl BaseArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy, - ImplicitParamKind::Other); - ImplicitParamDecl BeginArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - ImplicitParamDecl SizeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, Int64Ty, - ImplicitParamKind::Other); - ImplicitParamDecl TypeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, Int64Ty, - ImplicitParamKind::Other); - ImplicitParamDecl NameArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy, - ImplicitParamKind::Other); - FunctionArgList Args; - Args.push_back(&HandleArg); - Args.push_back(&BaseArg); - Args.push_back(&BeginArg); - Args.push_back(&SizeArg); - Args.push_back(&TypeArg); - Args.push_back(&NameArg); - const CGFunctionInfo &FnInfo = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); - llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo); + CodeGenFunction MapperCGF(CGM); + MappableExprsHandler::MapCombinedInfoTy CombinedInfo; + auto PrivatizeAndGenMapInfoCB = + [&](llvm::OpenMPIRBuilder::InsertPointTy CodeGenIP, llvm::Value *PtrPHI, + llvm::Value *BeginArg) -> llvm::OpenMPIRBuilder::MapInfosTy & { + MapperCGF.Builder.restoreIP(CodeGenIP); + + // Privatize the declared variable of mapper to be the current array + // element. + Address PtrCurrent( + PtrPHI, ElemTy, + Address(BeginArg, MapperCGF.VoidPtrTy, CGM.getPointerAlign()) + .getAlignment() + .alignmentOfArrayElement(ElementSize)); + CodeGenFunction::OMPPrivateScope Scope(MapperCGF); + Scope.addPrivate(MapperVarDecl, PtrCurrent); + (void)Scope.Privatize(); + + // Get map clause information. + MappableExprsHandler MEHandler(*D, MapperCGF); + MEHandler.generateAllInfoForMapper(CombinedInfo, OMPBuilder); + + auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) { + return emitMappingInformation(MapperCGF, OMPBuilder, MapExpr); + }; + if (CGM.getCodeGenOpts().getDebugInfo() != + llvm::codegenoptions::NoDebugInfo) { + CombinedInfo.Names.resize(CombinedInfo.Exprs.size()); + llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(), + FillInfoMap); + } + + return CombinedInfo; + }; + + auto CustomMapperCB = [&](unsigned I, llvm::Function **MapperFunc) { + if (CombinedInfo.Mappers[I]) { + // Call the corresponding mapper function. + *MapperFunc = getOrCreateUserDefinedMapperFunc( + cast(CombinedInfo.Mappers[I])); + assert(*MapperFunc && "Expect a valid mapper function is available."); + return true; + } + return false; + }; + SmallString<64> TyStr; llvm::raw_svector_ostream Out(TyStr); CGM.getCXXABI().getMangleContext().mangleCanonicalTypeName(Ty, Out); std::string Name = getName({"omp_mapper", TyStr, D->getName()}); - auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage, - Name, &CGM.getModule()); - CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo); - Fn->removeFnAttr(llvm::Attribute::OptimizeNone); - // Start the mapper function code generation. - CodeGenFunction MapperCGF(CGM); - MapperCGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc); - // Compute the starting and end addresses of array elements. - llvm::Value *Size = MapperCGF.EmitLoadOfScalar( - MapperCGF.GetAddrOfLocalVar(&SizeArg), /*Volatile=*/false, - C.getPointerType(Int64Ty), Loc); - // Prepare common arguments for array initiation and deletion. - llvm::Value *Handle = MapperCGF.EmitLoadOfScalar( - MapperCGF.GetAddrOfLocalVar(&HandleArg), - /*Volatile=*/false, C.getPointerType(C.VoidPtrTy), Loc); - llvm::Value *BaseIn = MapperCGF.EmitLoadOfScalar( - MapperCGF.GetAddrOfLocalVar(&BaseArg), - /*Volatile=*/false, C.getPointerType(C.VoidPtrTy), Loc); - llvm::Value *BeginIn = MapperCGF.EmitLoadOfScalar( - MapperCGF.GetAddrOfLocalVar(&BeginArg), - /*Volatile=*/false, C.getPointerType(C.VoidPtrTy), Loc); - // Convert the size in bytes into the number of array elements. - Size = MapperCGF.Builder.CreateExactUDiv( - Size, MapperCGF.Builder.getInt64(ElementSize.getQuantity())); - llvm::Value *PtrBegin = MapperCGF.Builder.CreateBitCast( - BeginIn, CGM.getTypes().ConvertTypeForMem(PtrTy)); - llvm::Value *PtrEnd = MapperCGF.Builder.CreateGEP(ElemTy, PtrBegin, Size); - llvm::Value *MapType = MapperCGF.EmitLoadOfScalar( - MapperCGF.GetAddrOfLocalVar(&TypeArg), /*Volatile=*/false, - C.getPointerType(Int64Ty), Loc); - llvm::Value *MapName = MapperCGF.EmitLoadOfScalar( - MapperCGF.GetAddrOfLocalVar(&NameArg), - /*Volatile=*/false, C.getPointerType(C.VoidPtrTy), Loc); - - // Emit array initiation if this is an array section and \p MapType indicates - // that memory allocation is required. - llvm::BasicBlock *HeadBB = MapperCGF.createBasicBlock("omp.arraymap.head"); - emitUDMapperArrayInitOrDel(MapperCGF, Handle, BaseIn, BeginIn, Size, MapType, - MapName, ElementSize, HeadBB, /*IsInit=*/true); - - // Emit a for loop to iterate through SizeArg of elements and map all of them. - - // Emit the loop header block. - MapperCGF.EmitBlock(HeadBB); - llvm::BasicBlock *BodyBB = MapperCGF.createBasicBlock("omp.arraymap.body"); - llvm::BasicBlock *DoneBB = MapperCGF.createBasicBlock("omp.done"); - // Evaluate whether the initial condition is satisfied. - llvm::Value *IsEmpty = - MapperCGF.Builder.CreateICmpEQ(PtrBegin, PtrEnd, "omp.arraymap.isempty"); - MapperCGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); - llvm::BasicBlock *EntryBB = MapperCGF.Builder.GetInsertBlock(); - - // Emit the loop body block. - MapperCGF.EmitBlock(BodyBB); - llvm::BasicBlock *LastBB = BodyBB; - llvm::PHINode *PtrPHI = MapperCGF.Builder.CreatePHI( - PtrBegin->getType(), 2, "omp.arraymap.ptrcurrent"); - PtrPHI->addIncoming(PtrBegin, EntryBB); - Address PtrCurrent(PtrPHI, ElemTy, - MapperCGF.GetAddrOfLocalVar(&BeginArg) - .getAlignment() - .alignmentOfArrayElement(ElementSize)); - // Privatize the declared variable of mapper to be the current array element. - CodeGenFunction::OMPPrivateScope Scope(MapperCGF); - Scope.addPrivate(MapperVarDecl, PtrCurrent); - (void)Scope.Privatize(); - // Get map clause information. Fill up the arrays with all mapped variables. - MappableExprsHandler::MapCombinedInfoTy Info; - MappableExprsHandler MEHandler(*D, MapperCGF); - MEHandler.generateAllInfoForMapper(Info, OMPBuilder); - - // Call the runtime API __tgt_mapper_num_components to get the number of - // pre-existing components. - llvm::Value *OffloadingArgs[] = {Handle}; - llvm::Value *PreviousSize = MapperCGF.EmitRuntimeCall( - OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), - OMPRTL___tgt_mapper_num_components), - OffloadingArgs); - llvm::Value *ShiftedPreviousSize = MapperCGF.Builder.CreateShl( - PreviousSize, - MapperCGF.Builder.getInt64(MappableExprsHandler::getFlagMemberOffset())); - - // Fill up the runtime mapper handle for all components. - for (unsigned I = 0; I < Info.BasePointers.size(); ++I) { - llvm::Value *CurBaseArg = MapperCGF.Builder.CreateBitCast( - Info.BasePointers[I], CGM.getTypes().ConvertTypeForMem(C.VoidPtrTy)); - llvm::Value *CurBeginArg = MapperCGF.Builder.CreateBitCast( - Info.Pointers[I], CGM.getTypes().ConvertTypeForMem(C.VoidPtrTy)); - llvm::Value *CurSizeArg = Info.Sizes[I]; - llvm::Value *CurNameArg = - (CGM.getCodeGenOpts().getDebugInfo() == - llvm::codegenoptions::NoDebugInfo) - ? llvm::ConstantPointerNull::get(CGM.VoidPtrTy) - : emitMappingInformation(MapperCGF, OMPBuilder, Info.Exprs[I]); - - // Extract the MEMBER_OF field from the map type. - llvm::Value *OriMapType = MapperCGF.Builder.getInt64( - static_cast>( - Info.Types[I])); - llvm::Value *MemberMapType = - MapperCGF.Builder.CreateNUWAdd(OriMapType, ShiftedPreviousSize); - - // Combine the map type inherited from user-defined mapper with that - // specified in the program. According to the OMP_MAP_TO and OMP_MAP_FROM - // bits of the \a MapType, which is the input argument of the mapper - // function, the following code will set the OMP_MAP_TO and OMP_MAP_FROM - // bits of MemberMapType. - // [OpenMP 5.0], 1.2.6. map-type decay. - // | alloc | to | from | tofrom | release | delete - // ---------------------------------------------------------- - // alloc | alloc | alloc | alloc | alloc | release | delete - // to | alloc | to | alloc | to | release | delete - // from | alloc | alloc | from | from | release | delete - // tofrom | alloc | to | from | tofrom | release | delete - llvm::Value *LeftToFrom = MapperCGF.Builder.CreateAnd( - MapType, - MapperCGF.Builder.getInt64( - static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_TO | - OpenMPOffloadMappingFlags::OMP_MAP_FROM))); - llvm::BasicBlock *AllocBB = MapperCGF.createBasicBlock("omp.type.alloc"); - llvm::BasicBlock *AllocElseBB = - MapperCGF.createBasicBlock("omp.type.alloc.else"); - llvm::BasicBlock *ToBB = MapperCGF.createBasicBlock("omp.type.to"); - llvm::BasicBlock *ToElseBB = MapperCGF.createBasicBlock("omp.type.to.else"); - llvm::BasicBlock *FromBB = MapperCGF.createBasicBlock("omp.type.from"); - llvm::BasicBlock *EndBB = MapperCGF.createBasicBlock("omp.type.end"); - llvm::Value *IsAlloc = MapperCGF.Builder.CreateIsNull(LeftToFrom); - MapperCGF.Builder.CreateCondBr(IsAlloc, AllocBB, AllocElseBB); - // In case of alloc, clear OMP_MAP_TO and OMP_MAP_FROM. - MapperCGF.EmitBlock(AllocBB); - llvm::Value *AllocMapType = MapperCGF.Builder.CreateAnd( - MemberMapType, - MapperCGF.Builder.getInt64( - ~static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_TO | - OpenMPOffloadMappingFlags::OMP_MAP_FROM))); - MapperCGF.Builder.CreateBr(EndBB); - MapperCGF.EmitBlock(AllocElseBB); - llvm::Value *IsTo = MapperCGF.Builder.CreateICmpEQ( - LeftToFrom, - MapperCGF.Builder.getInt64( - static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_TO))); - MapperCGF.Builder.CreateCondBr(IsTo, ToBB, ToElseBB); - // In case of to, clear OMP_MAP_FROM. - MapperCGF.EmitBlock(ToBB); - llvm::Value *ToMapType = MapperCGF.Builder.CreateAnd( - MemberMapType, - MapperCGF.Builder.getInt64( - ~static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_FROM))); - MapperCGF.Builder.CreateBr(EndBB); - MapperCGF.EmitBlock(ToElseBB); - llvm::Value *IsFrom = MapperCGF.Builder.CreateICmpEQ( - LeftToFrom, - MapperCGF.Builder.getInt64( - static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_FROM))); - MapperCGF.Builder.CreateCondBr(IsFrom, FromBB, EndBB); - // In case of from, clear OMP_MAP_TO. - MapperCGF.EmitBlock(FromBB); - llvm::Value *FromMapType = MapperCGF.Builder.CreateAnd( - MemberMapType, - MapperCGF.Builder.getInt64( - ~static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_TO))); - // In case of tofrom, do nothing. - MapperCGF.EmitBlock(EndBB); - LastBB = EndBB; - llvm::PHINode *CurMapType = - MapperCGF.Builder.CreatePHI(CGM.Int64Ty, 4, "omp.maptype"); - CurMapType->addIncoming(AllocMapType, AllocBB); - CurMapType->addIncoming(ToMapType, ToBB); - CurMapType->addIncoming(FromMapType, FromBB); - CurMapType->addIncoming(MemberMapType, ToElseBB); - - llvm::Value *OffloadingArgs[] = {Handle, CurBaseArg, CurBeginArg, - CurSizeArg, CurMapType, CurNameArg}; - if (Info.Mappers[I]) { - // Call the corresponding mapper function. - llvm::Function *MapperFunc = getOrCreateUserDefinedMapperFunc( - cast(Info.Mappers[I])); - assert(MapperFunc && "Expect a valid mapper function is available."); - MapperCGF.EmitNounwindRuntimeCall(MapperFunc, OffloadingArgs); - } else { - // Call the runtime API __tgt_push_mapper_component to fill up the runtime - // data structure. - MapperCGF.EmitRuntimeCall( - OMPBuilder.getOrCreateRuntimeFunction( - CGM.getModule(), OMPRTL___tgt_push_mapper_component), - OffloadingArgs); - } - } - - // Update the pointer to point to the next element that needs to be mapped, - // and check whether we have mapped all elements. - llvm::Value *PtrNext = MapperCGF.Builder.CreateConstGEP1_32( - ElemTy, PtrPHI, /*Idx0=*/1, "omp.arraymap.next"); - PtrPHI->addIncoming(PtrNext, LastBB); - llvm::Value *IsDone = - MapperCGF.Builder.CreateICmpEQ(PtrNext, PtrEnd, "omp.arraymap.isdone"); - llvm::BasicBlock *ExitBB = MapperCGF.createBasicBlock("omp.arraymap.exit"); - MapperCGF.Builder.CreateCondBr(IsDone, ExitBB, BodyBB); - - MapperCGF.EmitBlock(ExitBB); - // Emit array deletion if this is an array section and \p MapType indicates - // that deletion is required. - emitUDMapperArrayInitOrDel(MapperCGF, Handle, BaseIn, BeginIn, Size, MapType, - MapName, ElementSize, DoneBB, /*IsInit=*/false); - - // Emit the function exit block. - MapperCGF.EmitBlock(DoneBB, /*IsFinished=*/true); - MapperCGF.FinishFunction(); - UDMMap.try_emplace(D, Fn); + auto *NewFn = OMPBuilder.emitUserDefinedMapper(PrivatizeAndGenMapInfoCB, + ElemTy, Name, CustomMapperCB); + UDMMap.try_emplace(D, NewFn); if (CGF) FunctionUDMMap[CGF->CurFn].push_back(D); } -/// Emit the array initialization or deletion portion for user-defined mapper -/// code generation. First, it evaluates whether an array section is mapped and -/// whether the \a MapType instructs to delete this section. If \a IsInit is -/// true, and \a MapType indicates to not delete this array, array -/// initialization code is generated. If \a IsInit is false, and \a MapType -/// indicates to not this array, array deletion code is generated. -void CGOpenMPRuntime::emitUDMapperArrayInitOrDel( - CodeGenFunction &MapperCGF, llvm::Value *Handle, llvm::Value *Base, - llvm::Value *Begin, llvm::Value *Size, llvm::Value *MapType, - llvm::Value *MapName, CharUnits ElementSize, llvm::BasicBlock *ExitBB, - bool IsInit) { - StringRef Prefix = IsInit ? ".init" : ".del"; - - // Evaluate if this is an array section. - llvm::BasicBlock *BodyBB = - MapperCGF.createBasicBlock(getName({"omp.array", Prefix})); - llvm::Value *IsArray = MapperCGF.Builder.CreateICmpSGT( - Size, MapperCGF.Builder.getInt64(1), "omp.arrayinit.isarray"); - llvm::Value *DeleteBit = MapperCGF.Builder.CreateAnd( - MapType, - MapperCGF.Builder.getInt64( - static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_DELETE))); - llvm::Value *DeleteCond; - llvm::Value *Cond; - if (IsInit) { - // base != begin? - llvm::Value *BaseIsBegin = MapperCGF.Builder.CreateICmpNE(Base, Begin); - // IsPtrAndObj? - llvm::Value *PtrAndObjBit = MapperCGF.Builder.CreateAnd( - MapType, - MapperCGF.Builder.getInt64( - static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ))); - PtrAndObjBit = MapperCGF.Builder.CreateIsNotNull(PtrAndObjBit); - BaseIsBegin = MapperCGF.Builder.CreateAnd(BaseIsBegin, PtrAndObjBit); - Cond = MapperCGF.Builder.CreateOr(IsArray, BaseIsBegin); - DeleteCond = MapperCGF.Builder.CreateIsNull( - DeleteBit, getName({"omp.array", Prefix, ".delete"})); - } else { - Cond = IsArray; - DeleteCond = MapperCGF.Builder.CreateIsNotNull( - DeleteBit, getName({"omp.array", Prefix, ".delete"})); - } - Cond = MapperCGF.Builder.CreateAnd(Cond, DeleteCond); - MapperCGF.Builder.CreateCondBr(Cond, BodyBB, ExitBB); - - MapperCGF.EmitBlock(BodyBB); - // Get the array size by multiplying element size and element number (i.e., \p - // Size). - llvm::Value *ArraySize = MapperCGF.Builder.CreateNUWMul( - Size, MapperCGF.Builder.getInt64(ElementSize.getQuantity())); - // Remove OMP_MAP_TO and OMP_MAP_FROM from the map type, so that it achieves - // memory allocation/deletion purpose only. - llvm::Value *MapTypeArg = MapperCGF.Builder.CreateAnd( - MapType, - MapperCGF.Builder.getInt64( - ~static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_TO | - OpenMPOffloadMappingFlags::OMP_MAP_FROM))); - MapTypeArg = MapperCGF.Builder.CreateOr( - MapTypeArg, - MapperCGF.Builder.getInt64( - static_cast>( - OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT))); - - // Call the runtime API __tgt_push_mapper_component to fill up the runtime - // data structure. - llvm::Value *OffloadingArgs[] = {Handle, Base, Begin, - ArraySize, MapTypeArg, MapName}; - MapperCGF.EmitRuntimeCall( - OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), - OMPRTL___tgt_push_mapper_component), - OffloadingArgs); -} - llvm::Function *CGOpenMPRuntime::getOrCreateUserDefinedMapperFunc( const OMPDeclareMapperDecl *D) { auto I = UDMMap.find(D); diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index 56d502d92806e..8ab5ee70a19fa 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -559,15 +559,6 @@ class CGOpenMPRuntime { llvm::Value *Ctor, llvm::Value *CopyCtor, llvm::Value *Dtor, SourceLocation Loc); - /// Emit the array initialization or deletion portion for user-defined mapper - /// code generation. - void emitUDMapperArrayInitOrDel(CodeGenFunction &MapperCGF, - llvm::Value *Handle, llvm::Value *BasePtr, - llvm::Value *Ptr, llvm::Value *Size, - llvm::Value *MapType, llvm::Value *MapName, - CharUnits ElementSize, - llvm::BasicBlock *ExitBB, bool IsInit); - struct TaskResultTy { llvm::Value *NewTask = nullptr; llvm::Function *TaskEntry = nullptr; diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 698baf853507f..6c604f44e283b 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -458,6 +458,21 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { case Stmt::OpenACCCombinedConstructClass: EmitOpenACCCombinedConstruct(cast(*S)); break; + case Stmt::OpenACCDataConstructClass: + EmitOpenACCDataConstruct(cast(*S)); + break; + case Stmt::OpenACCEnterDataConstructClass: + EmitOpenACCEnterDataConstruct(cast(*S)); + break; + case Stmt::OpenACCExitDataConstructClass: + EmitOpenACCExitDataConstruct(cast(*S)); + break; + case Stmt::OpenACCHostDataConstructClass: + EmitOpenACCHostDataConstruct(cast(*S)); + break; + case Stmt::OpenACCWaitConstructClass: + EmitOpenACCWaitConstruct(cast(*S)); + break; } } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 2bc10cdd2d344..af58fa64f8658 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -837,6 +837,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, Fn->addFnAttr(llvm::Attribute::SanitizeMemTag); if (SanOpts.has(SanitizerKind::Thread)) Fn->addFnAttr(llvm::Attribute::SanitizeThread); + if (SanOpts.has(SanitizerKind::Type)) + Fn->addFnAttr(llvm::Attribute::SanitizeType); if (SanOpts.has(SanitizerKind::NumericalStability)) Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability); if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory)) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index eaea0d8a08ac0..4d4139180e100 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4094,6 +4094,35 @@ class CodeGenFunction : public CodeGenTypeCache { EmitStmt(S.getLoop()); } + void EmitOpenACCDataConstruct(const OpenACCDataConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // simply emitting its structured block, but in the future we will implement + // some sort of IR. + EmitStmt(S.getStructuredBlock()); + } + + void EmitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // but in the future we will implement some sort of IR. + } + + void EmitOpenACCExitDataConstruct(const OpenACCExitDataConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // but in the future we will implement some sort of IR. + } + + void EmitOpenACCHostDataConstruct(const OpenACCHostDataConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // simply emitting its structured block, but in the future we will implement + // some sort of IR. + EmitStmt(S.getStructuredBlock()); + } + + void EmitOpenACCWaitConstruct(const OpenACCWaitConstruct &S) { + // TODO OpenACC: Implement this. It is currently implemented as a 'no-op', + // but in the future we will implement some sort of IR. + } + //===--------------------------------------------------------------------===// // LValue Expression Emission //===--------------------------------------------------------------------===// @@ -5142,7 +5171,8 @@ class CodeGenFunction : public CodeGenTypeCache { /// Create a basic block that will call the trap intrinsic, and emit a /// conditional branch to it, for the -ftrapv checks. - void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID); + void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID, + bool NoMerge = false); /// Emit a call to trap or debugtrap and attach function attribute /// "trap-func-name" if specified. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index d3d5c0743a520..5ac3eefbd6c51 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -397,8 +397,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, if (LangOpts.HLSL) createHLSLRuntime(); - // Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0. - if (LangOpts.Sanitize.has(SanitizerKind::Thread) || + // Enable TBAA unless it's suppressed. TSan and TySan need TBAA even at O0. + if (LangOpts.Sanitize.hasOneOf(SanitizerKind::Thread | SanitizerKind::Type) || (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0)) TBAA.reset(new CodeGenTBAA(Context, getTypes(), TheModule, CodeGenOpts, getLangOpts())); @@ -1218,6 +1218,9 @@ void CodeGenModule::Release() { getModule().addModuleFlag(llvm::Module::Min, "ptrauth-elf-got", 1); if (getTriple().isOSLinux()) { + if (LangOpts.PointerAuthCalls) + getModule().addModuleFlag(llvm::Module::Min, "ptrauth-sign-personality", + 1); assert(getTriple().isOSBinFormatELF()); using namespace llvm::ELF; uint64_t PAuthABIVersion = diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 6eed8e1d2b671..75e66bae79afd 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -314,8 +314,10 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) { } llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) { - // At -O0 or relaxed aliasing, TBAA is not emitted for regular types. - if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing) + // At -O0 or relaxed aliasing, TBAA is not emitted for regular types (unless + // we're running TypeSanitizer). + if (!Features.Sanitize.has(SanitizerKind::Type) && + (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)) return nullptr; // If the type has the may_alias attribute (even on a typedef), it is diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 96c89b2728e5b..cda218eac34af 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1146,12 +1146,15 @@ struct CounterCoverageMappingBuilder /// Create a Branch Region around a SwitchCase for code coverage /// and add it to the function's SourceRegions. - void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt) { + /// Returns Counter that corresponds to SC. + Counter createSwitchCaseRegion(const SwitchCase *SC, Counter ParentCount) { // Push region onto RegionStack but immediately pop it (which adds it to // the function's SourceRegions) because it doesn't apply to any other // source other than the SwitchCase. + Counter TrueCnt = getRegionCounter(SC); popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), - Counter::getZero())); + subtractCounters(ParentCount, TrueCnt))); + return TrueCnt; } /// Check whether a region with bounds \c StartLoc and \c EndLoc @@ -1863,16 +1866,22 @@ struct CounterCoverageMappingBuilder const SwitchCase *Case = S->getSwitchCaseList(); for (; Case; Case = Case->getNextSwitchCase()) { HasDefaultCase = HasDefaultCase || isa(Case); - auto CaseCount = getRegionCounter(Case); + auto CaseCount = createSwitchCaseRegion(Case, ParentCount); CaseCountSum = addCounters(CaseCountSum, CaseCount, /*Simplify=*/false); - createSwitchCaseRegion(Case, CaseCount); } // If no explicit default case exists, create a branch region to represent // the hidden branch, which will be added later by the CodeGen. This region // will be associated with the switch statement's condition. if (!HasDefaultCase) { - Counter DefaultCount = subtractCounters(ParentCount, CaseCountSum); - createBranchRegion(S->getCond(), Counter::getZero(), DefaultCount); + // Simplify is skipped while building the counters above: it can get + // really slow on top of switches with thousands of cases. Instead, + // trigger simplification by adding zero to the last counter. + CaseCountSum = + addCounters(CaseCountSum, Counter::getZero(), /*Simplify=*/true); + + // This is considered as the False count on SwitchStmt. + Counter SwitchFalse = subtractCounters(ParentCount, CaseCountSum); + createBranchRegion(S->getCond(), CaseCountSum, SwitchFalse); } } @@ -2370,8 +2379,7 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName, } else { Ctx.dump(R.Count, OS); - if (R.Kind == CounterMappingRegion::BranchRegion || - R.Kind == CounterMappingRegion::MCDCBranchRegion) { + if (R.isBranch()) { OS << ", "; Ctx.dump(R.FalseCount, OS); } diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 8cbd09d02c755..cf9e338236e55 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -3302,6 +3302,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( CharUnits Align = CGM.getContext().getDeclAlign(VD); Val = Builder.CreateAlignedLoad(Var->getValueType(), Val, Align); } + Val = Builder.CreateAddrSpaceCast(Val, Wrapper->getReturnType()); Builder.CreateRet(Val); } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index d587daac5a88a..90651c3bafe26 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -3454,7 +3454,7 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion( if (inheritanceModelHasOnlyOneField(IsFunc, DstInheritance)) { Dst = FirstField; } else { - Dst = llvm::UndefValue::get(ConvertMemberPointerType(DstTy)); + Dst = llvm::PoisonValue::get(ConvertMemberPointerType(DstTy)); unsigned Idx = 0; Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++); if (inheritanceModelHasNVOffsetField(IsFunc, DstInheritance)) diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index c1a6b223480a1..405124c8b8717 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -19,9 +19,10 @@ using namespace CodeGen; SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {} -static bool isAsanHwasanOrMemTag(const SanitizerSet &SS) { +static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) { return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress | - SanitizerKind::HWAddress | SanitizerKind::MemTag); + SanitizerKind::HWAddress | SanitizerKind::MemTag | + SanitizerKind::Type); } static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) { @@ -31,13 +32,44 @@ static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) { return Mask; } +static bool shouldTagGlobal(const llvm::GlobalVariable &G) { + // For now, don't instrument constant data, as it'll be in .rodata anyway. It + // may be worth instrumenting these in future to stop them from being used as + // gadgets. + if (G.getName().starts_with("llvm.") || G.isThreadLocal() || G.isConstant()) + return false; + + // Globals can be placed implicitly or explicitly in sections. There's two + // different types of globals that meet this criteria that cause problems: + // 1. Function pointers that are going into various init arrays (either + // explicitly through `__attribute__((section()))` or implicitly + // through `__attribute__((constructor)))`, such as ".(pre)init(_array)", + // ".fini(_array)", ".ctors", and ".dtors". These function pointers end up + // overaligned and overpadded, making iterating over them problematic, and + // each function pointer is individually tagged (so the iteration over + // them causes SIGSEGV/MTE[AS]ERR). + // 2. Global variables put into an explicit section, where the section's name + // is a valid C-style identifier. The linker emits a `__start_` and + // `__stop_` symbol for the section, so that you can iterate over + // globals within this section. Unfortunately, again, these globals would + // be tagged and so iteration causes SIGSEGV/MTE[AS]ERR. + // + // To mitigate both these cases, and because specifying a section is rare + // outside of these two cases, disable MTE protection for globals in any + // section. + if (G.hasSection()) + return false; + + return true; +} + void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc, StringRef Name, QualType Ty, SanitizerMask NoSanitizeAttrMask, bool IsDynInit) { SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize; - if (!isAsanHwasanOrMemTag(FsanitizeArgument)) + if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument)) return; FsanitizeArgument.Mask = expandKernelSanitizerMasks(FsanitizeArgument.Mask); @@ -57,11 +89,15 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, Meta.NoHWAddress |= CGM.isInNoSanitizeList( FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty); - Meta.Memtag |= - static_cast(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals); - Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag); - Meta.Memtag &= !CGM.isInNoSanitizeList( - FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty); + if (shouldTagGlobal(*GV)) { + Meta.Memtag |= static_cast(FsanitizeArgument.Mask & + SanitizerKind::MemtagGlobals); + Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag); + Meta.Memtag &= !CGM.isInNoSanitizeList( + FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty); + } else { + Meta.Memtag = false; + } Meta.IsDynInit = IsDynInit && !Meta.NoAddress && FsanitizeArgument.has(SanitizerKind::Address) && @@ -70,11 +106,32 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, GV, Loc, Ty, "init"); GV->setSanitizerMetadata(Meta); + + if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) || + NoSanitizeAttrMask & SanitizerKind::Type) + return; + + llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(Ty); + if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy)) + return; + + llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV), + TBAAInfo}; + + // Metadata for the global already registered. + if (llvm::MDNode::getIfExists(CGM.getLLVMContext(), GlobalMetadata)) + return; + + llvm::MDNode *ThisGlobal = + llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata); + llvm::NamedMDNode *TysanGlobals = + CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals"); + TysanGlobals->addOperand(ThisGlobal); } void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, bool IsDynInit) { - if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize)) + if (!isAsanHwasanMemTagOrTysan(CGM.getLangOpts().Sanitize)) return; std::string QualName; llvm::raw_string_ostream OS(QualName); diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 6ba13d7341169..dc84c1b9d1cc4 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1165,6 +1165,34 @@ bool Driver::loadConfigFiles() { return false; } +static bool findTripleConfigFile(llvm::cl::ExpansionContext &ExpCtx, + SmallString<128> &ConfigFilePath, + llvm::Triple Triple, std::string Suffix) { + // First, try the full unmodified triple. + if (ExpCtx.findConfigFile(Triple.str() + Suffix, ConfigFilePath)) + return true; + + // Don't continue if we didn't find a parsable version in the triple. + VersionTuple OSVersion = Triple.getOSVersion(); + if (!OSVersion.getMinor().has_value()) + return false; + + std::string BaseOSName = Triple.getOSTypeName(Triple.getOS()).str(); + + // Next try strip the version to only include the major component. + // e.g. arm64-apple-darwin23.6.0 -> arm64-apple-darwin23 + if (OSVersion.getMajor() != 0) { + Triple.setOSName(BaseOSName + llvm::utostr(OSVersion.getMajor())); + if (ExpCtx.findConfigFile(Triple.str() + Suffix, ConfigFilePath)) + return true; + } + + // Finally, try without any version suffix at all. + // e.g. arm64-apple-darwin23.6.0 -> arm64-apple-darwin + Triple.setOSName(BaseOSName); + return ExpCtx.findConfigFile(Triple.str() + Suffix, ConfigFilePath); +} + bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) { // Disable default config if CLANG_NO_DEFAULT_CONFIG is set to a non-empty // value. @@ -1176,7 +1204,7 @@ bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) { return false; std::string RealMode = getExecutableForDriverMode(Mode); - std::string Triple; + llvm::Triple Triple; // If name prefix is present, no --target= override was passed via CLOptions // and the name prefix is not a valid triple, force it for backwards @@ -1187,15 +1215,13 @@ bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) { llvm::Triple PrefixTriple{ClangNameParts.TargetPrefix}; if (PrefixTriple.getArch() == llvm::Triple::UnknownArch || PrefixTriple.isOSUnknown()) - Triple = PrefixTriple.str(); + Triple = PrefixTriple; } // Otherwise, use the real triple as used by the driver. - if (Triple.empty()) { - llvm::Triple RealTriple = - computeTargetTriple(*this, TargetTriple, *CLOptions); - Triple = RealTriple.str(); - assert(!Triple.empty()); + if (Triple.str().empty()) { + Triple = computeTargetTriple(*this, TargetTriple, *CLOptions); + assert(!Triple.str().empty()); } // Search for config files in the following order: @@ -1210,21 +1236,21 @@ bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) { // Try loading -.cfg, and return if we find a match. SmallString<128> CfgFilePath; - std::string CfgFileName = Triple + '-' + RealMode + ".cfg"; - if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + if (findTripleConfigFile(ExpCtx, CfgFilePath, Triple, + "-" + RealMode + ".cfg")) return readConfigFile(CfgFilePath, ExpCtx); bool TryModeSuffix = !ClangNameParts.ModeSuffix.empty() && ClangNameParts.ModeSuffix != RealMode; if (TryModeSuffix) { - CfgFileName = Triple + '-' + ClangNameParts.ModeSuffix + ".cfg"; - if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + if (findTripleConfigFile(ExpCtx, CfgFilePath, Triple, + "-" + ClangNameParts.ModeSuffix + ".cfg")) return readConfigFile(CfgFilePath, ExpCtx); } // Try loading .cfg, and return if loading failed. If a matching file // was not found, still proceed on to try .cfg. - CfgFileName = RealMode + ".cfg"; + std::string CfgFileName = RealMode + ".cfg"; if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) { if (readConfigFile(CfgFilePath, ExpCtx)) return true; @@ -1236,8 +1262,7 @@ bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) { } // Try loading .cfg and return if we find a match. - CfgFileName = Triple + ".cfg"; - if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + if (findTripleConfigFile(ExpCtx, CfgFilePath, Triple, ".cfg")) return readConfigFile(CfgFilePath, ExpCtx); // If we were unable to find a config file deduced from executable name, @@ -5815,15 +5840,10 @@ InputInfoList Driver::BuildJobsForActionNoCache( } } else { if (UnbundlingResults.empty()) - T->ConstructJob( - C, *JA, Result, InputInfos, - C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), - LinkingOutput); + T->ConstructJob(C, *JA, Result, InputInfos, Args, LinkingOutput); else - T->ConstructJobMultipleOutputs( - C, *JA, UnbundlingResults, InputInfos, - C.getArgsForToolChain(TC, BoundArch, JA->getOffloadingDeviceKind()), - LinkingOutput); + T->ConstructJobMultipleOutputs(C, *JA, UnbundlingResults, InputInfos, + Args, LinkingOutput); } return {Result}; } diff --git a/clang/lib/Driver/DriverOptions.cpp b/clang/lib/Driver/DriverOptions.cpp index 053e7f1c6404f..cde1f8989935b 100644 --- a/clang/lib/Driver/DriverOptions.cpp +++ b/clang/lib/Driver/DriverOptions.cpp @@ -14,24 +14,21 @@ using namespace clang::driver; using namespace clang::driver::options; using namespace llvm::opt; +#define OPTTABLE_STR_TABLE_CODE +#include "clang/Driver/Options.inc" +#undef OPTTABLE_STR_TABLE_CODE + #define OPTTABLE_VALUES_CODE #include "clang/Driver/Options.inc" #undef OPTTABLE_VALUES_CODE -#define PREFIX(NAME, VALUE) \ - static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \ - static constexpr llvm::ArrayRef NAME( \ - NAME##_init, std::size(NAME##_init) - 1); +#define OPTTABLE_PREFIXES_TABLE_CODE #include "clang/Driver/Options.inc" -#undef PREFIX +#undef OPTTABLE_PREFIXES_TABLE_CODE -static constexpr const llvm::StringLiteral PrefixTable_init[] = -#define PREFIX_UNION(VALUES) VALUES +#define OPTTABLE_PREFIXES_UNION_CODE #include "clang/Driver/Options.inc" -#undef PREFIX_UNION - ; -static constexpr const llvm::ArrayRef - PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1); +#undef OPTTABLE_PREFIXES_UNION_CODE static constexpr OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), @@ -43,7 +40,9 @@ namespace { class DriverOptTable : public PrecomputedOptTable { public: - DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {} + DriverOptTable() + : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable, + OptionPrefixesUnion) {} }; } diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 1abfe8fd92807..595bfb45f97f4 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -37,15 +37,15 @@ static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr; static const SanitizerMask NotAllowedWithExecuteOnly = SanitizerKind::Function | SanitizerKind::KCFI; static const SanitizerMask NeedsUnwindTables = - SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread | - SanitizerKind::Memory | SanitizerKind::DataFlow | + SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | + SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow | SanitizerKind::NumericalStability; static const SanitizerMask SupportsCoverage = SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress | - SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap | - SanitizerKind::MemtagGlobals | SanitizerKind::Memory | - SanitizerKind::KernelMemory | SanitizerKind::Leak | + SanitizerKind::Type | SanitizerKind::MemtagStack | + SanitizerKind::MemtagHeap | SanitizerKind::MemtagGlobals | + SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak | SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::DataFlow | SanitizerKind::Fuzzer | @@ -68,6 +68,7 @@ static const SanitizerMask TrappingSupported = SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::LocalBounds | SanitizerKind::CFI | SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast; +static const SanitizerMask MergeDefault = SanitizerKind::Undefined; static const SanitizerMask TrappingDefault = SanitizerKind::CFI; static const SanitizerMask CFIClasses = SanitizerKind::CFIVCall | SanitizerKind::CFINVCall | @@ -182,6 +183,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, {"msan_ignorelist.txt", SanitizerKind::Memory}, {"nsan_ignorelist.txt", SanitizerKind::NumericalStability}, {"tsan_ignorelist.txt", SanitizerKind::Thread}, + {"tysan_blacklist.txt", SanitizerKind::Type}, {"dfsan_abilist.txt", SanitizerKind::DataFlow}, {"cfi_ignorelist.txt", SanitizerKind::CFI}, {"ubsan_ignorelist.txt", @@ -247,39 +249,77 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) { return Kinds; } -static SanitizerMask parseSanitizeTrapArgs(const Driver &D, - const llvm::opt::ArgList &Args, - bool DiagnoseErrors) { - SanitizerMask TrapRemove; // During the loop below, the accumulated set of - // sanitizers disabled by the current sanitizer - // argument or any argument after it. - SanitizerMask TrappingKinds; - SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported); - - for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) { - if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) { +// Computes the sanitizer mask as: +// Default + Arguments (in or out) +// with arguments parsed from left to right. +// +// Error messages are printed if the AlwaysIn or AlwaysOut invariants are +// violated, but the caller must enforce these invariants themselves. +static SanitizerMask +parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args, + bool DiagnoseErrors, SanitizerMask Default, + SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID, + int OptOutID) { + assert(!(AlwaysIn & AlwaysOut) && + "parseSanitizeArgs called with contradictory in/out requirements"); + + SanitizerMask Output = Default; + // Keep track of which violations we have already reported, to avoid + // duplicate error messages. + SanitizerMask DiagnosedAlwaysInViolations; + SanitizerMask DiagnosedAlwaysOutViolations; + for (const auto *Arg : Args) { + if (Arg->getOption().matches(OptInID)) { + SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors); + // Report error if user explicitly tries to opt-in to an always-out + // sanitizer. + if (SanitizerMask KindsToDiagnose = + Add & AlwaysOut & ~DiagnosedAlwaysOutViolations) { + if (DiagnoseErrors) { + SanitizerSet SetToDiagnose; + SetToDiagnose.Mask |= KindsToDiagnose; + D.Diag(diag::err_drv_unsupported_option_argument) + << Arg->getSpelling() << toString(SetToDiagnose); + DiagnosedAlwaysOutViolations |= KindsToDiagnose; + } + } + Output |= expandSanitizerGroups(Add); Arg->claim(); - SanitizerMask Add = parseArgValues(D, Arg, true); - Add &= ~TrapRemove; - SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups; - if (InvalidValues && DiagnoseErrors) { - SanitizerSet S; - S.Mask = InvalidValues; - D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getSpelling() << toString(S); + } else if (Arg->getOption().matches(OptOutID)) { + SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors); + // Report error if user explicitly tries to opt-out of an always-in + // sanitizer. + if (SanitizerMask KindsToDiagnose = + Remove & AlwaysIn & ~DiagnosedAlwaysInViolations) { + if (DiagnoseErrors) { + SanitizerSet SetToDiagnose; + SetToDiagnose.Mask |= KindsToDiagnose; + D.Diag(diag::err_drv_unsupported_option_argument) + << Arg->getSpelling() << toString(SetToDiagnose); + DiagnosedAlwaysInViolations |= KindsToDiagnose; + } } - TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; - } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { + Output &= ~expandSanitizerGroups(Remove); Arg->claim(); - TrapRemove |= - expandSanitizerGroups(parseArgValues(D, Arg, DiagnoseErrors)); } } - // Apply default trapping behavior. - TrappingKinds |= TrappingDefault & ~TrapRemove; + return Output; +} - return TrappingKinds; +static SanitizerMask parseSanitizeTrapArgs(const Driver &D, + const llvm::opt::ArgList &Args, + bool DiagnoseErrors) { + SanitizerMask AlwaysTrap; // Empty + SanitizerMask NeverTrap = ~(setGroupBits(TrappingSupported)); + + // N.B. We do *not* enforce NeverTrap. This maintains the behavior of + // '-fsanitize=undefined -fsanitize-trap=undefined' + // (clang/test/Driver/fsanitize.c ), which is that vptr is not enabled at all + // (not even in recover mode) in order to avoid the need for a ubsan runtime. + return parseSanitizeArgs(D, Args, DiagnoseErrors, TrappingDefault, AlwaysTrap, + NeverTrap, options::OPT_fsanitize_trap_EQ, + options::OPT_fno_sanitize_trap_EQ); } bool SanitizerArgs::needsFuzzerInterceptors() const { @@ -418,8 +458,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Add & NotAllowedWithExecuteOnly & ~DiagnosedKinds) { if (DiagnoseErrors) { std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose); - D.Diag(diag::err_drv_argument_not_allowed_with) - << Desc << Triple.str(); + llvm::opt::Arg *A = Args.getLastArgNoClaim( + options::OPT_mexecute_only, options::OPT_mno_execute_only); + if (A && A->getOption().matches(options::OPT_mexecute_only)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << Desc << A->getAsString(Args); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Desc << Triple.str(); } DiagnosedKinds |= KindsToDiagnose; } @@ -526,6 +572,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, std::pair IncompatibleGroups[] = { std::make_pair(SanitizerKind::Address, SanitizerKind::Thread | SanitizerKind::Memory), + std::make_pair(SanitizerKind::Type, + SanitizerKind::Address | SanitizerKind::KernelAddress | + SanitizerKind::Memory | SanitizerKind::Leak | + SanitizerKind::Thread | SanitizerKind::KernelAddress), std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory), std::make_pair(SanitizerKind::Leak, SanitizerKind::Thread | SanitizerKind::Memory), @@ -636,48 +686,24 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // default in ASan? // Parse -f(no-)?sanitize-recover flags. - SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable; - SanitizerMask DiagnosedUnrecoverableKinds; - SanitizerMask DiagnosedAlwaysRecoverableKinds; - for (const auto *Arg : Args) { - if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) { - SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors); - // Report error if user explicitly tries to recover from unrecoverable - // sanitizer. - if (SanitizerMask KindsToDiagnose = - Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { - SanitizerSet SetToDiagnose; - SetToDiagnose.Mask |= KindsToDiagnose; - if (DiagnoseErrors) - D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getSpelling() << toString(SetToDiagnose); - DiagnosedUnrecoverableKinds |= KindsToDiagnose; - } - RecoverableKinds |= expandSanitizerGroups(Add); - Arg->claim(); - } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) { - SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors); - // Report error if user explicitly tries to disable recovery from - // always recoverable sanitizer. - if (SanitizerMask KindsToDiagnose = - Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) { - SanitizerSet SetToDiagnose; - SetToDiagnose.Mask |= KindsToDiagnose; - if (DiagnoseErrors) - D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getSpelling() << toString(SetToDiagnose); - DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose; - } - RecoverableKinds &= ~expandSanitizerGroups(Remove); - Arg->claim(); - } - } - RecoverableKinds &= Kinds; + SanitizerMask RecoverableKinds = parseSanitizeArgs( + D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable, + Unrecoverable, options::OPT_fsanitize_recover_EQ, + options::OPT_fno_sanitize_recover_EQ); + RecoverableKinds |= AlwaysRecoverable; RecoverableKinds &= ~Unrecoverable; + RecoverableKinds &= Kinds; TrappingKinds &= Kinds; RecoverableKinds &= ~TrappingKinds; + // Parse -f(no-)?sanitize-nonmerged-handlers flags + SanitizerMask MergeKinds = + parseSanitizeArgs(D, Args, DiagnoseErrors, MergeDefault, {}, {}, + options::OPT_fsanitize_merge_handlers_EQ, + options::OPT_fno_sanitize_merge_handlers_EQ); + MergeKinds &= Kinds; + // Setup ignorelist files. // Add default ignorelist from resource directory for activated sanitizers, // and validate special case lists format. @@ -1095,6 +1121,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, TrapSanitizers.Mask |= TrappingKinds; assert(!(RecoverableKinds & TrappingKinds) && "Overlap between recoverable and trapping sanitizers"); + + MergeHandlers.Mask |= MergeKinds; } static std::string toString(const clang::SanitizerSet &Sanitizers) { @@ -1256,6 +1284,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, CmdArgs.push_back( Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); + if (!MergeHandlers.empty()) + CmdArgs.push_back( + Args.MakeArgString("-fsanitize-merge=" + toString(MergeHandlers))); + addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-ignorelist=", UserIgnorelistFiles); addSpecialCaseListOpt(Args, CmdArgs, @@ -1423,13 +1455,16 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors) { - assert((A->getOption().matches(options::OPT_fsanitize_EQ) || - A->getOption().matches(options::OPT_fno_sanitize_EQ) || - A->getOption().matches(options::OPT_fsanitize_recover_EQ) || - A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) || - A->getOption().matches(options::OPT_fsanitize_trap_EQ) || - A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) && - "Invalid argument in parseArgValues!"); + assert( + (A->getOption().matches(options::OPT_fsanitize_EQ) || + A->getOption().matches(options::OPT_fno_sanitize_EQ) || + A->getOption().matches(options::OPT_fsanitize_recover_EQ) || + A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) || + A->getOption().matches(options::OPT_fsanitize_trap_EQ) || + A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) || + A->getOption().matches(options::OPT_fsanitize_merge_handlers_EQ) || + A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ)) && + "Invalid argument in parseArgValues!"); SanitizerMask Kinds; for (int i = 0, n = A->getNumValues(); i != n; ++i) { const char *Value = A->getValue(i); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 7ef55a33547c5..a020e00cd1739 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3773,11 +3773,13 @@ static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple(); - if (!EffectiveTriple.isOSFreeBSD() && !EffectiveTriple.isOSLinux()) + if (!EffectiveTriple.isOSFreeBSD() && !EffectiveTriple.isOSLinux() && + !EffectiveTriple.isOSFuchsia()) return; if (!EffectiveTriple.isX86() && !EffectiveTriple.isSystemZ() && - !EffectiveTriple.isPPC64() && !EffectiveTriple.isAArch64()) + !EffectiveTriple.isPPC64() && !EffectiveTriple.isAArch64() && + !EffectiveTriple.isRISCV()) return; Args.addOptInFlag(CmdArgs, options::OPT_fstack_clash_protection, @@ -4260,7 +4262,7 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D, if (Args.hasArg(options::OPT_modules_reduced_bmi) && (Input.getType() == driver::types::TY_CXXModule || Input.getType() == driver::types::TY_PP_CXXModule)) { - CmdArgs.push_back("-fexperimental-modules-reduced-bmi"); + CmdArgs.push_back("-fmodules-reduced-bmi"); if (Args.hasArg(options::OPT_fmodule_output_EQ)) Args.AddLastArg(CmdArgs, options::OPT_fmodule_output_EQ); @@ -4270,7 +4272,7 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D, getCXX20NamedModuleOutputPath(Args, Input.getBaseInput()))); } - // Noop if we see '-fexperimental-modules-reduced-bmi' with other translation + // Noop if we see '-fmodules-reduced-bmi' with other translation // units than module units. This is more user friendly to allow end uers to // enable this feature without asking for help from build systems. Args.ClaimAllArgs(options::OPT_modules_reduced_bmi); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 03dbdc27975b4..47df650e5b948 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -494,6 +494,39 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, else A.renderAsInput(Args, CmdArgs); } + if (const Arg *A = Args.getLastArg(options::OPT_fveclib)) { + const llvm::Triple &Triple = TC.getTriple(); + StringRef V = A->getValue(); + if (V == "ArmPL" && (Triple.isOSLinux() || Triple.isOSDarwin())) { + // To support -fveclib=ArmPL we need to link against libamath. Some of the + // libamath functions depend on libm, at the same time, libamath exports + // its own implementation of some of the libm functions. These are faster + // and potentially less accurate implementations, hence we need to be + // careful what is being linked in. Since here we are interested only in + // the subset of libamath functions that is covered by the veclib + // mappings, we need to prioritize libm functions by putting -lm before + // -lamath (and then -lm again, to fulfill libamath requirements). + // + // Therefore we need to do the following: + // + // 1. On Linux, link only when actually needed. + // + // 2. Prefer libm functions over libamath. + // + // 3. Link against libm to resolve libamath dependencies. + // + if (Triple.isOSLinux()) { + CmdArgs.push_back(Args.MakeArgString("--push-state")); + CmdArgs.push_back(Args.MakeArgString("--as-needed")); + } + CmdArgs.push_back(Args.MakeArgString("-lm")); + CmdArgs.push_back(Args.MakeArgString("-lamath")); + CmdArgs.push_back(Args.MakeArgString("-lm")); + if (Triple.isOSLinux()) + CmdArgs.push_back(Args.MakeArgString("--pop-state")); + addArchSpecificRPath(TC, Args, CmdArgs); + } + } } void tools::addLinkerCompressDebugSectionsOption( @@ -1410,7 +1443,7 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, // libresolv.a, even if exists, is an empty archive to satisfy POSIX -lresolv // requirement. if (TC.getTriple().isOSLinux() && !TC.getTriple().isAndroid() && - !TC.getTriple().isMusl() && TC.getSanitizerArgs(Args).needsMsanRt()) + !TC.getTriple().isMusl()) CmdArgs.push_back("-lresolv"); } @@ -1447,6 +1480,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, } if (SanArgs.needsTsanRt()) SharedRuntimes.push_back("tsan"); + if (SanArgs.needsTysanRt()) + SharedRuntimes.push_back("tysan"); if (SanArgs.needsHwasanRt()) { if (SanArgs.needsHwasanAliasesRt()) SharedRuntimes.push_back("hwasan_aliases"); @@ -1519,6 +1554,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("tsan_cxx"); } + if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt()) + StaticRuntimes.push_back("tysan"); if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("ubsan_minimal"); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 87380869f6fda..4105d38d15d7d 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -430,13 +430,17 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, // Give --sysroot= preference, over the Apple specific behavior to also use // --isysroot as the syslibroot. - StringRef sysroot = C.getSysRoot(); - if (sysroot != "") { + // We check `OPT__sysroot_EQ` directly instead of `getSysRoot` to make sure we + // prioritise command line arguments over configuration of `DEFAULT_SYSROOT`. + if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) { CmdArgs.push_back("-syslibroot"); - CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); + CmdArgs.push_back(A->getValue()); } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { CmdArgs.push_back("-syslibroot"); CmdArgs.push_back(A->getValue()); + } else if (StringRef sysroot = C.getSysRoot(); sysroot != "") { + CmdArgs.push_back("-syslibroot"); + CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); } Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); @@ -1596,6 +1600,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, "Static sanitizer runtimes not supported"); AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); } + if (Sanitize.needsTysanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "tysan"); if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); @@ -3599,6 +3605,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const { Res |= SanitizerKind::Thread; } + if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) { + Res |= SanitizerKind::Type; + } + if (IsX86_64) Res |= SanitizerKind::NumericalStability; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 9186647b09c88..7034e5b475c1d 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -55,7 +55,9 @@ void Flang::addFortranDialectOptions(const ArgList &Args, options::OPT_fdefault_double_8, options::OPT_flarge_sizes, options::OPT_fno_automatic, - options::OPT_fhermetic_module_files}); + options::OPT_fhermetic_module_files, + options::OPT_frealloc_lhs, + options::OPT_fno_realloc_lhs}); } void Flang::addPreprocessingOptions(const ArgList &Args, @@ -120,7 +122,8 @@ void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { options::OPT_fintrinsic_modules_path, options::OPT_pedantic, options::OPT_std_EQ, options::OPT_W_Joined, options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ, - options::OPT_funderscoring, options::OPT_fno_underscoring}); + options::OPT_funderscoring, options::OPT_fno_underscoring, + options::OPT_funsigned, options::OPT_fno_unsigned}); llvm::codegenoptions::DebugInfoKind DebugInfoKind; if (Args.hasArg(options::OPT_gN_Group)) { @@ -148,7 +151,6 @@ void Flang::addCodegenOptions(const ArgList &Args, Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir, options::OPT_flang_deprecated_no_hlfir, - options::OPT_flang_experimental_integer_overflow, options::OPT_fno_ppc_native_vec_elem_order, options::OPT_fppc_native_vec_elem_order}); } diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index 3d744bc087f46..be44fc4fe1a84 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -213,6 +213,14 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-m"); CmdArgs.push_back("elf64lriscv"); break; + case llvm::Triple::loongarch32: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf32loongarch"); + break; + case llvm::Triple::loongarch64: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf64loongarch"); + break; default: break; } @@ -223,6 +231,12 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--no-relax"); } + if (Triple.isLoongArch64()) { + CmdArgs.push_back("-X"); + if (Args.hasArg(options::OPT_mno_relax)) + CmdArgs.push_back("--no-relax"); + } + if (Arg *A = Args.getLastArg(options::OPT_G)) { if (ToolChain.getTriple().isMIPS()) { StringRef v = A->getValue(); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 46962e88d4550..c91b55b5a2948 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -837,6 +837,8 @@ SanitizerMask Linux::getSupportedSanitizers() const { if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ || IsLoongArch64 || IsRISCV64) Res |= SanitizerKind::Thread; + if (IsX86_64 || IsAArch64) + Res |= SanitizerKind::Type; if (IsX86_64 || IsSystemZ || IsPowerPC64) Res |= SanitizerKind::KernelMemory; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 80799d1e715f0..752c2e2751ab6 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -84,6 +84,12 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, else if (TC.getTriple().isWindowsArm64EC()) CmdArgs.push_back("-machine:arm64ec"); + if (const Arg *A = Args.getLastArg(options::OPT_fveclib)) { + StringRef V = A->getValue(); + if (V == "ArmPL") + CmdArgs.push_back(Args.MakeArgString("--dependent-lib=amath")); + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { CmdArgs.push_back("-defaultlib:libcmt"); diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp index de5c38ebc3abb..f8c213334a2b4 100644 --- a/clang/lib/Driver/XRayArgs.cpp +++ b/clang/lib/Driver/XRayArgs.cpp @@ -51,6 +51,8 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::systemz: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: break; default: D.Diag(diag::err_drv_unsupported_opt_for_target) diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index c730c062b6a1d..e881d56258e5e 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -1067,9 +1067,8 @@ void SymbolGraphSerializer::serializeWithExtensionGraphs( for (auto &ExtensionSGF : Serializer.ExtendedModules) { if (auto ExtensionOS = - CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName)) - Serializer.serializeGraphToStream(*ExtensionOS, Options, - ExtensionSGF.getKey(), + CreateOutputStream(API.ProductName + "@" + ExtensionSGF.getKey())) + Serializer.serializeGraphToStream(*ExtensionOS, Options, API.ProductName, std::move(ExtensionSGF.getValue())); } } diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index aed86c1fb9955..554b55fa75c92 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -461,9 +461,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { getColumnLimit(State) || CurrentState.BreakBeforeParameter) && (!Current.isTrailingComment() || Current.NewlinesBefore > 0) && - (Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All || - Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon || - Style.ColumnLimit != 0)) { + (Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon || + Style.ColumnLimit > 0 || Current.NewlinesBefore > 0)) { return true; } @@ -826,8 +825,10 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, for (const auto *Prev = &Tok; Prev; Prev = Prev->Previous) { if (Prev->is(TT_TemplateString) && Prev->opensScope()) return true; - if (Prev->is(TT_TemplateString) && Prev->closesScope()) + if (Prev->opensScope() || + (Prev->is(TT_TemplateString) && Prev->closesScope())) { break; + } } return false; }; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 49482973223c6..6a8caa23753f3 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -492,7 +492,8 @@ class AnnotatingParser { ProbablyFunctionType && CurrentToken->Next && (CurrentToken->Next->is(tok::l_paren) || (CurrentToken->Next->is(tok::l_square) && - Line.MustBeDeclaration))) { + (Line.MustBeDeclaration || + PrevNonComment->isTypeName(LangOpts))))) { OpeningParen.setType(OpeningParen.Next->is(tok::caret) ? TT_ObjCBlockLParen : TT_FunctionTypeLParen); @@ -2403,7 +2404,8 @@ class AnnotatingParser { // not auto operator->() -> xxx; Current.setType(TT_TrailingReturnArrow); } else if (Current.is(tok::arrow) && Current.Previous && - Current.Previous->is(tok::r_brace)) { + Current.Previous->is(tok::r_brace) && + Current.Previous->is(BK_Block)) { // Concept implicit conversion constraint needs to be treated like // a trailing return type ... } -> . Current.setType(TT_TrailingReturnArrow); @@ -6110,6 +6112,35 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return false; } + // We can break before an r_brace if there was a break after the matching + // l_brace, which is tracked by BreakBeforeClosingBrace, or if we are in a + // block-indented initialization list. + if (Right.is(tok::r_brace)) { + return Right.MatchingParen && (Right.MatchingParen->is(BK_Block) || + (Right.isBlockIndentedInitRBrace(Style))); + } + + // We only break before r_paren if we're in a block indented context. + if (Right.is(tok::r_paren)) { + if (Style.AlignAfterOpenBracket != FormatStyle::BAS_BlockIndent || + !Right.MatchingParen) { + return false; + } + auto Next = Right.Next; + if (Next && Next->is(tok::r_paren)) + Next = Next->Next; + if (Next && Next->is(tok::l_paren)) + return false; + const FormatToken *Previous = Right.MatchingParen->Previous; + return !(Previous && (Previous->is(tok::kw_for) || Previous->isIf())); + } + + if (Left.isOneOf(tok::r_paren, TT_TrailingAnnotation) && + Right.is(TT_TrailingAnnotation) && + Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) { + return false; + } + if (Left.is(tok::at)) return false; if (Left.Tok.getObjCKeywordID() == tok::objc_interface) @@ -6265,34 +6296,6 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return false; } - // We only break before r_brace if there was a corresponding break before - // the l_brace, which is tracked by BreakBeforeClosingBrace. - if (Right.is(tok::r_brace)) { - return Right.MatchingParen && (Right.MatchingParen->is(BK_Block) || - (Right.isBlockIndentedInitRBrace(Style))); - } - - // We only break before r_paren if we're in a block indented context. - if (Right.is(tok::r_paren)) { - if (Style.AlignAfterOpenBracket != FormatStyle::BAS_BlockIndent || - !Right.MatchingParen) { - return false; - } - auto Next = Right.Next; - if (Next && Next->is(tok::r_paren)) - Next = Next->Next; - if (Next && Next->is(tok::l_paren)) - return false; - const FormatToken *Previous = Right.MatchingParen->Previous; - return !(Previous && (Previous->is(tok::kw_for) || Previous->isIf())); - } - - if (Left.isOneOf(tok::r_paren, TT_TrailingAnnotation) && - Right.is(TT_TrailingAnnotation) && - Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) { - return false; - } - // Allow breaking after a trailing annotation, e.g. after a method // declaration. if (Left.is(TT_TrailingAnnotation)) { diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index c182aaf0876d1..654148a161bd7 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -512,7 +512,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { break; do { NextTok = Tokens->getNextToken(); - } while (NextTok->NewlinesBefore == 0 && NextTok->isNot(tok::eof)); + } while (!NextTok->HasUnescapedNewline && NextTok->isNot(tok::eof)); while (NextTok->is(tok::comment)) NextTok = Tokens->getNextToken(); @@ -570,8 +570,9 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, Keywords.kw_as)); ProbablyBracedList = - ProbablyBracedList || (IsCpp && (PrevTok->Tok.isLiteral() || - NextTok->is(tok::l_paren))); + ProbablyBracedList || + (IsCpp && (PrevTok->Tok.isLiteral() || + NextTok->isOneOf(tok::l_paren, tok::arrow))); // If there is a comma, semicolon or right paren after the closing // brace, we assume this is a braced initializer list. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 98136b7a455d9..348c56cc37da3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -277,6 +277,14 @@ CowCompilerInvocation::getMutPreprocessorOutputOpts() { using ArgumentConsumer = CompilerInvocation::ArgumentConsumer; +#define OPTTABLE_STR_TABLE_CODE +#include "clang/Driver/Options.inc" +#undef OPTTABLE_STR_TABLE_CODE + +static llvm::StringRef lookupStrInTable(unsigned Offset) { + return &OptionStrTable[Offset]; +} + #define SIMPLE_ENUM_VALUE_TABLE #include "clang/Driver/Options.inc" #undef SIMPLE_ENUM_VALUE_TABLE @@ -303,6 +311,11 @@ static std::optional normalizeSimpleNegativeFlag(OptSpecifier Opt, /// denormalizeSimpleFlags never looks at it. Avoid bloating compile-time with /// unnecessary template instantiations and just ignore it with a variadic /// argument. +static void denormalizeSimpleFlag(ArgumentConsumer Consumer, + unsigned SpellingOffset, Option::OptionClass, + unsigned, /*T*/...) { + Consumer(lookupStrInTable(SpellingOffset)); +} static void denormalizeSimpleFlag(ArgumentConsumer Consumer, const Twine &Spelling, Option::OptionClass, unsigned, /*T*/...) { @@ -343,10 +356,10 @@ static auto makeBooleanOptionNormalizer(bool Value, bool OtherValue, } static auto makeBooleanOptionDenormalizer(bool Value) { - return [Value](ArgumentConsumer Consumer, const Twine &Spelling, + return [Value](ArgumentConsumer Consumer, unsigned SpellingOffset, Option::OptionClass, unsigned, bool KeyPath) { if (KeyPath == Value) - Consumer(Spelling); + Consumer(lookupStrInTable(SpellingOffset)); }; } @@ -371,6 +384,14 @@ static void denormalizeStringImpl(ArgumentConsumer Consumer, } } +template +static void +denormalizeString(ArgumentConsumer Consumer, unsigned SpellingOffset, + Option::OptionClass OptClass, unsigned TableIndex, T Value) { + denormalizeStringImpl(Consumer, lookupStrInTable(SpellingOffset), OptClass, + TableIndex, Twine(Value)); +} + template static void denormalizeString(ArgumentConsumer Consumer, const Twine &Spelling, Option::OptionClass OptClass, unsigned TableIndex, @@ -417,14 +438,14 @@ static std::optional normalizeSimpleEnum(OptSpecifier Opt, } static void denormalizeSimpleEnumImpl(ArgumentConsumer Consumer, - const Twine &Spelling, + unsigned SpellingOffset, Option::OptionClass OptClass, unsigned TableIndex, unsigned Value) { assert(TableIndex < SimpleEnumValueTablesSize); const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex]; if (auto MaybeEnumVal = findValueTableByValue(Table, Value)) { - denormalizeString(Consumer, Spelling, OptClass, TableIndex, - MaybeEnumVal->Name); + denormalizeString(Consumer, lookupStrInTable(SpellingOffset), OptClass, + TableIndex, MaybeEnumVal->Name); } else { llvm_unreachable("The simple enum value was not correctly defined in " "the tablegen option description"); @@ -433,11 +454,11 @@ static void denormalizeSimpleEnumImpl(ArgumentConsumer Consumer, template static void denormalizeSimpleEnum(ArgumentConsumer Consumer, - const Twine &Spelling, + unsigned SpellingOffset, Option::OptionClass OptClass, unsigned TableIndex, T Value) { - return denormalizeSimpleEnumImpl(Consumer, Spelling, OptClass, TableIndex, - static_cast(Value)); + return denormalizeSimpleEnumImpl(Consumer, SpellingOffset, OptClass, + TableIndex, static_cast(Value)); } static std::optional normalizeString(OptSpecifier Opt, @@ -473,7 +494,7 @@ normalizeStringVector(OptSpecifier Opt, int, const ArgList &Args, } static void denormalizeStringVector(ArgumentConsumer Consumer, - const Twine &Spelling, + unsigned SpellingOffset, Option::OptionClass OptClass, unsigned TableIndex, const std::vector &Values) { @@ -487,15 +508,16 @@ static void denormalizeStringVector(ArgumentConsumer Consumer, CommaJoinedValue.append(Value); } } - denormalizeString(Consumer, Spelling, Option::OptionClass::JoinedClass, - TableIndex, CommaJoinedValue); + denormalizeString(Consumer, SpellingOffset, + Option::OptionClass::JoinedClass, TableIndex, + CommaJoinedValue); break; } case Option::JoinedClass: case Option::SeparateClass: case Option::JoinedOrSeparateClass: for (const std::string &Value : Values) - denormalizeString(Consumer, Spelling, OptClass, TableIndex, Value); + denormalizeString(Consumer, SpellingOffset, OptClass, TableIndex, Value); break; default: llvm_unreachable("Cannot denormalize an option with option class " @@ -532,10 +554,11 @@ static T extractMaskValue(T KeyPath) { } #define PARSE_OPTION_WITH_MARSHALLING( \ - ARGS, DIAGS, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, \ - FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \ - SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, \ - IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ + ARGS, DIAGS, PREFIX_TYPE, SPELLING_OFFSET, ID, KIND, GROUP, ALIAS, \ + ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \ + METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ + IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, \ + TABLE_INDEX) \ if ((VISIBILITY) & options::CC1Option) { \ KEYPATH = MERGER(KEYPATH, DEFAULT_VALUE); \ if (IMPLIED_CHECK) \ @@ -549,8 +572,8 @@ static T extractMaskValue(T KeyPath) { // Capture the extracted value as a lambda argument to avoid potential issues // with lifetime extension of the reference. #define GENERATE_OPTION_WITH_MARSHALLING( \ - CONSUMER, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ - VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \ + CONSUMER, PREFIX_TYPE, SPELLING_OFFSET, ID, KIND, GROUP, ALIAS, ALIASARGS, \ + FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \ SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, \ IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ if ((VISIBILITY) & options::CC1Option) { \ @@ -559,8 +582,8 @@ static T extractMaskValue(T KeyPath) { (Extracted != \ static_cast((IMPLIED_CHECK) ? (IMPLIED_VALUE) \ : (DEFAULT_VALUE)))) \ - DENORMALIZER(CONSUMER, SPELLING, Option::KIND##Class, TABLE_INDEX, \ - Extracted); \ + DENORMALIZER(CONSUMER, SPELLING_OFFSET, Option::KIND##Class, \ + TABLE_INDEX, Extracted); \ }(EXTRACTOR(KEYPATH)); \ } @@ -1769,6 +1792,10 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeTrap)) GenerateArg(Consumer, OPT_fsanitize_trap_EQ, Sanitizer); + for (StringRef Sanitizer : + serializeSanitizerKinds(Opts.SanitizeMergeHandlers)) + GenerateArg(Consumer, OPT_fsanitize_merge_handlers_EQ, Sanitizer); + if (!Opts.EmitVersionIdentMetadata) GenerateArg(Consumer, OPT_Qn); @@ -2246,6 +2273,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, parseSanitizerKinds("-fsanitize-trap=", Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags, Opts.SanitizeTrap); + parseSanitizerKinds("-fsanitize-merge=", + Args.getAllArgValues(OPT_fsanitize_merge_handlers_EQ), + Diags, Opts.SanitizeMergeHandlers); Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); @@ -4234,6 +4264,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, if (TT.getArch() == llvm::Triple::UnknownArch || !(TT.getArch() == llvm::Triple::aarch64 || TT.isPPC() || TT.getArch() == llvm::Triple::systemz || + TT.getArch() == llvm::Triple::loongarch64 || TT.getArch() == llvm::Triple::nvptx || TT.getArch() == llvm::Triple::nvptx64 || TT.getArch() == llvm::Triple::amdgcn || diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index e20feedb840b5..29723b573e771 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -752,6 +752,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_if_consteval", "202106L"); Builder.defineMacro("__cpp_multidimensional_subscript", "202211L"); Builder.defineMacro("__cpp_auto_cast", "202110L"); + Builder.defineMacro("__cpp_explicit_this_parameter", "202110L"); } // We provide those C++23 features as extensions in earlier language modes, so diff --git a/clang/lib/Headers/avx10_2copyintrin.h b/clang/lib/Headers/avx10_2copyintrin.h index 7fc31190781d9..76b8f8ced540d 100644 --- a/clang/lib/Headers/avx10_2copyintrin.h +++ b/clang/lib/Headers/avx10_2copyintrin.h @@ -19,11 +19,43 @@ __attribute__((__always_inline__, __nodebug__, __target__("avx10.2-256"), \ __min_vector_width__(128))) +/// Constructs a 128-bit integer vector, setting the lower 32 bits to the +/// lower 32 bits of the parameter \a __A; the upper bits are zeoroed. +/// +/// \code{.operation} +/// result[31:0] := __A[31:0] +/// result[MAX:32] := 0 +/// \endcode +/// +/// \headerfile +/// +/// This intrinsic corresponds to the VMOVD instruction. +/// +/// \param __A +/// A 128-bit integer vector. +/// \returns A 128-bit integer vector. The lower 32 bits are copied from the +/// parameter \a __A; the upper bits are zeroed. static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_move_epi32(__m128i __A) { return (__m128i)__builtin_shufflevector( (__v4si)__A, (__v4si)_mm_setzero_si128(), 0, 4, 4, 4); } +/// Constructs a 128-bit integer vector, setting the lower 16 bits to the +/// lower 16 bits of the parameter \a __A; the upper bits are zeoroed. +/// +/// \code{.operation} +/// result[15:0] := __A[15:0] +/// result[MAX:16] := 0 +/// \endcode +/// +/// \headerfile +/// +/// This intrinsic corresponds to the VMOVW instruction. +/// +/// \param __A +/// A 128-bit integer vector. +/// \returns A 128-bit integer vector. The lower 16 bits are copied from the +/// parameter \a __A; the upper bits are zeroed. static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_move_epi16(__m128i __A) { return (__m128i)__builtin_shufflevector( (__v8hi)__A, (__v8hi)_mm_setzero_si128(), 0, 8, 8, 8, 8, 8, 8, 8); diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 1126e13600f8a..b745997f1d5a2 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -2241,6 +2241,15 @@ float4 trunc(float4); // Wave* builtins //===----------------------------------------------------------------------===// +/// \brief Returns true if the expression is true in all active lanes in the +/// current wave. +/// +/// \param Val The boolean expression to evaluate. +/// \return True if the expression is true in all lanes. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_all_true) +__attribute__((convergent)) bool WaveActiveAllTrue(bool Val); + /// \brief Returns true if the expression is true in any active lane in the /// current wave. /// diff --git a/clang/lib/Index/FileIndexRecord.cpp b/clang/lib/Index/FileIndexRecord.cpp index f3a5e6b63bbc2..449c33637eb7e 100644 --- a/clang/lib/Index/FileIndexRecord.cpp +++ b/clang/lib/Index/FileIndexRecord.cpp @@ -65,7 +65,7 @@ void FileIndexRecord::print(llvm::raw_ostream &OS, SourceManager &SM) const { OS << ' ' << ND->getDeclName(); } } else { - const auto *MI = DclInfo.DeclOrMacro.get(); + const auto *MI = cast(DclInfo.DeclOrMacro); SourceLocation Loc = SM.getFileLoc(MI->getDefinitionLoc()); PresumedLoc PLoc = SM.getPresumedLoc(Loc); OS << llvm::sys::path::filename(PLoc.getFilename()) << ':' diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp index a7fa6c5e6898e..6c971bf0f381b 100644 --- a/clang/lib/Index/IndexDecl.cpp +++ b/clang/lib/Index/IndexDecl.cpp @@ -665,9 +665,9 @@ class IndexingDeclVisitor : public ConstDeclVisitor { ClassTemplatePartialSpecializationDecl *> Template = D->getSpecializedTemplateOrPartial(); const Decl *SpecializationOf = - Template.is() - ? (Decl *)Template.get() - : Template.get(); + isa(Template) + ? (Decl *)cast(Template) + : cast(Template); if (!D->isThisDeclarationADefinition()) IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); IndexCtx.indexTagDecl( diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 2ec66fe95708e..6c01af55ef3c4 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -722,8 +722,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, EqualLoc); - Actions.ActOnFinishCXXInClassMemberInitializer(MI.Field, EqualLoc, - Init.get()); + Actions.ActOnFinishCXXInClassMemberInitializer(MI.Field, EqualLoc, Init); // The next token should be our artificial terminating EOF token. if (Tok.isNot(tok::eof)) { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 03a58048e53a9..33a90e0cb8a42 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -238,7 +238,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier( else if (!HasScopeSpecifier && Tok.is(tok::identifier) && GetLookAheadToken(1).is(tok::ellipsis) && - GetLookAheadToken(2).is(tok::l_square)) { + GetLookAheadToken(2).is(tok::l_square) && + !GetLookAheadToken(3).is(tok::r_square)) { SourceLocation Start = Tok.getLocation(); DeclSpec DS(AttrFactory); SourceLocation CCLoc; @@ -253,6 +254,19 @@ bool Parser::ParseOptionalCXXScopeSpecifier( if (Type.isNull()) return false; + // C++ [cpp23.dcl.dcl-2]: + // Previously, T...[n] would declare a pack of function parameters. + // T...[n] is now a pack-index-specifier. [...] Valid C++ 2023 code that + // declares a pack of parameters without specifying a declarator-id + // becomes ill-formed. + // + // However, we still treat it as a pack indexing type because the use case + // is fairly rare, to ensure semantic consistency given that we have + // backported this feature to pre-C++26 modes. + if (!Tok.is(tok::coloncolon) && !getLangOpts().CPlusPlus26 && + getCurScope()->isFunctionDeclarationScope()) + Diag(Start, diag::warn_pre_cxx26_ambiguous_pack_indexing_type) << Type; + if (!TryConsumeToken(tok::coloncolon, CCLoc)) { AnnotateExistingIndexedTypeNamePack(ParsedType::make(Type), Start, EndLoc); diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index 4de342b63ed80..443bf2b9ec626 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -280,6 +280,7 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, case ParsedAttr::UnknownAttribute: Diag(Loc, diag::err_unknown_hlsl_semantic) << II; return; + case ParsedAttr::AT_HLSLSV_GroupThreadID: case ParsedAttr::AT_HLSLSV_GroupID: case ParsedAttr::AT_HLSLSV_GroupIndex: case ParsedAttr::AT_HLSLSV_DispatchThreadID: diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index b64c72904b19a..5da34a2f5db92 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -86,10 +86,14 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { if (Tok.is(tok::kw_if)) return OpenACCClauseKind::If; - // 'private' is also a keyword, make sure we pare it correctly. + // 'private' is also a keyword, make sure we parse it correctly. if (Tok.is(tok::kw_private)) return OpenACCClauseKind::Private; + // 'delete' is a keyword, make sure we parse it correctly. + if (Tok.is(tok::kw_delete)) + return OpenACCClauseKind::Delete; + if (!Tok.is(tok::identifier)) return OpenACCClauseKind::Invalid; @@ -567,6 +571,9 @@ void SkipUntilEndOfDirective(Parser &P) { bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) { switch (DirKind) { default: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Wait: return false; case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: @@ -575,6 +582,8 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) { case OpenACCDirectiveKind::SerialLoop: case OpenACCDirectiveKind::KernelsLoop: case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::HostData: return true; } llvm_unreachable("Unhandled directive->assoc stmt"); @@ -592,6 +601,12 @@ unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) { // so that we can diagnose trying to 'break'/'continue' inside of one. return Scope::BreakScope | Scope::ContinueScope | Scope::OpenACCComputeConstructScope; + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::HostData: + case OpenACCDirectiveKind::Wait: + return 0; case OpenACCDirectiveKind::Invalid: llvm_unreachable("Shouldn't be creating a scope for an invalid construct"); default: @@ -985,17 +1000,17 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( // make sure we get the right differentiator. assert(DirKind == OpenACCDirectiveKind::Update); [[fallthrough]]; - case OpenACCClauseKind::Delete: - case OpenACCClauseKind::Detach: case OpenACCClauseKind::Device: case OpenACCClauseKind::DeviceResident: case OpenACCClauseKind::Host: case OpenACCClauseKind::Link: - case OpenACCClauseKind::UseDevice: ParseOpenACCVarList(ClauseKind); break; case OpenACCClauseKind::Attach: + case OpenACCClauseKind::Delete: + case OpenACCClauseKind::Detach: case OpenACCClauseKind::DevicePtr: + case OpenACCClauseKind::UseDevice: ParsedClause.setVarListDetails(ParseOpenACCVarList(ClauseKind), /*IsReadOnly=*/false, /*IsZero=*/false); break; @@ -1275,7 +1290,8 @@ Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) { return Result; } - Result.QueueIdExprs.push_back(Res.first.get()); + if (Res.first.isUsable()) + Result.QueueIdExprs.push_back(Res.first.get()); } return Result; @@ -1409,6 +1425,7 @@ Parser::ParseOpenACCDirective() { SourceLocation StartLoc = ConsumeAnnotationToken(); SourceLocation DirLoc = getCurToken().getLocation(); OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); + Parser::OpenACCWaitParseInfo WaitInfo; getActions().OpenACC().ActOnConstruct(DirKind, DirLoc); @@ -1449,7 +1466,8 @@ Parser::ParseOpenACCDirective() { break; case OpenACCDirectiveKind::Wait: // OpenACC has an optional paren-wrapped 'wait-argument'. - if (ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true).Failed) + WaitInfo = ParseOpenACCWaitArgument(DirLoc, /*IsDirective=*/true); + if (WaitInfo.Failed) T.skipToEnd(); else T.consumeClose(); @@ -1463,8 +1481,14 @@ Parser::ParseOpenACCDirective() { } // Parses the list of clauses, if present, plus set up return value. - OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, DirLoc, - SourceLocation{}, + OpenACCDirectiveParseInfo ParseInfo{DirKind, + StartLoc, + DirLoc, + T.getOpenLocation(), + T.getCloseLocation(), + /*EndLoc=*/SourceLocation{}, + WaitInfo.QueuesLoc, + WaitInfo.getAllExprs(), ParseOpenACCClauseList(DirKind)}; assert(Tok.is(tok::annot_pragma_openacc_end) && @@ -1499,15 +1523,15 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { ParsingOpenACCDirectiveRAII DirScope(*this); OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); - if (getActions().OpenACC().ActOnStartStmtDirective(DirInfo.DirKind, - DirInfo.StartLoc)) + if (getActions().OpenACC().ActOnStartStmtDirective( + DirInfo.DirKind, DirInfo.StartLoc, DirInfo.Clauses)) return StmtError(); StmtResult AssocStmt; - SemaOpenACC::AssociatedStmtRAII AssocStmtRAII(getActions().OpenACC(), - DirInfo.DirKind, DirInfo.DirLoc, - {}, DirInfo.Clauses); if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) { + SemaOpenACC::AssociatedStmtRAII AssocStmtRAII( + getActions().OpenACC(), DirInfo.DirKind, DirInfo.DirLoc, {}, + DirInfo.Clauses); ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false); ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind)); @@ -1516,6 +1540,7 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { } return getActions().OpenACC().ActOnEndStmtDirective( - DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.EndLoc, + DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc, + DirInfo.MiscLoc, DirInfo.Exprs, DirInfo.RParenLoc, DirInfo.EndLoc, DirInfo.Clauses, AssocStmt); } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index b91928063169e..b4e973bc84a7b 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3474,6 +3474,16 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, Clause = ParseOpenMPOMPXAttributesClause(WrongDirective); break; case OMPC_ompx_bare: + if (DKind == llvm::omp::Directive::OMPD_target) { + // Flang splits the combined directives which requires OMPD_target to be + // marked as accepting the `ompx_bare` clause in `OMP.td`. Thus, we need + // to explicitly check whether this clause is applied to an `omp target` + // without `teams` and emit an error. + Diag(Tok, diag::err_omp_unexpected_clause) + << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + ErrorFound = true; + WrongDirective = true; + } if (WrongDirective) Diag(Tok, diag::note_ompx_bare_clause) << getOpenMPClauseName(CKind) << "target teams"; diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 868081292bc32..843fdb4a65cd7 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -367,6 +367,8 @@ static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) { if (Callee->getReturnType()->isReferenceType()) { if (!Callee->getIdentifier()) { auto OO = Callee->getOverloadedOperator(); + if (!Callee->getParent()->hasAttr()) + return false; return OO == OverloadedOperatorKind::OO_Subscript || OO == OverloadedOperatorKind::OO_Star; } @@ -1152,6 +1154,86 @@ static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) { } return false; } +// Result of analyzing the Path for GSLPointer. +enum AnalysisResult { + // Path does not correspond to a GSLPointer. + NotGSLPointer, + + // A relevant case was identified. + Report, + // Stop the entire traversal. + Abandon, + // Skip this step and continue traversing inner AST nodes. + Skip, +}; +// Analyze cases where a GSLPointer is initialized or assigned from a +// temporary owner object. +static AnalysisResult analyzePathForGSLPointer(const IndirectLocalPath &Path, + Local L) { + if (!pathOnlyHandlesGslPointer(Path)) + return NotGSLPointer; + + // At this point, Path represents a series of operations involving a + // GSLPointer, either in the process of initialization or assignment. + + // Note: A LifetimeBoundCall can appear interleaved in this sequence. + // For example: + // const std::string& Ref(const std::string& a [[clang::lifetimebound]]); + // string_view abc = Ref(std::string()); + // The "Path" is [GSLPointerInit, LifetimeboundCall], where "L" is the + // temporary "std::string()" object. We need to check the return type of the + // function with the lifetimebound attribute. + if (Path.back().Kind == IndirectLocalPathEntry::LifetimeBoundCall) { + // The lifetimebound applies to the implicit object parameter of a method. + const FunctionDecl *FD = + llvm::dyn_cast_or_null(Path.back().D); + // The lifetimebound applies to a function parameter. + if (const auto *PD = llvm::dyn_cast(Path.back().D)) + FD = llvm::dyn_cast(PD->getDeclContext()); + + if (isa_and_present(FD)) { + // Constructor case: the parameter is annotated with lifetimebound + // e.g., GSLPointer(const S& s [[clang::lifetimebound]]) + // We still respect this case even the type S is not an owner. + return Report; + } + // Check the return type, e.g. + // const GSLOwner& func(const Foo& foo [[clang::lifetimebound]]) + // GSLPointer func(const Foo& foo [[clang::lifetimebound]]) + if (FD && + ((FD->getReturnType()->isReferenceType() && + isRecordWithAttr(FD->getReturnType()->getPointeeType())) || + isPointerLikeType(FD->getReturnType()))) + return Report; + + return Abandon; + } + + if (isa(L)) { + // We do not want to follow the references when returning a pointer + // originating from a local owner to avoid the following false positive: + // int &p = *localUniquePtr; + // someContainer.add(std::move(localUniquePtr)); + // return p; + if (!pathContainsInit(Path) && isRecordWithAttr(L->getType())) + return Report; + return Abandon; + } + + // The GSLPointer is from a temporary object. + auto *MTE = dyn_cast(L); + + bool IsGslPtrValueFromGslTempOwner = + MTE && !MTE->getExtendingDecl() && + isRecordWithAttr(MTE->getType()); + // Skipping a chain of initializing gsl::Pointer annotated objects. + // We are looking only for the final source to find out if it was + // a local or temporary owner or the address of a local + // variable/param. + if (!IsGslPtrValueFromGslTempOwner) + return Skip; + return Report; +} static bool isAssignmentOperatorLifetimeBound(CXXMethodDecl *CMD) { return CMD && isNormalAssignmentOperator(CMD) && CMD->param_size() == 1 && @@ -1189,27 +1271,17 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity, auto *MTE = dyn_cast(L); - bool IsGslPtrValueFromGslTempOwner = false; - if (pathOnlyHandlesGslPointer(Path)) { - if (isa(L)) { - // We do not want to follow the references when returning a pointer - // originating from a local owner to avoid the following false positive: - // int &p = *localUniquePtr; - // someContainer.add(std::move(localUniquePtr)); - // return p; - if (pathContainsInit(Path) || - !isRecordWithAttr(L->getType())) - return false; - } else { - IsGslPtrValueFromGslTempOwner = - MTE && !MTE->getExtendingDecl() && - isRecordWithAttr(MTE->getType()); - // Skipping a chain of initializing gsl::Pointer annotated objects. - // We are looking only for the final source to find out if it was - // a local or temporary owner or the address of a local variable/param. - if (!IsGslPtrValueFromGslTempOwner) - return true; - } + bool IsGslPtrValueFromGslTempOwner = true; + switch (analyzePathForGSLPointer(Path, L)) { + case Abandon: + return false; + case Skip: + return true; + case NotGSLPointer: + IsGslPtrValueFromGslTempOwner = false; + LLVM_FALLTHROUGH; + case Report: + break; } switch (LK) { diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index ee237ffc4d2b9..47644680b720b 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -1343,8 +1343,7 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { S.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. - } else if (TypeSpecType == TST_int || TypeSpecType == TST_char || - TypeSpecType == TST_bitint) { + } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. if (!S.getLangOpts().CPlusPlus) S.Diag(TSTLoc, diag::ext_integer_complex); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 8e57123c503cb..f3362fb619afc 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -191,6 +191,19 @@ class BuiltinTypeDeclBuilder { return *this; } + BuiltinTypeDeclBuilder &addLoadMethods() { + if (Record->isCompleteDefinition()) + return *this; + + ASTContext &AST = Record->getASTContext(); + IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier); + DeclarationName Load(&II); + // TODO: We also need versions with status for CheckAccessFullyMapped. + addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false); + + return *this; + } + FieldDecl *getResourceHandleField() { auto I = Fields.find("__handle"); assert(I != Fields.end() && @@ -246,6 +259,8 @@ class BuiltinTypeDeclBuilder { BuiltinTypeDeclBuilder &addDecrementCounterMethod(); BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name, bool IsConst, bool IsRef); + BuiltinTypeDeclBuilder &addAppendMethod(); + BuiltinTypeDeclBuilder &addConsumeMethod(); }; struct TemplateParameterListBuilder { @@ -323,9 +338,9 @@ struct TemplateParameterListBuilder { Context, // AST context Builder.Record->getDeclContext(), // DeclContext SourceLocation(), SourceLocation(), - /*depth=*/0, // Depth in the template parameter list - /*position=*/0, // Position in the template parameter list - /*id=*/nullptr, // Identifier for 'T' + /*D=*/0, // Depth in the template parameter list + /*P=*/0, // Position in the template parameter list + /*Id=*/nullptr, // Identifier for 'T' /*Typename=*/true, // Indicates this is a 'typename' or 'class' /*ParameterPack=*/false, // Not a parameter pack /*HasTypeConstraint=*/false // Has no type constraint @@ -443,14 +458,26 @@ struct BuiltinTypeMethodBuilder { llvm::SmallVector StmtsList; // Argument placeholders, inspired by std::placeholder. These are the indices - // of arguments to forward to `callBuiltin`, and additionally `Handle` which - // refers to the resource handle. - enum class PlaceHolder { _0, _1, _2, _3, Handle = 127 }; + // of arguments to forward to `callBuiltin` and other method builder methods. + // Additional special values are: + // Handle - refers to the resource handle. + // LastStmt - refers to the last statement in the method body; referencing + // LastStmt will remove the statement from the method body since + // it will be linked from the new expression being constructed. + enum class PlaceHolder { _0, _1, _2, _3, Handle = 128, LastStmt }; Expr *convertPlaceholder(PlaceHolder PH) { if (PH == PlaceHolder::Handle) return getResourceHandleExpr(); + if (PH == PlaceHolder::LastStmt) { + assert(!StmtsList.empty() && "no statements in the list"); + Stmt *LastStmt = StmtsList.pop_back_val(); + assert(isa(LastStmt) && + "last statement does not have a value"); + return cast(LastStmt)->getExprStmt(); + } + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); ParmVarDecl *ParamDecl = Method->getParamDecl(static_cast(PH)); return DeclRefExpr::Create( @@ -532,6 +559,10 @@ struct BuiltinTypeMethodBuilder { public: ~BuiltinTypeMethodBuilder() { finalizeMethod(); } + BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete; + BuiltinTypeMethodBuilder & + operator=(const BuiltinTypeMethodBuilder &Other) = delete; + Expr *getResourceHandleExpr() { // The first statement added to a method or access to 'this' creates the // declaration. @@ -573,17 +604,25 @@ struct BuiltinTypeMethodBuilder { return *this; } - BuiltinTypeMethodBuilder &dereference() { - assert(!StmtsList.empty() && "Nothing to dereference"); - ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + template + BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS) { + Expr *LHSExpr = convertPlaceholder(LHS); + Expr *RHSExpr = convertPlaceholder(RHS); + Stmt *AssignStmt = BinaryOperator::Create( + DeclBuilder.SemaRef.getASTContext(), LHSExpr, RHSExpr, BO_Assign, + LHSExpr->getType(), ExprValueKind::VK_PRValue, + ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride()); + StmtsList.push_back(AssignStmt); + return *this; + } - Expr *LastExpr = dyn_cast(StmtsList.back()); - assert(LastExpr && "No expression to dereference"); - Expr *Deref = UnaryOperator::Create( - AST, LastExpr, UO_Deref, LastExpr->getType()->getPointeeType(), - VK_PRValue, OK_Ordinary, SourceLocation(), - /*CanOverflow=*/false, FPOptionsOverride()); - StmtsList.pop_back(); + template BuiltinTypeMethodBuilder &dereference(T Ptr) { + Expr *PtrExpr = convertPlaceholder(Ptr); + Expr *Deref = + UnaryOperator::Create(DeclBuilder.SemaRef.getASTContext(), PtrExpr, + UO_Deref, PtrExpr->getType()->getPointeeType(), + VK_PRValue, OK_Ordinary, SourceLocation(), + /*CanOverflow=*/false, FPOptionsOverride()); StmtsList.push_back(Deref); return *this; } @@ -685,7 +724,35 @@ BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name, .addParam("Index", AST.UnsignedIntTy) .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle, PH::_0) - .dereference() + .dereference(PH::LastStmt) + .finalizeMethod(); +} + +BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() { + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + ASTContext &AST = SemaRef.getASTContext(); + QualType ElemTy = getHandleElementType(); + return BuiltinTypeMethodBuilder(*this, "Append", AST.VoidTy) + .addParam("value", ElemTy) + .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy, + PH::Handle, getConstantIntExpr(1)) + .callBuiltin("__builtin_hlsl_resource_getpointer", + AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt) + .dereference(PH::LastStmt) + .assign(PH::LastStmt, PH::_0) + .finalizeMethod(); +} + +BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() { + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + ASTContext &AST = SemaRef.getASTContext(); + QualType ElemTy = getHandleElementType(); + return BuiltinTypeMethodBuilder(*this, "Consume", ElemTy) + .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy, + PH::Handle, getConstantIntExpr(-1)) + .callBuiltin("__builtin_hlsl_resource_getpointer", + AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt) + .dereference(PH::LastStmt) .finalizeMethod(); } @@ -801,7 +868,7 @@ static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc, TemplateTypeParmDecl *T) { ASTContext &Context = S.getASTContext(); - // Obtain the QualType for 'unsigned long' + // Obtain the QualType for 'bool' QualType BoolTy = Context.BoolTy; // Create a QualType that points to this TemplateTypeParmDecl @@ -827,9 +894,9 @@ static ConceptDecl *constructTypedBufferConceptDecl(Sema &S, IdentifierInfo &ElementTypeII = Context.Idents.get("element_type"); TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create( Context, NSD->getDeclContext(), DeclLoc, DeclLoc, - /*depth=*/0, - /*position=*/0, - /*id=*/&ElementTypeII, + /*D=*/0, + /*P=*/0, + /*Id=*/&ElementTypeII, /*Typename=*/true, /*ParameterPack=*/false); @@ -871,6 +938,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { ResourceKind::TypedBuffer, /*IsROV=*/false, /*RawBuffer=*/false) .addArraySubscriptOperators() + .addLoadMethods() .completeDefinition(); }); @@ -883,6 +951,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { ResourceKind::TypedBuffer, /*IsROV=*/true, /*RawBuffer=*/false) .addArraySubscriptOperators() + .addLoadMethods() .completeDefinition(); }); @@ -915,6 +984,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer, /*IsROV=*/false, /*RawBuffer=*/true) + .addAppendMethod() .completeDefinition(); }); @@ -925,6 +995,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer, /*IsROV=*/false, /*RawBuffer=*/true) + .addConsumeMethod() .completeDefinition(); }); diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index cd44483b5cbe0..54944267b4868 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -115,6 +115,23 @@ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { return AnyDeclsFound; } +bool MultiplexExternalSemaSource::LoadExternalSpecializations( + const Decl *D, bool OnlyPartial) { + bool Loaded = false; + for (size_t i = 0; i < Sources.size(); ++i) + Loaded |= Sources[i]->LoadExternalSpecializations(D, OnlyPartial); + return Loaded; +} + +bool MultiplexExternalSemaSource::LoadExternalSpecializations( + const Decl *D, ArrayRef TemplateArgs) { + bool AnyNewSpecsLoaded = false; + for (size_t i = 0; i < Sources.size(); ++i) + AnyNewSpecsLoaded |= + Sources[i]->LoadExternalSpecializations(D, TemplateArgs); + return AnyNewSpecsLoaded; +} + void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){ for(size_t i = 0; i < Sources.size(); ++i) Sources[i]->completeVisibleDeclsMap(DC); diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index 0dedfc490c86f..4f79775bc5e91 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -511,6 +511,11 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc, AnyTypeChanged = true; } + // returns_(un)retained + if (!Info.SwiftReturnOwnership.empty()) + D->addAttr(SwiftAttrAttr::Create(S.Context, + "returns_" + Info.SwiftReturnOwnership)); + // Result type override. QualType OverriddenResultType; if (Metadata.IsActive && !Info.ResultType.empty() && diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 479f47962a7c3..44485e71d57a0 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -1310,6 +1310,8 @@ void Sema::AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, } void Sema::AddImplicitMSFunctionNoBuiltinAttr(FunctionDecl *FD) { + if (FD->isDeleted() || FD->isDefaulted()) + return; SmallVector V(MSFunctionNoBuiltins.begin(), MSFunctionNoBuiltins.end()); if (!MSFunctionNoBuiltins.empty()) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 4fd8ef6dbebf8..5d7ee09738377 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7114,6 +7114,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLWaveSize: S.HLSL().handleWaveSizeAttr(D, AL); break; + case ParsedAttr::AT_HLSLSV_GroupThreadID: + S.HLSL().handleSV_GroupThreadIDAttr(D, AL); + break; case ParsedAttr::AT_HLSLSV_GroupID: S.HLSL().handleSV_GroupIDAttr(D, AL); break; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f7a0b3c059ec9..c5a72cf812ebc 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4074,24 +4074,28 @@ ExprResult Sema::ConvertMemberDefaultInitExpression(FieldDecl *FD, void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc, - Expr *InitExpr) { + ExprResult InitExpr) { // Pop the notional constructor scope we created earlier. PopFunctionScopeInfo(nullptr, D); - FieldDecl *FD = dyn_cast(D); - assert((isa(D) || FD->getInClassInitStyle() != ICIS_NoInit) && - "must set init style when field is created"); - - if (!InitExpr) { + // Microsoft C++'s property declaration cannot have a default member + // initializer. + if (isa(D)) { D->setInvalidDecl(); - if (FD) - FD->removeInClassInitializer(); return; } - if (DiagnoseUnexpandedParameterPack(InitExpr, UPPC_Initializer)) { + FieldDecl *FD = dyn_cast(D); + assert((FD && FD->getInClassInitStyle() != ICIS_NoInit) && + "must set init style when field is created"); + + if (!InitExpr.isUsable() || + DiagnoseUnexpandedParameterPack(InitExpr.get(), UPPC_Initializer)) { FD->setInvalidDecl(); - FD->removeInClassInitializer(); + ExprResult RecoveryInit = + CreateRecoveryExpr(InitLoc, InitLoc, {}, FD->getType()); + if (RecoveryInit.isUsable()) + FD->setInClassInitializer(RecoveryInit.get()); return; } @@ -11927,7 +11931,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) { if (TemplateClass->getIdentifier() != &PP.getIdentifierTable().get("initializer_list") || !getStdNamespace()->InEnclosingNamespaceSetOf( - TemplateClass->getDeclContext())) + TemplateClass->getNonTransparentDeclContext())) return false; // This is a template called std::initializer_list, but is it the right // template? diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 6a9f43d6f5215..505cc5e153fa7 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1396,6 +1396,9 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::ConceptSpecializationExprClass: case Expr::RequiresExprClass: case Expr::HLSLOutArgExprClass: + case Stmt::OpenACCEnterDataConstructClass: + case Stmt::OpenACCExitDataConstructClass: + case Stmt::OpenACCWaitConstructClass: // These expressions can never throw. return CT_Cannot; @@ -1407,6 +1410,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OpenACCComputeConstructClass: case Stmt::OpenACCLoopConstructClass: case Stmt::OpenACCCombinedConstructClass: + case Stmt::OpenACCDataConstructClass: + case Stmt::OpenACCHostDataConstructClass: case Stmt::AttributedStmtClass: case Stmt::BreakStmtClass: case Stmt::CapturedStmtClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 14564b99de44c..e06a092177ef0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5587,10 +5587,6 @@ static FieldDecl *FindFieldDeclInstantiationPattern(const ASTContext &Ctx, ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { assert(Field->hasInClassInitializer()); - // If we might have already tried and failed to instantiate, don't try again. - if (Field->isInvalidDecl()) - return ExprError(); - CXXThisScopeRAII This(*this, Field->getParent(), Qualifiers()); auto *ParentRD = cast(Field->getParent()); @@ -5948,7 +5944,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, SmallVector AllArgs; VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn); - Invalid = GatherArgumentsForCall(Call->getBeginLoc(), FDecl, Proto, 0, Args, + Invalid = GatherArgumentsForCall(Call->getExprLoc(), FDecl, Proto, 0, Args, AllArgs, CallType); if (Invalid) return true; @@ -11790,6 +11786,50 @@ static bool checkForArray(const Expr *E) { return D->getType()->isArrayType() && !D->isWeak(); } +/// Detect patterns ptr + size >= ptr and ptr + size < ptr, where ptr is a +/// pointer and size is an unsigned integer. Return whether the result is +/// always true/false. +static std::optional isTautologicalBoundsCheck(const Expr *LHS, + const Expr *RHS, + BinaryOperatorKind Opc) { + if (!LHS->getType()->isPointerType()) + return std::nullopt; + + // Canonicalize to >= or < predicate. + switch (Opc) { + case BO_GE: + case BO_LT: + break; + case BO_GT: + std::swap(LHS, RHS); + Opc = BO_LT; + break; + case BO_LE: + std::swap(LHS, RHS); + Opc = BO_GE; + break; + default: + return std::nullopt; + } + + auto *BO = dyn_cast(LHS); + if (!BO || BO->getOpcode() != BO_Add) + return std::nullopt; + + Expr *Other; + if (Expr::isSameComparisonOperand(BO->getLHS(), RHS)) + Other = BO->getRHS(); + else if (Expr::isSameComparisonOperand(BO->getRHS(), RHS)) + Other = BO->getLHS(); + else + return std::nullopt; + + if (!Other->getType()->isUnsignedIntegerType()) + return std::nullopt; + + return Opc == BO_GE; +} + /// Diagnose some forms of syntactically-obvious tautological comparison. static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, Expr *LHS, Expr *RHS, @@ -11899,6 +11939,12 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, S.PDiag(diag::warn_comparison_always) << 1 /*array comparison*/ << Result); + } else if (std::optional Res = + isTautologicalBoundsCheck(LHS, RHS, Opc)) { + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_comparison_always) + << 2 /*pointer comparison*/ + << (*Res ? AlwaysTrue : AlwaysFalse)); } } @@ -19297,7 +19343,7 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E, if (VD->getType()->isReferenceType()) return true; if (auto *RD = VD->getType()->getAsCXXRecordDecl()) - if (RD->hasMutableFields()) + if (RD->hasDefinition() && RD->hasMutableFields()) return true; if (!VD->isUsableInConstantExpressions(S.Context)) return true; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index caea13b192ad5..e04ece0bda82e 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8201,7 +8201,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, return ExprError(); if (!ObjectType->isDependentType() && !ObjectType->isScalarType() && - !ObjectType->isVectorType()) { + !ObjectType->isVectorType() && !ObjectType->isMatrixType()) { if (getLangOpts().MSVCCompat && ObjectType->isVoidType()) Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange(); else { diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 85d5dfcb3db6d..bcc1b92ffdec7 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1003,15 +1003,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, : !isDependentScopeSpecifier(SS) || computeDeclContext(SS)) && "dependent lookup context that isn't the current instantiation?"); - // C++1z [expr.ref]p2: - // For the first option (dot) the first expression shall be a glvalue [...] - if (!IsArrow && BaseExpr && BaseExpr->isPRValue()) { - ExprResult Converted = TemporaryMaterializationConversion(BaseExpr); - if (Converted.isInvalid()) - return ExprError(); - BaseExpr = Converted.get(); - } - const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo(); DeclarationName MemberName = MemberNameInfo.getName(); SourceLocation MemberLoc = MemberNameInfo.getLoc(); @@ -1128,26 +1119,68 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, BaseExpr = BuildCXXThisExpr(Loc, BaseExprType, /*IsImplicit=*/true); } + // C++17 [expr.ref]p2, per CWG2813: + // For the first option (dot), if the id-expression names a static member or + // an enumerator, the first expression is a discarded-value expression; if + // the id-expression names a non-static data member, the first expression + // shall be a glvalue. + auto ConvertBaseExprToDiscardedValue = [&] { + assert(getLangOpts().CPlusPlus && + "Static member / member enumerator outside of C++"); + if (IsArrow) + return false; + ExprResult Converted = IgnoredValueConversions(BaseExpr); + if (Converted.isInvalid()) + return true; + BaseExpr = Converted.get(); + DiagnoseDiscardedExprMarkedNodiscard(BaseExpr); + return false; + }; + auto ConvertBaseExprToGLValue = [&] { + if (IsArrow || !BaseExpr->isPRValue()) + return false; + ExprResult Converted = TemporaryMaterializationConversion(BaseExpr); + if (Converted.isInvalid()) + return true; + BaseExpr = Converted.get(); + return false; + }; + // Check the use of this member. if (DiagnoseUseOfDecl(MemberDecl, MemberLoc)) return ExprError(); - if (FieldDecl *FD = dyn_cast(MemberDecl)) + if (FieldDecl *FD = dyn_cast(MemberDecl)) { + if (ConvertBaseExprToGLValue()) + return ExprError(); return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl, MemberNameInfo); + } - if (MSPropertyDecl *PD = dyn_cast(MemberDecl)) + if (MSPropertyDecl *PD = dyn_cast(MemberDecl)) { + // No temporaries are materialized for property references yet. + // They might be materialized when this is transformed into a member call. + // Note that this is slightly different behaviour from MSVC which doesn't + // implement CWG2813 yet: MSVC might materialize an extra temporary if the + // getter or setter function is an explicit object member function. return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, MemberNameInfo); + } - if (IndirectFieldDecl *FD = dyn_cast(MemberDecl)) + if (IndirectFieldDecl *FD = dyn_cast(MemberDecl)) { + if (ConvertBaseExprToGLValue()) + return ExprError(); // We may have found a field within an anonymous union or struct // (C++ [class.union]). return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, FoundDecl, BaseExpr, OpLoc); + } + // Static data member if (VarDecl *Var = dyn_cast(MemberDecl)) { + if (ConvertBaseExprToDiscardedValue()) + return ExprError(); return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, SS.getWithLocInContext(Context), TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, @@ -1161,7 +1194,13 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (MemberFn->isInstance()) { valueKind = VK_PRValue; type = Context.BoundMemberTy; + if (MemberFn->isImplicitObjectMemberFunction() && + ConvertBaseExprToGLValue()) + return ExprError(); } else { + // Static member function + if (ConvertBaseExprToDiscardedValue()) + return ExprError(); valueKind = VK_LValue; type = MemberFn->getType(); } @@ -1174,6 +1213,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, assert(!isa(MemberDecl) && "member function not C++ method?"); if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { + if (ConvertBaseExprToDiscardedValue()) + return ExprError(); return BuildMemberExpr( BaseExpr, IsArrow, OpLoc, SS.getWithLocInContext(Context), TemplateKWLoc, Enum, FoundDecl, /*HadMultipleCandidates=*/false, @@ -1181,6 +1222,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { + if (ConvertBaseExprToDiscardedValue()) + return ExprError(); if (!TemplateArgs) { diagnoseMissingTemplateArguments( SS, /*TemplateKeyword=*/TemplateKWLoc.isValid(), VarTempl, MemberLoc); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 88db3e1254119..600c800029fd0 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -434,6 +434,7 @@ void SemaHLSL::CheckSemanticAnnotation( switch (AnnotationAttr->getKind()) { case attr::HLSLSV_DispatchThreadID: case attr::HLSLSV_GroupIndex: + case attr::HLSLSV_GroupThreadID: case attr::HLSLSV_GroupID: if (ST == llvm::Triple::Compute) return; @@ -787,6 +788,15 @@ void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) { HLSLSV_DispatchThreadIDAttr(getASTContext(), AL)); } +void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) { + auto *VD = cast(D); + if (!diagnoseInputIDType(VD->getType(), AL)) + return; + + D->addAttr(::new (getASTContext()) + HLSLSV_GroupThreadIDAttr(getASTContext(), AL)); +} + void SemaHLSL::handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL) { auto *VD = cast(D); if (!diagnoseInputIDType(VD->getType(), AL)) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 7c03a12e81280..5909457b04e66 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -745,6 +745,7 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, if (Field->hasInClassInitializer()) { if (VerifyOnly) return; + ExprResult DIE; { // Enter a default initializer rebuild context, then we can support diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 18d58a43d265c..aa9097bfa1743 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -37,6 +37,11 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K, case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::HostData: + case OpenACCDirectiveKind::Wait: if (!IsStmt) return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K; break; @@ -404,6 +409,49 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, return false; } } + case OpenACCClauseKind::Finalize: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::ExitData: + return true; + default: + return false; + } + } + case OpenACCClauseKind::IfPresent: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::HostData: + case OpenACCDirectiveKind::Update: + return true; + default: + return false; + } + } + case OpenACCClauseKind::Delete: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::ExitData: + return true; + default: + return false; + } + } + + case OpenACCClauseKind::Detach: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::ExitData: + return true; + default: + return false; + } + } + + case OpenACCClauseKind::UseDevice: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::HostData: + return true; + default: + return false; + } + } } default: @@ -431,11 +479,12 @@ bool checkAlreadyHasClauseOfKind( bool checkValidAfterDeviceType( SemaOpenACC &S, const OpenACCDeviceTypeClause &DeviceTypeClause, const SemaOpenACC::OpenACCParsedClause &NewClause) { - // This is only a requirement on compute and loop constructs so far, so this - // is fine otherwise. + // This is only a requirement on compute, combined, data and loop constructs + // so far, so this is fine otherwise. if (!isOpenACCComputeDirectiveKind(NewClause.getDirectiveKind()) && !isOpenACCCombinedDirectiveKind(NewClause.getDirectiveKind()) && - NewClause.getDirectiveKind() != OpenACCDirectiveKind::Loop) + NewClause.getDirectiveKind() != OpenACCDirectiveKind::Loop && + NewClause.getDirectiveKind() != OpenACCDirectiveKind::Data) return false; // OpenACC3.3: Section 2.4: Clauses that precede any device_type clause are @@ -500,6 +549,16 @@ bool checkValidAfterDeviceType( default: break; } + } else if (NewClause.getDirectiveKind() == OpenACCDirectiveKind::Data) { + // OpenACC3.3 section 2.6.5: Only the async and wait clauses may follow a + // device_type clause. + switch (NewClause.getClauseKind()) { + case OpenACCClauseKind::Async: + case OpenACCClauseKind::Wait: + return false; + default: + break; + } } S.Diag(NewClause.getBeginLoc(), diag::err_acc_clause_after_device_type) << NewClause.getClauseKind() << DeviceTypeClause.getClauseKind() @@ -508,6 +567,16 @@ bool checkValidAfterDeviceType( return true; } +// A temporary function that helps implement the 'not implemented' check at the +// top of each clause checking function. This should only be used in conjunction +// with the one being currently implemented/only updated after the entire +// construct has been implemented. +bool isDirectiveKindImplemented(OpenACCDirectiveKind DK) { + return isOpenACCComputeDirectiveKind(DK) || + isOpenACCCombinedDirectiveKind(DK) || isOpenACCDataDirectiveKind(DK) || + DK == OpenACCDirectiveKind::Loop || DK == OpenACCDirectiveKind::Wait; +} + class SemaOpenACCClauseVisitor { SemaOpenACC &SemaRef; ASTContext &Ctx; @@ -572,14 +641,6 @@ class SemaOpenACCClauseVisitor { OpenACCClause *SemaOpenACCClauseVisitor::VisitDefaultClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - // Only 'data' is left. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) - return isNotImplemented(); - // Don't add an invalid clause to the AST. if (Clause.getDefaultClauseKind() == OpenACCDefaultClauseKind::Invalid) return nullptr; @@ -626,16 +687,18 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitTileClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitIfClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute'/'combined'/'data' + // constructs, and 'compute'/'combined'/'data' constructs are the only + // constructs that can do anything with this yet, so skip/treat as + // unimplemented in this case. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // There is no prose in the standard that says duplicates aren't allowed, // but this diagnostic is present in other compilers, as well as makes - // sense. + // sense. Prose DOES exist for 'data' and 'host_data', 'enter data' and 'exit + // data' both don't, but other implmementations do this. OpenACC issue 519 + // filed for the latter two. if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause)) return nullptr; @@ -663,8 +726,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSelfClause( // Restrictions only properly implemented on 'compute' constructs, and // 'compute' constructs are the only construct that can do anything with // this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // TODO OpenACC: When we implement this for 'update', this takes a @@ -719,11 +781,35 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitNumGangsClause( << /*NoArgs=*/1 << Clause.getDirectiveKind() << MaxArgs << Clause.getIntExprs().size(); + // OpenACC 3.3 Section 2.9.11: A reduction clause may not appear on a loop + // directive that has a gang clause and is within a compute construct that has + // a num_gangs clause with more than one explicit argument. + if (Clause.getIntExprs().size() > 1 && + isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) { + auto *GangClauseItr = + llvm::find_if(ExistingClauses, llvm::IsaPred); + auto *ReductionClauseItr = + llvm::find_if(ExistingClauses, llvm::IsaPred); + + if (GangClauseItr != ExistingClauses.end() && + ReductionClauseItr != ExistingClauses.end()) { + SemaRef.Diag(Clause.getBeginLoc(), + diag::err_acc_gang_reduction_numgangs_conflict) + << OpenACCClauseKind::Reduction << OpenACCClauseKind::Gang + << Clause.getDirectiveKind() << /*is on combined directive=*/1; + SemaRef.Diag((*ReductionClauseItr)->getBeginLoc(), + diag::note_acc_previous_clause_here); + SemaRef.Diag((*GangClauseItr)->getBeginLoc(), + diag::note_acc_previous_clause_here); + return nullptr; + } + } + // OpenACC 3.3 Section 2.5.4: // A reduction clause may not appear on a parallel construct with a // num_gangs clause that has more than one argument. - // TODO: OpenACC: Reduction on Combined Construct needs to do this too. - if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel && + if ((Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel || + Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop) && Clause.getIntExprs().size() > 1) { auto *Parallel = llvm::find_if(ExistingClauses, llvm::IsaPred); @@ -731,7 +817,8 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitNumGangsClause( if (Parallel != ExistingClauses.end()) { SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_reduction_num_gangs_conflict) - << Clause.getIntExprs().size(); + << /*>1 arg in first loc=*/1 << Clause.getClauseKind() + << Clause.getDirectiveKind() << OpenACCClauseKind::Reduction; SemaRef.Diag((*Parallel)->getBeginLoc(), diag::note_acc_previous_clause_here); return nullptr; @@ -739,7 +826,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitNumGangsClause( } // OpenACC 3.3 Section 2.9.2: - // An argument with no keyword or with the 'num' wkeyword is allowed only when + // An argument with no keyword or with the 'num' keyword is allowed only when // the 'num_gangs' does not appear on the 'kernel' construct. if (Clause.getDirectiveKind() == OpenACCDirectiveKind::KernelsLoop) { auto GangClauses = llvm::make_filter_range( @@ -832,11 +919,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorLengthClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitAsyncClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute'/'combined'/'data' + // constructs, and 'compute'/'combined'/'data' constructs are the only + // construct that can do anything with this yet, so skip/treat as + // unimplemented in this case. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // There is no prose in the standard that says duplicates aren't allowed, @@ -877,12 +964,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitNoCreateClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) - return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though // it isn't apparent in the standard where this is justified. @@ -894,11 +975,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitNoCreateClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitPresentClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute'/'combined'/'data' + // constructs, and 'compute'/'combined'/'data' constructs are the only + // construct that can do anything with this yet, so skip/treat as + // unimplemented in this case. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though @@ -911,11 +992,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPresentClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute'/'combined'/'data' + // constructs, and 'compute'/'combined'/'data' constructs are the only + // construct that can do anything with this yet, so skip/treat as + // unimplemented in this case. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though @@ -928,11 +1009,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyInClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute'/'combined'/'data' + // constructs, and 'compute'/'combined'/'data' constructs are the only + // construct that can do anything with this yet, so skip/treat as + // unimplemented in this case. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though @@ -945,11 +1026,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyInClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyOutClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute'/'combined'/'data' + // constructs, and 'compute'/'combined'/'data' constructs are the only + // construct that can do anything with this yet, so skip/treat as + // unimplemented in this case. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though @@ -962,12 +1043,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyOutClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitCreateClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) - return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, so there // really isn't anything to do here. GCC does some duplicate-finding, though // it isn't apparent in the standard where this is justified. @@ -979,13 +1054,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCreateClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitAttachClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) - return isNotImplemented(); - // ActOnVar ensured that everything is a valid variable reference, but we // still have to make sure it is a pointer type. llvm::SmallVector VarList{Clause.getVarList()}; @@ -999,13 +1067,47 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitAttachClause( Clause.getEndLoc()); } +OpenACCClause *SemaOpenACCClauseVisitor::VisitDetachClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + // ActOnVar ensured that everything is a valid variable reference, but we + // still have to make sure it is a pointer type. + llvm::SmallVector VarList{Clause.getVarList()}; + llvm::erase_if(VarList, [&](Expr *E) { + return SemaRef.CheckVarIsPointerType(OpenACCClauseKind::Detach, E); + }); + Clause.setVarListDetails(VarList, + /*IsReadOnly=*/false, /*IsZero=*/false); + return OpenACCDetachClause::Create(Ctx, Clause.getBeginLoc(), + Clause.getLParenLoc(), Clause.getVarList(), + Clause.getEndLoc()); +} + +OpenACCClause *SemaOpenACCClauseVisitor::VisitDeleteClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + // ActOnVar ensured that everything is a valid variable reference, so there + // really isn't anything to do here. GCC does some duplicate-finding, though + // it isn't apparent in the standard where this is justified. + return OpenACCDeleteClause::Create(Ctx, Clause.getBeginLoc(), + Clause.getLParenLoc(), Clause.getVarList(), + Clause.getEndLoc()); +} + +OpenACCClause *SemaOpenACCClauseVisitor::VisitUseDeviceClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + // ActOnVar ensured that everything is a valid variable or array, so nothing + // left to do here. + return OpenACCUseDeviceClause::Create( + Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), + Clause.getEndLoc()); +} + OpenACCClause *SemaOpenACCClauseVisitor::VisitDevicePtrClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute'/'combined'/'data' + // constructs, and 'compute'/'combined'/'data' constructs are the only + // construct that can do anything with this yet, so skip/treat as + // unimplemented in this case. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // ActOnVar ensured that everything is a valid variable reference, but we @@ -1024,11 +1126,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDevicePtrClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute'/'combined' constructs, - // and 'compute'/'combined' constructs are the only construct that can do - // anything with this yet, so skip/treat as unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + // Restrictions only properly implemented on 'compute'/'combined'/'data' + // constructs, and 'compute'/'combined'/'data' constructs are the only + // construct that can do anything with this yet, so skip/treat as + // unimplemented in this case. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); return OpenACCWaitClause::Create( @@ -1038,13 +1140,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitWaitClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceTypeClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute', 'combined', and - // 'loop' constructs, and 'compute'/'combined'/'loop' constructs are the only - // construct that can do anything with this yet, so skip/treat as + // Restrictions only properly implemented on 'compute', 'combined', 'data' and + // 'loop' constructs, and 'compute'/'combined'/'data'/'loop' constructs are + // the only construct that can do anything with this yet, so skip/treat as // unimplemented in this case. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // TODO OpenACC: Once we get enough of the CodeGen implemented that we have @@ -1238,8 +1338,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitVectorClause( // Restrictions only properly implemented on 'loop'/'combined' constructs, and // it is the only construct that can do anything with this, so skip/treat as // unimplemented for the routine constructs. - if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); Expr *IntExpr = @@ -1337,8 +1436,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitWorkerClause( // Restrictions only properly implemented on 'loop'/'combined' constructs, and // it is the only construct that can do anything with this, so skip/treat as // unimplemented for the routine constructs. - if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); Expr *IntExpr = @@ -1450,39 +1548,42 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitGangClause( // Restrictions only properly implemented on 'loop' constructs, and it is // the only construct that can do anything with this, so skip/treat as // unimplemented for the combined constructs. - if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop && - !isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // OpenACC 3.3 Section 2.9.11: A reduction clause may not appear on a loop // directive that has a gang clause and is within a compute construct that has // a num_gangs clause with more than one explicit argument. - // TODO OpenACC: When we implement reduction on combined constructs, we need - // to do this too. - if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop && - SemaRef.getActiveComputeConstructInfo().Kind != - OpenACCDirectiveKind::Invalid) { + if ((Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop && + SemaRef.getActiveComputeConstructInfo().Kind != + OpenACCDirectiveKind::Invalid) || + isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) { // num_gangs clause on the active compute construct. - auto *NumGangsClauseItr = - llvm::find_if(SemaRef.getActiveComputeConstructInfo().Clauses, - llvm::IsaPred); - - auto *ReductionClauseItr = - llvm::find_if(ExistingClauses, llvm::IsaPred); - - if (ReductionClauseItr != ExistingClauses.end() && - NumGangsClauseItr != - SemaRef.getActiveComputeConstructInfo().Clauses.end() && + auto ActiveComputeConstructContainer = + isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) + ? ExistingClauses + : SemaRef.getActiveComputeConstructInfo().Clauses; + auto *NumGangsClauseItr = llvm::find_if( + ActiveComputeConstructContainer, llvm::IsaPred); + + if (NumGangsClauseItr != ActiveComputeConstructContainer.end() && cast(*NumGangsClauseItr)->getIntExprs().size() > 1) { - SemaRef.Diag(Clause.getBeginLoc(), - diag::err_acc_gang_reduction_numgangs_conflict) - << OpenACCClauseKind::Gang << OpenACCClauseKind::Reduction; - SemaRef.Diag((*ReductionClauseItr)->getBeginLoc(), - diag::note_acc_previous_clause_here); - SemaRef.Diag((*NumGangsClauseItr)->getBeginLoc(), - diag::note_acc_previous_clause_here); - return nullptr; + auto *ReductionClauseItr = + llvm::find_if(ExistingClauses, llvm::IsaPred); + + if (ReductionClauseItr != ExistingClauses.end()) { + SemaRef.Diag(Clause.getBeginLoc(), + diag::err_acc_gang_reduction_numgangs_conflict) + << OpenACCClauseKind::Gang << OpenACCClauseKind::Reduction + << Clause.getDirectiveKind() + << isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()); + SemaRef.Diag((*ReductionClauseItr)->getBeginLoc(), + diag::note_acc_previous_clause_here); + SemaRef.Diag((*NumGangsClauseItr)->getBeginLoc(), + diag::note_acc_previous_clause_here); + return nullptr; + } } } @@ -1563,9 +1664,27 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitGangClause( } } - return SemaRef.CheckGangClause(ExistingClauses, Clause.getBeginLoc(), - Clause.getLParenLoc(), GangKinds, IntExprs, - Clause.getEndLoc()); + return SemaRef.CheckGangClause(Clause.getDirectiveKind(), ExistingClauses, + Clause.getBeginLoc(), Clause.getLParenLoc(), + GangKinds, IntExprs, Clause.getEndLoc()); +} + +OpenACCClause *SemaOpenACCClauseVisitor::VisitFinalizeClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + // There isn't anything to do here, this is only valid on one construct, and + // has no associated rules. + return OpenACCFinalizeClause::Create(Ctx, Clause.getBeginLoc(), + Clause.getEndLoc()); +} + +OpenACCClause *SemaOpenACCClauseVisitor::VisitIfPresentClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) + return isNotImplemented(); + // There isn't anything to do here, this is only valid on one construct, and + // has no associated rules. + return OpenACCIfPresentClause::Create(Ctx, Clause.getBeginLoc(), + Clause.getEndLoc()); } OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause( @@ -1573,7 +1692,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause( // Restrictions only properly implemented on 'loop' constructs and combined , // and it is the only construct that can do anything with this, so skip/treat // as unimplemented for the routine constructs. - if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Routine) + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) return isNotImplemented(); // OpenACC 3.3 2.9: @@ -1609,41 +1728,39 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause( OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause( SemaOpenACC::OpenACCParsedClause &Clause) { - // Restrictions only properly implemented on 'compute' constructs, and - // 'compute' constructs are the only construct that can do anything with - // this yet, so skip/treat as unimplemented in this case. - // TODO: OpenACC: Remove check once we get combined constructs for this clause. - if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) && - Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop) - return isNotImplemented(); - // OpenACC 3.3 Section 2.9.11: A reduction clause may not appear on a loop // directive that has a gang clause and is within a compute construct that has // a num_gangs clause with more than one explicit argument. - if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop && - SemaRef.getActiveComputeConstructInfo().Kind != - OpenACCDirectiveKind::Invalid) { + if ((Clause.getDirectiveKind() == OpenACCDirectiveKind::Loop && + SemaRef.getActiveComputeConstructInfo().Kind != + OpenACCDirectiveKind::Invalid) || + isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind())) { // num_gangs clause on the active compute construct. - auto *NumGangsClauseItr = - llvm::find_if(SemaRef.getActiveComputeConstructInfo().Clauses, - llvm::IsaPred); - - auto *GangClauseItr = - llvm::find_if(ExistingClauses, llvm::IsaPred); - - if (GangClauseItr != ExistingClauses.end() && - NumGangsClauseItr != - SemaRef.getActiveComputeConstructInfo().Clauses.end() && + auto ActiveComputeConstructContainer = + isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()) + ? ExistingClauses + : SemaRef.getActiveComputeConstructInfo().Clauses; + auto *NumGangsClauseItr = llvm::find_if( + ActiveComputeConstructContainer, llvm::IsaPred); + + if (NumGangsClauseItr != ActiveComputeConstructContainer.end() && cast(*NumGangsClauseItr)->getIntExprs().size() > 1) { - SemaRef.Diag(Clause.getBeginLoc(), - diag::err_acc_gang_reduction_numgangs_conflict) - << OpenACCClauseKind::Reduction << OpenACCClauseKind::Gang; - SemaRef.Diag((*GangClauseItr)->getBeginLoc(), - diag::note_acc_previous_clause_here); - SemaRef.Diag((*NumGangsClauseItr)->getBeginLoc(), - diag::note_acc_previous_clause_here); - return nullptr; + auto *GangClauseItr = + llvm::find_if(ExistingClauses, llvm::IsaPred); + + if (GangClauseItr != ExistingClauses.end()) { + SemaRef.Diag(Clause.getBeginLoc(), + diag::err_acc_gang_reduction_numgangs_conflict) + << OpenACCClauseKind::Reduction << OpenACCClauseKind::Gang + << Clause.getDirectiveKind() + << isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()); + SemaRef.Diag((*GangClauseItr)->getBeginLoc(), + diag::note_acc_previous_clause_here); + SemaRef.Diag((*NumGangsClauseItr)->getBeginLoc(), + diag::note_acc_previous_clause_here); + return nullptr; + } } } @@ -1667,7 +1784,8 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause( // OpenACC 3.3 Section 2.5.4: // A reduction clause may not appear on a parallel construct with a // num_gangs clause that has more than one argument. - if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel) { + if (Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel || + Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop) { auto NumGangsClauses = llvm::make_filter_range( ExistingClauses, llvm::IsaPred); @@ -1678,7 +1796,8 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause( if (NumExprs > 1) { SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_reduction_num_gangs_conflict) - << NumExprs; + << /*>1 arg in first loc=*/0 << Clause.getClauseKind() + << Clause.getDirectiveKind() << OpenACCClauseKind::NumGangs; SemaRef.Diag(NGC->getBeginLoc(), diag::note_acc_previous_clause_here); return nullptr; } @@ -1731,6 +1850,32 @@ void CollectActiveReductionClauses( } } +// Depth needs to be preserved for all associated statements that aren't +// supposed to modify the compute/combined/loop construct information. +bool PreserveLoopRAIIDepthInAssociatedStmtRAII(OpenACCDirectiveKind DK) { + switch (DK) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::KernelsLoop: + case OpenACCDirectiveKind::Loop: + return false; + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::HostData: + return true; + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Wait: + llvm_unreachable("Doesn't have an associated stmt"); + default: + case OpenACCDirectiveKind::Invalid: + llvm_unreachable("Unhandled directive kind?"); + } + llvm_unreachable("Unhandled directive kind?"); +} + } // namespace SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {} @@ -1745,7 +1890,7 @@ SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII( OldLoopVectorClauseLoc(S.LoopVectorClauseLoc), OldLoopWithoutSeqInfo(S.LoopWithoutSeqInfo), ActiveReductionClauses(S.ActiveReductionClauses), - LoopRAII(SemaRef, /*PreserveDepth=*/false) { + LoopRAII(SemaRef, PreserveLoopRAIIDepthInAssociatedStmtRAII(DirKind)) { // Compute constructs end up taking their 'loop'. if (DirKind == OpenACCDirectiveKind::Parallel || @@ -1921,24 +2066,23 @@ void SemaOpenACC::AssociatedStmtRAII::SetTileInfoBeforeAssociatedStmt( } SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() { - SemaRef.ActiveComputeConstructInfo = OldActiveComputeConstructInfo; - SemaRef.LoopGangClauseOnKernel = OldLoopGangClauseOnKernel; - SemaRef.LoopWorkerClauseLoc = OldLoopWorkerClauseLoc; - SemaRef.LoopVectorClauseLoc = OldLoopVectorClauseLoc; - SemaRef.LoopWithoutSeqInfo = OldLoopWithoutSeqInfo; - SemaRef.ActiveReductionClauses.swap(ActiveReductionClauses); - if (DirKind == OpenACCDirectiveKind::Parallel || DirKind == OpenACCDirectiveKind::Serial || DirKind == OpenACCDirectiveKind::Kernels || + DirKind == OpenACCDirectiveKind::Loop || DirKind == OpenACCDirectiveKind::ParallelLoop || DirKind == OpenACCDirectiveKind::SerialLoop || DirKind == OpenACCDirectiveKind::KernelsLoop) { - // Nothing really to do here, the restorations above should be enough for - // now. - } else if (DirKind == OpenACCDirectiveKind::Loop) { - // Nothing really to do here, the LoopInConstruct should handle restorations - // correctly. + SemaRef.ActiveComputeConstructInfo = OldActiveComputeConstructInfo; + SemaRef.LoopGangClauseOnKernel = OldLoopGangClauseOnKernel; + SemaRef.LoopWorkerClauseLoc = OldLoopWorkerClauseLoc; + SemaRef.LoopVectorClauseLoc = OldLoopVectorClauseLoc; + SemaRef.LoopWithoutSeqInfo = OldLoopWithoutSeqInfo; + SemaRef.ActiveReductionClauses.swap(ActiveReductionClauses); + } else if (DirKind == OpenACCDirectiveKind::Data || + DirKind == OpenACCDirectiveKind::HostData) { + // Intentionally doesn't reset the Loop, Compute Construct, or reduction + // effects. } } @@ -2146,9 +2290,17 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, case OpenACCDirectiveKind::SerialLoop: case OpenACCDirectiveKind::KernelsLoop: case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::HostData: // Nothing to do here, there is no real legalization that needs to happen // here as these constructs do not take any arguments. break; + case OpenACCDirectiveKind::Wait: + // Nothing really to do here, the arguments to the 'wait' should have + // already been handled by the time we get here. + break; default: Diag(DirLoc, diag::warn_acc_construct_unimplemented) << K; break; @@ -2289,6 +2441,15 @@ bool SemaOpenACC::CheckVarIsPointerType(OpenACCClauseKind ClauseKind, ExprResult SemaOpenACC::ActOnVar(OpenACCClauseKind CK, Expr *VarExpr) { Expr *CurVarExpr = VarExpr->IgnoreParenImpCasts(); + // 'use_device' doesn't allow array subscript or array sections. + // OpenACC3.3 2.8: + // A 'var' in a 'use_device' clause must be the name of a variable or array. + if (CK == OpenACCClauseKind::UseDevice && + isa(CurVarExpr)) { + Diag(VarExpr->getExprLoc(), diag::err_acc_not_a_var_ref_use_device); + return ExprError(); + } + // Sub-arrays/subscript-exprs are fine as long as the base is a // VarExpr/MemberExpr. So strip all of those off. while (isa(CurVarExpr)) { @@ -2309,16 +2470,20 @@ ExprResult SemaOpenACC::ActOnVar(OpenACCClauseKind CK, Expr *VarExpr) { // If CK is a Reduction, this special cases for OpenACC3.3 2.5.15: "A var in a // reduction clause must be a scalar variable name, an aggregate variable // name, an array element, or a subarray. - // A MemberExpr that references a Field is valid. - if (CK != OpenACCClauseKind::Reduction) { + // If CK is a 'use_device', this also isn't valid, as it isn' the name of a + // variable or array. + // A MemberExpr that references a Field is valid for other clauses. + if (CK != OpenACCClauseKind::Reduction && + CK != OpenACCClauseKind::UseDevice) { if (const auto *ME = dyn_cast(CurVarExpr)) { if (isa(ME->getMemberDecl()->getCanonicalDecl())) return VarExpr; } } - // Referring to 'this' is always OK. - if (isa(CurVarExpr)) + // Referring to 'this' is ok for the most part, but for 'use_device' doesn't + // fall into 'variable or array name' + if (CK != OpenACCClauseKind::UseDevice && isa(CurVarExpr)) return VarExpr; // Nothing really we can do here, as these are dependent. So just return they @@ -2333,8 +2498,11 @@ ExprResult SemaOpenACC::ActOnVar(OpenACCClauseKind CK, Expr *VarExpr) { if (isa(CurVarExpr)) return ExprError(); - Diag(VarExpr->getExprLoc(), diag::err_acc_not_a_var_ref) - << (CK != OpenACCClauseKind::Reduction); + if (CK == OpenACCClauseKind::UseDevice) + Diag(VarExpr->getExprLoc(), diag::err_acc_not_a_var_ref_use_device); + else + Diag(VarExpr->getExprLoc(), diag::err_acc_not_a_var_ref) + << (CK != OpenACCClauseKind::Reduction); return ExprError(); } @@ -2624,7 +2792,8 @@ SemaOpenACC::CheckGangExpr(ArrayRef ExistingClauses, } OpenACCClause * -SemaOpenACC::CheckGangClause(ArrayRef ExistingClauses, +SemaOpenACC::CheckGangClause(OpenACCDirectiveKind DirKind, + ArrayRef ExistingClauses, SourceLocation BeginLoc, SourceLocation LParenLoc, ArrayRef GangKinds, ArrayRef IntExprs, SourceLocation EndLoc) { @@ -2649,7 +2818,7 @@ SemaOpenACC::CheckGangClause(ArrayRef ExistingClauses, if (const auto *DimVal = dyn_cast(DimExpr); DimVal && DimVal->getResultAsAPSInt() > 1) { Diag(DimVal->getBeginLoc(), diag::err_acc_gang_reduction_conflict) - << /*gang/reduction=*/0; + << /*gang/reduction=*/0 << DirKind; Diag((*ReductionItr)->getBeginLoc(), diag::note_acc_previous_clause_here); return nullptr; @@ -2666,30 +2835,29 @@ OpenACCClause *SemaOpenACC::CheckReductionClause( OpenACCDirectiveKind DirectiveKind, SourceLocation BeginLoc, SourceLocation LParenLoc, OpenACCReductionOperator ReductionOp, ArrayRef Vars, SourceLocation EndLoc) { - if (DirectiveKind == OpenACCDirectiveKind::Loop) { + if (DirectiveKind == OpenACCDirectiveKind::Loop || + isOpenACCCombinedDirectiveKind(DirectiveKind)) { // OpenACC 3.3 2.9.11: A reduction clause may not appear on a loop directive // that has a gang clause with a dim: argument whose value is greater // than 1. - const auto *GangItr = - llvm::find_if(ExistingClauses, llvm::IsaPred); + const auto GangClauses = llvm::make_filter_range( + ExistingClauses, llvm::IsaPred); - while (GangItr != ExistingClauses.end()) { - auto *GangClause = cast(*GangItr); + for (auto *GC : GangClauses) { + const auto *GangClause = cast(GC); for (unsigned I = 0; I < GangClause->getNumExprs(); ++I) { std::pair EPair = GangClause->getExpr(I); - // We know there is only 1 on this gang, so move onto the next gang. if (EPair.first != OpenACCGangKind::Dim) - break; + continue; if (const auto *DimVal = dyn_cast(EPair.second); DimVal && DimVal->getResultAsAPSInt() > 1) { Diag(BeginLoc, diag::err_acc_gang_reduction_conflict) - << /*reduction/gang=*/1; - Diag((*GangItr)->getBeginLoc(), diag::note_acc_previous_clause_here); + << /*reduction/gang=*/1 << DirectiveKind; + Diag(GangClause->getBeginLoc(), diag::note_acc_previous_clause_here); return nullptr; } } - ++GangItr; } } @@ -3351,8 +3519,35 @@ void SemaOpenACC::ActOnForStmtEnd(SourceLocation ForLoc, StmtResult Body) { } } -bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc) { +namespace { +// Get a list of clause Kinds for diagnosing a list, joined by a commas and an +// 'or'. +std::string GetListOfClauses(llvm::ArrayRef Clauses) { + assert(!Clauses.empty() && "empty clause list not supported"); + + std::string Output; + llvm::raw_string_ostream OS{Output}; + + if (Clauses.size() == 1) { + OS << '\'' << Clauses[0] << '\''; + return Output; + } + + llvm::ArrayRef AllButLast{Clauses.begin(), + Clauses.end() - 1}; + + llvm::interleave( + AllButLast, [&](OpenACCClauseKind K) { OS << '\'' << K << '\''; }, + [&] { OS << ", "; }); + + OS << " or \'" << Clauses.back() << '\''; + return Output; +} +} // namespace + +bool SemaOpenACC::ActOnStartStmtDirective( + OpenACCDirectiveKind K, SourceLocation StartLoc, + ArrayRef Clauses) { SemaRef.DiscardCleanupsInEvaluationContext(); SemaRef.PopExpressionEvaluationContext(); @@ -3379,15 +3574,67 @@ bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, << OpenACCClauseKind::Tile; } + // OpenACC3.3 2.6.5: At least one copy, copyin, copyout, create, no_create, + // present, deviceptr, attach, or default clause must appear on a 'data' + // construct. + if (K == OpenACCDirectiveKind::Data && + llvm::find_if(Clauses, + llvm::IsaPred) == Clauses.end()) + return Diag(StartLoc, diag::err_acc_construct_one_clause_of) + << K + << GetListOfClauses( + {OpenACCClauseKind::Copy, OpenACCClauseKind::CopyIn, + OpenACCClauseKind::CopyOut, OpenACCClauseKind::Create, + OpenACCClauseKind::NoCreate, OpenACCClauseKind::Present, + OpenACCClauseKind::DevicePtr, OpenACCClauseKind::Attach, + OpenACCClauseKind::Default}); + + // OpenACC3.3 2.6.6: At least one copyin, create, or attach clause must appear + // on an enter data directive. + if (K == OpenACCDirectiveKind::EnterData && + llvm::find_if(Clauses, + llvm::IsaPred) == Clauses.end()) + return Diag(StartLoc, diag::err_acc_construct_one_clause_of) + << K + << GetListOfClauses({ + OpenACCClauseKind::CopyIn, + OpenACCClauseKind::Create, + OpenACCClauseKind::Attach, + }); + // OpenACC3.3 2.6.6: At least one copyout, delete, or detach clause must + // appear on an exit data directive. + if (K == OpenACCDirectiveKind::ExitData && + llvm::find_if(Clauses, + llvm::IsaPred) == Clauses.end()) + return Diag(StartLoc, diag::err_acc_construct_one_clause_of) + << K + << GetListOfClauses({ + OpenACCClauseKind::CopyOut, + OpenACCClauseKind::Delete, + OpenACCClauseKind::Detach, + }); + + // OpenACC3.3 2.8: At least 'one use_device' clause must appear. + if (K == OpenACCDirectiveKind::HostData && + llvm::find_if(Clauses, llvm::IsaPred) == + Clauses.end()) + return Diag(StartLoc, diag::err_acc_construct_one_clause_of) + << K << GetListOfClauses({OpenACCClauseKind::UseDevice}); + return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true); } -StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc, - SourceLocation DirLoc, - SourceLocation EndLoc, - ArrayRef Clauses, - StmtResult AssocStmt) { +StmtResult SemaOpenACC::ActOnEndStmtDirective( + OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc, + SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef Exprs, + SourceLocation RParenLoc, SourceLocation EndLoc, + ArrayRef Clauses, StmtResult AssocStmt) { switch (K) { default: return StmtEmpty(); @@ -3412,6 +3659,29 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, getASTContext(), ActiveComputeConstructInfo.Kind, StartLoc, DirLoc, EndLoc, Clauses, AssocStmt.isUsable() ? AssocStmt.get() : nullptr); } + case OpenACCDirectiveKind::Data: { + return OpenACCDataConstruct::Create( + getASTContext(), StartLoc, DirLoc, EndLoc, Clauses, + AssocStmt.isUsable() ? AssocStmt.get() : nullptr); + } + case OpenACCDirectiveKind::EnterData: { + return OpenACCEnterDataConstruct::Create(getASTContext(), StartLoc, DirLoc, + EndLoc, Clauses); + } + case OpenACCDirectiveKind::ExitData: { + return OpenACCExitDataConstruct::Create(getASTContext(), StartLoc, DirLoc, + EndLoc, Clauses); + } + case OpenACCDirectiveKind::HostData: { + return OpenACCHostDataConstruct::Create( + getASTContext(), StartLoc, DirLoc, EndLoc, Clauses, + AssocStmt.isUsable() ? AssocStmt.get() : nullptr); + } + case OpenACCDirectiveKind::Wait: { + return OpenACCWaitConstruct::Create( + getASTContext(), StartLoc, DirLoc, LParenLoc, Exprs.front(), MiscLoc, + Exprs.drop_front(), RParenLoc, EndLoc, Clauses); + } } llvm_unreachable("Unhandled case in directive handling?"); } @@ -3422,9 +3692,16 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt( switch (K) { default: llvm_unreachable("Unimplemented associated statement application"); + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Wait: + llvm_unreachable( + "these don't have associated statements, so shouldn't get here"); case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::HostData: // There really isn't any checking here that could happen. As long as we // have a statement to associate, this should be fine. // OpenACC 3.3 Section 6: diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 3dabe362802c9..fff49b759c935 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5933,7 +5933,9 @@ ExprResult Sema::PerformImplicitObjectArgumentInitialization( DestType = ImplicitParamRecordType; FromClassification = From->Classify(Context); - // When performing member access on a prvalue, materialize a temporary. + // CWG2813 [expr.call]p6: + // If the function is an implicit object member function, the object + // expression of the class member access shall be a glvalue [...] if (From->isPRValue()) { From = CreateMaterializeTemporaryExpr(FromRecordType, From, Method->getRefQualifier() != @@ -6464,11 +6466,6 @@ static Expr *GetExplicitObjectExpr(Sema &S, Expr *Obj, VK_LValue, OK_Ordinary, SourceLocation(), /*CanOverflow=*/false, FPOptionsOverride()); } - if (Obj->Classify(S.getASTContext()).isPRValue()) { - Obj = S.CreateMaterializeTemporaryExpr( - ObjType, Obj, - !Fun->getParamDecl(0)->getType()->isRValueReferenceType()); - } return Obj; } @@ -15584,8 +15581,6 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, CurFPFeatureOverrides(), Proto->getNumParams()); } else { // Convert the object argument (for a non-static member function call). - // We only need to do this if there was actually an overload; otherwise - // it was done at lookup. ExprResult ObjectArg = PerformImplicitObjectArgumentInitialization( MemExpr->getBase(), Qualifier, FoundDecl, Method); if (ObjectArg.isInvalid()) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 0e5c6cd49dcca..d9149f7ee40bb 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -226,17 +226,18 @@ static bool DiagnoseNoDiscard(Sema &S, const NamedDecl *OffendingDecl, return S.Diag(Loc, diag::warn_unused_result) << A << true << Msg << R1 << R2; } -void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { - if (const LabelStmt *Label = dyn_cast_or_null(S)) - return DiagnoseUnusedExprResult(Label->getSubStmt(), DiagID); +namespace { - const Expr *E = dyn_cast_or_null(S); - if (!E) - return; +// Diagnoses unused expressions that call functions marked [[nodiscard]], +// [[gnu::warn_unused_result]] and similar. +// Additionally, a DiagID can be provided to emit a warning in additional +// contexts (such as for an unused LHS of a comma expression) +void DiagnoseUnused(Sema &S, const Expr *E, std::optional DiagID) { + bool NoDiscardOnly = !DiagID.has_value(); // If we are in an unevaluated expression context, then there can be no unused // results because the results aren't expected to be used in the first place. - if (isUnevaluatedContext()) + if (S.isUnevaluatedContext()) return; SourceLocation ExprLoc = E->IgnoreParenImpCasts()->getExprLoc(); @@ -245,30 +246,31 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { // expression is a call to a function with the warn_unused_result attribute, // we warn no matter the location. Because of the order in which the various // checks need to happen, we factor out the macro-related test here. - bool ShouldSuppress = - SourceMgr.isMacroBodyExpansion(ExprLoc) || - SourceMgr.isInSystemMacro(ExprLoc); + bool ShouldSuppress = S.SourceMgr.isMacroBodyExpansion(ExprLoc) || + S.SourceMgr.isInSystemMacro(ExprLoc); const Expr *WarnExpr; SourceLocation Loc; SourceRange R1, R2; - if (!E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context)) - return; - - // If this is a GNU statement expression expanded from a macro, it is probably - // unused because it is a function-like macro that can be used as either an - // expression or statement. Don't warn, because it is almost certainly a - // false positive. - if (isa(E) && Loc.isMacroID()) + if (!E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, S.Context)) return; - // Check if this is the UNREFERENCED_PARAMETER from the Microsoft headers. - // That macro is frequently used to suppress "unused parameter" warnings, - // but its implementation makes clang's -Wunused-value fire. Prevent this. - if (isa(E->IgnoreImpCasts()) && Loc.isMacroID()) { - SourceLocation SpellLoc = Loc; - if (findMacroSpelling(SpellLoc, "UNREFERENCED_PARAMETER")) + if (!NoDiscardOnly) { + // If this is a GNU statement expression expanded from a macro, it is + // probably unused because it is a function-like macro that can be used as + // either an expression or statement. Don't warn, because it is almost + // certainly a false positive. + if (isa(E) && Loc.isMacroID()) return; + + // Check if this is the UNREFERENCED_PARAMETER from the Microsoft headers. + // That macro is frequently used to suppress "unused parameter" warnings, + // but its implementation makes clang's -Wunused-value fire. Prevent this. + if (isa(E->IgnoreImpCasts()) && Loc.isMacroID()) { + SourceLocation SpellLoc = Loc; + if (S.findMacroSpelling(SpellLoc, "UNREFERENCED_PARAMETER")) + return; + } } // Okay, we have an unused result. Depending on what the base expression is, @@ -279,7 +281,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { if (const CXXBindTemporaryExpr *TempExpr = dyn_cast(E)) E = TempExpr->getSubExpr(); - if (DiagnoseUnusedComparison(*this, E)) + if (DiagnoseUnusedComparison(S, E)) return; E = WarnExpr; @@ -293,8 +295,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { if (E->getType()->isVoidType()) return; - auto [OffendingDecl, A] = CE->getUnusedResultAttr(Context); - if (DiagnoseNoDiscard(*this, OffendingDecl, + auto [OffendingDecl, A] = CE->getUnusedResultAttr(S.Context); + if (DiagnoseNoDiscard(S, OffendingDecl, cast_or_null(A), Loc, R1, R2, /*isCtor=*/false)) return; @@ -307,11 +309,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { if (ShouldSuppress) return; if (FD->hasAttr()) { - Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure"; + S.Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure"; return; } if (FD->hasAttr()) { - Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const"; + S.Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const"; return; } } @@ -323,15 +325,15 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { OffendingDecl = Ctor->getParent(); A = OffendingDecl->getAttr(); } - if (DiagnoseNoDiscard(*this, OffendingDecl, A, Loc, R1, R2, + if (DiagnoseNoDiscard(S, OffendingDecl, A, Loc, R1, R2, /*isCtor=*/true)) return; } } else if (const auto *ILE = dyn_cast(E)) { if (const TagDecl *TD = ILE->getType()->getAsTagDecl()) { - if (DiagnoseNoDiscard(*this, TD, TD->getAttr(), Loc, - R1, R2, /*isCtor=*/false)) + if (DiagnoseNoDiscard(S, TD, TD->getAttr(), Loc, R1, + R2, /*isCtor=*/false)) return; } } else if (ShouldSuppress) @@ -339,23 +341,24 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { E = WarnExpr; if (const ObjCMessageExpr *ME = dyn_cast(E)) { - if (getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) { - Diag(Loc, diag::err_arc_unused_init_message) << R1; + if (S.getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) { + S.Diag(Loc, diag::err_arc_unused_init_message) << R1; return; } const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD) { - if (DiagnoseNoDiscard(*this, nullptr, MD->getAttr(), - Loc, R1, R2, /*isCtor=*/false)) + if (DiagnoseNoDiscard(S, nullptr, MD->getAttr(), + Loc, R1, R2, + /*isCtor=*/false)) return; } } else if (const PseudoObjectExpr *POE = dyn_cast(E)) { const Expr *Source = POE->getSyntacticForm(); // Handle the actually selected call of an OpenMP specialized call. - if (LangOpts.OpenMP && isa(Source) && + if (S.LangOpts.OpenMP && isa(Source) && POE->getNumSemanticExprs() == 1 && isa(POE->getSemanticExpr(0))) - return DiagnoseUnusedExprResult(POE->getSemanticExpr(0), DiagID); + return DiagnoseUnused(S, POE->getSemanticExpr(0), DiagID); if (isa(Source)) DiagID = diag::warn_unused_container_subscript_expr; else if (isa(Source)) @@ -372,17 +375,21 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { if (!RD->getAttr()) return; } + + if (NoDiscardOnly) + return; + // Diagnose "(void*) blah" as a typo for "(void) blah". - else if (const CStyleCastExpr *CE = dyn_cast(E)) { + if (const CStyleCastExpr *CE = dyn_cast(E)) { TypeSourceInfo *TI = CE->getTypeInfoAsWritten(); QualType T = TI->getType(); // We really do want to use the non-canonical type here. - if (T == Context.VoidPtrTy) { + if (T == S.Context.VoidPtrTy) { PointerTypeLoc TL = TI->getTypeLoc().castAs(); - Diag(Loc, diag::warn_unused_voidptr) - << FixItHint::CreateRemoval(TL.getStarLoc()); + S.Diag(Loc, diag::warn_unused_voidptr) + << FixItHint::CreateRemoval(TL.getStarLoc()); return; } } @@ -391,16 +398,34 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { // isn't an array. if (E->isGLValue() && E->getType().isVolatileQualified() && !E->getType()->isArrayType()) { - Diag(Loc, diag::warn_unused_volatile) << R1 << R2; + S.Diag(Loc, diag::warn_unused_volatile) << R1 << R2; return; } // Do not diagnose use of a comma operator in a SFINAE context because the // type of the left operand could be used for SFINAE, so technically it is // *used*. - if (DiagID != diag::warn_unused_comma_left_operand || !isSFINAEContext()) - DiagIfReachable(Loc, S ? llvm::ArrayRef(S) : llvm::ArrayRef(), - PDiag(DiagID) << R1 << R2); + if (DiagID == diag::warn_unused_comma_left_operand && S.isSFINAEContext()) + return; + + S.DiagIfReachable(Loc, llvm::ArrayRef(E), + S.PDiag(*DiagID) << R1 << R2); +} +} // namespace + +void Sema::DiagnoseDiscardedExprMarkedNodiscard(const Expr *E) { + DiagnoseUnused(*this, E, std::nullopt); +} + +void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { + if (const LabelStmt *Label = dyn_cast_if_present(S)) + S = Label->getSubStmt(); + + const Expr *E = dyn_cast_if_present(S); + if (!E) + return; + + DiagnoseUnused(*this, E, DiagID); } void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) { diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 0b272b806391c..a0b203fbdfec2 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -664,11 +664,16 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, SmallerValueMentioned |= OutSize < InSize; } + // If the input is an integer register while the output is floating point, + // or vice-versa, there is no way they can work together. + bool FPTiedToInt = (InputDomain == AD_FP) ^ (OutputDomain == AD_FP); + // If the smaller value wasn't mentioned in the asm string, and if the // output was a register, just extend the shorter one to the size of the // larger one. - if (!SmallerValueMentioned && InputDomain != AD_Other && + if (!SmallerValueMentioned && !FPTiedToInt && InputDomain != AD_Other && OutputConstraintInfos[TiedTo].allowsRegister()) { + // FIXME: GCC supports the OutSize to be 128 at maximum. Currently codegen // crash when the size larger than the register size. So we limit it here. if (OutTy->isStructureType() && diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 39f8ece62ed5c..e058afe81da58 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2146,6 +2146,23 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // Check whether there is already a function template specialization for // this declaration. FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); + bool isFriend; + if (FunctionTemplate) + isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None); + else + isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + + // Friend function defined withing class template may stop being function + // definition during AST merges from different modules, in this case decl + // with function body should be used for instantiation. + if (isFriend) { + const FunctionDecl *Defn = nullptr; + if (D->hasBody(Defn)) { + D = const_cast(Defn); + FunctionTemplate = Defn->getDescribedFunctionTemplate(); + } + } + if (FunctionTemplate && !TemplateParams) { ArrayRef Innermost = TemplateArgs.getInnermost(); @@ -2158,12 +2175,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( return SpecFunc; } - bool isFriend; - if (FunctionTemplate) - isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None); - else - isFriend = (D->getFriendObjectKind() != Decl::FOK_None); - bool MergeWithParentScope = (TemplateParams != nullptr) || Owner->isFunctionOrMethod() || !(isa(Owner) && @@ -4692,6 +4703,17 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { assert(Param->hasUninstantiatedDefaultArg()); + // FIXME: We don't track member specialization info for non-defining + // friend declarations, so we will not be able to later find the function + // pattern. As a workaround, don't instantiate the default argument in this + // case. This is correct per the standard and only an issue for recovery + // purposes. [dcl.fct.default]p4: + // if a friend declaration D specifies a default argument expression, + // that declaration shall be a definition. + if (FD->getFriendObjectKind() != Decl::FOK_None && + !FD->getTemplateInstantiationPattern()) + return true; + // Instantiate the expression. // // FIXME: Pass in a correct Pattern argument, otherwise diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 4893bb0ec2d26..83464c50b4b23 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2312,6 +2312,17 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM, return T; } +static bool CheckBitIntElementType(Sema &S, SourceLocation AttrLoc, + const BitIntType *BIT, + bool ForMatrixType = false) { + // Only support _BitInt elements with byte-sized power of 2 NumBits. + unsigned NumBits = BIT->getNumBits(); + if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) + return S.Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) + << ForMatrixType << (NumBits < 8); + return false; +} + QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, SourceLocation AttrLoc) { // The base type must be integer (not Boolean or enumeration) or float, and @@ -2324,15 +2335,10 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType; return QualType(); } - // Only support _BitInt elements with byte-sized power of 2 NumBits. - if (const auto *BIT = CurType->getAs()) { - unsigned NumBits = BIT->getNumBits(); - if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) { - Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) - << (NumBits < 8); - return QualType(); - } - } + + if (const auto *BIT = CurType->getAs(); + BIT && CheckBitIntElementType(*this, AttrLoc, BIT)) + return QualType(); if (SizeExpr->isTypeDependent() || SizeExpr->isValueDependent()) return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, @@ -2402,15 +2408,9 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } - // Only support _BitInt elements with byte-sized power of 2 NumBits. - if (T->isBitIntType()) { - unsigned NumBits = T->castAs()->getNumBits(); - if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) { - Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) - << (NumBits < 8); - return QualType(); - } - } + if (const auto *BIT = T->getAs(); + BIT && CheckBitIntElementType(*this, AttrLoc, BIT)) + return QualType(); if (!ArraySize->isTypeDependent() && !ArraySize->isValueDependent()) { std::optional vecSize = @@ -2455,6 +2455,11 @@ QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols, return QualType(); } + if (const auto *BIT = ElementTy->getAs(); + BIT && + CheckBitIntElementType(*this, AttrLoc, BIT, /*ForMatrixType=*/true)) + return QualType(); + if (NumRows->isTypeDependent() || NumCols->isTypeDependent() || NumRows->isValueDependent() || NumCols->isValueDependent()) return Context.getDependentSizedMatrixType(ElementTy, NumRows, NumCols, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 81e515e7cb2a9..c097465374cba 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4087,8 +4087,9 @@ class TreeTransform { SourceLocation EndLoc, ArrayRef Clauses, StmtResult StrBlock) { - return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, DirLoc, - EndLoc, Clauses, StrBlock); + return getSema().OpenACC().ActOnEndStmtDirective( + K, BeginLoc, DirLoc, SourceLocation{}, SourceLocation{}, {}, + SourceLocation{}, EndLoc, Clauses, StrBlock); } StmtResult RebuildOpenACCLoopConstruct(SourceLocation BeginLoc, @@ -4097,7 +4098,8 @@ class TreeTransform { ArrayRef Clauses, StmtResult Loop) { return getSema().OpenACC().ActOnEndStmtDirective( - OpenACCDirectiveKind::Loop, BeginLoc, DirLoc, EndLoc, Clauses, Loop); + OpenACCDirectiveKind::Loop, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, Loop); } StmtResult RebuildOpenACCCombinedConstruct(OpenACCDirectiveKind K, @@ -4106,8 +4108,60 @@ class TreeTransform { SourceLocation EndLoc, ArrayRef Clauses, StmtResult Loop) { - return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, DirLoc, - EndLoc, Clauses, Loop); + return getSema().OpenACC().ActOnEndStmtDirective( + K, BeginLoc, DirLoc, SourceLocation{}, SourceLocation{}, {}, + SourceLocation{}, EndLoc, Clauses, Loop); + } + + StmtResult RebuildOpenACCDataConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + StmtResult StrBlock) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Data, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, StrBlock); + } + + StmtResult + RebuildOpenACCEnterDataConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, SourceLocation EndLoc, + ArrayRef Clauses) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::EnterData, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); + } + + StmtResult + RebuildOpenACCExitDataConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, SourceLocation EndLoc, + ArrayRef Clauses) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::ExitData, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); + } + + StmtResult RebuildOpenACCHostDataConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + StmtResult StrBlock) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::HostData, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, StrBlock); + } + + StmtResult RebuildOpenACCWaitConstruct( + SourceLocation BeginLoc, SourceLocation DirLoc, SourceLocation LParenLoc, + Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef QueueIdExprs, + SourceLocation RParenLoc, SourceLocation EndLoc, + ArrayRef Clauses) { + llvm::SmallVector Exprs; + Exprs.push_back(DevNumExpr); + Exprs.insert(Exprs.end(), QueueIdExprs.begin(), QueueIdExprs.end()); + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Wait, BeginLoc, DirLoc, LParenLoc, QueuesLoc, + Exprs, RParenLoc, EndLoc, Clauses, {}); } ExprResult RebuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) { @@ -11719,6 +11773,50 @@ void OpenACCClauseTransform::VisitAttachClause( ParsedClause.getEndLoc()); } +template +void OpenACCClauseTransform::VisitDetachClause( + const OpenACCDetachClause &C) { + llvm::SmallVector VarList = VisitVarList(C.getVarList()); + + // Ensure each var is a pointer type. + VarList.erase( + std::remove_if(VarList.begin(), VarList.end(), + [&](Expr *E) { + return Self.getSema().OpenACC().CheckVarIsPointerType( + OpenACCClauseKind::Detach, E); + }), + VarList.end()); + + ParsedClause.setVarListDetails(VarList, + /*IsReadOnly=*/false, /*IsZero=*/false); + NewClause = OpenACCDetachClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getVarList(), + ParsedClause.getEndLoc()); +} + +template +void OpenACCClauseTransform::VisitDeleteClause( + const OpenACCDeleteClause &C) { + ParsedClause.setVarListDetails(VisitVarList(C.getVarList()), + /*IsReadOnly=*/false, /*IsZero=*/false); + NewClause = OpenACCDeleteClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getVarList(), + ParsedClause.getEndLoc()); +} + +template +void OpenACCClauseTransform::VisitUseDeviceClause( + const OpenACCUseDeviceClause &C) { + ParsedClause.setVarListDetails(VisitVarList(C.getVarList()), + /*IsReadOnly=*/false, /*IsZero=*/false); + NewClause = OpenACCUseDeviceClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getVarList(), + ParsedClause.getEndLoc()); +} + template void OpenACCClauseTransform::VisitDevicePtrClause( const OpenACCDevicePtrClause &C) { @@ -11942,6 +12040,21 @@ void OpenACCClauseTransform::VisitSeqClause( ParsedClause.getBeginLoc(), ParsedClause.getEndLoc()); } +template +void OpenACCClauseTransform::VisitFinalizeClause( + const OpenACCFinalizeClause &C) { + NewClause = OpenACCFinalizeClause::Create(Self.getSema().getASTContext(), + ParsedClause.getBeginLoc(), + ParsedClause.getEndLoc()); +} + +template +void OpenACCClauseTransform::VisitIfPresentClause( + const OpenACCIfPresentClause &C) { + NewClause = OpenACCIfPresentClause::Create(Self.getSema().getASTContext(), + ParsedClause.getBeginLoc(), + ParsedClause.getEndLoc()); +} template void OpenACCClauseTransform::VisitReductionClause( @@ -12037,7 +12150,8 @@ void OpenACCClauseTransform::VisitGangClause( } NewClause = Self.getSema().OpenACC().CheckGangClause( - ExistingClauses, ParsedClause.getBeginLoc(), ParsedClause.getLParenLoc(), + ParsedClause.getDirectiveKind(), ExistingClauses, + ParsedClause.getBeginLoc(), ParsedClause.getLParenLoc(), TransformedGangKinds, TransformedIntExprs, ParsedClause.getEndLoc()); } } // namespace @@ -12082,8 +12196,8 @@ StmtResult TreeTransform::TransformOpenACCComputeConstruct( getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), C->clauses()); - if (getSema().OpenACC().ActOnStartStmtDirective(C->getDirectiveKind(), - C->getBeginLoc())) + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) return StmtError(); // Transform Structured Block. @@ -12109,8 +12223,8 @@ TreeTransform::TransformOpenACCLoopConstruct(OpenACCLoopConstruct *C) { getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), C->clauses()); - if (getSema().OpenACC().ActOnStartStmtDirective(C->getDirectiveKind(), - C->getBeginLoc())) + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) return StmtError(); // Transform Loop. @@ -12135,8 +12249,8 @@ StmtResult TreeTransform::TransformOpenACCCombinedConstruct( getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), C->clauses()); - if (getSema().OpenACC().ActOnStartStmtDirective(C->getDirectiveKind(), - C->getBeginLoc())) + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) return StmtError(); // Transform Loop. @@ -12152,6 +12266,132 @@ StmtResult TreeTransform::TransformOpenACCCombinedConstruct( C->getEndLoc(), TransformedClauses, Loop); } +template +StmtResult +TreeTransform::TransformOpenACCDataConstruct(OpenACCDataConstruct *C) { + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + llvm::SmallVector TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) + return StmtError(); + + SemaOpenACC::AssociatedStmtRAII AssocStmtRAII( + getSema().OpenACC(), C->getDirectiveKind(), C->getDirectiveLoc(), + C->clauses(), TransformedClauses); + StmtResult StrBlock = getDerived().TransformStmt(C->getStructuredBlock()); + StrBlock = getSema().OpenACC().ActOnAssociatedStmt( + C->getBeginLoc(), C->getDirectiveKind(), TransformedClauses, StrBlock); + + return getDerived().RebuildOpenACCDataConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses, StrBlock); +} + +template +StmtResult TreeTransform::TransformOpenACCEnterDataConstruct( + OpenACCEnterDataConstruct *C) { + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + llvm::SmallVector TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) + return StmtError(); + + return getDerived().RebuildOpenACCEnterDataConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses); +} + +template +StmtResult TreeTransform::TransformOpenACCExitDataConstruct( + OpenACCExitDataConstruct *C) { + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + llvm::SmallVector TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) + return StmtError(); + + return getDerived().RebuildOpenACCExitDataConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses); +} + +template +StmtResult TreeTransform::TransformOpenACCHostDataConstruct( + OpenACCHostDataConstruct *C) { + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + llvm::SmallVector TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) + return StmtError(); + + SemaOpenACC::AssociatedStmtRAII AssocStmtRAII( + getSema().OpenACC(), C->getDirectiveKind(), C->getDirectiveLoc(), + C->clauses(), TransformedClauses); + StmtResult StrBlock = getDerived().TransformStmt(C->getStructuredBlock()); + StrBlock = getSema().OpenACC().ActOnAssociatedStmt( + C->getBeginLoc(), C->getDirectiveKind(), TransformedClauses, StrBlock); + + return getDerived().RebuildOpenACCHostDataConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses, StrBlock); +} + +template +StmtResult +TreeTransform::TransformOpenACCWaitConstruct(OpenACCWaitConstruct *C) { + getSema().OpenACC().ActOnConstruct(C->getDirectiveKind(), C->getBeginLoc()); + + ExprResult DevNumExpr; + if (C->hasDevNumExpr()) { + DevNumExpr = getDerived().TransformExpr(C->getDevNumExpr()); + + if (DevNumExpr.isUsable()) + DevNumExpr = getSema().OpenACC().ActOnIntExpr( + OpenACCDirectiveKind::Wait, OpenACCClauseKind::Invalid, + C->getBeginLoc(), DevNumExpr.get()); + } + + llvm::SmallVector QueueIdExprs; + + for (Expr *QE : C->getQueueIdExprs()) { + assert(QE && "Null queue id expr?"); + ExprResult NewEQ = getDerived().TransformExpr(QE); + + if (!NewEQ.isUsable()) + break; + NewEQ = getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Wait, + OpenACCClauseKind::Invalid, + C->getBeginLoc(), NewEQ.get()); + if (NewEQ.isUsable()) + QueueIdExprs.push_back(NewEQ.get()); + } + + llvm::SmallVector TransformedClauses = + getDerived().TransformOpenACCClauseList(C->getDirectiveKind(), + C->clauses()); + + if (getSema().OpenACC().ActOnStartStmtDirective( + C->getDirectiveKind(), C->getBeginLoc(), TransformedClauses)) + return StmtError(); + + return getDerived().RebuildOpenACCWaitConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getLParenLoc(), + DevNumExpr.isUsable() ? DevNumExpr.get() : nullptr, C->getQueuesLoc(), + QueueIdExprs, C->getRParenLoc(), C->getEndLoc(), TransformedClauses); +} + template ExprResult TreeTransform::TransformOpenACCAsteriskSizeExpr( OpenACCAsteriskSizeExpr *E) { diff --git a/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h index 2a765eafe0895..7c9ec884ea049 100644 --- a/clang/lib/Serialization/ASTCommon.h +++ b/clang/lib/Serialization/ASTCommon.h @@ -24,7 +24,6 @@ namespace serialization { enum DeclUpdateKind { UPD_CXX_ADDED_IMPLICIT_MEMBER, - UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, UPD_CXX_ADDED_FUNCTION_DEFINITION, UPD_CXX_ADDED_VAR_DEFINITION, diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index ec85fad3389a1..21f6b2ecc58c4 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12,6 +12,7 @@ #include "ASTCommon.h" #include "ASTReaderInternals.h" +#include "TemplateArgumentHasher.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -1295,6 +1296,42 @@ void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, } } +ModuleFile * +LazySpecializationInfoLookupTrait::ReadFileRef(const unsigned char *&d) { + using namespace llvm::support; + + uint32_t ModuleFileID = + endian::readNext(d); + return Reader.getLocalModuleFile(F, ModuleFileID); +} + +LazySpecializationInfoLookupTrait::internal_key_type +LazySpecializationInfoLookupTrait::ReadKey(const unsigned char *d, unsigned) { + using namespace llvm::support; + return endian::readNext(d); +} + +std::pair +LazySpecializationInfoLookupTrait::ReadKeyDataLength(const unsigned char *&d) { + return readULEBKeyDataLength(d); +} + +void LazySpecializationInfoLookupTrait::ReadDataInto(internal_key_type, + const unsigned char *d, + unsigned DataLen, + data_type_builder &Val) { + using namespace llvm::support; + + for (unsigned NumDecls = + DataLen / sizeof(serialization::reader::LazySpecializationInfo); + NumDecls; --NumDecls) { + LocalDeclID LocalID = LocalDeclID::get( + Reader, F, + endian::readNext(d)); + Val.insert(Reader.getGlobalDeclID(F, LocalID)); + } +} + bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, BitstreamCursor &Cursor, uint64_t Offset, @@ -1379,7 +1416,52 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, // We can't safely determine the primary context yet, so delay attaching the // lookup table until we're done with recursive deserialization. auto *Data = (const unsigned char*)Blob.data(); - PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data}); + PendingVisibleUpdates[ID].push_back(UpdateData{&M, Data}); + return false; +} + +void ASTReader::AddSpecializations(const Decl *D, const unsigned char *Data, + ModuleFile &M, bool IsPartial) { + D = D->getCanonicalDecl(); + auto &SpecLookups = + IsPartial ? PartialSpecializationsLookups : SpecializationsLookups; + SpecLookups[D].Table.add(&M, Data, + reader::LazySpecializationInfoLookupTrait(*this, M)); +} + +bool ASTReader::ReadSpecializations(ModuleFile &M, BitstreamCursor &Cursor, + uint64_t Offset, Decl *D, bool IsPartial) { + assert(Offset != 0); + + SavedStreamPosition SavedPosition(Cursor); + if (llvm::Error Err = Cursor.JumpToBit(Offset)) { + Error(std::move(Err)); + return true; + } + + RecordData Record; + StringRef Blob; + Expected MaybeCode = Cursor.ReadCode(); + if (!MaybeCode) { + Error(MaybeCode.takeError()); + return true; + } + unsigned Code = MaybeCode.get(); + + Expected MaybeRecCode = Cursor.readRecord(Code, Record, &Blob); + if (!MaybeRecCode) { + Error(MaybeRecCode.takeError()); + return true; + } + unsigned RecCode = MaybeRecCode.get(); + if (RecCode != DECL_SPECIALIZATIONS && + RecCode != DECL_PARTIAL_SPECIALIZATIONS) { + Error("Expected decl specs block"); + return true; + } + + auto *Data = (const unsigned char *)Blob.data(); + AddSpecializations(D, Data, M, IsPartial); return false; } @@ -3458,7 +3540,33 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, unsigned Idx = 0; GlobalDeclID ID = ReadDeclID(F, Record, Idx); auto *Data = (const unsigned char*)Blob.data(); - PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data}); + PendingVisibleUpdates[ID].push_back(UpdateData{&F, Data}); + // If we've already loaded the decl, perform the updates when we finish + // loading this block. + if (Decl *D = GetExistingDecl(ID)) + PendingUpdateRecords.push_back( + PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); + break; + } + + case CXX_ADDED_TEMPLATE_SPECIALIZATION: { + unsigned Idx = 0; + GlobalDeclID ID = ReadDeclID(F, Record, Idx); + auto *Data = (const unsigned char *)Blob.data(); + PendingSpecializationsUpdates[ID].push_back(UpdateData{&F, Data}); + // If we've already loaded the decl, perform the updates when we finish + // loading this block. + if (Decl *D = GetExistingDecl(ID)) + PendingUpdateRecords.push_back( + PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); + break; + } + + case CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION: { + unsigned Idx = 0; + GlobalDeclID ID = ReadDeclID(F, Record, Idx); + auto *Data = (const unsigned char *)Blob.data(); + PendingPartialSpecializationsUpdates[ID].push_back(UpdateData{&F, Data}); // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) @@ -3855,14 +3963,14 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, break; } - case FUNCTION_DECL_TO_LAMBDAS_MAP: + case RELATED_DECLS_MAP: for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) { GlobalDeclID ID = ReadDeclID(F, Record, I); - auto &Lambdas = FunctionToLambdasMap[ID]; + auto &RelatedDecls = RelatedDeclsMap[ID]; unsigned NN = Record[I++]; - Lambdas.reserve(NN); + RelatedDecls.reserve(NN); for (unsigned II = 0; II < NN; II++) - Lambdas.push_back(ReadDeclID(F, Record, I)); + RelatedDecls.push_back(ReadDeclID(F, Record, I)); } break; @@ -7654,13 +7762,28 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { } } - if (auto *CTSD = dyn_cast(D)) - CTSD->getSpecializedTemplate()->LoadLazySpecializations(); - if (auto *VTSD = dyn_cast(D)) - VTSD->getSpecializedTemplate()->LoadLazySpecializations(); - if (auto *FD = dyn_cast(D)) { - if (auto *Template = FD->getPrimaryTemplate()) - Template->LoadLazySpecializations(); + RedeclarableTemplateDecl *Template = nullptr; + ArrayRef Args; + if (auto *CTSD = dyn_cast(D)) { + Template = CTSD->getSpecializedTemplate(); + Args = CTSD->getTemplateArgs().asArray(); + } else if (auto *VTSD = dyn_cast(D)) { + Template = VTSD->getSpecializedTemplate(); + Args = VTSD->getTemplateArgs().asArray(); + } else if (auto *FD = dyn_cast(D)) { + if (auto *Tmplt = FD->getPrimaryTemplate()) { + Template = Tmplt; + Args = FD->getTemplateSpecializationArgs()->asArray(); + } + } + + if (Template) { + // For partitial specialization, load all the specializations for safety. + if (isa(D)) + Template->loadLazySpecializationsImpl(); + else + Template->loadLazySpecializationsImpl(Args); } } @@ -8042,6 +8165,86 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { return ReadStmtFromStream(*Loc.F); } +bool ASTReader::LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, + const Decl *D) { + assert(D); + + auto It = SpecLookups.find(D); + if (It == SpecLookups.end()) + return false; + + // Get Decl may violate the iterator from SpecializationsLookups so we store + // the DeclIDs in ahead. + llvm::SmallVector Infos = + It->second.Table.findAll(); + + // Since we've loaded all the specializations, we can erase it from + // the lookup table. + SpecLookups.erase(It); + + bool NewSpecsFound = false; + Deserializing LookupResults(this); + for (auto &Info : Infos) { + if (GetExistingDecl(Info)) + continue; + NewSpecsFound = true; + GetDecl(Info); + } + + return NewSpecsFound; +} + +bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) { + assert(D); + + bool NewSpecsFound = + LoadExternalSpecializationsImpl(PartialSpecializationsLookups, D); + if (OnlyPartial) + return NewSpecsFound; + + NewSpecsFound |= LoadExternalSpecializationsImpl(SpecializationsLookups, D); + return NewSpecsFound; +} + +bool ASTReader::LoadExternalSpecializationsImpl( + SpecLookupTableTy &SpecLookups, const Decl *D, + ArrayRef TemplateArgs) { + assert(D); + + auto It = SpecLookups.find(D); + if (It == SpecLookups.end()) + return false; + + Deserializing LookupResults(this); + auto HashValue = StableHashForTemplateArguments(TemplateArgs); + + // Get Decl may violate the iterator from SpecLookups + llvm::SmallVector Infos = + It->second.Table.find(HashValue); + + bool NewSpecsFound = false; + for (auto &Info : Infos) { + if (GetExistingDecl(Info)) + continue; + NewSpecsFound = true; + GetDecl(Info); + } + + return NewSpecsFound; +} + +bool ASTReader::LoadExternalSpecializations( + const Decl *D, ArrayRef TemplateArgs) { + assert(D); + + bool NewDeclsFound = LoadExternalSpecializationsImpl( + PartialSpecializationsLookups, D, TemplateArgs); + NewDeclsFound |= + LoadExternalSpecializationsImpl(SpecializationsLookups, D, TemplateArgs); + + return NewDeclsFound; +} + void ASTReader::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Decls) { @@ -8221,6 +8424,22 @@ ASTReader::getLoadedLookupTables(DeclContext *Primary) const { return I == Lookups.end() ? nullptr : &I->second; } +serialization::reader::LazySpecializationInfoLookupTable * +ASTReader::getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial) { + assert(D->isCanonicalDecl()); + auto &LookupTable = + IsPartial ? PartialSpecializationsLookups : SpecializationsLookups; + auto I = LookupTable.find(D); + return I == LookupTable.end() ? nullptr : &I->second; +} + +bool ASTReader::haveUnloadedSpecializations(const Decl *D) const { + assert(D->isCanonicalDecl()); + return (PartialSpecializationsLookups.find(D) != + PartialSpecializationsLookups.end()) || + (SpecializationsLookups.find(D) != SpecializationsLookups.end()); +} + /// Under non-PCH compilation the consumer receives the objc methods /// before receiving the implementation, and codegen depends on this. /// We simulate this by deserializing and passing to consumer the methods of the @@ -10059,19 +10278,6 @@ void ASTReader::finishPendingActions() { PBEnd = PendingBodies.end(); PB != PBEnd; ++PB) { if (FunctionDecl *FD = dyn_cast(PB->first)) { - // For a function defined inline within a class template, force the - // canonical definition to be the one inside the canonical definition of - // the template. This ensures that we instantiate from a correct view - // of the template. - // - // Sadly we can't do this more generally: we can't be sure that all - // copies of an arbitrary class definition will have the same members - // defined (eg, some member functions may not be instantiated, and some - // special members may or may not have been implicitly defined). - if (auto *RD = dyn_cast(FD->getLexicalParent())) - if (RD->isDependentContext() && !RD->isThisDeclarationADefinition()) - continue; - // FIXME: Check for =delete/=default? const FunctionDecl *Defn = nullptr; if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) { @@ -12223,6 +12429,24 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { return OpenACCAttachClause::Create(getContext(), BeginLoc, LParenLoc, VarList, EndLoc); } + case OpenACCClauseKind::Detach: { + SourceLocation LParenLoc = readSourceLocation(); + llvm::SmallVector VarList = readOpenACCVarList(); + return OpenACCDetachClause::Create(getContext(), BeginLoc, LParenLoc, + VarList, EndLoc); + } + case OpenACCClauseKind::Delete: { + SourceLocation LParenLoc = readSourceLocation(); + llvm::SmallVector VarList = readOpenACCVarList(); + return OpenACCDeleteClause::Create(getContext(), BeginLoc, LParenLoc, + VarList, EndLoc); + } + case OpenACCClauseKind::UseDevice: { + SourceLocation LParenLoc = readSourceLocation(); + llvm::SmallVector VarList = readOpenACCVarList(); + return OpenACCUseDeviceClause::Create(getContext(), BeginLoc, LParenLoc, + VarList, EndLoc); + } case OpenACCClauseKind::DevicePtr: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); @@ -12315,6 +12539,10 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { } case OpenACCClauseKind::Seq: return OpenACCSeqClause::Create(getContext(), BeginLoc, EndLoc); + case OpenACCClauseKind::Finalize: + return OpenACCFinalizeClause::Create(getContext(), BeginLoc, EndLoc); + case OpenACCClauseKind::IfPresent: + return OpenACCIfPresentClause::Create(getContext(), BeginLoc, EndLoc); case OpenACCClauseKind::Independent: return OpenACCIndependentClause::Create(getContext(), BeginLoc, EndLoc); case OpenACCClauseKind::Auto: @@ -12360,12 +12588,7 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { VectorExpr, EndLoc); } - case OpenACCClauseKind::Finalize: - case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::NoHost: - case OpenACCClauseKind::UseDevice: - case OpenACCClauseKind::Delete: - case OpenACCClauseKind::Detach: case OpenACCClauseKind::Device: case OpenACCClauseKind::DeviceResident: case OpenACCClauseKind::Host: diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index ff0b963039238..719bc0d06f5b1 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -187,11 +187,6 @@ class ASTDeclReader : public DeclVisitor { std::string readString() { return Record.readString(); } - void readDeclIDList(SmallVectorImpl &IDs) { - for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) - IDs.push_back(readDeclID()); - } - Decl *readDecl() { return Record.readDecl(); } template T *readDeclAs() { return Record.readDeclAs(); } @@ -284,30 +279,6 @@ class ASTDeclReader : public DeclVisitor { : Reader(Reader), MergeImpl(Reader), Record(Record), Loc(Loc), ThisDeclID(thisDeclID), ThisDeclLoc(ThisDeclLoc) {} - template - static void AddLazySpecializations(T *D, SmallVectorImpl &IDs) { - if (IDs.empty()) - return; - - // FIXME: We should avoid this pattern of getting the ASTContext. - ASTContext &C = D->getASTContext(); - - auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; - - if (auto &Old = LazySpecializations) { - IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].getRawValue()); - llvm::sort(IDs); - IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); - } - - auto *Result = new (C) GlobalDeclID[1 + IDs.size()]; - *Result = GlobalDeclID(IDs.size()); - - std::copy(IDs.begin(), IDs.end(), Result + 1); - - LazySpecializations = Result; - } - template static Decl *getMostRecentDeclImpl(Redeclarable *D); static Decl *getMostRecentDeclImpl(...); @@ -332,10 +303,13 @@ class ASTDeclReader : public DeclVisitor { static void markIncompleteDeclChainImpl(Redeclarable *D); static void markIncompleteDeclChainImpl(...); + void ReadSpecializations(ModuleFile &M, Decl *D, + llvm::BitstreamCursor &DeclsCursor, bool IsPartial); + void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D, SmallVectorImpl &); + void UpdateDecl(Decl *D); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -2418,6 +2392,16 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl( void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { } +void ASTDeclReader::ReadSpecializations(ModuleFile &M, Decl *D, + llvm::BitstreamCursor &DeclsCursor, + bool IsPartial) { + uint64_t Offset = ReadLocalOffset(); + bool Failed = + Reader.ReadSpecializations(M, DeclsCursor, Offset, D, IsPartial); + (void)Failed; + assert(!Failed); +} + RedeclarableResult ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); @@ -2456,9 +2440,8 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - SmallVector SpecIDs; - readDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true); } if (D->getTemplatedDecl()->TemplateOrInstantiation) { @@ -2484,9 +2467,8 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. - SmallVector SpecIDs; - readDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/true); } } @@ -2585,9 +2567,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This FunctionTemplateDecl owns a CommonPtr; read it. - SmallVector SpecIDs; - readDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor, /*IsPartial=*/false); } } @@ -3877,6 +3857,8 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) { switch ((DeclCode)MaybeDeclCode.get()) { case DECL_CONTEXT_LEXICAL: case DECL_CONTEXT_VISIBLE: + case DECL_SPECIALIZATIONS: + case DECL_PARTIAL_SPECIALIZATIONS: llvm_unreachable("Record cannot be de-serialized with readDeclRecord"); case DECL_TYPEDEF: D = TypedefDecl::CreateDeserialized(Context, ID); @@ -4286,8 +4268,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); - SmallVector PendingLazySpecializationIDs; - if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); DeclUpdateOffsets.erase(UpdI); @@ -4324,7 +4304,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID, SourceLocation()); - Reader.UpdateDecl(D, PendingLazySpecializationIDs); + Reader.UpdateDecl(D); // We might have made this declaration interesting. If so, remember that // we need to hand it off to the consumer. @@ -4334,17 +4314,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { } } } - // Add the lazy specializations to the template. - assert((PendingLazySpecializationIDs.empty() || isa(D) || - isa(D)) && - "Must not have pending specializations"); - if (auto *CTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs); - else if (auto *FTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs); - else if (auto *VTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs); - PendingLazySpecializationIDs.clear(); // Load the pending visible updates for this decl context, if it has any. auto I = PendingVisibleUpdates.find(ID); @@ -4360,15 +4329,34 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { DC->setHasExternalVisibleStorage(true); } - // Load any pending lambdas for the function. - if (auto *FD = dyn_cast(D); FD && FD->isCanonicalDecl()) { - if (auto IT = FunctionToLambdasMap.find(ID); - IT != FunctionToLambdasMap.end()) { + // Load any pending related decls. + if (D->isCanonicalDecl()) { + if (auto IT = RelatedDeclsMap.find(ID); IT != RelatedDeclsMap.end()) { for (auto LID : IT->second) GetDecl(LID); - FunctionToLambdasMap.erase(IT); + RelatedDeclsMap.erase(IT); } } + + // Load the pending specializations update for this decl, if it has any. + if (auto I = PendingSpecializationsUpdates.find(ID); + I != PendingSpecializationsUpdates.end()) { + auto SpecializationUpdates = std::move(I->second); + PendingSpecializationsUpdates.erase(I); + + for (const auto &Update : SpecializationUpdates) + AddSpecializations(D, Update.Data, *Update.Mod, /*IsPartial=*/false); + } + + // Load the pending specializations update for this decl, if it has any. + if (auto I = PendingPartialSpecializationsUpdates.find(ID); + I != PendingPartialSpecializationsUpdates.end()) { + auto SpecializationUpdates = std::move(I->second); + PendingPartialSpecializationsUpdates.erase(I); + + for (const auto &Update : SpecializationUpdates) + AddSpecializations(D, Update.Data, *Update.Mod, /*IsPartial=*/true); + } } void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { @@ -4561,9 +4549,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } } -void ASTDeclReader::UpdateDecl( - Decl *D, - llvm::SmallVectorImpl &PendingLazySpecializationIDs) { +void ASTDeclReader::UpdateDecl(Decl *D) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -4574,11 +4560,6 @@ void ASTDeclReader::UpdateDecl( break; } - case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: - // It will be added to the template's lazy specialization set. - PendingLazySpecializationIDs.push_back(readDeclID()); - break; - case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { auto *Anon = readDeclAs(); diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h index 4f7e6f4b2741b..be0d22d1f4094 100644 --- a/clang/lib/Serialization/ASTReaderInternals.h +++ b/clang/lib/Serialization/ASTReaderInternals.h @@ -119,6 +119,88 @@ struct DeclContextLookupTable { MultiOnDiskHashTable Table; }; +using LazySpecializationInfo = GlobalDeclID; + +/// Class that performs lookup to specialized decls. +class LazySpecializationInfoLookupTrait { + ASTReader &Reader; + ModuleFile &F; + +public: + // Maximum number of lookup tables we allow before condensing the tables. + static const int MaxTables = 4; + + /// The lookup result is a list of global declaration IDs. + using data_type = SmallVector; + + struct data_type_builder { + data_type &Data; + llvm::DenseSet Found; + + data_type_builder(data_type &D) : Data(D) {} + + void insert(LazySpecializationInfo Info) { + // Just use a linear scan unless we have more than a few IDs. + if (Found.empty() && !Data.empty()) { + if (Data.size() <= 4) { + for (auto I : Found) + if (I == Info) + return; + Data.push_back(Info); + return; + } + + // Switch to tracking found IDs in the set. + Found.insert(Data.begin(), Data.end()); + } + + if (Found.insert(Info).second) + Data.push_back(Info); + } + }; + using hash_value_type = unsigned; + using offset_type = unsigned; + using file_type = ModuleFile *; + + using external_key_type = unsigned; + using internal_key_type = unsigned; + + explicit LazySpecializationInfoLookupTrait(ASTReader &Reader, ModuleFile &F) + : Reader(Reader), F(F) {} + + static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { + return a == b; + } + + static hash_value_type ComputeHash(const internal_key_type &Key) { + return Key; + } + + static internal_key_type GetInternalKey(const external_key_type &Name) { + return Name; + } + + static std::pair + ReadKeyDataLength(const unsigned char *&d); + + internal_key_type ReadKey(const unsigned char *d, unsigned); + + void ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen, + data_type_builder &Val); + + static void MergeDataInto(const data_type &From, data_type_builder &To) { + To.Data.reserve(To.Data.size() + From.size()); + for (LazySpecializationInfo Info : From) + To.insert(Info); + } + + file_type ReadFileRef(const unsigned char *&d); +}; + +struct LazySpecializationInfoLookupTable { + MultiOnDiskHashTable Table; +}; + /// Base class for the trait describing the on-disk hash table for the /// identifiers in an AST file. /// diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 9f4877b19d870..8fe0412706ce3 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2849,6 +2849,43 @@ void ASTStmtReader::VisitOpenACCCombinedConstruct(OpenACCCombinedConstruct *S) { VisitOpenACCAssociatedStmtConstruct(S); } +void ASTStmtReader::VisitOpenACCDataConstruct(OpenACCDataConstruct *S) { + VisitStmt(S); + VisitOpenACCAssociatedStmtConstruct(S); +} + +void ASTStmtReader::VisitOpenACCEnterDataConstruct( + OpenACCEnterDataConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); +} + +void ASTStmtReader::VisitOpenACCExitDataConstruct(OpenACCExitDataConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); +} + +void ASTStmtReader::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { + VisitStmt(S); + VisitOpenACCAssociatedStmtConstruct(S); +} + +void ASTStmtReader::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) { + VisitStmt(S); + // Consume the count of Expressions. + (void)Record.readInt(); + VisitOpenACCConstructStmt(S); + S->LParenLoc = Record.readSourceLocation(); + S->RParenLoc = Record.readSourceLocation(); + S->QueuesLoc = Record.readSourceLocation(); + + for (unsigned I = 0; I < S->NumExprs; ++I) { + S->getExprPtr()[I] = cast_if_present(Record.readSubStmt()); + assert((I == 0 || S->getExprPtr()[I] != nullptr) && + "Only first expression should be null"); + } +} + //===----------------------------------------------------------------------===// // HLSL Constructs/Directives. //===----------------------------------------------------------------------===// @@ -4324,6 +4361,32 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = OpenACCCombinedConstruct::CreateEmpty(Context, NumClauses); break; } + case STMT_OPENACC_DATA_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCDataConstruct::CreateEmpty(Context, NumClauses); + break; + } + case STMT_OPENACC_ENTER_DATA_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCEnterDataConstruct::CreateEmpty(Context, NumClauses); + break; + } + case STMT_OPENACC_EXIT_DATA_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCExitDataConstruct::CreateEmpty(Context, NumClauses); + break; + } + case STMT_OPENACC_HOST_DATA_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCHostDataConstruct::CreateEmpty(Context, NumClauses); + break; + } + case STMT_OPENACC_WAIT_CONSTRUCT: { + unsigned NumExprs = Record[ASTStmtReader::NumStmtFields]; + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1]; + S = OpenACCWaitConstruct::CreateEmpty(Context, NumExprs, NumClauses); + break; + } case EXPR_REQUIRES: { unsigned numLocalParameters = Record[ASTStmtReader::NumExprFields]; unsigned numRequirement = Record[ASTStmtReader::NumExprFields + 1]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 368e8f2367543..6db2262a7952e 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -13,6 +13,7 @@ #include "ASTCommon.h" #include "ASTReaderInternals.h" #include "MultiOnDiskHashTable.h" +#include "TemplateArgumentHasher.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/AbstractTypeWriter.h" @@ -940,7 +941,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(PENDING_IMPLICIT_INSTANTIATIONS); RECORD(UPDATE_VISIBLE); RECORD(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD); - RECORD(FUNCTION_DECL_TO_LAMBDAS_MAP); + RECORD(RELATED_DECLS_MAP); RECORD(DECL_UPDATE_OFFSETS); RECORD(DECL_UPDATES); RECORD(CUDA_SPECIAL_DECL_REFS); @@ -4167,6 +4168,175 @@ class ASTDeclContextNameLookupTrait { } // namespace +namespace { +class LazySpecializationInfoLookupTrait { + ASTWriter &Writer; + llvm::SmallVector Specs; + +public: + using key_type = unsigned; + using key_type_ref = key_type; + + /// A start and end index into Specs, representing a sequence of decls. + using data_type = std::pair; + using data_type_ref = const data_type &; + + using hash_value_type = unsigned; + using offset_type = unsigned; + + explicit LazySpecializationInfoLookupTrait(ASTWriter &Writer) + : Writer(Writer) {} + + template + data_type getData(Col &&C, Col2 &ExistingInfo) { + unsigned Start = Specs.size(); + for (auto *D : C) { + NamedDecl *ND = getDeclForLocalLookup(Writer.getLangOpts(), + const_cast(D)); + Specs.push_back(GlobalDeclID(Writer.GetDeclRef(ND).getRawValue())); + } + for (const serialization::reader::LazySpecializationInfo &Info : + ExistingInfo) + Specs.push_back(Info); + return std::make_pair(Start, Specs.size()); + } + + data_type ImportData( + const reader::LazySpecializationInfoLookupTrait::data_type &FromReader) { + unsigned Start = Specs.size(); + for (auto ID : FromReader) + Specs.push_back(ID); + return std::make_pair(Start, Specs.size()); + } + + static bool EqualKey(key_type_ref a, key_type_ref b) { return a == b; } + + hash_value_type ComputeHash(key_type Name) { return Name; } + + void EmitFileRef(raw_ostream &Out, ModuleFile *F) const { + assert(Writer.hasChain() && + "have reference to loaded module file but no chain?"); + + using namespace llvm::support; + endian::write(Out, Writer.getChain()->getModuleFileID(F), + llvm::endianness::little); + } + + std::pair EmitKeyDataLength(raw_ostream &Out, + key_type HashValue, + data_type_ref Lookup) { + // 4 bytes for each slot. + unsigned KeyLen = 4; + unsigned DataLen = sizeof(serialization::reader::LazySpecializationInfo) * + (Lookup.second - Lookup.first); + + return emitULEBKeyDataLength(KeyLen, DataLen, Out); + } + + void EmitKey(raw_ostream &Out, key_type HashValue, unsigned) { + using namespace llvm::support; + + endian::Writer LE(Out, llvm::endianness::little); + LE.write(HashValue); + } + + void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup, + unsigned DataLen) { + using namespace llvm::support; + + endian::Writer LE(Out, llvm::endianness::little); + uint64_t Start = Out.tell(); + (void)Start; + for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) { + LE.write(Specs[I].getRawValue()); + } + assert(Out.tell() - Start == DataLen && "Data length is wrong"); + } +}; + +unsigned CalculateODRHashForSpecs(const Decl *Spec) { + ArrayRef Args; + if (auto *CTSD = dyn_cast(Spec)) + Args = CTSD->getTemplateArgs().asArray(); + else if (auto *VTSD = dyn_cast(Spec)) + Args = VTSD->getTemplateArgs().asArray(); + else if (auto *FD = dyn_cast(Spec)) + Args = FD->getTemplateSpecializationArgs()->asArray(); + else + llvm_unreachable("New Specialization Kind?"); + + return StableHashForTemplateArguments(Args); +} +} // namespace + +void ASTWriter::GenerateSpecializationInfoLookupTable( + const NamedDecl *D, llvm::SmallVectorImpl &Specializations, + llvm::SmallVectorImpl &LookupTable, bool IsPartial) { + assert(D->isFirstDecl()); + + // Create the on-disk hash table representation. + MultiOnDiskHashTableGenerator + Generator; + LazySpecializationInfoLookupTrait Trait(*this); + + llvm::DenseMap> + SpecializationMaps; + + for (auto *Specialization : Specializations) { + unsigned HashedValue = CalculateODRHashForSpecs(Specialization); + + auto Iter = SpecializationMaps.find(HashedValue); + if (Iter == SpecializationMaps.end()) + Iter = SpecializationMaps + .try_emplace(HashedValue, + llvm::SmallVector()) + .first; + + Iter->second.push_back(cast(Specialization)); + } + + auto *Lookups = + Chain ? Chain->getLoadedSpecializationsLookupTables(D, IsPartial) + : nullptr; + + for (auto &[HashValue, Specs] : SpecializationMaps) { + SmallVector + ExisitingSpecs; + // We have to merge the lookup table manually here. We can't depend on the + // merge mechanism offered by + // clang::serialization::MultiOnDiskHashTableGenerator since that generator + // assumes the we'll get the same value with the same key. + // And also underlying llvm::OnDiskChainedHashTableGenerator assumes that we + // won't insert the values with the same key twice. So we have to merge the + // lookup table here manually. + if (Lookups) + ExisitingSpecs = Lookups->Table.find(HashValue); + + Generator.insert(HashValue, Trait.getData(Specs, ExisitingSpecs), Trait); + } + + Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr); +} + +uint64_t ASTWriter::WriteSpecializationInfoLookupTable( + const NamedDecl *D, llvm::SmallVectorImpl &Specializations, + bool IsPartial) { + + llvm::SmallString<4096> LookupTable; + GenerateSpecializationInfoLookupTable(D, Specializations, LookupTable, + IsPartial); + + uint64_t Offset = Stream.GetCurrentBitNo(); + RecordData::value_type Record[] = {static_cast( + IsPartial ? DECL_PARTIAL_SPECIALIZATIONS : DECL_SPECIALIZATIONS)}; + Stream.EmitRecordWithBlob(IsPartial ? DeclPartialSpecializationsAbbrev + : DeclSpecializationsAbbrev, + Record, LookupTable); + + return Offset; +} + bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC) { return Result.hasExternalDecls() && @@ -5748,7 +5918,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { // Keep writing types, declarations, and declaration update records // until we've emitted all of them. RecordData DeclUpdatesOffsetsRecord; - Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5); + Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/ 6); DeclTypesBlockStartOffset = Stream.GetCurrentBitNo(); WriteTypeAbbrevs(); WriteDeclAbbrevs(); @@ -5802,26 +5972,36 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { Stream.EmitRecord(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD, DelayedNamespaceRecord); - if (!FunctionToLambdasMap.empty()) { - // TODO: on disk hash table for function to lambda mapping might be more + if (!RelatedDeclsMap.empty()) { + // TODO: on disk hash table for related decls mapping might be more // efficent becuase it allows lazy deserialization. - RecordData FunctionToLambdasMapRecord; - for (const auto &Pair : FunctionToLambdasMap) { - FunctionToLambdasMapRecord.push_back(Pair.first.getRawValue()); - FunctionToLambdasMapRecord.push_back(Pair.second.size()); + RecordData RelatedDeclsMapRecord; + for (const auto &Pair : RelatedDeclsMap) { + RelatedDeclsMapRecord.push_back(Pair.first.getRawValue()); + RelatedDeclsMapRecord.push_back(Pair.second.size()); for (const auto &Lambda : Pair.second) - FunctionToLambdasMapRecord.push_back(Lambda.getRawValue()); + RelatedDeclsMapRecord.push_back(Lambda.getRawValue()); } auto Abv = std::make_shared(); - Abv->Add(llvm::BitCodeAbbrevOp(FUNCTION_DECL_TO_LAMBDAS_MAP)); + Abv->Add(llvm::BitCodeAbbrevOp(RELATED_DECLS_MAP)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); unsigned FunctionToLambdaMapAbbrev = Stream.EmitAbbrev(std::move(Abv)); - Stream.EmitRecord(FUNCTION_DECL_TO_LAMBDAS_MAP, FunctionToLambdasMapRecord, + Stream.EmitRecord(RELATED_DECLS_MAP, RelatedDeclsMapRecord, FunctionToLambdaMapAbbrev); } + if (!SpecializationsUpdates.empty()) { + WriteSpecializationsUpdates(/*IsPartial=*/false); + SpecializationsUpdates.clear(); + } + + if (!PartialSpecializationsUpdates.empty()) { + WriteSpecializationsUpdates(/*IsPartial=*/true); + PartialSpecializationsUpdates.clear(); + } + const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); // Create a lexical update block containing all of the declarations in the // translation unit that do not come from other AST files. @@ -5865,6 +6045,33 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { WriteDeclContextVisibleUpdate(Context, DC); } +void ASTWriter::WriteSpecializationsUpdates(bool IsPartial) { + auto RecordType = IsPartial ? CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION + : CXX_ADDED_TEMPLATE_SPECIALIZATION; + + auto Abv = std::make_shared(); + Abv->Add(llvm::BitCodeAbbrevOp(RecordType)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + auto UpdateSpecializationAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + auto &SpecUpdates = + IsPartial ? PartialSpecializationsUpdates : SpecializationsUpdates; + for (auto &SpecializationUpdate : SpecUpdates) { + const NamedDecl *D = SpecializationUpdate.first; + + llvm::SmallString<4096> LookupTable; + GenerateSpecializationInfoLookupTable(D, SpecializationUpdate.second, + LookupTable, IsPartial); + + // Write the lookup table + RecordData::value_type Record[] = { + static_cast(RecordType), + getDeclID(D).getRawValue()}; + Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable); + } +} + void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context, RecordDataImpl &OffsetsRecord) { if (DeclUpdates.empty()) @@ -5894,12 +6101,10 @@ void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context, switch (Kind) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: - case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: assert(Update.getDecl() && "no decl to add?"); Record.AddDeclRef(Update.getDecl()); break; - case UPD_CXX_ADDED_FUNCTION_DEFINITION: case UPD_CXX_ADDED_VAR_DEFINITION: break; @@ -8151,6 +8356,24 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeOpenACCVarList(AC); return; } + case OpenACCClauseKind::Detach: { + const auto *DC = cast(C); + writeSourceLocation(DC->getLParenLoc()); + writeOpenACCVarList(DC); + return; + } + case OpenACCClauseKind::Delete: { + const auto *DC = cast(C); + writeSourceLocation(DC->getLParenLoc()); + writeOpenACCVarList(DC); + return; + } + case OpenACCClauseKind::UseDevice: { + const auto *UDC = cast(C); + writeSourceLocation(UDC->getLParenLoc()); + writeOpenACCVarList(UDC); + return; + } case OpenACCClauseKind::DevicePtr: { const auto *DPC = cast(C); writeSourceLocation(DPC->getLParenLoc()); @@ -8246,6 +8469,8 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::Seq: case OpenACCClauseKind::Independent: case OpenACCClauseKind::Auto: + case OpenACCClauseKind::Finalize: + case OpenACCClauseKind::IfPresent: // Nothing to do here, there is no additional information beyond the // begin/end loc and clause kind. return; @@ -8291,12 +8516,7 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { return; } - case OpenACCClauseKind::Finalize: - case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::NoHost: - case OpenACCClauseKind::UseDevice: - case OpenACCClauseKind::Delete: - case OpenACCClauseKind::Detach: case OpenACCClauseKind::Device: case OpenACCClauseKind::DeviceResident: case OpenACCClauseKind::Host: diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index c5112d46a95d7..75c1d9a6d438c 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -177,11 +177,12 @@ namespace clang { Record.AddSourceLocation(typeParams->getRAngleLoc()); } - /// Add to the record the first declaration from each module file that - /// provides a declaration of D. The intent is to provide a sufficient - /// set such that reloading this set will load all current redeclarations. - void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) { - llvm::MapVector Firsts; + /// Collect the first declaration from each module file that provides a + /// declaration of D. + void CollectFirstDeclFromEachModule( + const Decl *D, bool IncludeLocal, + llvm::MapVector &Firsts) { + // FIXME: We can skip entries that we know are implied by others. for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) { if (R->isFromASTFile()) @@ -189,10 +190,41 @@ namespace clang { else if (IncludeLocal) Firsts[nullptr] = R; } + } + + /// Add to the record the first declaration from each module file that + /// provides a declaration of D. The intent is to provide a sufficient + /// set such that reloading this set will load all current redeclarations. + void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) { + llvm::MapVector Firsts; + CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts); + for (const auto &F : Firsts) Record.AddDeclRef(F.second); } + /// Add to the record the first template specialization from each module + /// file that provides a declaration of D. We store the DeclId and an + /// ODRHash of the template arguments of D which should provide enough + /// information to load D only if the template instantiator needs it. + void AddFirstSpecializationDeclFromEachModule( + const Decl *D, llvm::SmallVectorImpl &SpecsInMap, + llvm::SmallVectorImpl &PartialSpecsInMap) { + assert((isa(D) || + isa(D) || isa(D)) && + "Must not be called with other decls"); + llvm::MapVector Firsts; + CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts); + + for (const auto &F : Firsts) { + if (isa(F.second)) + PartialSpecsInMap.push_back(F.second); + else + SpecsInMap.push_back(F.second); + } + } + /// Get the specialization decl from an entry in the specialization list. template typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType * @@ -205,8 +237,9 @@ namespace clang { decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) { return Common->PartialSpecializations; } - ArrayRef getPartialSpecializations(FunctionTemplateDecl::Common *) { - return {}; + MutableArrayRef + getPartialSpecializations(FunctionTemplateDecl::Common *) { + return std::nullopt; } template @@ -217,37 +250,37 @@ namespace clang { // our chained AST reader, we can just write out the DeclIDs. Otherwise, // we need to resolve them to actual declarations. if (Writer.Chain != Record.getASTContext().getExternalSource() && - Common->LazySpecializations) { + Writer.Chain && Writer.Chain->haveUnloadedSpecializations(D)) { D->LoadLazySpecializations(); - assert(!Common->LazySpecializations); + assert(!Writer.Chain->haveUnloadedSpecializations(D)); } - ArrayRef LazySpecializations; - if (auto *LS = Common->LazySpecializations) - LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].getRawValue()); - - // Add a slot to the record for the number of specializations. - unsigned I = Record.size(); - Record.push_back(0); - - // AddFirstDeclFromEachModule might trigger deserialization, invalidating - // *Specializations iterators. - llvm::SmallVector Specs; + // AddFirstSpecializationDeclFromEachModule might trigger deserialization, + // invalidating *Specializations iterators. + llvm::SmallVector AllSpecs; for (auto &Entry : Common->Specializations) - Specs.push_back(getSpecializationDecl(Entry)); + AllSpecs.push_back(getSpecializationDecl(Entry)); for (auto &Entry : getPartialSpecializations(Common)) - Specs.push_back(getSpecializationDecl(Entry)); + AllSpecs.push_back(getSpecializationDecl(Entry)); - for (auto *D : Specs) { + llvm::SmallVector Specs; + llvm::SmallVector PartialSpecs; + for (auto *D : AllSpecs) { assert(D->isCanonicalDecl() && "non-canonical decl in set"); - AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); + AddFirstSpecializationDeclFromEachModule(D, Specs, PartialSpecs); + } + + Record.AddOffset(Writer.WriteSpecializationInfoLookupTable( + D, Specs, /*IsPartial=*/false)); + + // Function Template Decl doesn't have partial decls. + if (isa(D)) { + assert(PartialSpecs.empty()); + return; } - Record.append( - DeclIDIterator(LazySpecializations.begin()), - DeclIDIterator(LazySpecializations.end())); - // Update the size entry we added earlier. - Record[I] = Record.size() - I - 1; + Record.AddOffset(Writer.WriteSpecializationInfoLookupTable( + D, PartialSpecs, /*IsPartial=*/true)); } /// Ensure that this template specialization is associated with the specified @@ -268,8 +301,13 @@ namespace clang { if (Writer.getFirstLocalDecl(Specialization) != Specialization) return; - Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate( - UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization)); + if (isa(Specialization)) + Writer.PartialSpecializationsUpdates[cast(Template)] + .push_back(cast(Specialization)); + else + Writer.SpecializationsUpdates[cast(Template)].push_back( + cast(Specialization)); } }; } @@ -760,6 +798,17 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { } } + if (D->getFriendObjectKind()) { + // For a function defined inline within a class template, we have to force + // the canonical definition to be the one inside the canonical definition of + // the template. Remember this relation to deserialize them together. + if (auto *RD = dyn_cast(D->getLexicalParent())) + if (RD->isDependentContext() && RD->isThisDeclarationADefinition()) { + Writer.RelatedDeclsMap[Writer.GetDeclRef(RD)].push_back( + Writer.GetDeclRef(D)); + } + } + Record.push_back(D->param_size()); for (auto *P : D->parameters()) Record.AddDeclRef(P); @@ -1525,7 +1574,7 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { // For lambdas inside canonical FunctionDecl remember the mapping. if (auto FD = llvm::dyn_cast_or_null(D->getDeclContext()); FD && FD->isCanonicalDecl()) { - Writer.FunctionToLambdasMap[Writer.GetDeclRef(FD)].push_back( + Writer.RelatedDeclsMap[Writer.GetDeclRef(FD)].push_back( Writer.GetDeclRef(D)); } } else { @@ -2774,6 +2823,16 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + Abv = std::make_shared(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_SPECIALIZATIONS)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + DeclSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + Abv = std::make_shared(); + Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARTIAL_SPECIALIZATIONS)); + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + DeclPartialSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv)); } /// isRequiredDecl - Check if this is a "required" Decl, which must be seen by diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 603aa5707ce9b..f13443d18b612 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2926,6 +2926,45 @@ void ASTStmtWriter::VisitOpenACCCombinedConstruct(OpenACCCombinedConstruct *S) { Code = serialization::STMT_OPENACC_COMBINED_CONSTRUCT; } +void ASTStmtWriter::VisitOpenACCDataConstruct(OpenACCDataConstruct *S) { + VisitStmt(S); + VisitOpenACCAssociatedStmtConstruct(S); + Code = serialization::STMT_OPENACC_DATA_CONSTRUCT; +} + +void ASTStmtWriter::VisitOpenACCEnterDataConstruct( + OpenACCEnterDataConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); + Code = serialization::STMT_OPENACC_ENTER_DATA_CONSTRUCT; +} + +void ASTStmtWriter::VisitOpenACCExitDataConstruct(OpenACCExitDataConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); + Code = serialization::STMT_OPENACC_EXIT_DATA_CONSTRUCT; +} + +void ASTStmtWriter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { + VisitStmt(S); + VisitOpenACCAssociatedStmtConstruct(S); + Code = serialization::STMT_OPENACC_HOST_DATA_CONSTRUCT; +} + +void ASTStmtWriter::VisitOpenACCWaitConstruct(OpenACCWaitConstruct *S) { + VisitStmt(S); + Record.push_back(S->getExprs().size()); + VisitOpenACCConstructStmt(S); + Record.AddSourceLocation(S->LParenLoc); + Record.AddSourceLocation(S->RParenLoc); + Record.AddSourceLocation(S->QueuesLoc); + + for(Expr *E : S->getExprs()) + Record.AddStmt(E); + + Code = serialization::STMT_OPENACC_WAIT_CONSTRUCT; +} + //===----------------------------------------------------------------------===// // HLSL Constructs/Directives. //===----------------------------------------------------------------------===// diff --git a/clang/lib/Serialization/CMakeLists.txt b/clang/lib/Serialization/CMakeLists.txt index 99c47c15a2f47..b1fc0345047f2 100644 --- a/clang/lib/Serialization/CMakeLists.txt +++ b/clang/lib/Serialization/CMakeLists.txt @@ -23,6 +23,7 @@ add_clang_library(clangSerialization ModuleManager.cpp PCHContainerOperations.cpp ObjectFilePCHContainerReader.cpp + TemplateArgumentHasher.cpp ADDITIONAL_HEADERS ASTCommon.h diff --git a/clang/lib/Serialization/TemplateArgumentHasher.cpp b/clang/lib/Serialization/TemplateArgumentHasher.cpp new file mode 100644 index 0000000000000..598f098f526d0 --- /dev/null +++ b/clang/lib/Serialization/TemplateArgumentHasher.cpp @@ -0,0 +1,409 @@ +//===- TemplateArgumentHasher.cpp - Hash Template Arguments -----*- 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 +// +//===----------------------------------------------------------------------===// + +#include "TemplateArgumentHasher.h" +#include "clang/AST/APValue.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/FoldingSet.h" + +using namespace clang; + +namespace { + +class TemplateArgumentHasher { + // If we bail out during the process of calculating hash values for + // template arguments for any reason. We're allowed to do it since + // TemplateArgumentHasher are only required to give the same hash value + // for the same template arguments, but not required to give different + // hash value for different template arguments. + // + // So in the worst case, it is still a valid implementation to give all + // inputs the same BailedOutValue as output. + bool BailedOut = false; + static constexpr unsigned BailedOutValue = 0x12345678; + + llvm::FoldingSetNodeID ID; + +public: + TemplateArgumentHasher() = default; + + void AddTemplateArgument(TemplateArgument TA); + + void AddInteger(unsigned V) { ID.AddInteger(V); } + + unsigned getValue() { + if (BailedOut) + return BailedOutValue; + + return ID.computeStableHash(); + } + + void setBailedOut() { BailedOut = true; } + + void AddType(const Type *T); + void AddQualType(QualType T); + void AddDecl(const Decl *D); + void AddStructuralValue(const APValue &); + void AddTemplateName(TemplateName Name); + void AddDeclarationName(DeclarationName Name); + void AddIdentifierInfo(const IdentifierInfo *II); +}; + +void TemplateArgumentHasher::AddTemplateArgument(TemplateArgument TA) { + const auto Kind = TA.getKind(); + AddInteger(Kind); + + switch (Kind) { + case TemplateArgument::Null: + llvm_unreachable("Expected valid TemplateArgument"); + case TemplateArgument::Type: + AddQualType(TA.getAsType()); + break; + case TemplateArgument::Declaration: + AddDecl(TA.getAsDecl()); + break; + case TemplateArgument::NullPtr: + ID.AddPointer(nullptr); + break; + case TemplateArgument::Integral: { + // There are integrals (e.g.: _BitInt(128)) that cannot be represented as + // any builtin integral type, so we use the hash of APSInt instead. + TA.getAsIntegral().Profile(ID); + break; + } + case TemplateArgument::StructuralValue: + AddQualType(TA.getStructuralValueType()); + AddStructuralValue(TA.getAsStructuralValue()); + break; + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + AddTemplateName(TA.getAsTemplateOrTemplatePattern()); + break; + case TemplateArgument::Expression: + // If we meet expression in template argument, it implies + // that the template is still dependent. It is meaningless + // to get a stable hash for the template. Bail out simply. + BailedOut = true; + break; + case TemplateArgument::Pack: + AddInteger(TA.pack_size()); + for (auto SubTA : TA.pack_elements()) { + AddTemplateArgument(SubTA); + } + break; + } +} + +void TemplateArgumentHasher::AddStructuralValue(const APValue &Value) { + auto Kind = Value.getKind(); + AddInteger(Kind); + + // 'APValue::Profile' uses pointer values to make hash for LValue and + // MemberPointer, but they differ from one compiler invocation to another. + // It may be difficult to handle such cases. Bail out simply. + + if (Kind == APValue::LValue || Kind == APValue::MemberPointer) { + BailedOut = true; + return; + } + + Value.Profile(ID); +} + +void TemplateArgumentHasher::AddTemplateName(TemplateName Name) { + switch (Name.getKind()) { + case TemplateName::Template: + AddDecl(Name.getAsTemplateDecl()); + break; + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName(); + AddTemplateName(QTN->getUnderlyingTemplate()); + break; + } + case TemplateName::OverloadedTemplate: + case TemplateName::AssumedTemplate: + case TemplateName::DependentTemplate: + case TemplateName::SubstTemplateTemplateParm: + case TemplateName::SubstTemplateTemplateParmPack: + BailedOut = true; + break; + case TemplateName::UsingTemplate: { + UsingShadowDecl *USD = Name.getAsUsingShadowDecl(); + if (USD) + AddDecl(USD->getTargetDecl()); + else + BailedOut = true; + break; + } + case TemplateName::DeducedTemplate: + AddTemplateName(Name.getAsDeducedTemplateName()->getUnderlying()); + break; + } +} + +void TemplateArgumentHasher::AddIdentifierInfo(const IdentifierInfo *II) { + assert(II && "Expecting non-null pointer."); + ID.AddString(II->getName()); +} + +void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) { + if (Name.isEmpty()) + return; + + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + AddIdentifierInfo(Name.getAsIdentifierInfo()); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + BailedOut = true; + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + AddQualType(Name.getCXXNameType()); + break; + case DeclarationName::CXXOperatorName: + AddInteger(Name.getCXXOverloadedOperator()); + break; + case DeclarationName::CXXLiteralOperatorName: + AddIdentifierInfo(Name.getCXXLiteralIdentifier()); + break; + case DeclarationName::CXXConversionFunctionName: + AddQualType(Name.getCXXNameType()); + break; + case DeclarationName::CXXUsingDirective: + break; + case DeclarationName::CXXDeductionGuideName: { + if (auto *Template = Name.getCXXDeductionGuideTemplate()) + AddDecl(Template); + } + } +} + +void TemplateArgumentHasher::AddDecl(const Decl *D) { + const NamedDecl *ND = dyn_cast(D); + if (!ND) { + BailedOut = true; + return; + } + + AddDeclarationName(ND->getDeclName()); +} + +void TemplateArgumentHasher::AddQualType(QualType T) { + if (T.isNull()) { + BailedOut = true; + return; + } + SplitQualType split = T.split(); + AddInteger(split.Quals.getAsOpaqueValue()); + AddType(split.Ty); +} + +// Process a Type pointer. Add* methods call back into TemplateArgumentHasher +// while Visit* methods process the relevant parts of the Type. +// Any unhandled type will make the hash computation bail out. +class TypeVisitorHelper : public TypeVisitor { + typedef TypeVisitor Inherited; + llvm::FoldingSetNodeID &ID; + TemplateArgumentHasher &Hash; + +public: + TypeVisitorHelper(llvm::FoldingSetNodeID &ID, TemplateArgumentHasher &Hash) + : ID(ID), Hash(Hash) {} + + void AddDecl(const Decl *D) { + if (D) + Hash.AddDecl(D); + else + Hash.AddInteger(0); + } + + void AddQualType(QualType T) { Hash.AddQualType(T); } + + void AddType(const Type *T) { + if (T) + Hash.AddType(T); + else + Hash.AddInteger(0); + } + + void VisitQualifiers(Qualifiers Quals) { + Hash.AddInteger(Quals.getAsOpaqueValue()); + } + + void Visit(const Type *T) { Inherited::Visit(T); } + + // Unhandled types. Bail out simply. + void VisitType(const Type *T) { Hash.setBailedOut(); } + + void VisitAdjustedType(const AdjustedType *T) { + AddQualType(T->getOriginalType()); + } + + void VisitDecayedType(const DecayedType *T) { + // getDecayedType and getPointeeType are derived from getAdjustedType + // and don't need to be separately processed. + VisitAdjustedType(T); + } + + void VisitArrayType(const ArrayType *T) { + AddQualType(T->getElementType()); + Hash.AddInteger(llvm::to_underlying(T->getSizeModifier())); + VisitQualifiers(T->getIndexTypeQualifiers()); + } + void VisitConstantArrayType(const ConstantArrayType *T) { + T->getSize().Profile(ID); + VisitArrayType(T); + } + + void VisitAttributedType(const AttributedType *T) { + Hash.AddInteger(T->getAttrKind()); + AddQualType(T->getModifiedType()); + } + + void VisitBuiltinType(const BuiltinType *T) { Hash.AddInteger(T->getKind()); } + + void VisitComplexType(const ComplexType *T) { + AddQualType(T->getElementType()); + } + + void VisitDecltypeType(const DecltypeType *T) { + AddQualType(T->getUnderlyingType()); + } + + void VisitDeducedType(const DeducedType *T) { + AddQualType(T->getDeducedType()); + } + + void VisitAutoType(const AutoType *T) { VisitDeducedType(T); } + + void VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + Hash.AddTemplateName(T->getTemplateName()); + VisitDeducedType(T); + } + + void VisitFunctionType(const FunctionType *T) { + AddQualType(T->getReturnType()); + T->getExtInfo().Profile(ID); + Hash.AddInteger(T->isConst()); + Hash.AddInteger(T->isVolatile()); + Hash.AddInteger(T->isRestrict()); + } + + void VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + VisitFunctionType(T); + } + + void VisitFunctionProtoType(const FunctionProtoType *T) { + Hash.AddInteger(T->getNumParams()); + for (auto ParamType : T->getParamTypes()) + AddQualType(ParamType); + + VisitFunctionType(T); + } + + void VisitMemberPointerType(const MemberPointerType *T) { + AddQualType(T->getPointeeType()); + AddType(T->getClass()); + } + + void VisitPackExpansionType(const PackExpansionType *T) { + AddQualType(T->getPattern()); + } + + void VisitParenType(const ParenType *T) { AddQualType(T->getInnerType()); } + + void VisitPointerType(const PointerType *T) { + AddQualType(T->getPointeeType()); + } + + void VisitReferenceType(const ReferenceType *T) { + AddQualType(T->getPointeeTypeAsWritten()); + } + + void VisitLValueReferenceType(const LValueReferenceType *T) { + VisitReferenceType(T); + } + + void VisitRValueReferenceType(const RValueReferenceType *T) { + VisitReferenceType(T); + } + + void + VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { + AddDecl(T->getAssociatedDecl()); + Hash.AddTemplateArgument(T->getArgumentPack()); + } + + void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { + AddDecl(T->getAssociatedDecl()); + AddQualType(T->getReplacementType()); + } + + void VisitTagType(const TagType *T) { AddDecl(T->getDecl()); } + + void VisitRecordType(const RecordType *T) { VisitTagType(T); } + void VisitEnumType(const EnumType *T) { VisitTagType(T); } + + void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { + Hash.AddInteger(T->template_arguments().size()); + for (const auto &TA : T->template_arguments()) { + Hash.AddTemplateArgument(TA); + } + Hash.AddTemplateName(T->getTemplateName()); + } + + void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + Hash.AddInteger(T->getDepth()); + Hash.AddInteger(T->getIndex()); + Hash.AddInteger(T->isParameterPack()); + } + + void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); } + + void VisitElaboratedType(const ElaboratedType *T) { + AddQualType(T->getNamedType()); + } + + void VisitUnaryTransformType(const UnaryTransformType *T) { + AddQualType(T->getUnderlyingType()); + AddQualType(T->getBaseType()); + } + + void VisitVectorType(const VectorType *T) { + AddQualType(T->getElementType()); + Hash.AddInteger(T->getNumElements()); + Hash.AddInteger(llvm::to_underlying(T->getVectorKind())); + } + + void VisitExtVectorType(const ExtVectorType *T) { VisitVectorType(T); } +}; + +void TemplateArgumentHasher::AddType(const Type *T) { + assert(T && "Expecting non-null pointer."); + TypeVisitorHelper(ID, *this).Visit(T); +} + +} // namespace + +unsigned clang::serialization::StableHashForTemplateArguments( + llvm::ArrayRef Args) { + TemplateArgumentHasher Hasher; + Hasher.AddInteger(Args.size()); + for (TemplateArgument Arg : Args) + Hasher.AddTemplateArgument(Arg); + return Hasher.getValue(); +} diff --git a/clang/lib/Serialization/TemplateArgumentHasher.h b/clang/lib/Serialization/TemplateArgumentHasher.h new file mode 100644 index 0000000000000..f23f1318afbbf --- /dev/null +++ b/clang/lib/Serialization/TemplateArgumentHasher.h @@ -0,0 +1,34 @@ +//===- TemplateArgumentHasher.h - Hash Template Arguments -------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TemplateBase.h" + +namespace clang { +namespace serialization { + +/// Calculate a stable hash value for template arguments. We guarantee that +/// the same template arguments must have the same hashed values. But we don't +/// guarantee that the template arguments with the same hashed value are the +/// same template arguments. +/// +/// ODR hashing may not be the best mechanism to hash the template +/// arguments. ODR hashing is (or perhaps, should be) about determining whether +/// two things are spelled the same way and have the same meaning (as required +/// by the C++ ODR), whereas what we want here is whether they have the same +/// meaning regardless of spelling. Maybe we can get away with reusing ODR +/// hashing anyway, on the basis that any canonical, non-dependent template +/// argument should have the same (invented) spelling in every translation +/// unit, but it is not sure that's true in all cases. There may still be cases +/// where the canonical type includes some aspect of "whatever we saw first", +/// in which case the ODR hash can differ across translation units for +/// non-dependent, canonical template arguments that are spelled differently +/// but have the same meaning. But it is not easy to raise examples. +unsigned StableHashForTemplateArguments(llvm::ArrayRef Args); + +} // namespace serialization +} // namespace clang diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b3cd594a0f352..abf5d3ec193a4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -13,6 +13,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtVisitor.h" #include namespace clang { @@ -33,7 +34,7 @@ bool tryToFindPtrOrigin( E = tempExpr->getSubExpr(); continue; } - if (auto *tempExpr = dyn_cast(E)) { + if (auto *tempExpr = dyn_cast(E)) { if (auto *C = tempExpr->getConstructor()) { if (auto *Class = C->getParent(); Class && isSafePtr(Class)) return callback(E, true); @@ -158,6 +159,9 @@ bool isConstOwnerPtrMemberExpr(const clang::Expr *E) { E = ThisArg; } } + } else if (auto *OCE = dyn_cast(E)) { + if (OCE->getOperator() == OO_Star && OCE->getNumArgs() == 1) + E = OCE->getArg(0); } auto *ME = dyn_cast(E); if (!ME) @@ -169,4 +173,42 @@ bool isConstOwnerPtrMemberExpr(const clang::Expr *E) { return isOwnerPtrType(T) && T.isConstQualified(); } +class EnsureFunctionVisitor + : public ConstStmtVisitor { +public: + bool VisitStmt(const Stmt *S) { + for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) + return false; + } + return true; + } + + bool VisitReturnStmt(const ReturnStmt *RS) { + if (auto *RV = RS->getRetValue()) { + RV = RV->IgnoreParenCasts(); + if (isa(RV)) + return true; + return isConstOwnerPtrMemberExpr(RV); + } + return false; + } +}; + +bool EnsureFunctionAnalysis::isACallToEnsureFn(const clang::Expr *E) const { + auto *MCE = dyn_cast(E); + if (!MCE) + return false; + auto *Callee = MCE->getDirectCallee(); + if (!Callee) + return false; + auto *Body = Callee->getBody(); + if (!Body) + return false; + auto [CacheIt, IsNew] = Cache.insert(std::make_pair(Callee, false)); + if (IsNew) + CacheIt->second = EnsureFunctionVisitor().Visit(Body); + return CacheIt->second; +} + } // namespace clang diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h index ddbef0fba0448..b508043d0f37f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h @@ -67,6 +67,16 @@ bool isASafeCallArg(const clang::Expr *E); /// \returns true if E is a MemberExpr accessing a const smart pointer type. bool isConstOwnerPtrMemberExpr(const clang::Expr *E); +/// \returns true if E is a CXXMemberCallExpr which returns a const smart +/// pointer type. +class EnsureFunctionAnalysis { + using CacheTy = llvm::DenseMap; + mutable CacheTy Cache{}; + +public: + bool isACallToEnsureFn(const Expr *E) const; +}; + /// \returns name of AST node or empty string. template std::string safeGetName(const T *ASTNode) { const auto *const ND = llvm::dyn_cast_or_null(ASTNode); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp index ef2d42ccada65..56fa72c100ec8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp @@ -33,6 +33,7 @@ class RawPtrRefCallArgsChecker mutable BugReporter *BR; TrivialFunctionAnalysis TFA; + EnsureFunctionAnalysis EFA; public: RawPtrRefCallArgsChecker(const char *description) @@ -140,7 +141,7 @@ class RawPtrRefCallArgsChecker bool isPtrOriginSafe(const Expr *Arg) const { return tryToFindPtrOrigin(Arg, /*StopAtFirstRefCountedObj=*/true, - [](const clang::Expr *ArgOrigin, bool IsSafe) { + [&](const clang::Expr *ArgOrigin, bool IsSafe) { if (IsSafe) return true; if (isa(ArgOrigin)) { @@ -154,6 +155,8 @@ class RawPtrRefCallArgsChecker } if (isASafeCallArg(ArgOrigin)) return true; + if (EFA.isACallToEnsureFn(ArgOrigin)) + return true; return false; }); } diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp index e0433c5c2c1a0..d586668399502 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp @@ -166,6 +166,7 @@ class RawPtrRefLocalVarsChecker : public Checker> { BugType Bug; mutable BugReporter *BR; + EnsureFunctionAnalysis EFA; public: RawPtrRefLocalVarsChecker(const char *description) @@ -263,7 +264,7 @@ class RawPtrRefLocalVarsChecker if (tryToFindPtrOrigin( Value, /*StopAtFirstRefCountedObj=*/false, [&](const clang::Expr *InitArgOrigin, bool IsSafe) { - if (!InitArgOrigin) + if (!InitArgOrigin || IsSafe) return true; if (isa(InitArgOrigin)) @@ -278,6 +279,9 @@ class RawPtrRefLocalVarsChecker if (isConstOwnerPtrMemberExpr(InitArgOrigin)) return true; + if (EFA.isACallToEnsureFn(InitArgOrigin)) + return true; + if (auto *Ref = llvm::dyn_cast(InitArgOrigin)) { if (auto *MaybeGuardian = dyn_cast_or_null(Ref->getFoundDecl())) { diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp index 599c2179db0f0..d786b02e2d7f3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp @@ -40,6 +40,7 @@ class UncountedLambdaCapturesChecker struct LocalVisitor : DynamicRecursiveASTVisitor { const UncountedLambdaCapturesChecker *Checker; llvm::DenseSet DeclRefExprsToIgnore; + llvm::DenseSet LambdasToIgnore; QualType ClsType; explicit LocalVisitor(const UncountedLambdaCapturesChecker *Checker) @@ -51,7 +52,7 @@ class UncountedLambdaCapturesChecker bool TraverseCXXMethodDecl(CXXMethodDecl *CXXMD) override { llvm::SaveAndRestore SavedDecl(ClsType); - if (CXXMD && CXXMD->isInstance()) + if (CXXMD->isInstance()) ClsType = CXXMD->getThisType(); return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD); } @@ -61,6 +62,24 @@ class UncountedLambdaCapturesChecker return result && *result; } + bool VisitLambdaExpr(LambdaExpr *L) override { + if (LambdasToIgnore.contains(L)) + return true; + Checker->visitLambdaExpr(L, shouldCheckThis()); + return true; + } + + bool VisitVarDecl(VarDecl *VD) override { + auto *Init = VD->getInit(); + if (!Init) + return true; + auto *L = dyn_cast_or_null(Init->IgnoreParenCasts()); + if (!L) + return true; + LambdasToIgnore.insert(L); // Evaluate lambdas in VisitDeclRefExpr. + return true; + } + bool VisitDeclRefExpr(DeclRefExpr *DRE) override { if (DeclRefExprsToIgnore.contains(DRE)) return true; @@ -73,6 +92,7 @@ class UncountedLambdaCapturesChecker auto *L = dyn_cast_or_null(Init->IgnoreParenCasts()); if (!L) return true; + LambdasToIgnore.insert(L); Checker->visitLambdaExpr(L, shouldCheckThis()); return true; } @@ -95,10 +115,10 @@ class UncountedLambdaCapturesChecker if (ArgIndex >= CE->getNumArgs()) return true; auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts(); - if (!Param->hasAttr() && !TreatAllArgsAsNoEscape) { - if (auto *L = dyn_cast_or_null(Arg)) { + if (auto *L = dyn_cast_or_null(Arg)) { + LambdasToIgnore.insert(L); + if (!Param->hasAttr() && !TreatAllArgsAsNoEscape) Checker->visitLambdaExpr(L, shouldCheckThis()); - } } ++ArgIndex; } @@ -117,6 +137,10 @@ class UncountedLambdaCapturesChecker if (!MD || CE->getNumArgs() < 1) return; auto *Arg = CE->getArg(0)->IgnoreParenCasts(); + if (auto *L = dyn_cast_or_null(Arg)) { + LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe. + return; + } auto *ArgRef = dyn_cast(Arg); if (!ArgRef) return; @@ -130,6 +154,7 @@ class UncountedLambdaCapturesChecker if (!L) return; DeclRefExprsToIgnore.insert(ArgRef); + LambdasToIgnore.insert(L); Checker->visitLambdaExpr(L, shouldCheckThis(), /* ignoreParamVarDecl */ true); } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index b46cd9fe86fc1..0a74a80a6a62f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1825,6 +1825,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OpenACCComputeConstructClass: case Stmt::OpenACCLoopConstructClass: case Stmt::OpenACCCombinedConstructClass: + case Stmt::OpenACCDataConstructClass: + case Stmt::OpenACCEnterDataConstructClass: + case Stmt::OpenACCExitDataConstructClass: + case Stmt::OpenACCHostDataConstructClass: + case Stmt::OpenACCWaitConstructClass: case Stmt::OMPUnrollDirectiveClass: case Stmt::OMPMetaDirectiveClass: case Stmt::HLSLOutArgExprClass: { diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index 8f20ce98152f0..9179217dd6ca8 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -261,6 +261,11 @@ SYMBOL(data, std::ranges::, ) SYMBOL(data, std::ranges::, ) SYMBOL(cdata, std::ranges::, ) SYMBOL(cdata, std::ranges::, ) +// https://eel.is/c++draft/tuple.general#2: +// In addition to being available via inclusion of the header, +// ignore ... is available when ... is included. +SYMBOL(ignore, std::, ) +SYMBOL(ignore, std::, ) // Ignore specializations SYMBOL(hash, std::, ) @@ -389,18 +394,10 @@ SYMBOL(make_error_condition, std::, /*no headers*/) SYMBOL(erase, std::, /*no headers*/) SYMBOL(erase_if, std::, /*no headers*/) -// cppreference symbol index page was missing these symbols. -// Remove them when the cppreference offline archive catches up. -SYMBOL(regular_invocable, std::, ) - // Symbols missing from the generated symbol map as reported by users. // Remove when the generator starts producing them. SYMBOL(div, std::, ) SYMBOL(abort, std::, ) -SYMBOL(atomic_wait, std::, ) -SYMBOL(atomic_wait_explicit, std::, ) -SYMBOL(move_backward, std::, ) -SYMBOL(month_weekday, std::chrono::, ) SYMBOL(binary_search, std::ranges::, ) SYMBOL(equal_range, std::ranges::, ) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc index b4afd0228694f..c1927180d3397 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc @@ -6,7 +6,7 @@ // This file was generated automatically by // clang/tools/include-mapping/gen_std.py, DO NOT EDIT! // -// Generated from cppreference offline HTML book (modified on 2024-06-10). +// Generated from cppreference offline HTML book (modified on 2024-11-10). //===----------------------------------------------------------------------===// SYMBOL(ATOMIC_BOOL_LOCK_FREE, None, ) @@ -578,6 +578,7 @@ SYMBOL(add_pointer, std::, ) SYMBOL(add_pointer_t, std::, ) SYMBOL(add_rvalue_reference, std::, ) SYMBOL(add_rvalue_reference_t, std::, ) +SYMBOL(add_sat, std::, ) SYMBOL(add_volatile, std::, ) SYMBOL(add_volatile_t, std::, ) SYMBOL(addressof, std::, ) @@ -699,6 +700,10 @@ SYMBOL(atomic_fetch_add, std::, ) SYMBOL(atomic_fetch_add_explicit, std::, ) SYMBOL(atomic_fetch_and, std::, ) SYMBOL(atomic_fetch_and_explicit, std::, ) +SYMBOL(atomic_fetch_max, std::, ) +SYMBOL(atomic_fetch_max_explicit, std::, ) +SYMBOL(atomic_fetch_min, std::, ) +SYMBOL(atomic_fetch_min_explicit, std::, ) SYMBOL(atomic_fetch_or, std::, ) SYMBOL(atomic_fetch_or_explicit, std::, ) SYMBOL(atomic_fetch_sub, std::, ) @@ -727,6 +732,8 @@ SYMBOL(atomic_signal_fence, std::, ) SYMBOL(atomic_store, std::, ) SYMBOL(atomic_store_explicit, std::, ) SYMBOL(atomic_thread_fence, std::, ) +SYMBOL(atomic_wait, std::, ) +SYMBOL(atomic_wait_explicit, std::, ) SYMBOL(atto, std::, ) SYMBOL(auto_ptr, std::, ) SYMBOL(back_insert_iterator, std::, ) @@ -829,6 +836,8 @@ SYMBOL(boolalpha, std::, ) SYMBOL(boolalpha, std::, ) SYMBOL(boyer_moore_horspool_searcher, std::, ) SYMBOL(boyer_moore_searcher, std::, ) +SYMBOL(breakpoint, std::, ) +SYMBOL(breakpoint_if_debugging, std::, ) SYMBOL(bsearch, std::, ) SYMBOL(bsearch, None, ) SYMBOL(bsearch, None, ) @@ -951,6 +960,7 @@ SYMBOL(copy_constructible, std::, ) SYMBOL(copy_if, std::, ) SYMBOL(copy_n, std::, ) SYMBOL(copyable, std::, ) +SYMBOL(copyable_function, std::, ) SYMBOL(copysign, std::, ) SYMBOL(copysign, None, ) SYMBOL(copysign, None, ) @@ -1048,12 +1058,14 @@ SYMBOL(dextents, std::, ) SYMBOL(difftime, std::, ) SYMBOL(difftime, None, ) SYMBOL(difftime, None, ) +SYMBOL(dims, std::, ) SYMBOL(disable_sized_sentinel_for, std::, ) SYMBOL(discard_block_engine, std::, ) SYMBOL(discrete_distribution, std::, ) SYMBOL(disjunction, std::, ) SYMBOL(disjunction_v, std::, ) SYMBOL(distance, std::, ) +SYMBOL(div_sat, std::, ) SYMBOL(div_t, std::, ) SYMBOL(div_t, None, ) SYMBOL(div_t, None, ) @@ -1077,6 +1089,7 @@ SYMBOL(emit_on_flush, std::, ) SYMBOL(emit_on_flush, std::, ) SYMBOL(enable_if, std::, ) SYMBOL(enable_if_t, std::, ) +SYMBOL(enable_nonlocking_formatter_optimization, std::, ) SYMBOL(enable_shared_from_this, std::, ) SYMBOL(endian, std::, ) SYMBOL(endl, std::, ) @@ -1241,8 +1254,7 @@ SYMBOL(fgetwc, None, ) SYMBOL(fgetws, std::, ) SYMBOL(fgetws, None, ) SYMBOL(fgetws, None, ) -SYMBOL(filebuf, std::, ) -SYMBOL(filebuf, std::, ) +SYMBOL(filebuf, std::, ) SYMBOL(filebuf, std::, ) SYMBOL(fill, std::, ) SYMBOL(fill_n, std::, ) @@ -1322,11 +1334,13 @@ SYMBOL(format, std::, ) SYMBOL(format_args, std::, ) SYMBOL(format_context, std::, ) SYMBOL(format_error, std::, ) +SYMBOL(format_kind, std::, ) SYMBOL(format_parse_context, std::, ) SYMBOL(format_string, std::, ) SYMBOL(format_to, std::, ) SYMBOL(format_to_n, std::, ) SYMBOL(format_to_n_result, std::, ) +SYMBOL(formattable, std::, ) SYMBOL(formatted_size, std::, ) SYMBOL(formatter, std::, ) SYMBOL(forward, std::, ) @@ -1398,6 +1412,7 @@ SYMBOL(ftell, std::, ) SYMBOL(ftell, None, ) SYMBOL(ftell, None, ) SYMBOL(function, std::, ) +SYMBOL(function_ref, std::, ) SYMBOL(future, std::, ) SYMBOL(future_category, std::, ) SYMBOL(future_errc, std::, ) @@ -1488,7 +1503,6 @@ SYMBOL(hypotl, None, ) SYMBOL(identity, std::, ) SYMBOL(ifstream, std::, ) SYMBOL(ifstream, std::, ) -SYMBOL(ignore, std::, ) SYMBOL(ilogb, std::, ) SYMBOL(ilogb, None, ) SYMBOL(ilogb, None, ) @@ -1544,6 +1558,7 @@ SYMBOL(inner_product, std::, ) SYMBOL(inout_ptr, std::, ) SYMBOL(inout_ptr_t, std::, ) SYMBOL(inplace_merge, std::, ) +SYMBOL(inplace_vector, std::, ) SYMBOL(input_iterator, std::, ) SYMBOL(input_iterator_tag, std::, ) SYMBOL(input_or_output_iterator, std::, ) @@ -1649,6 +1664,7 @@ SYMBOL(is_copy_assignable_v, std::, ) SYMBOL(is_copy_constructible, std::, ) SYMBOL(is_copy_constructible_v, std::, ) SYMBOL(is_corresponding_member, std::, ) +SYMBOL(is_debugger_present, std::, ) SYMBOL(is_default_constructible, std::, ) SYMBOL(is_default_constructible_v, std::, ) SYMBOL(is_destructible, std::, ) @@ -1790,6 +1806,8 @@ SYMBOL(is_union, std::, ) SYMBOL(is_union_v, std::, ) SYMBOL(is_unsigned, std::, ) SYMBOL(is_unsigned_v, std::, ) +SYMBOL(is_virtual_base_of, std::, ) +SYMBOL(is_virtual_base_of_v, std::, ) SYMBOL(is_void, std::, ) SYMBOL(is_void_v, std::, ) SYMBOL(is_volatile, std::, ) @@ -1938,7 +1956,9 @@ SYMBOL(latch, std::, ) SYMBOL(launch, std::, ) SYMBOL(launder, std::, ) SYMBOL(layout_left, std::, ) +SYMBOL(layout_left_padded, std::, ) SYMBOL(layout_right, std::, ) +SYMBOL(layout_right_padded, std::, ) SYMBOL(layout_stride, std::, ) SYMBOL(lcm, std::, ) SYMBOL(lconv, std::, ) @@ -2222,6 +2242,7 @@ SYMBOL(moneypunct, std::, ) SYMBOL(moneypunct_byname, std::, ) SYMBOL(monostate, std::, ) SYMBOL(movable, std::, ) +SYMBOL(move_backward, std::, ) SYMBOL(move_constructible, std::, ) SYMBOL(move_if_noexcept, std::, ) SYMBOL(move_iterator, std::, ) @@ -2229,6 +2250,7 @@ SYMBOL(move_only_function, std::, ) SYMBOL(move_sentinel, std::, ) SYMBOL(mt19937, std::, ) SYMBOL(mt19937_64, std::, ) +SYMBOL(mul_sat, std::, ) SYMBOL(multimap, std::, ) SYMBOL(multiplies, std::, ) SYMBOL(multiset, std::, ) @@ -2283,6 +2305,8 @@ SYMBOL(noboolalpha, std::, ) SYMBOL(noemit_on_flush, std::, ) SYMBOL(noemit_on_flush, std::, ) SYMBOL(none_of, std::, ) +SYMBOL(nontype, std::, ) +SYMBOL(nontype_t, std::, ) SYMBOL(noop_coroutine, std::, ) SYMBOL(noop_coroutine_handle, std::, ) SYMBOL(noop_coroutine_promise, std::, ) @@ -2442,6 +2466,8 @@ SYMBOL(random_access_iterator_tag, std::, ) SYMBOL(random_device, std::, ) SYMBOL(random_shuffle, std::, ) SYMBOL(range_error, std::, ) +SYMBOL(range_format, std::, ) +SYMBOL(range_formatter, std::, ) SYMBOL(rank, std::, ) SYMBOL(rank_v, std::, ) SYMBOL(ranlux24, std::, ) @@ -2486,6 +2512,7 @@ SYMBOL(regex_search, std::, ) SYMBOL(regex_token_iterator, std::, ) SYMBOL(regex_traits, std::, ) SYMBOL(regular, std::, ) +SYMBOL(regular_invocable, std::, ) SYMBOL(reinterpret_pointer_cast, std::, ) SYMBOL(relation, std::, ) SYMBOL(relaxed, std::, ) @@ -2580,8 +2607,10 @@ SYMBOL(roundl, std::, ) SYMBOL(roundl, None, ) SYMBOL(roundl, None, ) SYMBOL(runtime_error, std::, ) +SYMBOL(runtime_format, std::, ) SYMBOL(same_as, std::, ) SYMBOL(sample, std::, ) +SYMBOL(saturate_cast, std::, ) SYMBOL(scalbln, std::, ) SYMBOL(scalbln, None, ) SYMBOL(scalbln, None, ) @@ -2786,6 +2815,7 @@ SYMBOL(strftime, None, ) SYMBOL(strftime, None, ) SYMBOL(strict, std::, ) SYMBOL(strict_weak_order, std::, ) +SYMBOL(strided_slice, std::, ) SYMBOL(string, std::, ) SYMBOL(string_view, std::, ) SYMBOL(stringbuf, std::, ) @@ -2857,6 +2887,8 @@ SYMBOL(strxfrm, None, ) SYMBOL(strxfrm, None, ) SYMBOL(student_t_distribution, std::, ) SYMBOL(sub_match, std::, ) +SYMBOL(sub_sat, std::, ) +SYMBOL(submdspan_mapping_result, std::, ) SYMBOL(subtract_with_carry_engine, std::, ) SYMBOL(suspend_always, std::, ) SYMBOL(suspend_never, std::, ) @@ -2897,6 +2929,7 @@ SYMBOL(tanl, None, ) SYMBOL(tera, std::, ) SYMBOL(terminate, std::, ) SYMBOL(terminate_handler, std::, ) +SYMBOL(text_encoding, std::, ) SYMBOL(tgamma, std::, ) SYMBOL(tgamma, None, ) SYMBOL(tgamma, None, ) @@ -3127,7 +3160,9 @@ SYMBOL(visit, std::, ) SYMBOL(visit_format_arg, std::, ) SYMBOL(void_t, std::, ) SYMBOL(vprint_nonunicode, std::, ) +SYMBOL(vprint_nonunicode_buffered, std::, ) SYMBOL(vprint_unicode, std::, ) +SYMBOL(vprint_unicode_buffered, std::, ) SYMBOL(vprintf, std::, ) SYMBOL(vprintf, None, ) SYMBOL(vprintf, None, ) @@ -3156,6 +3191,7 @@ SYMBOL(vwscanf, std::, ) SYMBOL(vwscanf, None, ) SYMBOL(vwscanf, None, ) SYMBOL(wbuffer_convert, std::, ) +SYMBOL(wbuffer_convert, std::, ) SYMBOL(wcerr, std::, ) SYMBOL(wcin, std::, ) SYMBOL(wclog, std::, ) @@ -3274,8 +3310,7 @@ SYMBOL(weak_ordering, std::, ) SYMBOL(weak_ptr, std::, ) SYMBOL(weakly_incrementable, std::, ) SYMBOL(weibull_distribution, std::, ) -SYMBOL(wfilebuf, std::, ) -SYMBOL(wfilebuf, std::, ) +SYMBOL(wfilebuf, std::, ) SYMBOL(wfilebuf, std::, ) SYMBOL(wformat_args, std::, ) SYMBOL(wformat_context, std::, ) @@ -3348,6 +3383,7 @@ SYMBOL(wstreampos, std::, ) SYMBOL(wstreampos, std::, ) SYMBOL(wstring, std::, ) SYMBOL(wstring_convert, std::, ) +SYMBOL(wstring_convert, std::, ) SYMBOL(wstring_view, std::, ) SYMBOL(wstringbuf, std::, ) SYMBOL(wstringbuf, std::, ) @@ -3423,6 +3459,7 @@ SYMBOL(minutes, std::chrono::, ) SYMBOL(month, std::chrono::, ) SYMBOL(month_day, std::chrono::, ) SYMBOL(month_day_last, std::chrono::, ) +SYMBOL(month_weekday, std::chrono::, ) SYMBOL(month_weekday_last, std::chrono::, ) SYMBOL(nanoseconds, std::chrono::, ) SYMBOL(nonexistent_local_time, std::chrono::, ) @@ -3605,6 +3642,7 @@ SYMBOL(chunk_view, std::ranges::, ) SYMBOL(clamp, std::ranges::, ) SYMBOL(common_range, std::ranges::, ) SYMBOL(common_view, std::ranges::, ) +SYMBOL(concat_view, std::ranges::, ) SYMBOL(const_iterator_t, std::ranges::, ) SYMBOL(constant_range, std::ranges::, ) SYMBOL(construct_at, std::ranges::, ) @@ -3629,11 +3667,13 @@ SYMBOL(disable_sized_range, std::ranges::, ) SYMBOL(distance, std::ranges::, ) SYMBOL(drop_view, std::ranges::, ) SYMBOL(drop_while_view, std::ranges::, ) +SYMBOL(elements_of, std::ranges::, ) SYMBOL(elements_view, std::ranges::, ) SYMBOL(empty_view, std::ranges::, ) SYMBOL(enable_borrowed_range, std::ranges::, ) SYMBOL(enable_view, std::ranges::, ) SYMBOL(ends_with, std::ranges::, ) +SYMBOL(enumerate_view, std::ranges::, ) SYMBOL(equal, std::ranges::, ) SYMBOL(equal_to, std::ranges::, ) SYMBOL(fill, std::ranges::, ) @@ -3833,11 +3873,13 @@ SYMBOL(cartesian_product, std::ranges::views::, ) SYMBOL(chunk, std::ranges::views::, ) SYMBOL(chunk_by, std::ranges::views::, ) SYMBOL(common, std::ranges::views::, ) +SYMBOL(concat, std::ranges::views::, ) SYMBOL(counted, std::ranges::views::, ) SYMBOL(drop, std::ranges::views::, ) SYMBOL(drop_while, std::ranges::views::, ) SYMBOL(elements, std::ranges::views::, ) SYMBOL(empty, std::ranges::views::, ) +SYMBOL(enumerate, std::ranges::views::, ) SYMBOL(filter, std::ranges::views::, ) SYMBOL(iota, std::ranges::views::, ) SYMBOL(istream, std::ranges::views::, ) @@ -3914,11 +3956,13 @@ SYMBOL(cartesian_product, std::views::, ) SYMBOL(chunk, std::views::, ) SYMBOL(chunk_by, std::views::, ) SYMBOL(common, std::views::, ) +SYMBOL(concat, std::views::, ) SYMBOL(counted, std::views::, ) SYMBOL(drop, std::views::, ) SYMBOL(drop_while, std::views::, ) SYMBOL(elements, std::views::, ) SYMBOL(empty, std::views::, ) +SYMBOL(enumerate, std::views::, ) SYMBOL(filter, std::views::, ) SYMBOL(iota, std::views::, ) SYMBOL(istream, std::views::, ) diff --git a/clang/runtime/CMakeLists.txt b/clang/runtime/CMakeLists.txt index 65fcdc2868f03..ff2605b23d25b 100644 --- a/clang/runtime/CMakeLists.txt +++ b/clang/runtime/CMakeLists.txt @@ -122,7 +122,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/) COMPONENT compiler-rt) # Add top-level targets that build specific compiler-rt runtimes. - set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan ubsan ubsan-minimal) + set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan tysan ubsan ubsan-minimal) foreach(runtime ${COMPILER_RT_RUNTIMES}) get_ext_project_build_command(build_runtime_cmd ${runtime}) add_custom_target(${runtime} diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes index c5171e2f287d2..88e0da1382d6c 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes @@ -3,6 +3,12 @@ Name: SwiftImportAs Tags: - Name: ImmortalRefType SwiftImportAs: reference + Methods: + - Name: methodReturningFrt__ + - Name: methodReturningFrt_returns_unretained + SwiftReturnOwnership: unretained + - Name: methodReturningFrt_returns_retained + SwiftReturnOwnership: retained - Name: RefCountedType SwiftImportAs: reference SwiftReleaseOp: RCRelease @@ -17,3 +23,10 @@ Tags: SwiftEscapable: false - Name: EscapableType SwiftEscapable: true + +Functions: + - Name: functionReturningFrt__ + - Name: functionReturningFrt_returns_unretained + SwiftReturnOwnership: unretained + - Name: functionReturningFrt_returns_retained + SwiftReturnOwnership: retained diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h index f205cd3c6e7b7..b6900fee8a979 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h @@ -1,4 +1,13 @@ -struct ImmortalRefType {}; +struct ImmortalRefType { + ImmortalRefType * methodReturningFrt__(void); + ImmortalRefType * methodReturningFrt_returns_unretained(void); + ImmortalRefType * methodReturningFrt_returns_retained(void); +}; + +ImmortalRefType * functionReturningFrt__(void); +ImmortalRefType * functionReturningFrt_returns_unretained(void); +ImmortalRefType * functionReturningFrt_returns_retained(void); + struct RefCountedType { int value; }; diff --git a/clang/test/APINotes/swift-import-as.cpp b/clang/test/APINotes/swift-import-as.cpp index d0e7e31fc1d72..3981ef1ed419a 100644 --- a/clang/test/APINotes/swift-import-as.cpp +++ b/clang/test/APINotes/swift-import-as.cpp @@ -6,6 +6,12 @@ // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter CopyableType | FileCheck -check-prefix=CHECK-COPYABLE %s // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter NonEscapableType | FileCheck -check-prefix=CHECK-NON-ESCAPABLE %s // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter EscapableType | FileCheck -check-prefix=CHECK-ESCAPABLE %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter functionReturningFrt__ | FileCheck -check-prefix=CHECK-FUNCTION-RETURNING-FRT %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter functionReturningFrt_returns_unretained | FileCheck -check-prefix=CHECK-FUNCTION-RETURNING-FRT-UNRETAINED %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter functionReturningFrt_returns_retained | FileCheck -check-prefix=CHECK-FUNCTION-RETURNING-FRT-RETAINED %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt__ | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt_returns_unretained | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT-UNRETAINED %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt_returns_retained | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT-RETAINED %s #include @@ -36,3 +42,29 @@ // CHECK-ESCAPABLE: Dumping EscapableType: // CHECK-ESCAPABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct EscapableType // CHECK-ESCAPABLE: SwiftAttrAttr {{.+}} "Escapable" + +// CHECK-FUNCTION-RETURNING-FRT: Dumping functionReturningFrt__: +// CHECK-FUNCTION-RETURNING-FRT: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt__ 'ImmortalRefType *()' +// CHECK-FUNCTION-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_unretained" +// CHECK-FUNCTION-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_retained" + +// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: Dumping functionReturningFrt_returns_unretained: +// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt_returns_unretained 'ImmortalRefType *()' +// CHECK-FUNCTION-RETURNING-FRT-UNRETAINED: `-SwiftAttrAttr {{.+}} "returns_unretained" + +// CHECK-FUNCTION-RETURNING-FRT-RETAINED: Dumping functionReturningFrt_returns_retained: +// CHECK-FUNCTION-RETURNING-FRT-RETAINED: FunctionDecl {{.+}} imported in SwiftImportAs functionReturningFrt_returns_retained 'ImmortalRefType *()' +// CHECK-FUNCTION-RETURNING-FRT-RETAINED: `-SwiftAttrAttr {{.+}} "returns_retained" + +// CHECK-METHOD-RETURNING-FRT: Dumping ImmortalRefType::methodReturningFrt__: +// CHECK-METHOD-RETURNING-FRT: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt__ 'ImmortalRefType *()' +// CHECK-METHOD-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_unretained" +// CHECK-METHOD-RETURNING-FRT-NOT: `-SwiftAttrAttr {{.+}} "returns_retained" + +// CHECK-METHOD-RETURNING-FRT-UNRETAINED: Dumping ImmortalRefType::methodReturningFrt_returns_unretained: +// CHECK-METHOD-RETURNING-FRT-UNRETAINED: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt_returns_unretained 'ImmortalRefType *()' +// CHECK-METHOD-RETURNING-FRT-UNRETAINED: `-SwiftAttrAttr {{.+}} "returns_unretained" + +// CHECK-METHOD-RETURNING-FRT-RETAINED: Dumping ImmortalRefType::methodReturningFrt_returns_retained: +// CHECK-METHOD-RETURNING-FRT-RETAINED: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt_returns_retained 'ImmortalRefType *()' +// CHECK-METHOD-RETURNING-FRT-RETAINED: `-SwiftAttrAttr {{.+}} "returns_retained" diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp index e99ab3904c339..187f180afd3da 100644 --- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp +++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp @@ -502,3 +502,16 @@ namespace OversizedBitField { // ref-note {{constexpr bit_cast involving bit-field is not yet supported}} #endif } + +typedef bool bool9 __attribute__((ext_vector_type(9))); +// both-error@+2 {{constexpr variable 'bad_bool9_to_short' must be initialized by a constant expression}} +// both-note@+1 {{bit_cast involving type 'bool __attribute__((ext_vector_type(9)))' (vector of 9 'bool' values) is not allowed in a constant expression; element size 1 * element count 9 is not a multiple of the byte size 8}} +constexpr unsigned short bad_bool9_to_short = __builtin_bit_cast(unsigned short, bool9{1,1,0,1,0,1,0,1,0}); + +// both-warning@+2 {{returning reference to local temporary object}} +// both-note@+1 {{temporary created here}} +constexpr const intptr_t &returns_local() { return 0L; } + +// both-error@+2 {{constexpr variable 'test_nullptr_bad' must be initialized by a constant expression}} +// both-note@+1 {{read of temporary whose lifetime has ended}} +constexpr nullptr_t test_nullptr_bad = __builtin_bit_cast(nullptr_t, returns_local()); diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index a67b6b665f379..5906cb970f06c 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -1198,13 +1198,91 @@ namespace BuiltinMemcpy { } static_assert(simpleMove() == 12); - constexpr int memcpyTypeRem() { // ref-error {{never produces a constant expression}} + constexpr int memcpyTypeRem() { // both-error {{never produces a constant expression}} int a = 12; int b = 0; __builtin_memmove(&b, &a, 1); // both-note {{'memmove' not supported: size to copy (1) is not a multiple of size of element type 'int'}} \ - // ref-note {{not supported}} + // both-note {{not supported}} return b; } static_assert(memcpyTypeRem() == 12); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} + + template + constexpr T result(T (&arr)[4]) { + return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3]; + } + + constexpr int test_memcpy(int a, int b, int n) { + int arr[4] = {1, 2, 3, 4}; + __builtin_memcpy(arr + a, arr + b, n); // both-note {{overlapping memory regions}} + return result(arr); + } + + static_assert(test_memcpy(1, 2, sizeof(int)) == 1334); + static_assert(test_memcpy(0, 1, sizeof(int) * 2) == 2334); // both-error {{not an integral constant expression}} \ + // both-note {{in call}} +} + +namespace Memcmp { + constexpr unsigned char ku00fe00[] = {0x00, 0xfe, 0x00}; + constexpr unsigned char ku00feff[] = {0x00, 0xfe, 0xff}; + constexpr signed char ks00fe00[] = {0, -2, 0}; + constexpr signed char ks00feff[] = {0, -2, -1}; + static_assert(__builtin_memcmp(ku00feff, ks00fe00, 2) == 0); + static_assert(__builtin_memcmp(ku00feff, ks00fe00, 99) == 1); + static_assert(__builtin_memcmp(ku00fe00, ks00feff, 99) == -1); + static_assert(__builtin_memcmp(ks00feff, ku00fe00, 2) == 0); + static_assert(__builtin_memcmp(ks00feff, ku00fe00, 99) == 1); + static_assert(__builtin_memcmp(ks00fe00, ku00feff, 99) == -1); + static_assert(__builtin_memcmp(ks00fe00, ks00feff, 2) == 0); + static_assert(__builtin_memcmp(ks00feff, ks00fe00, 99) == 1); + static_assert(__builtin_memcmp(ks00fe00, ks00feff, 99) == -1); + + struct Bool3Tuple { bool bb[3]; }; + constexpr Bool3Tuple kb000100 = {{false, true, false}}; + static_assert(sizeof(bool) != 1u || __builtin_memcmp(ks00fe00, kb000100.bb, 1) == 0); // both-error {{constant}} \ + // both-note {{not supported}} + + constexpr char a = 'a'; + constexpr char b = 'a'; + static_assert(__builtin_memcmp(&a, &b, 1) == 0); + + extern struct Incomplete incomplete; + static_assert(__builtin_memcmp(&incomplete, "", 0u) == 0); + static_assert(__builtin_memcmp("", &incomplete, 0u) == 0); + static_assert(__builtin_memcmp(&incomplete, "", 1u) == 42); // both-error {{not an integral constant}} \ + // both-note {{not supported}} + static_assert(__builtin_memcmp("", &incomplete, 1u) == 42); // both-error {{not an integral constant}} \ + // both-note {{not supported}} + + static_assert(__builtin_memcmp(u8"abab\0banana", u8"abab\0banana", 100) == 0); // both-error {{not an integral constant}} \ + // both-note {{dereferenced one-past-the-end}} + + static_assert(__builtin_bcmp("abaa", "abba", 3) != 0); + static_assert(__builtin_bcmp("abaa", "abba", 2) == 0); + static_assert(__builtin_bcmp("a\203", "a", 2) != 0); + static_assert(__builtin_bcmp("a\203", "a\003", 2) != 0); + static_assert(__builtin_bcmp(0, 0, 0) == 0); + static_assert(__builtin_bcmp("abab\0banana", "abab\0banana", 100) == 0); // both-error {{not an integral constant}}\ + // both-note {{dereferenced one-past-the-end}} + static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 100) != 0); // FIXME: Should we reject this? + static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 7) != 0); + static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 6) != 0); + static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 5) == 0); + + + static_assert(__builtin_wmemcmp(L"abaa", L"abba", 3) == -1); + static_assert(__builtin_wmemcmp(L"abaa", L"abba", 2) == 0); + static_assert(__builtin_wmemcmp(0, 0, 0) == 0); +#if __WCHAR_WIDTH__ == 32 + static_assert(__builtin_wmemcmp(L"a\x83838383", L"aa", 2) == + (wchar_t)-1U >> 31); +#endif + static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0banana", 100) == 0); // both-error {{not an integral constant}} \ + // both-note {{dereferenced one-past-the-end}} + static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 100) == -1); // FIXME: Should we reject this? + static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 7) == -1); + static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 6) == -1); + static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 5) == 0); } diff --git a/clang/test/AST/ByteCode/complex.cpp b/clang/test/AST/ByteCode/complex.cpp index ee11c6214b70c..2c0111c53d3bf 100644 --- a/clang/test/AST/ByteCode/complex.cpp +++ b/clang/test/AST/ByteCode/complex.cpp @@ -146,11 +146,6 @@ constexpr _Complex int I3 = {15}; static_assert(__real(I3) == 15, ""); static_assert(__imag(I3) == 0, ""); -constexpr _Complex _BitInt(8) A = {4}; -static_assert(__real(A) == 4, ""); -static_assert(__imag(A) == 0, ""); - - constexpr _Complex double Doubles[4] = {{1.0, 2.0}}; static_assert(__real(Doubles[0]) == 1.0, ""); static_assert(__imag(Doubles[0]) == 2.0, ""); @@ -163,9 +158,6 @@ static_assert(__imag(Doubles[3]) == 0.0, ""); static_assert(~(0.5 + 1.5j) == (0.5 + -1.5j), ""); -static_assert(__extension__ __imag(A) == 0, ""); -static_assert(__imag(__extension__ A) == 0, ""); - void func(void) { __complex__ int arr; _Complex int result; diff --git a/clang/test/AST/ByteCode/functions.cpp b/clang/test/AST/ByteCode/functions.cpp index b00f59a8d8d43..10bea3a0d017e 100644 --- a/clang/test/AST/ByteCode/functions.cpp +++ b/clang/test/AST/ByteCode/functions.cpp @@ -303,21 +303,17 @@ namespace ReturnLocalPtr { return &a; // both-warning {{address of stack memory}} } - /// GCC rejects the expression below, just like the new interpreter. The current interpreter - /// however accepts it and only warns about the function above returning an address to stack - /// memory. If we change the condition to 'p() != nullptr', it even succeeds. - static_assert(p() == nullptr, ""); // ref-error {{static assertion failed}} \ - // expected-error {{not an integral constant expression}} - - /// FIXME: The current interpreter emits diagnostics in the reference case below, but the - /// new one does not. + /// FIXME: Both interpreters should diagnose this. We're returning a pointer to a local + /// variable. + static_assert(p() == nullptr, ""); // both-error {{static assertion failed}} + constexpr const int &p2() { - int a = 12; // ref-note {{declared here}} + int a = 12; // both-note {{declared here}} return a; // both-warning {{reference to stack memory associated with local variable}} } static_assert(p2() == 12, ""); // both-error {{not an integral constant expression}} \ - // ref-note {{read of variable whose lifetime has ended}} + // both-note {{read of variable whose lifetime has ended}} } namespace VoidReturn { diff --git a/clang/test/AST/ByteCode/shifts.cpp b/clang/test/AST/ByteCode/shifts.cpp index 0b3383731c677..f02aaf004cbd6 100644 --- a/clang/test/AST/ByteCode/shifts.cpp +++ b/clang/test/AST/ByteCode/shifts.cpp @@ -1,7 +1,9 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,all %s // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17,all %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=cxx17,all -triple armv8 %s // RUN: %clang_cc1 -std=c++20 -verify=ref,all %s // RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17,all %s +// RUN: %clang_cc1 -std=c++17 -verify=ref-cxx17,all -triple armv8 %s #define INT_MIN (~__INT_MAX__) @@ -21,27 +23,15 @@ namespace shifts { c = 1 << 0; c = 1 << -0; c = 1 >> -0; - c = 1 << -1; // expected-warning {{shift count is negative}} \ - // expected-note {{negative shift count -1}} \ - // cxx17-note {{negative shift count -1}} \ - // cxx17-warning {{shift count is negative}} \ - // ref-warning {{shift count is negative}} \ - // ref-note {{negative shift count -1}} \ - // ref-cxx17-warning {{shift count is negative}} \ - // ref-cxx17-note {{negative shift count -1}} + c = 1 << -1; // all-warning {{shift count is negative}} \ + // all-note {{negative shift count -1}} c = 1 >> -1; // expected-warning {{shift count is negative}} \ // cxx17-warning {{shift count is negative}} \ // ref-warning {{shift count is negative}} \ // ref-cxx17-warning {{shift count is negative}} - c = 1 << (unsigned)-1; // expected-warning {{shift count >= width of type}} \ - // expected-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \ - // cxx17-warning {{shift count >= width of type}} \ - // cxx17-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \ - // ref-warning {{shift count >= width of type}} \ - // ref-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \ - // ref-cxx17-warning {{shift count >= width of type}} \ - // ref-cxx17-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} + c = 1 << (unsigned)-1; // all-warning {{shift count >= width of type}} \ + // all-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} c = 1 >> (unsigned)-1; // expected-warning {{shift count >= width of type}} \ // cxx17-warning {{shift count >= width of type}} \ // ref-warning {{shift count >= width of type}} \ @@ -212,3 +202,28 @@ enum shiftof { X3 = (1<<32) // all-error {{expression is not an integral constant expression}} \ // all-note {{shift count 32 >= width of type 'int'}} }; + +#if __WCHAR_WIDTH__ == 32 +# if !defined(__WCHAR_UNSIGNED__) +static_assert(((wchar_t)-1U >> 31) == -1); +# else +static_assert(((wchar_t)-1U >> 31) == 1); +# endif +#endif + +#if __INT_WIDTH__ == 32 +static_assert(((int)-1U >> 32) == -1); // all-error {{not an integral constant expression}} \ + // all-note {{shift count 32 >= width of type 'int' (32 bits)}} +#endif + +static_assert((-4 << 32) == 0); // all-error {{not an integral constant expression}} \ + // all-note {{shift count}} + +static_assert((-4 << 1) == -8); // ref-cxx17-error {{not an integral constant expression}} \ + // ref-cxx17-note {{left shift of negative value -4}} \ + // cxx17-error {{not an integral constant expression}} \ + // cxx17-note {{left shift of negative value -4}} +static_assert((-4 << 31) == 0); // ref-cxx17-error {{not an integral constant expression}} \ + // ref-cxx17-note {{left shift of negative value -4}} \ + // cxx17-error {{not an integral constant expression}} \ + // cxx17-note {{left shift of negative value -4}} diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index afee0e120afdb..6cb4379ef5f55 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -20,7 +20,7 @@ // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \ // RUN: -DRESOURCE=AppendStructuredBuffer %s | FileCheck -DRESOURCE=AppendStructuredBuffer \ -// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-NOSUBSCRIPT %s +// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-NOSUBSCRIPT,CHECK-APPEND %s // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \ // RUN: -DRESOURCE=ConsumeStructuredBuffer %s | FileCheck -DRESOURCE=ConsumeStructuredBuffer \ @@ -28,7 +28,7 @@ // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \ // RUN: -DRESOURCE=ConsumeStructuredBuffer %s | FileCheck -DRESOURCE=ConsumeStructuredBuffer \ -// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-NOSUBSCRIPT %s +// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-NOSUBSCRIPT,CHECK-CONSUME %s // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \ // RUN: -DRESOURCE=RasterizerOrderedStructuredBuffer %s | FileCheck -DRESOURCE=RasterizerOrderedStructuredBuffer \ @@ -135,6 +135,48 @@ RESOURCE Buffer; // CHECK-COUNTER-NEXT: IntegerLiteral 0x{{[0-9A-Fa-f]+}} <> 'int' -1 // CHECK-COUNTER-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <> Implicit always_inline +// CHECK-APPEND: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> Append 'void (element_type)' +// CHECK-APPEND-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <> value 'element_type' +// CHECK-APPEND-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-APPEND-NEXT: BinaryOperator 0x{{[0-9A-Fa-f]+}} <> 'element_type' '=' +// CHECK-APPEND-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <> 'element_type' prefix '*' cannot overflow +// CHECK-APPEND-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type *' +// CHECK-APPEND-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> '' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' +// CHECK-APPEND-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> '__hlsl_resource_t +// CHECK-APPEND-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-APPEND-SAME{LITERAL}: [[hlsl::raw_buffer]] +// CHECK-APPEND-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle +// CHECK-APPEND-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> '[[RESOURCE]]' lvalue implicit this +// CHECK-APPEND-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <> 'unsigned int' +// CHECK-APPEND-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> '' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept' +// CHECK-APPEND-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> '__hlsl_resource_t +// CHECK-APPEND-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-APPEND-SAME{LITERAL}: [[hlsl::raw_buffer]] +// CHECK-APPEND-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle +// CHECK-APPEND-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> '[[RESOURCE]]' lvalue implicit this +// CHECK-APPEND-NEXT: IntegerLiteral 0x{{[0-9A-Fa-f]+}} <> 'int' 1 +// CHECK-APPEND-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type' ParmVar 0x{{[0-9A-Fa-f]+}} 'value' 'element_type' + +// CHECK-CONSUME: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> Consume 'element_type ()' +// CHECK-CONSUME-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-CONSUME-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-CONSUME-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <> 'element_type' prefix '*' cannot overflow +// CHECK-CONSUME-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type *' +// CHECK-CONSUME-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> '' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' +// CHECK-CONSUME-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> '__hlsl_resource_t +// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::raw_buffer]] +// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle +// CHECK-CONSUME-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> '[[RESOURCE]]' lvalue implicit this +// CHECK-CONSUME-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <> 'unsigned int' +// CHECK-CONSUME-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> '' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept' +// CHECK-CONSUME-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> '__hlsl_resource_t +// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::raw_buffer]] +// CHECK-CONSUME-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]' lvalue .__handle +// CHECK-CONSUME-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> '[[RESOURCE]]' lvalue implicit this +// CHECK-CONSUME-NEXT: IntegerLiteral 0x{{[0-9A-Fa-f]+}} <> 'int' -1 + // CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <> class [[RESOURCE]] definition // CHECK: TemplateArgument type 'float' diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl index 6bab39de5a233..d6dfb0caba5d9 100644 --- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl @@ -87,6 +87,21 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <> Implicit always_inline +// CHECK-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> Load 'element_type (unsigned int)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <> Index 'unsigned int' +// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <> 'element_type' prefix '*' cannot overflow +// CHECK-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type *' +// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> '' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' +// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> '__hlsl_resource_t +// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// CHECK-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> '[[RESOURCE]]' lvalue implicit this +// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int' +// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <> Implicit always_inline + // CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <> class [[RESOURCE]] definition // CHECK: TemplateArgument type 'float' diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp index 4388462224026..b59fa3778192f 100644 --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -480,3 +480,37 @@ void RecoveryForStmtCond() { // CHECK-NEXT: `-CompoundStmt {{.*}} for (int i = 0; i < invalid; ++i) {} } + +// Fix crash issue https://github.com/llvm/llvm-project/issues/112560. +// Make sure clang compiles the following code without crashing: + +// CHECK:NamespaceDecl {{.*}} GH112560 +// CHECK-NEXT: |-CXXRecordDecl {{.*}} referenced union U definition +// CHECK-NEXT: | |-DefinitionData {{.*}} +// CHECK-NEXT: | | |-DefaultConstructor {{.*}} +// CHECK-NEXT: | | |-CopyConstructor {{.*}} +// CHECK-NEXT: | | |-MoveConstructor {{.*}} +// CHECK-NEXT: | | |-CopyAssignment {{.*}} +// CHECK-NEXT: | | |-MoveAssignment {{.*}} +// CHECK-NEXT: | | `-Destructor {{.*}} +// CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit union U +// CHECK-NEXT: | `-FieldDecl {{.*}} invalid f 'int' +// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'int' contains-errors +// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors +namespace GH112560 { +union U { + int f = ; +}; + +// CHECK: FunctionDecl {{.*}} foo 'void ()' +// CHECK-NEXT: `-CompoundStmt {{.*}} +// CHECK-NEXT: `-DeclStmt {{.*}} +// CHECK-NEXT: `-VarDecl {{.*}} g 'U':'GH112560::U' listinit +// CHECK-NEXT: `-InitListExpr {{.*}} 'U':'GH112560::U' contains-errors field Field {{.*}} 'f' 'int' +// CHECK-NEXT: `-CXXDefaultInitExpr {{.*}} 'int' contains-errors has rewritten init +// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors +// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors +void foo() { + U g{}; +} +} // namespace GH112560 diff --git a/clang/test/AST/ast-print-openacc-combined-construct.cpp b/clang/test/AST/ast-print-openacc-combined-construct.cpp index 1a11f036b07ae..25fa29cbbe04e 100644 --- a/clang/test/AST/ast-print-openacc-combined-construct.cpp +++ b/clang/test/AST/ast-print-openacc-combined-construct.cpp @@ -386,4 +386,31 @@ void foo() { #pragma acc serial loop vector for(int i = 0;i<5;++i); +//CHECK: #pragma acc parallel loop reduction(+: iPtr) +#pragma acc parallel loop reduction(+: iPtr) + for(int i = 0;i<5;++i); +//CHECK: #pragma acc serial loop reduction(*: i) +#pragma acc serial loop reduction(*: i) + for(int i = 0;i<5;++i); +//CHECK: #pragma acc kernels loop reduction(max: SomeB) +#pragma acc kernels loop reduction(max: SomeB) + for(int i = 0;i<5;++i); +//CHECK: #pragma acc parallel loop reduction(min: iPtr) +#pragma acc parallel loop reduction(min: iPtr) + for(int i = 0;i<5;++i); +//CHECK: #pragma acc serial loop reduction(&: i) +#pragma acc serial loop reduction(&: i) + for(int i = 0;i<5;++i); +//CHECK: #pragma acc kernels loop reduction(|: SomeB) +#pragma acc kernels loop reduction(|: SomeB) + for(int i = 0;i<5;++i); +//CHECK: #pragma acc parallel loop reduction(^: iPtr) +#pragma acc parallel loop reduction(^: iPtr) + for(int i = 0;i<5;++i); +//CHECK: #pragma acc serial loop reduction(&&: i) +#pragma acc serial loop reduction(&&: i) + for(int i = 0;i<5;++i); +//CHECK: #pragma acc kernels loop reduction(||: SomeB) +#pragma acc kernels loop reduction(||: SomeB) + for(int i = 0;i<5;++i); } diff --git a/clang/test/AST/ast-print-openacc-data-construct.cpp b/clang/test/AST/ast-print-openacc-data-construct.cpp new file mode 100644 index 0000000000000..f568ae5ce6346 --- /dev/null +++ b/clang/test/AST/ast-print-openacc-data-construct.cpp @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -fopenacc -Wno-openacc-deprecated-clause-alias -Wno-source-uses-openacc -ast-print %s -o - | FileCheck %s + +void foo() { + int Var; + // TODO OpenACC: These are only legal if they have one of a list of clauses on + // them, so the 'check' lines should start to include those once we implement + // them. For now, they don't emit those because they are 'not implemented'. + +// CHECK: #pragma acc data default(none) +#pragma acc data default(none) + ; + +// CHECK: #pragma acc data default(none) device_type(int) +#pragma acc data default(none) device_type(int) + ; + +// CHECK: #pragma acc enter data copyin(Var) +#pragma acc enter data copyin(Var) + ; +// CHECK: #pragma acc exit data copyout(Var) +#pragma acc exit data copyout(Var) + ; +// CHECK: #pragma acc host_data use_device(Var) +#pragma acc host_data use_device(Var) + ; + + int i; + int *iPtr; + int array[5]; + +// CHECK: #pragma acc data default(none) if(i == array[1]) +#pragma acc data default(none) if(i == array[1]) + ; +// CHECK: #pragma acc enter data copyin(Var) if(i == array[1]) +#pragma acc enter data copyin(Var) if(i == array[1]) + ; +// CHECK: #pragma acc exit data copyout(Var) if(i == array[1]) +#pragma acc exit data copyout(Var) if(i == array[1]) + ; +// CHECK: #pragma acc host_data use_device(Var) if(i == array[1]) +#pragma acc host_data use_device(Var) if(i == array[1]) + ; + +// CHECK: #pragma acc data default(none) async(i) +#pragma acc data default(none) async(i) + ; +// CHECK: #pragma acc enter data copyin(i) async(i) +#pragma acc enter data copyin(i) async(i) +// CHECK: #pragma acc exit data copyout(i) async +#pragma acc exit data copyout(i) async + +// CHECK: #pragma acc data default(none) wait +#pragma acc data default(none) wait() + ; + +// CHECK: #pragma acc enter data copyin(Var) wait() +#pragma acc enter data copyin(Var) wait() + +// CHECK: #pragma acc exit data copyout(Var) wait(*iPtr, i) +#pragma acc exit data copyout(Var) wait(*iPtr, i) + +// CHECK: #pragma acc data default(none) wait(queues: *iPtr, i) +#pragma acc data default(none) wait(queues:*iPtr, i) + ; + +// CHECK: #pragma acc enter data copyin(Var) wait(devnum: i : *iPtr, i) +#pragma acc enter data copyin(Var) wait(devnum:i:*iPtr, i) + +// CHECK: #pragma acc exit data copyout(Var) wait(devnum: i : queues: *iPtr, i) +#pragma acc exit data copyout(Var) wait(devnum:i:queues:*iPtr, i) + +// CHECK: #pragma acc data default(none) +#pragma acc data default(none) + ; + +// CHECK: #pragma acc data default(present) +#pragma acc data default(present) + ; + +// CHECK: #pragma acc data default(none) no_create(i, array[1], array, array[1:2]) +#pragma acc data default(none) no_create(i, array[1], array, array[1:2]) + ; + +// CHECK: #pragma acc data default(none) no_create(i, array[1], array, array[1:2]) present(i, array[1], array, array[1:2]) +#pragma acc data default(none) no_create(i, array[1], array, array[1:2]) present(i, array[1], array, array[1:2]) + ; +// CHECK: #pragma acc data present(i, array[1], array, array[1:2]) +#pragma acc data present(i, array[1], array, array[1:2]) + ; + +// CHECK: #pragma acc data default(none) copy(i, array[1], array, array[1:2]) pcopy(i, array[1], array, array[1:2]) present_or_copy(i, array[1], array, array[1:2]) +#pragma acc data default(none) copy(i, array[1], array, array[1:2]) pcopy(i, array[1], array, array[1:2]) present_or_copy(i, array[1], array, array[1:2]) + ; + +// CHECK: #pragma acc enter data copyin(i, array[1], array, array[1:2]) pcopyin(readonly: i, array[1], array, array[1:2]) present_or_copyin(i, array[1], array, array[1:2]) +#pragma acc enter data copyin(i, array[1], array, array[1:2]) pcopyin(readonly:i, array[1], array, array[1:2]) present_or_copyin(i, array[1], array, array[1:2]) + +// CHECK: #pragma acc exit data copyout(i, array[1], array, array[1:2]) pcopyout(zero: i, array[1], array, array[1:2]) present_or_copyout(i, array[1], array, array[1:2]) +#pragma acc exit data copyout(i, array[1], array, array[1:2]) pcopyout(zero: i, array[1], array, array[1:2]) present_or_copyout(i, array[1], array, array[1:2]) + +// CHECK: #pragma acc enter data create(i, array[1], array, array[1:2]) pcreate(zero: i, array[1], array, array[1:2]) present_or_create(i, array[1], array, array[1:2]) +#pragma acc enter data create(i, array[1], array, array[1:2]) pcreate(zero: i, array[1], array, array[1:2]) present_or_create(i, array[1], array, array[1:2]) + + float *arrayPtr[5]; + +// CHECK: #pragma acc data default(none) deviceptr(iPtr, arrayPtr[0]) +#pragma acc data default(none) deviceptr(iPtr, arrayPtr[0]) + +// CHECK: #pragma acc data default(none) attach(iPtr, arrayPtr[0]) +#pragma acc data default(none) attach(iPtr, arrayPtr[0]) + ; + +// CHECK: #pragma acc exit data copyout(i) finalize +#pragma acc exit data copyout(i) finalize + +// CHECK: #pragma acc host_data use_device(i) if_present +#pragma acc host_data use_device(i) if_present + ; +// CHECK: #pragma acc exit data copyout(i) detach(iPtr, arrayPtr[0]) +#pragma acc exit data copyout(i) detach(iPtr, arrayPtr[0]) + +// CHECK: #pragma acc exit data copyout(i) delete(i, array[1], array, array[1:2]) +#pragma acc exit data copyout(i) delete(i, array[1], array, array[1:2]) + ; + +// CHECK: #pragma acc exit data copyout(i) delete(i, array[1], array, array[1:2]) +#pragma acc exit data copyout(i) delete(i, array[1], array, array[1:2]) + +// CHECK: #pragma acc host_data use_device(i) +#pragma acc host_data use_device(i) + ; +} diff --git a/clang/test/AST/ast-print-openacc-wait-construct.cpp b/clang/test/AST/ast-print-openacc-wait-construct.cpp new file mode 100644 index 0000000000000..35354596be8d0 --- /dev/null +++ b/clang/test/AST/ast-print-openacc-wait-construct.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fopenacc -ast-print %s -o - | FileCheck %s + +void uses() { + int *iPtr; + int I; + float array[5]; + +// CHECK: #pragma acc wait() if(I == array[I]) +#pragma acc wait() if(I == array[I]) + +// CHECK: #pragma acc wait(*iPtr, I) async +#pragma acc wait(*iPtr, I) async + +// CHECK: #pragma acc wait(queues: *iPtr, I) async(*iPtr) +#pragma acc wait(queues:*iPtr, I) async(*iPtr) + +// CHECK: #pragma acc wait(devnum: I : *iPtr, I) async(I) +#pragma acc wait(devnum:I:*iPtr, I) async(I) + +// CHECK: #pragma acc wait(devnum: I : queues: *iPtr, I) if(I == array[I]) async(I) +#pragma acc wait(devnum:I:queues:*iPtr, I) if(I == array[I]) async(I) +} diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp index 76f80a12c1703..f7095606c77a4 100644 --- a/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp +++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp @@ -49,15 +49,44 @@ class Foo { Foo(); void bar(); + CheckedObj& ensureObj3() { + if (!m_obj3) + const_cast&>(m_obj3) = new CheckedObj; + return *m_obj3; + } + + CheckedObj& badEnsureObj4() { + if (!m_obj4) + const_cast&>(m_obj4) = new CheckedObj; + if (auto* next = m_obj4->next()) + return *next; + return *m_obj4; + } + + CheckedObj* ensureObj5() { + if (!m_obj5) + const_cast&>(m_obj5) = new CheckedObj; + if (m_obj5->next()) + return nullptr; + return m_obj5.get(); + } + private: const std::unique_ptr m_obj1; std::unique_ptr m_obj2; + const std::unique_ptr m_obj3; + const std::unique_ptr m_obj4; + const std::unique_ptr m_obj5; }; void Foo::bar() { m_obj1->method(); m_obj2->method(); // expected-warning@-1{{Call argument for 'this' parameter is unchecked and unsafe}} + ensureObj3().method(); + badEnsureObj4().method(); + // expected-warning@-1{{Call argument for 'this' parameter is unchecked and unsafe}} + ensureObj5()->method(); } } // namespace call_args_const_unique_ptr diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp index 072bceedcf961..59f247d6d007c 100644 --- a/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp +++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp @@ -117,7 +117,7 @@ namespace null_ptr { namespace ref_counted_lookalike { struct Decoy { - CheckedObj* get() { return nullptr; } + CheckedObj* get(); }; void foo() { diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp index b3296507a5c92..215238a7fcf07 100644 --- a/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp +++ b/clang/test/Analysis/Checkers/WebKit/call-args-counted-const-member.cpp @@ -52,15 +52,44 @@ class Foo { Foo(); void bar(); + RefCountable& ensureObj3() { + if (!m_obj3) + const_cast&>(m_obj3) = RefCountable::makeUnique(); + return *m_obj3; + } + + RefCountable& badEnsureObj4() { + if (!m_obj4) + const_cast&>(m_obj4) = RefCountable::makeUnique(); + if (auto* next = m_obj4->next()) + return *next; + return *m_obj4; + } + + RefCountable* ensureObj5() { + if (!m_obj5) + const_cast&>(m_obj5) = RefCountable::makeUnique(); + if (m_obj5->next()) + return nullptr; + return m_obj5.get(); + } + private: const std::unique_ptr m_obj1; std::unique_ptr m_obj2; + const std::unique_ptr m_obj3; + const std::unique_ptr m_obj4; + const std::unique_ptr m_obj5; }; void Foo::bar() { m_obj1->method(); m_obj2->method(); // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} + ensureObj3().method(); + badEnsureObj4().method(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} + ensureObj5()->method(); } } // namespace call_args_const_unique_ptr diff --git a/clang/test/Analysis/Checkers/WebKit/call-args.cpp b/clang/test/Analysis/Checkers/WebKit/call-args.cpp index 94efddeaf66cd..2146eae9975b9 100644 --- a/clang/test/Analysis/Checkers/WebKit/call-args.cpp +++ b/clang/test/Analysis/Checkers/WebKit/call-args.cpp @@ -117,7 +117,7 @@ namespace null_ptr { namespace ref_counted_lookalike { struct Decoy { - RefCountable* get() { return nullptr; } + RefCountable* get(); }; void foo() { @@ -364,4 +364,15 @@ namespace call_with_explicit_temporary_obj { Ref { *provide() }->method(); RefPtr { provide() }->method(); } + template + void bar() { + Ref(*provide())->method(); + RefPtr(provide())->method(); + } + void baz() { + bar(); + } +} + +namespace call_with_explicit_construct { } diff --git a/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp index e52d1e735f637..be04cf26be2e8 100644 --- a/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp +++ b/clang/test/Analysis/Checkers/WebKit/local-vars-checked-const-member.cpp @@ -12,9 +12,36 @@ class Foo { Foo(); void bar(); + CheckedObj& ensureObj3() { + if (!m_obj3) + const_cast&>(m_obj3) = new CheckedObj; + return *m_obj3; + } + + CheckedObj& ensureObj4() { + if (!m_obj4) + const_cast&>(m_obj4) = new CheckedObj; + if (auto* next = m_obj4->next()) { + // expected-warning@-1{{Local variable 'next' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}} + return *next; + } + return *m_obj4; + } + + CheckedObj* ensureObj5() { + if (!m_obj5) + const_cast&>(m_obj5) = new CheckedObj; + if (m_obj5->next()) + return nullptr; + return m_obj5.get(); + } + private: const CheckedPtr m_obj1; CheckedPtr m_obj2; + const CheckedPtr m_obj3; + const CheckedPtr m_obj4; + const CheckedPtr m_obj5; }; void Foo::bar() { @@ -23,6 +50,12 @@ void Foo::bar() { auto* obj2 = m_obj2.get(); // expected-warning@-1{{Local variable 'obj2' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}} obj2->method(); + auto& obj3 = ensureObj3(); + obj3.method(); + auto& obj4 = ensureObj4(); + // expected-warning@-1{{Local variable 'obj4' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}} + obj4.method(); + auto* obj5 = ensureObj5(); } } // namespace local_vars_const_checkedptr_member diff --git a/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp index 03d16285f88b5..e12c9b900a423 100644 --- a/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp +++ b/clang/test/Analysis/Checkers/WebKit/local-vars-counted-const-member.cpp @@ -12,9 +12,36 @@ class Foo { Foo(); void bar(); + RefCountable& ensureObj3() { + if (!m_obj3) + const_cast&>(m_obj3) = RefCountable::create(); + return *m_obj3; + } + + RefCountable& ensureObj4() { + if (!m_obj4) + const_cast&>(m_obj4) = RefCountable::create(); + if (auto* next = m_obj4->next()) { + // expected-warning@-1{{Local variable 'next' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} + return *next; + } + return *m_obj4; + } + + RefCountable* ensureObj5() { + if (!m_obj5) + const_cast&>(m_obj5) = RefCountable::create(); + if (m_obj5->next()) + return nullptr; + return m_obj5.get(); + } + private: const RefPtr m_obj1; RefPtr m_obj2; + const RefPtr m_obj3; + const RefPtr m_obj4; + const RefPtr m_obj5; }; void Foo::bar() { @@ -23,6 +50,12 @@ void Foo::bar() { auto* obj2 = m_obj2.get(); // expected-warning@-1{{Local variable 'obj2' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} obj2->method(); + auto& obj3 = ensureObj3(); + obj3.method(); + auto& obj4 = ensureObj4(); + // expected-warning@-1{{Local variable 'obj4' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} + obj4.method(); + auto* obj5 = ensureObj5(); } } // namespace local_vars_const_refptr_member diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index fb1ee51c7ec1d..f3bd20f8bcf60 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -1,6 +1,34 @@ #ifndef mock_types_1103988513531 #define mock_types_1103988513531 +namespace std { + +template +class unique_ptr { +private: + T *t; + +public: + unique_ptr() : t(nullptr) { } + unique_ptr(T *t) : t(t) { } + ~unique_ptr() { + if (t) + delete t; + } + template unique_ptr(unique_ptr&& u) + : t(u.t) + { + u.t = nullptr; + } + T *get() const { return t; } + T *operator->() const { return t; } + T &operator*() const { return *t; } + unique_ptr &operator=(T *) { return *this; } + explicit operator bool() const { return !!t; } +}; + +}; + template struct RawPtrTraits { using StorageType = T*; @@ -103,7 +131,7 @@ template struct RefPtr { } T *get() const { return t; } T *operator->() const { return t; } - T &operator*() { return *t; } + T &operator*() const { return *t; } RefPtr &operator=(T *t) { RefPtr o(t); swap(o); @@ -130,6 +158,7 @@ template bool operator!=(const RefPtr &, T &) { return false; } struct RefCountable { static Ref create(); + static std::unique_ptr makeUnique(); void ref() {} void deref() {} void method(); @@ -176,7 +205,7 @@ template struct CheckedPtr { } T *get() const { return t; } T *operator->() const { return t; } - T &operator*() { return *t; } + T &operator*() const { return *t; } CheckedPtr &operator=(T *) { return *this; } operator bool() const { return t; } }; @@ -187,6 +216,7 @@ class CheckedObj { void decrementCheckedPtrCount(); void method(); int trivial() { return 123; } + CheckedObj* next(); }; class RefCountableAndCheckable { @@ -220,31 +250,4 @@ class UniqueRef { UniqueRef &operator=(T &) { return *this; } }; -namespace std { - -template -class unique_ptr { -private: - T *t; - -public: - unique_ptr() : t(nullptr) { } - unique_ptr(T *t) : t(t) { } - ~unique_ptr() { - if (t) - delete t; - } - template unique_ptr(unique_ptr&& u) - : t(u.t) - { - u.t = nullptr; - } - T *get() const { return t; } - T *operator->() const { return t; } - T &operator*() { return *t; } - unique_ptr &operator=(T *) { return *this; } -}; - -}; - #endif diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp index 65eee9d49106d..daff32e9940c8 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp @@ -1,16 +1,72 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=webkit.UncountedLambdaCapturesChecker -verify %s -struct A { - static void b(); +#include "mock-types.h" + +namespace WTF { + +namespace Detail { + +template +class CallableWrapperBase { +public: + virtual ~CallableWrapperBase() { } + virtual Out call(In...) = 0; +}; + +template class CallableWrapper; + +template +class CallableWrapper : public CallableWrapperBase { +public: + explicit CallableWrapper(CallableType& callable) + : m_callable(callable) { } + Out call(In... in) final { return m_callable(in...); } + +private: + CallableType m_callable; +}; + +} // namespace Detail + +template class Function; + +template Function adopt(Detail::CallableWrapperBase*); + +template +class Function { +public: + using Impl = Detail::CallableWrapperBase; + + Function() = default; + + template + Function(FunctionType f) + : m_callableWrapper(new Detail::CallableWrapper(f)) { } + + Out operator()(In... in) const { return m_callableWrapper->call(in...); } + explicit operator bool() const { return !!m_callableWrapper; } + +private: + enum AdoptTag { Adopt }; + Function(Impl* impl, AdoptTag) + : m_callableWrapper(impl) + { + } + + friend Function adopt(Impl*); + + std::unique_ptr m_callableWrapper; }; -struct RefCountable { - void ref() {} - void deref() {} - void method(); - void constMethod() const; - int trivial() { return 123; } - RefCountable* next(); +template Function adopt(Detail::CallableWrapperBase* impl) +{ + return Function(impl, Function::Adopt); +} + +} // namespace WTF + +struct A { + static void b(); }; RefCountable* make_obj(); @@ -185,3 +241,21 @@ void lambda_with_args(RefCountable* obj) { }; trivial_lambda(1); } + +void callFunctionOpaque(WTF::Function&&); +void callFunction(WTF::Function&& function) { + someFunction(); + function(); +} + +void lambda_converted_to_function(RefCountable* obj) +{ + callFunction([&]() { + obj->method(); + // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} + }); + callFunctionOpaque([&]() { + obj->method(); + // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} + }); +} diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp index d7fb689557a6f..52854cd10f68c 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp @@ -456,3 +456,12 @@ int TreeNode::recursiveWeight() { } } // namespace local_var_in_recursive_function + +namespace local_var_for_singleton { + RefCountable *singleton(); + RefCountable *otherSingleton(); + void foo() { + RefCountable* bar = singleton(); + RefCountable* baz = otherSingleton(); + } +} \ No newline at end of file diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index 47594e8317bc7..8ce6184144d4b 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -40,9 +40,9 @@ // CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals // CHECK-NEXT: cplusplus.SmartPtrModeling:ModelSmartPtrDereference = false // CHECK-NEXT: crosscheck-with-z3 = false -// CHECK-NEXT: crosscheck-with-z3-eqclass-timeout-threshold = 700 -// CHECK-NEXT: crosscheck-with-z3-rlimit-threshold = 400000 -// CHECK-NEXT: crosscheck-with-z3-timeout-threshold = 300 +// CHECK-NEXT: crosscheck-with-z3-eqclass-timeout-threshold = 0 +// CHECK-NEXT: crosscheck-with-z3-rlimit-threshold = 0 +// CHECK-NEXT: crosscheck-with-z3-timeout-threshold = 15000 // CHECK-NEXT: ctu-dir = "" // CHECK-NEXT: ctu-import-cpp-threshold = 8 // CHECK-NEXT: ctu-import-threshold = 24 diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp index da1f8201f55dc..18f4bd5e9c0fa 100644 --- a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify=expected,cxx11,cxx11-17 -pedantic %s // RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify=expected,cxx11-17,since-cxx17 -pedantic %s // RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify=expected,since-cxx17 -pedantic %s +// RUN: %clang_cc1 -fsyntax-only -std=c++23 -verify=expected,since-cxx17 -pedantic %s struct [[nodiscard]] S {}; // cxx11-warning@-1 {{use of the 'nodiscard' attribute is a C++17 extension}} @@ -134,3 +135,50 @@ void usage() { static_cast(s); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: Don't throw away as a double}} } } // namespace p1771 + +namespace discarded_member_access { +struct X { + union { + int variant_member; + }; + struct { // expected-warning {{anonymous structs are a GNU extension}} + int anonymous_struct_member; + }; + int data_member; + static int static_data_member; + enum { + unscoped_enum + }; + enum class scoped_enum_t { + scoped_enum + }; + using enum scoped_enum_t; + // cxx11-17-warning@-1 {{using enum declaration is a C++20 extension}} + + void implicit_object_member_function(); + static void static_member_function(); +#if __cplusplus >= 202302L + void explicit_object_member_function(this X self); +#endif +}; + +[[nodiscard]] X get_X(); +// cxx11-warning@-1 {{use of the 'nodiscard' attribute is a C++17 extension}} +void f() { + (void) get_X().variant_member; + (void) get_X().anonymous_struct_member; + (void) get_X().data_member; + (void) get_X().static_data_member; + // expected-warning@-1 {{ignoring return value of function declared with 'nodiscard' attribute}} + (void) get_X().unscoped_enum; + // expected-warning@-1 {{ignoring return value of function declared with 'nodiscard' attribute}} + (void) get_X().scoped_enum; + // expected-warning@-1 {{ignoring return value of function declared with 'nodiscard' attribute}} + (void) get_X().implicit_object_member_function(); + (void) get_X().static_member_function(); + // expected-warning@-1 {{ignoring return value of function declared with 'nodiscard' attribute}} +#if __cplusplus >= 202302L + (void) get_X().explicit_object_member_function(); +#endif +} +} // namespace discarded_member_access diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp index dbb6e60d9b93d..a633c108bc22c 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp @@ -57,9 +57,11 @@ template void b(T[] ...); template -void c(T ... []); // expected-error {{expected expression}} \ - // expected-error {{'T' does not refer to the name of a parameter pack}} \ - // expected-warning {{pack indexing is a C++2c extension}} +void c(T ... []); // expected-error {{type 'T[]' of function parameter pack does not contain any unexpanded parameter packs}} + +// A function that takes pointers to each type T as arguments, after any decay. +template +void g(T...[]); template void d(T ... x[]); // expected-error{{type 'T[]' of function parameter pack does not contain any unexpanded parameter packs}} diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp index 9796607a790ce..ff625a4a985bc 100644 --- a/clang/test/CXX/drs/cwg28xx.cpp +++ b/clang/test/CXX/drs/cwg28xx.cpp @@ -30,7 +30,25 @@ using U2 = decltype(&main); #endif } // namespace cwg2811 -namespace cwg2819 { // cwg2819: 19 +namespace cwg2813 { // cwg2813: 20 +#if __cplusplus >= 202302L +struct X { + X() = default; + + X(const X&) = delete; + X& operator=(const X&) = delete; + + void f(this X self) { } +}; + +void f() { + X{}.f(); +} +#endif +} // namespace cwg2813 + +namespace cwg2819 { // cwg2819: 19 tentatively ready 2023-12-01 + #if __cpp_constexpr >= 202306L constexpr void* p = nullptr; constexpr int* q = static_cast(p); diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp index 87c22a0d7e944..50dedb1a158d3 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s // expected-no-diagnostics namespace pr12262 { @@ -201,3 +202,24 @@ void func() } } + +#if __cplusplus >= 202002L +namespace GH81436 { + +template struct Bar; + +template +Bar(E) -> Bar; + +template struct Foo {}; + +// Bar doesn't have to be of a complete type. +template +auto func() requires requires(Bar ...init_lists) { + sizeof...(init_lists) > 0; +} {} + +void f() { func(); } + +} // namespace GH81436 +#endif diff --git a/clang/test/CXX/temp/temp.res/p4.cpp b/clang/test/CXX/temp/temp.res/p4.cpp index f54d8649f5da8..9dbdd235e925d 100644 --- a/clang/test/CXX/temp/temp.res/p4.cpp +++ b/clang/test/CXX/temp/temp.res/p4.cpp @@ -185,3 +185,23 @@ template struct S { friend void X::f(T::type); }; } + +namespace GH113324 { +template struct S1 { + friend void f1(S1, int = 0); // expected-error {{friend declaration specifying a default argument must be a definition}} + friend void f2(S1 a, S1 = decltype(a){}); // expected-error {{friend declaration specifying a default argument must be a definition}} +}; + +template using alias = int; +template struct S2 { + // FIXME: We miss diagnosing the default argument instantiation failure + // (forming reference to void) + friend void f3(S2, int a = alias(1)); // expected-error {{friend declaration specifying a default argument must be a definition}} +}; + +void test() { + f1(S1<>{}); + f2(S1<>{}); + f3(S2()); +} +} // namespace GH113324 diff --git a/clang/test/CodeGen/AArch64/cpu-supports.c b/clang/test/CodeGen/AArch64/cpu-supports.c index 76fcea0be3158..406201781d480 100644 --- a/clang/test/CodeGen/AArch64/cpu-supports.c +++ b/clang/test/CodeGen/AArch64/cpu-supports.c @@ -18,8 +18,8 @@ // CHECK-NEXT: br label [[RETURN:%.*]] // CHECK: if.end: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 17867063951360 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 17867063951360 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 17936857268992 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 17936857268992 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[IF_THEN1:%.*]], label [[IF_END2:%.*]] // CHECK: if.then1: @@ -27,8 +27,8 @@ // CHECK-NEXT: br label [[RETURN]] // CHECK: if.end2: // CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 171136785840078848 -// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 171136785840078848 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 171141184020873984 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 171141184020873984 // CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] // CHECK-NEXT: br i1 [[TMP11]], label [[IF_THEN3:%.*]], label [[IF_END4:%.*]] // CHECK: if.then3: diff --git a/clang/test/CodeGen/AArch64/fixed-register-global.c b/clang/test/CodeGen/AArch64/fixed-register-global.c index a5e634310ec94..25c7aa254547b 100644 --- a/clang/test/CodeGen/AArch64/fixed-register-global.c +++ b/clang/test/CodeGen/AArch64/fixed-register-global.c @@ -2,13 +2,13 @@ /// Regression test for #76426, #109778 // REQUIRES: aarch64-registered-target -// RUN: %clang -c --target=aarch64-none-gnu -ffixed-x15 %s 2>&1 | count 0 +// RUN: %clang -c --target=aarch64-none-gnu -ffixed-x15 %s -o /dev/null 2>&1 | count 0 -// RUN: not %clang -c --target=aarch64-none-gnu %s 2>&1 | \ +// RUN: not %clang -c --target=aarch64-none-gnu %s -o /dev/null 2>&1 | \ // RUN: FileCheck %s --check-prefix=ERR_INVREG // ERR_INVREG: error: register 'x15' unsuitable for global register variables on this target -// RUN: not %clang -c --target=aarch64-none-gnu -ffixed-x15 -DTYPE=short %s 2>&1 | \ +// RUN: not %clang -c --target=aarch64-none-gnu -ffixed-x15 -DTYPE=short %s -o /dev/null 2>&1 | \ // RUN: FileCheck %s --check-prefix=ERR_SIZE // ERR_SIZE: error: size of register 'x15' does not match variable size diff --git a/clang/test/CodeGen/AArch64/fmv-dependencies.c b/clang/test/CodeGen/AArch64/fmv-dependencies.c index f74b7aa32c7dc..3a524b89496e0 100644 --- a/clang/test/CodeGen/AArch64/fmv-dependencies.c +++ b/clang/test/CodeGen/AArch64/fmv-dependencies.c @@ -183,10 +183,10 @@ int caller() { // CHECK: attributes #[[sha2]] = { {{.*}} "target-features"="+fmv,+fp-armv8,+neon,+outline-atomics,+sha2,+v8a" // CHECK: attributes #[[sha3]] = { {{.*}} "target-features"="+fmv,+fp-armv8,+neon,+outline-atomics,+sha2,+sha3,+v8a" // CHECK: attributes #[[sm4]] = { {{.*}} "target-features"="+fmv,+fp-armv8,+neon,+outline-atomics,+sm4,+v8a" -// CHECK: attributes #[[sme]] = { {{.*}} "target-features"="+bf16,+fmv,+fp-armv8,+neon,+outline-atomics,+sme,+v8a" -// CHECK: attributes #[[sme_f64f64]] = { {{.*}} "target-features"="+bf16,+fmv,+fp-armv8,+neon,+outline-atomics,+sme,+sme-f64f64,+v8a" -// CHECK: attributes #[[sme_i16i64]] = { {{.*}} "target-features"="+bf16,+fmv,+fp-armv8,+neon,+outline-atomics,+sme,+sme-i16i64,+v8a" -// CHECK: attributes #[[sme2]] = { {{.*}} "target-features"="+bf16,+fmv,+fp-armv8,+neon,+outline-atomics,+sme,+sme2,+v8a" +// CHECK: attributes #[[sme]] = { {{.*}} "target-features"="+bf16,+fmv,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+v8a" +// CHECK: attributes #[[sme_f64f64]] = { {{.*}} "target-features"="+bf16,+fmv,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme-f64f64,+v8a" +// CHECK: attributes #[[sme_i16i64]] = { {{.*}} "target-features"="+bf16,+fmv,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme-i16i64,+v8a" +// CHECK: attributes #[[sme2]] = { {{.*}} "target-features"="+bf16,+fmv,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sme,+sme2,+v8a" // CHECK: attributes #[[ssbs]] = { {{.*}} "target-features"="+fmv,+fp-armv8,+neon,+outline-atomics,+ssbs,+v8a" // CHECK: attributes #[[sve]] = { {{.*}} "target-features"="+fmv,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+v8a" // CHECK: attributes #[[sve2]] = { {{.*}} "target-features"="+fmv,+fp-armv8,+fullfp16,+neon,+outline-atomics,+sve,+sve2,+v8a" diff --git a/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sme2_fp8_cvt.c b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sme2_fp8_cvt.c index 13609f034da33..ae2e780f84cfe 100644 --- a/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sme2_fp8_cvt.c +++ b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sme2_fp8_cvt.c @@ -16,6 +16,70 @@ #define SVE_ACLE_FUNC(A1,A2,A3) A1##A2##A3 #endif +// CHECK-LABEL: @test_cvt_f16_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt.x2.nxv8f16( [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_cvt_f16_x213svfloat16x2_tm( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt.x2.nxv8f16( [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_cvt_f16_x2(svfloat16x2_t zn, fpm_t fpmr) __arm_streaming { + return SVE_ACLE_FUNC(svcvt_mf8,_f16_x2,_fpm)(zn, fpmr); +} + +// CHECK-LABEL: @test_cvt_f32_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt.x4( [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z15test_cvt_f32_x413svfloat32x4_tm( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt.x4( [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_cvt_f32_x4(svfloat32x4_t zn, fpm_t fpmr) __arm_streaming { + return SVE_ACLE_FUNC(svcvt_mf8,_f32_x4,_fpm)(zn, fpmr); +} + +// CHECK-LABEL: @test_cvtn_f32_x4( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtn.x4( [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z16test_cvtn_f32_x413svfloat32x4_tm( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtn.x4( [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_cvtn_f32_x4(svfloat32x4_t zn, fpm_t fpmr) __arm_streaming { + return SVE_ACLE_FUNC(svcvtn_mf8,_f32_x4,_fpm)(zn, fpmr); +} + +// CHECK-LABEL: @test_cvt_bf16_x2( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt.x2.nxv8bf16( [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: @_Z16test_cvt_bf16_x214svbfloat16x2_tm( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt.x2.nxv8bf16( [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_cvt_bf16_x2(svbfloat16x2_t zn, fpm_t fpmr) __arm_streaming { + return SVE_ACLE_FUNC(svcvt_mf8,_bf16_x2,_fpm)(zn, fpmr); +} + // CHECK-LABEL: @test_cvt1_f16_x2( // CHECK-NEXT: entry: // CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]]) diff --git a/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sme2_fp8_mla.c b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sme2_fp8_mla.c new file mode 100644 index 0000000000000..d603045edf282 --- /dev/null +++ b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sme2_fp8_mla.c @@ -0,0 +1,316 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// REQUIRES: aarch64-registered-target + +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -DSME_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -DSME_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -passes=mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme-f8f16 -target-feature +sme-f8f32 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +#include + +#ifdef SME_OVERLOADED_FORMS +#define SME_ACLE_FUNC(A1, A2_UNUSED, A3, A4_UNUSED, A5) A1##A3##A5 +#else +#define SME_ACLE_FUNC(A1, A2, A3, A4, A5) A1##A2##A3##A4##A5 +#endif + +// FMLAL (indexed) + +// CHECK-LABEL: define dso_local void @test_svmla_lane_za16_vg2x1( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.lane.za16.vg2x1(i32 [[SLICE]], [[ZN]], [[ZM]], i32 0) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z26test_svmla_lane_za16_vg2x1ju13__SVMfloat8_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.lane.za16.vg2x1(i32 [[SLICE]], [[ZN]], [[ZM]], i32 0) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_lane_za16_vg2x1(uint32_t slice, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_lane_za16,_mf8,_vg2x1_fpm,,)(slice, zn, zm, 0, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_lane_za16_vg2x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.lane.za16.vg2x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 15) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z26test_svmla_lane_za16_vg2x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.lane.za16.vg2x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 15) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_lane_za16_vg2x2(uint32_t slice, svmfloat8x2_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_lane_za16,_mf8,_vg2x2_fpm,,)(slice, zn, zm, 15, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_lane_za16_vg2x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.lane.za16.vg2x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]], i32 7) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z26test_svmla_lane_za16_vg2x4j13svmfloat8x4_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.lane.za16.vg2x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]], i32 7) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_lane_za16_vg2x4(uint32_t slice, svmfloat8x4_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_lane_za16,_mf8,_vg2x4_fpm,,)(slice, zn, zm, 7, fpm); +} + +// FMLALL (indexed) + +// CHECK-LABEL: define dso_local void @test_svmla_lane_za32_vg4x1( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.lane.za32.vg4x1(i32 [[SLICE]], [[ZN]], [[ZM]], i32 0) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z26test_svmla_lane_za32_vg4x1ju13__SVMfloat8_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.lane.za32.vg4x1(i32 [[SLICE]], [[ZN]], [[ZM]], i32 0) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_lane_za32_vg4x1(uint32_t slice, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_lane_za32,_mf8,_vg4x1_fpm,,)(slice, zn, zm, 0, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_lane_za32_vg4x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.lane.za32.vg4x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 15) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z26test_svmla_lane_za32_vg4x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.lane.za32.vg4x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 15) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_lane_za32_vg4x2(uint32_t slice, svmfloat8x2_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_lane_za32,_mf8,_vg4x2_fpm,,)(slice, zn, zm, 15, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_lane_za32_vg4x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.lane.za32.vg4x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]], i32 7) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z26test_svmla_lane_za32_vg4x4j13svmfloat8x4_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.lane.za32.vg4x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]], i32 7) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_lane_za32_vg4x4(uint32_t slice, svmfloat8x4_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_lane_za32,_mf8,_vg4x4_fpm,,)(slice, zn, zm, 7, fpm); +} + +// FMLAL (single) + +// CHECK-LABEL: define dso_local void @test_svmla_single_za16_vg2x1( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.single.za16.vg2x1(i32 [[SLICE]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z28test_svmla_single_za16_vg2x1ju13__SVMfloat8_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.single.za16.vg2x1(i32 [[SLICE]], [[ZN]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_single_za16_vg2x1(uint32_t slice, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla,_single,_za16,_mf8,_vg2x1_fpm)(slice, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_single_za16_vg2x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.single.za16.vg2x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z28test_svmla_single_za16_vg2x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.single.za16.vg2x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_single_za16_vg2x2(uint32_t slice, svmfloat8x2_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla,_single,_za16,_mf8,_vg2x2_fpm)(slice, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_single_za16_vg2x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.single.za16.vg2x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z28test_svmla_single_za16_vg2x4j13svmfloat8x4_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.single.za16.vg2x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_single_za16_vg2x4(uint32_t slice, svmfloat8x4_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla,_single,_za16,_mf8,_vg2x4_fpm)(slice, zn, zm, fpm); +} + +// FMLALL (single) + +// CHECK-LABEL: define dso_local void @test_svmla_single_za32_vg4x1( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.single.za32.vg4x1(i32 [[SLICE]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z28test_svmla_single_za32_vg4x1ju13__SVMfloat8_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.single.za32.vg4x1(i32 [[SLICE]], [[ZN]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_single_za32_vg4x1(uint32_t slice, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla,_single,_za32,_mf8,_vg4x1_fpm)(slice, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_single_za32_vg4x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.single.za32.vg4x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z28test_svmla_single_za32_vg4x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.single.za32.vg4x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_single_za32_vg4x2(uint32_t slice, svmfloat8x2_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla,_single,_za32,_mf8,_vg4x2_fpm)(slice, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_single_za32_vg4x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.single.za32.vg4x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z28test_svmla_single_za32_vg4x4j13svmfloat8x4_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.single.za32.vg4x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_single_za32_vg4x4(uint32_t slice, svmfloat8x4_t zn, svmfloat8_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla,_single,_za32,_mf8,_vg4x4_fpm)(slice, zn, zm, fpm); +} + +// FMLAL (multi) + +// CHECK-LABEL: define dso_local void @test_svmla_multi_za16_vg2x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.multi.za16.vg2x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM_COERCE0]], [[ZM_COERCE1]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z27test_svmla_multi_za16_vg2x2j13svmfloat8x2_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.multi.za16.vg2x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM_COERCE0]], [[ZM_COERCE1]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_multi_za16_vg2x2(uint32_t slice, svmfloat8x2_t zn, svmfloat8x2_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_za16,_mf8,_vg2x2_fpm,,)(slice, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_multi_za16_vg2x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], [[ZM_COERCE2:%.*]], [[ZM_COERCE3:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.multi.za16.vg2x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM_COERCE0]], [[ZM_COERCE1]], [[ZM_COERCE2]], [[ZM_COERCE3]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z27test_svmla_multi_za16_vg2x4j13svmfloat8x4_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], [[ZM_COERCE2:%.*]], [[ZM_COERCE3:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlal.multi.za16.vg2x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM_COERCE0]], [[ZM_COERCE1]], [[ZM_COERCE2]], [[ZM_COERCE3]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_multi_za16_vg2x4(uint32_t slice, svmfloat8x4_t zn, svmfloat8x4_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_za16,_mf8,_vg2x4_fpm,,)(slice, zn, zm, fpm); +} + +// FMLALL (multi) + +// CHECK-LABEL: define dso_local void @test_svmla_multi_za32_vg4x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.multi.za32.vg4x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM_COERCE0]], [[ZM_COERCE1]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z27test_svmla_multi_za32_vg4x2j13svmfloat8x2_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.multi.za32.vg4x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM_COERCE0]], [[ZM_COERCE1]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_multi_za32_vg4x2(uint32_t slice, svmfloat8x2_t zn, svmfloat8x2_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_za32,_mf8,_vg4x2_fpm,,)(slice, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local void @test_svmla_multi_za32_vg4x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], [[ZM_COERCE2:%.*]], [[ZM_COERCE3:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.multi.za32.vg4x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM_COERCE0]], [[ZM_COERCE1]], [[ZM_COERCE2]], [[ZM_COERCE3]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z27test_svmla_multi_za32_vg4x4j13svmfloat8x4_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], [[ZM_COERCE2:%.*]], [[ZM_COERCE3:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fmlall.multi.za32.vg4x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM_COERCE0]], [[ZM_COERCE1]], [[ZM_COERCE2]], [[ZM_COERCE3]]) +// CPP-CHECK-NEXT: ret void +// +void test_svmla_multi_za32_vg4x4(uint32_t slice, svmfloat8x4_t zn, svmfloat8x4_t zm, fpm_t fpm) __arm_streaming __arm_inout("za") { + SME_ACLE_FUNC(svmla_za32,_mf8,_vg4x4_fpm,,)(slice, zn, zm, fpm); +} diff --git a/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_cvt.c b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_cvt.c new file mode 100644 index 0000000000000..c026b8aa216f3 --- /dev/null +++ b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_cvt.c @@ -0,0 +1,173 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -x c++ -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CHECK-CXX + +// RUN: %clang_cc1 -DSME_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -DSME_OVERLOADED_FORMS -x c++ -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CHECK-CXX + +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +// REQUIRES: aarch64-registered-target + +#ifdef __ARM_FEATURE_SME +#include +#else +#include +#endif + +#ifdef SVE_OVERLOADED_FORMS +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3) A1##A2##A3 +#endif + +#ifdef __ARM_FEATURE_SME +#define STREAMING __arm_streaming +#else +#define STREAMING +#endif + +// CHECK-LABEL: define dso_local @test_svcvt1_bf16_mf8( +// CHECK-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt1.nxv8bf16( [[ZN]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z20test_svcvt1_bf16_mf8u13__SVMfloat8_tm( +// CHECK-CXX-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt1.nxv8bf16( [[ZN]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svbfloat16_t test_svcvt1_bf16_mf8(svmfloat8_t zn, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvt1_bf16,_mf8,_fpm)(zn, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvt2_bf16_mf8( +// CHECK-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt2.nxv8bf16( [[ZN]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z20test_svcvt2_bf16_mf8u13__SVMfloat8_tm( +// CHECK-CXX-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt2.nxv8bf16( [[ZN]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svbfloat16_t test_svcvt2_bf16_mf8(svmfloat8_t zn, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvt2_bf16,_mf8,_fpm)(zn, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvtlt1_bf16_mf8( +// CHECK-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtlt1.nxv8bf16( [[ZN]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z22test_svcvtlt1_bf16_mf8u13__SVMfloat8_tm( +// CHECK-CXX-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtlt1.nxv8bf16( [[ZN]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svbfloat16_t test_svcvtlt1_bf16_mf8(svmfloat8_t zn, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvtlt1_bf16,_mf8,_fpm)(zn, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvtlt2_bf16_mf8( +// CHECK-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtlt2.nxv8bf16( [[ZN]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z22test_svcvtlt2_bf16_mf8u13__SVMfloat8_tm( +// CHECK-CXX-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtlt2.nxv8bf16( [[ZN]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svbfloat16_t test_svcvtlt2_bf16_mf8(svmfloat8_t zn, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvtlt2_bf16,_mf8,_fpm)(zn, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvt1_f16_mf8( +// CHECK-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt1.nxv8f16( [[ZN]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z19test_svcvt1_f16_mf8u13__SVMfloat8_tm( +// CHECK-CXX-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt1.nxv8f16( [[ZN]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svcvt1_f16_mf8(svmfloat8_t zn, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvt1_f16,_mf8,_fpm)(zn, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvt2_f16_mf8( +// CHECK-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt2.nxv8f16( [[ZN]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z19test_svcvt2_f16_mf8u13__SVMfloat8_tm( +// CHECK-CXX-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvt2.nxv8f16( [[ZN]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svcvt2_f16_mf8(svmfloat8_t zn, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvt2_f16,_mf8,_fpm)(zn, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvtlt1_f16_mf8( +// CHECK-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtlt1.nxv8f16( [[ZN]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z21test_svcvtlt1_f16_mf8u13__SVMfloat8_tm( +// CHECK-CXX-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtlt1.nxv8f16( [[ZN]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svcvtlt1_f16_mf8(svmfloat8_t zn, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvtlt1_f16,_mf8,_fpm)(zn, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvtlt2_f16_mf8( +// CHECK-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtlt2.nxv8f16( [[ZN]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z21test_svcvtlt2_f16_mf8u13__SVMfloat8_tm( +// CHECK-CXX-SAME: [[ZN:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtlt2.nxv8f16( [[ZN]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svcvtlt2_f16_mf8(svmfloat8_t zn, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvtlt2_f16,_mf8,_fpm)(zn, fpm); +} diff --git a/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_cvtn.c b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_cvtn.c new file mode 100644 index 0000000000000..ed5b0ce02af4b --- /dev/null +++ b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_cvtn.c @@ -0,0 +1,101 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -x c++ -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CHECK-CXX + +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -x c++ -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CHECK-CXX + +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +// REQUIRES: aarch64-registered-target + +#ifdef __ARM_FEATURE_SME +#include +#else +#include +#endif + +#ifdef SVE_OVERLOADED_FORMS +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3) A1##A2##A3 +#endif + +#ifdef __ARM_FEATURE_SME +#define STREAMING __arm_streaming +#else +#define STREAMING +#endif + +// CHECK-LABEL: define dso_local @test_svcvtn_f8_bf16( +// CHECK-SAME: [[ZN_ZM_COERCE0:%.*]], [[ZN_ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtn.nxv8bf16( [[ZN_ZM_COERCE0]], [[ZN_ZM_COERCE1]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z19test_svcvtn_f8_bf1614svbfloat16x2_tm( +// CHECK-CXX-SAME: [[ZN_ZM_COERCE0:%.*]], [[ZN_ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtn.nxv8bf16( [[ZN_ZM_COERCE0]], [[ZN_ZM_COERCE1]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svcvtn_f8_bf16(svbfloat16x2_t zn_zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvtn_mf8,_bf16_x2,_fpm)(zn_zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvtn_f8_f16( +// CHECK-SAME: [[ZN_ZM_COERCE0:%.*]], [[ZN_ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtn.nxv8f16( [[ZN_ZM_COERCE0]], [[ZN_ZM_COERCE1]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z18test_svcvtn_f8_f1613svfloat16x2_tm( +// CHECK-CXX-SAME: [[ZN_ZM_COERCE0:%.*]], [[ZN_ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtn.nxv8f16( [[ZN_ZM_COERCE0]], [[ZN_ZM_COERCE1]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svcvtn_f8_f16(svfloat16x2_t zn_zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvtn_mf8,_f16_x2,_fpm)(zn_zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvtnb_f8_f32( +// CHECK-SAME: [[ZN_ZM_COERCE0:%.*]], [[ZN_ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtnb.nxv4f32( [[ZN_ZM_COERCE0]], [[ZN_ZM_COERCE1]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z19test_svcvtnb_f8_f3213svfloat32x2_tm( +// CHECK-CXX-SAME: [[ZN_ZM_COERCE0:%.*]], [[ZN_ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtnb.nxv4f32( [[ZN_ZM_COERCE0]], [[ZN_ZM_COERCE1]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svcvtnb_f8_f32(svfloat32x2_t zn_zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvtnb_mf8,_f32_x2,_fpm)(zn_zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svcvtnt_f8_f32( +// CHECK-SAME: [[ZD:%.*]], [[ZN_ZM_COERCE0:%.*]], [[ZN_ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtnt.nxv4f32( [[ZD]], [[ZN_ZM_COERCE0]], [[ZN_ZM_COERCE1]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z19test_svcvtnt_f8_f32u13__SVMfloat8_t13svfloat32x2_tm( +// CHECK-CXX-SAME: [[ZD:%.*]], [[ZN_ZM_COERCE0:%.*]], [[ZN_ZM_COERCE1:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.cvtnt.nxv4f32( [[ZD]], [[ZN_ZM_COERCE0]], [[ZN_ZM_COERCE1]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svcvtnt_f8_f32(svmfloat8_t zd, svfloat32x2_t zn_zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svcvtnt_mf8,_f32_x2,_fpm)(zd, zn_zm, fpm); +} diff --git a/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_fdot.c b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_fdot.c new file mode 100644 index 0000000000000..950a19115811e --- /dev/null +++ b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_fdot.c @@ -0,0 +1,149 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -target-feature +fp8dot2 -target-feature +fp8dot4 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -x c++ -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +fp8 -target-feature +ssve-fp8dot2 -target-feature +ssve-fp8dot4 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CHECK-CXX + +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -target-feature +fp8dot2 -target-feature +fp8dot4 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -x c++ -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +fp8 -target-feature +ssve-fp8dot2 -target-feature +ssve-fp8dot4 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CHECK-CXX + +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -target-feature +fp8dot2 -target-feature +fp8dot4 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -target-feature +ssve-fp8dot2 -target-feature +ssve-fp8dot4 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +// REQUIRES: aarch64-registered-target + +#ifdef __ARM_FEATURE_SME +#include +#else +#include +#endif + +#ifdef SVE_OVERLOADED_FORMS +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3) A1##A2##A3 +#endif + +#ifdef __ARM_FEATURE_SME +#define STREAMING __arm_streaming +#else +#define STREAMING +#endif + +// CHECK-LABEL: define dso_local @test_svdot_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.nxv4f32( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z18test_svdot_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.nxv4f32( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svdot_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svdot,_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svdot_n_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-NEXT: ret [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local @_Z20test_svdot_n_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tu6__mfp8m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-CXX-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-CXX-NEXT: ret [[TMP1]] +// +svfloat32_t test_svdot_n_f32_mf8(svfloat32_t zda, svmfloat8_t zn, mfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svdot,_n_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svdot_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.nxv8f16( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z18test_svdot_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.nxv8f16( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svdot_f16_mf8(svfloat16_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svdot,_f16_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svdot_n_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.nxv8f16( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-NEXT: ret [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local @_Z20test_svdot_n_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tu6__mfp8m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-CXX-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.nxv8f16( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-CXX-NEXT: ret [[TMP1]] +// +svfloat16_t test_svdot_n_f16_mf8(svfloat16_t zda, svmfloat8_t zn, mfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svdot,_n_f16_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svdot_lane_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 3) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z23test_svdot_lane_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 3) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svdot_lane_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svdot_lane,_f32_mf8,_fpm)(zda, zn, zm, 3, fpm); +} + +// CHECK-LABEL: define dso_local @test_svdot_lane_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.lane.nxv8f16( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z23test_svdot_lane_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fdot.lane.nxv8f16( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svdot_lane_f16_mf8(svfloat16_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svdot_lane,_f16_mf8,_fpm)(zda, zn, zm, 7, fpm); +} diff --git a/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_fmla.c b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_fmla.c new file mode 100644 index 0000000000000..425e6a57ffe3c --- /dev/null +++ b/clang/test/CodeGen/AArch64/fp8-intrinsics/acle_sve2_fp8_fmla.c @@ -0,0 +1,389 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -target-feature +fp8fma -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -x c++ -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +fp8 -target-feature +ssve-fp8fma -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CHECK-CXX + +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -target-feature +fp8fma -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -x c++ -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +fp8 -target-feature +ssve-fp8fma -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CHECK-CXX + +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sve2 -target-feature +fp8 -target-feature +fp8fma -S -disable-O0-optnone -Werror -Wall -o /dev/null %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -target-feature +ssve-fp8fma -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +// REQUIRES: aarch64-registered-target + +#ifdef __ARM_FEATURE_SME +#include +#else +#include +#endif + +#ifdef SVE_OVERLOADED_FORMS +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3) A1##A2##A3 +#endif + +#ifdef __ARM_FEATURE_SME +#define STREAMING __arm_streaming +#else +#define STREAMING +#endif + +// CHECK-LABEL: define dso_local @test_svmlalb_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalb.nxv8f16( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z20test_svmlalb_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalb.nxv8f16( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svmlalb_f16_mf8(svfloat16_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalb,_f16_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalb_n_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalb.nxv8f16( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-NEXT: ret [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local @_Z22test_svmlalb_n_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tu6__mfp8m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-CXX-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalb.nxv8f16( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-CXX-NEXT: ret [[TMP1]] +// +svfloat16_t test_svmlalb_n_f16_mf8(svfloat16_t zda, svmfloat8_t zn, mfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalb,_n_f16_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalt_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalt.nxv8f16( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z20test_svmlalt_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalt.nxv8f16( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svmlalt_f16_mf8(svfloat16_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalt,_f16_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalt_n_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalt.nxv8f16( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-NEXT: ret [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local @_Z22test_svmlalt_n_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tu6__mfp8m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-CXX-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalt.nxv8f16( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-CXX-NEXT: ret [[TMP1]] +// +svfloat16_t test_svmlalt_n_f16_mf8(svfloat16_t zda, svmfloat8_t zn, mfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalt,_n_f16_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalb_lane_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalb.lane.nxv8f16( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z25test_svmlalb_lane_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalb.lane.nxv8f16( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svmlalb_lane_f16_mf8(svfloat16_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalb_lane,_f16_mf8,_fpm)(zda, zn, zm, 7, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalt_lane_f16_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalt.lane.nxv8f16( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z25test_svmlalt_lane_f16_mf8u13__SVFloat16_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalt.lane.nxv8f16( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat16_t test_svmlalt_lane_f16_mf8(svfloat16_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalt_lane,_f16_mf8,_fpm)(zda, zn, zm, 7, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlallbb_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbb.nxv4f32( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z22test_svmlallbb_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbb.nxv4f32( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svmlallbb_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlallbb,_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlallbb_n_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbb.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-NEXT: ret [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local @_Z24test_svmlallbb_n_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tu6__mfp8m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-CXX-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbb.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-CXX-NEXT: ret [[TMP1]] +// +svfloat32_t test_svmlallbb_n_f32_mf8(svfloat32_t zda, svmfloat8_t zn, mfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlallbb,_n_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlallbt_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbt.nxv4f32( [[ZDA]], [[ZM]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z22test_svmlallbt_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbt.nxv4f32( [[ZDA]], [[ZM]], [[ZM]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svmlallbt_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlallbt,_f32_mf8,_fpm)(zda, zm, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlallbt_n_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbt.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-NEXT: ret [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local @_Z24test_svmlallbt_n_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tu6__mfp8m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-CXX-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbt.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-CXX-NEXT: ret [[TMP1]] +// +svfloat32_t test_svmlallbt_n_f32_mf8(svfloat32_t zda, svmfloat8_t zn, mfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlallbt,_n_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalltb_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltb.nxv4f32( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z22test_svmlalltb_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltb.nxv4f32( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svmlalltb_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalltb,_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalltb_n_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltb.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-NEXT: ret [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local @_Z24test_svmlalltb_n_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tu6__mfp8m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-CXX-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltb.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-CXX-NEXT: ret [[TMP1]] +// +svfloat32_t test_svmlalltb_n_f32_mf8(svfloat32_t zda, svmfloat8_t zn, mfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalltb,_n_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalltt_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltt.nxv4f32( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z22test_svmlalltt_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltt.nxv4f32( [[ZDA]], [[ZN]], [[ZM]]) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svmlalltt_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalltt,_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalltt_n_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltt.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-NEXT: ret [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local @_Z24test_svmlalltt_n_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tu6__mfp8m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], <1 x i8> [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = extractelement <1 x i8> [[ZM]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement poison, i8 [[TMP0]], i64 0 +// CHECK-CXX-NEXT: [[DOTSPLAT:%.*]] = shufflevector [[DOTSPLATINSERT]], poison, zeroinitializer +// CHECK-CXX-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltt.nxv4f32( [[ZDA]], [[ZN]], [[DOTSPLAT]]) +// CHECK-CXX-NEXT: ret [[TMP1]] +// +svfloat32_t test_svmlalltt_n_f32_mf8(svfloat32_t zda, svmfloat8_t zn, mfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalltt,_n_f32_mf8,_fpm)(zda, zn, zm, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlallbb_lane_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbb.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z27test_svmlallbb_lane_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbb.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svmlallbb_lane_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlallbb_lane,_f32_mf8,_fpm)(zda, zn, zm, 7, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlallbt_lane_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbt.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z27test_svmlallbt_lane_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlallbt.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svmlallbt_lane_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlallbt_lane,_f32_mf8,_fpm)(zda, zn, zm, 7, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalltb_lane_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltb.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z27test_svmlalltb_lane_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltb.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svmlalltb_lane_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalltb_lane,_f32_mf8,_fpm)(zda, zn, zm, 7, fpm); +} + +// CHECK-LABEL: define dso_local @test_svmlalltt_lane_f32_mf8( +// CHECK-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltt.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-NEXT: ret [[TMP0]] +// +// CHECK-CXX-LABEL: define dso_local @_Z27test_svmlalltt_lane_f32_mf8u13__SVFloat32_tu13__SVMfloat8_tS0_m( +// CHECK-CXX-SAME: [[ZDA:%.*]], [[ZN:%.*]], [[ZM:%.*]], i64 noundef [[FPM:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPM]]) +// CHECK-CXX-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.fp8.fmlalltt.lane.nxv4f32( [[ZDA]], [[ZN]], [[ZM]], i32 7) +// CHECK-CXX-NEXT: ret [[TMP0]] +// +svfloat32_t test_svmlalltt_lane_f32_mf8(svfloat32_t zda, svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) STREAMING { + return SVE_ACLE_FUNC(svmlalltt_lane,_f32_mf8,_fpm)(zda, zn, zm, 7, fpm); +} diff --git a/clang/test/CodeGen/AArch64/mixed-target-attributes.c b/clang/test/CodeGen/AArch64/mixed-target-attributes.c index bb6fb7eb8862a..1ccb0c6177c8c 100644 --- a/clang/test/CodeGen/AArch64/mixed-target-attributes.c +++ b/clang/test/CodeGen/AArch64/mixed-target-attributes.c @@ -66,24 +66,24 @@ __attribute__((target_version("jscvt"))) int default_def_with_version_decls(void // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1048576 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048576 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1048832 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048832 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @explicit_default._Mjscvt // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 64 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 64 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 832 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 832 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: // CHECK-NEXT: ret ptr @explicit_default._Mrdm // CHECK: resolver_else2: // CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 16 -// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 16 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 784 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 784 // CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] // CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] // CHECK: resolver_return3: @@ -140,24 +140,24 @@ __attribute__((target_version("jscvt"))) int default_def_with_version_decls(void // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1048576 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048576 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1048832 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048832 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @implicit_default._Mjscvt // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 64 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 64 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 832 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 832 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: // CHECK-NEXT: ret ptr @implicit_default._Mrdm // CHECK: resolver_else2: // CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 16 -// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 16 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 784 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 784 // CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] // CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] // CHECK: resolver_return3: @@ -207,16 +207,16 @@ __attribute__((target_version("jscvt"))) int default_def_with_version_decls(void // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1048576 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048576 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1048832 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048832 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @default_def_with_version_decls._Mjscvt // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 784 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 784 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: diff --git a/clang/test/CodeGen/AArch64/sme2-intrinsics/acle_sme2_fp8_fdot.c b/clang/test/CodeGen/AArch64/sme2-intrinsics/acle_sme2_fp8_fdot.c new file mode 100644 index 0000000000000..a151d162e0108 --- /dev/null +++ b/clang/test/CodeGen/AArch64/sme2-intrinsics/acle_sme2_fp8_fdot.c @@ -0,0 +1,256 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// REQUIRES: aarch64-registered-target + +// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -passes mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -passes mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -target-feature -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +#include + +#ifdef SVE_OVERLOADED_FORMS +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED,A5) A1##A3##A5 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4,A5) A1##A2##A3##A4##A5 +#endif + +// CHECK-LABEL: define dso_local void @test_svdot_lane_za32_f8_vg1x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.lane.za32.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 3) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z29test_svdot_lane_za32_f8_vg1x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.lane.za32.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 3) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_lane_za32_f8_vg1x2(uint32_t slice, svmfloat8x2_t zn, + svmfloat8_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot_lane_za32,_mf8,_vg1x2_fpm,,)(slice, zn, zm, 3, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_lane_za32_f8_vg1x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.lane.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]], i32 3) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z29test_svdot_lane_za32_f8_vg1x4j13svmfloat8x4_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.lane.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]], i32 3) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_lane_za32_f8_vg1x4(uint32_t slice, svmfloat8x4_t zn, + svmfloat8_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot_lane_za32,_mf8,_vg1x4_fpm,,)(slice, zn, zm, 3, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_lane_za16_f8_vg1x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.lane.za16.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 3) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z29test_svdot_lane_za16_f8_vg1x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.lane.za16.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 3) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_lane_za16_f8_vg1x2(uint32_t slice, svmfloat8x2_t zn, + svmfloat8_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot_lane_za16,_mf8,_vg1x2_fpm,,)(slice, zn, zm, 3, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_lane_za16_f8_vg1x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.lane.za16.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]], i32 3) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z29test_svdot_lane_za16_f8_vg1x4j13svmfloat8x4_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.lane.za16.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]], i32 3) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_lane_za16_f8_vg1x4(uint32_t slice, svmfloat8x4_t zn, + svmfloat8_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot_lane_za16,_mf8,_vg1x4_fpm,,)(slice, zn, zm, 3, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_single_za32_f8_vg1x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.single.za32.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z31test_svdot_single_za32_f8_vg1x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.single.za32.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_single_za32_f8_vg1x2(uint32_t slice, svmfloat8x2_t zn, + svmfloat8_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot,_single,_za32,_mf8,_vg1x2_fpm)(slice, zn, zm, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_single_za32_f8_vg1x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.single.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z31test_svdot_single_za32_f8_vg1x4j13svmfloat8x4_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.single.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_single_za32_f8_vg1x4(uint32_t slice, svmfloat8x4_t zn, + svmfloat8_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot,_single,_za32,_mf8,_vg1x4_fpm)(slice, zn, zm, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_multi_za32_f8_vg1x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.multi.za32.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM_COERCE0]], [[ZM_COERCE1]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z30test_svdot_multi_za32_f8_vg1x2j13svmfloat8x2_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.multi.za32.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM_COERCE0]], [[ZM_COERCE1]]) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_multi_za32_f8_vg1x2(uint32_t slice, svmfloat8x2_t zn, + svmfloat8x2_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot,,_za32,_mf8,_vg1x2_fpm) (slice, zn, zm, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_multi_za32_f8_vg1x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], [[ZM_COERCE2:%.*]], [[ZM_COERCE3:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.multi.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM_COERCE0]], [[ZM_COERCE1]], [[ZM_COERCE2]], [[ZM_COERCE3]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z30test_svdot_multi_za32_f8_vg1x4j13svmfloat8x4_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], [[ZM_COERCE2:%.*]], [[ZM_COERCE3:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.multi.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM_COERCE0]], [[ZM_COERCE1]], [[ZM_COERCE2]], [[ZM_COERCE3]]) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_multi_za32_f8_vg1x4(uint32_t slice, svmfloat8x4_t zn, + svmfloat8x4_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot,,_za32,_mf8,_vg1x4_fpm)(slice, zn, zm, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_single_za16_f8_vg1x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.single.za16.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z31test_svdot_single_za16_f8_vg1x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.single.za16.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_single_za16_f8_vg1x2(uint32_t slice, svmfloat8x2_t zn, + svmfloat8_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot,_single,_za16,_mf8,_vg1x2_fpm)(slice, zn, zm, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_single_za16_f8_vg1x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.single.za16.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z31test_svdot_single_za16_f8_vg1x4j13svmfloat8x4_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.single.za16.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM]]) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_single_za16_f8_vg1x4(uint32_t slice, svmfloat8x4_t zn, + svmfloat8_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot,_single,_za16,_mf8,_vg1x4_fpm)(slice, zn, zm, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_multi_za16_f8_vg1x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.multi.za16.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM_COERCE0]], [[ZM_COERCE1]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z30test_svdot_multi_za16_f8_vg1x2j13svmfloat8x2_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.multi.za16.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM_COERCE0]], [[ZM_COERCE1]]) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_multi_za16_f8_vg1x2(uint32_t slice, svmfloat8x2_t zn, + svmfloat8x2_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot,,_za16,_mf8,_vg1x2_fpm) (slice, zn, zm, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svdot_multi_za16_f8_vg1x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], [[ZM_COERCE2:%.*]], [[ZM_COERCE3:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.multi.za16.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM_COERCE0]], [[ZM_COERCE1]], [[ZM_COERCE2]], [[ZM_COERCE3]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z30test_svdot_multi_za16_f8_vg1x4j13svmfloat8x4_tS_m( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZN_COERCE2:%.*]], [[ZN_COERCE3:%.*]], [[ZM_COERCE0:%.*]], [[ZM_COERCE1:%.*]], [[ZM_COERCE2:%.*]], [[ZM_COERCE3:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fdot.multi.za16.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZN_COERCE2]], [[ZN_COERCE3]], [[ZM_COERCE0]], [[ZM_COERCE1]], [[ZM_COERCE2]], [[ZM_COERCE3]]) +// CPP-CHECK-NEXT: ret void +// +void test_svdot_multi_za16_f8_vg1x4(uint32_t slice, svmfloat8x4_t zn, + svmfloat8x4_t zm, fpm_t fpmr) + __arm_streaming __arm_inout("za") { + SVE_ACLE_FUNC(svdot,,_za16,_mf8,_vg1x4_fpm)(slice, zn, zm, fpmr); +} diff --git a/clang/test/CodeGen/AArch64/sme2-intrinsics/acle_sme2_fp8_fvdot.c b/clang/test/CodeGen/AArch64/sme2-intrinsics/acle_sme2_fp8_fvdot.c new file mode 100644 index 0000000000000..fc95cf541172a --- /dev/null +++ b/clang/test/CodeGen/AArch64/sme2-intrinsics/acle_sme2_fp8_fvdot.c @@ -0,0 +1,80 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4 + +// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -passes mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -passes mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -passes mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme-f8f16 -target-feature +sme-f8f32 -target-feature -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +// REQUIRES: aarch64-registered-target + +#include + +#ifdef SVE_OVERLOADED_FORMS +#define SVE_ACLE_FUNC(A1, A2_UNUSED, A3) A1##A3 +#else +#define SVE_ACLE_FUNC(A1, A2, A3) A1##A2##A3 +#endif + +// CHECK-LABEL: define dso_local void @test_svvdot_lane_za16_mf8_vg1x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fvdot.lane.za16.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 7) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z31test_svvdot_lane_za16_mf8_vg1x2j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fvdot.lane.za16.vg1x2(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 7) +// CPP-CHECK-NEXT: ret void +// +void test_svvdot_lane_za16_mf8_vg1x2(uint32_t slice, svmfloat8x2_t zn, + svmfloat8_t zm, + fpm_t fpmr) __arm_streaming + __arm_inout("za") { + SVE_ACLE_FUNC(svvdot_lane_za16, _mf8, _vg1x2_fpm)(slice, zn, zm, 7, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svvdotb_lane_za32_mf8_vg1x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fvdotb.lane.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 3) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z32test_svvdotb_lane_za32_mf8_vg1x4j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fvdotb.lane.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 3) +// CPP-CHECK-NEXT: ret void +// +void test_svvdotb_lane_za32_mf8_vg1x4(uint32_t slice, svmfloat8x2_t zn, + svmfloat8_t zm, + fpm_t fpmr) __arm_streaming + __arm_inout("za") { + SVE_ACLE_FUNC(svvdotb_lane_za32, _mf8, _vg1x4_fpm)(slice, zn, zm, 3, fpmr); +} + +// CHECK-LABEL: define dso_local void @test_svvdott_lane_za32_mf8_vg1x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fvdott.lane.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 3) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z32test_svvdott_lane_za32_mf8_vg1x4j13svmfloat8x2_tu13__SVMfloat8_tm( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]], [[ZN_COERCE0:%.*]], [[ZN_COERCE1:%.*]], [[ZM:%.*]], i64 noundef [[FPMR:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.fp8.fvdott.lane.za32.vg1x4(i32 [[SLICE]], [[ZN_COERCE0]], [[ZN_COERCE1]], [[ZM]], i32 3) +// CPP-CHECK-NEXT: ret void +// +void test_svvdott_lane_za32_mf8_vg1x4(uint32_t slice, svmfloat8x2_t zn, + svmfloat8_t zm, + fpm_t fpmr) __arm_streaming + __arm_inout("za") { + SVE_ACLE_FUNC(svvdott_lane_za32, _mf8, _vg1x4_fpm)(slice, zn, zm, 3, fpmr); +} diff --git a/clang/test/CodeGen/AArch64/sve-acle-__ARM_FEATURE_SVE_VECTOR_OPERATORS.c b/clang/test/CodeGen/AArch64/sve-acle-__ARM_FEATURE_SVE_VECTOR_OPERATORS.c index 54e90223a31de..28d69d52c9ae7 100644 --- a/clang/test/CodeGen/AArch64/sve-acle-__ARM_FEATURE_SVE_VECTOR_OPERATORS.c +++ b/clang/test/CodeGen/AArch64/sve-acle-__ARM_FEATURE_SVE_VECTOR_OPERATORS.c @@ -53,7 +53,7 @@ typedef int8_t vec_int8 __attribute__((vector_size(N / 8))); // CHECK128-LABEL: define{{.*}} <16 x i8> @f2(<16 x i8> noundef %x) // CHECK128-NEXT: entry: // CHECK128-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.ptrue.nxv16i1(i32 31) -// CHECK128-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv16i8.v16i8( undef, <16 x i8> [[X:%.*]], i64 0) +// CHECK128-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv16i8.v16i8( poison, <16 x i8> [[X:%.*]], i64 0) // CHECK128-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.asrd.nxv16i8( [[TMP0]], [[CASTSCALABLESVE]], i32 1) // CHECK128-NEXT: [[CASTFIXEDSVE:%.*]] = tail call <16 x i8> @llvm.vector.extract.v16i8.nxv16i8( [[TMP1]], i64 0) // CHECK128-NEXT: ret <16 x i8> [[CASTFIXEDSVE]] @@ -63,7 +63,7 @@ typedef int8_t vec_int8 __attribute__((vector_size(N / 8))); // CHECK-NEXT: entry: // CHECK-NEXT: [[X:%.*]] = load <[[#div(VBITS,8)]] x i8>, ptr [[TMP0:%.*]], align 16, [[TBAA6:!tbaa !.*]] // CHECK-NEXT: [[TMP1:%.*]] = tail call @llvm.aarch64.sve.ptrue.nxv16i1(i32 31) -// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv16i8.v[[#div(VBITS,8)]]i8( undef, <[[#div(VBITS,8)]] x i8> [[X]], i64 0) +// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv16i8.v[[#div(VBITS,8)]]i8( poison, <[[#div(VBITS,8)]] x i8> [[X]], i64 0) // CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.aarch64.sve.asrd.nxv16i8( [[TMP1]], [[CASTSCALABLESVE]], i32 1) // CHECK-NEXT: [[CASTFIXEDSVE:%.*]] = tail call <[[#div(VBITS,8)]] x i8> @llvm.vector.extract.v[[#div(VBITS,8)]]i8.nxv16i8( [[TMP2]], i64 0) // CHECK-NEXT: store <[[#div(VBITS,8)]] x i8> [[CASTFIXEDSVE]], ptr [[AGG_RESULT:%.*]], align 16, [[TBAA6]] diff --git a/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-bitcast.c b/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-bitcast.c index e684513bb1442..ecde52eb3d762 100644 --- a/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-bitcast.c +++ b/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-bitcast.c @@ -71,21 +71,21 @@ DEFINE_STRUCT(bool64) // CHECK-64-NEXT: entry: // CHECK-64-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 8 // CHECK-64-NEXT: [[TMP0:%.*]] = load <1 x i64>, ptr [[Y]], align 8, !tbaa [[TBAA6:![0-9]+]] -// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v1i64( undef, <1 x i64> [[TMP0]], i64 0) +// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v1i64( poison, <1 x i64> [[TMP0]], i64 0) // CHECK-64-NEXT: ret [[CAST_SCALABLE]] // // CHECK-128-LABEL: @read_int64m1( // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 16 // CHECK-128-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[Y]], align 8, !tbaa [[TBAA6:![0-9]+]] -// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v2i64( undef, <2 x i64> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v2i64( poison, <2 x i64> [[TMP0]], i64 0) // CHECK-128-NEXT: ret [[CAST_SCALABLE]] // // CHECK-256-LABEL: @read_int64m1( // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 32 // CHECK-256-NEXT: [[TMP0:%.*]] = load <4 x i64>, ptr [[Y]], align 8, !tbaa [[TBAA6:![0-9]+]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v4i64( undef, <4 x i64> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v4i64( poison, <4 x i64> [[TMP0]], i64 0) // CHECK-256-NEXT: ret [[CAST_SCALABLE]] // vint64m1_t read_int64m1(struct struct_int64m1 *s) { @@ -125,21 +125,21 @@ void write_int64m1(struct struct_int64m1 *s, vint64m1_t x) { // CHECK-64-NEXT: entry: // CHECK-64-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 8 // CHECK-64-NEXT: [[TMP0:%.*]] = load <1 x double>, ptr [[Y]], align 8, !tbaa [[TBAA6]] -// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1f64.v1f64( undef, <1 x double> [[TMP0]], i64 0) +// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1f64.v1f64( poison, <1 x double> [[TMP0]], i64 0) // CHECK-64-NEXT: ret [[CAST_SCALABLE]] // // CHECK-128-LABEL: @read_float64m1( // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 16 // CHECK-128-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[Y]], align 8, !tbaa [[TBAA6]] -// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1f64.v2f64( undef, <2 x double> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1f64.v2f64( poison, <2 x double> [[TMP0]], i64 0) // CHECK-128-NEXT: ret [[CAST_SCALABLE]] // // CHECK-256-LABEL: @read_float64m1( // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 32 // CHECK-256-NEXT: [[TMP0:%.*]] = load <4 x double>, ptr [[Y]], align 8, !tbaa [[TBAA6]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1f64.v4f64( undef, <4 x double> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1f64.v4f64( poison, <4 x double> [[TMP0]], i64 0) // CHECK-256-NEXT: ret [[CAST_SCALABLE]] // vfloat64m1_t read_float64m1(struct struct_float64m1 *s) { @@ -179,7 +179,7 @@ void write_float64m1(struct struct_float64m1 *s, vfloat64m1_t x) { // CHECK-64-NEXT: entry: // CHECK-64-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 8 // CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA6]] -// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v8i8( undef, <8 x i8> [[TMP0]], i64 0) +// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v8i8( poison, <8 x i8> [[TMP0]], i64 0) // CHECK-64-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-64-NEXT: ret [[TMP1]] // @@ -187,7 +187,7 @@ void write_float64m1(struct struct_float64m1 *s, vfloat64m1_t x) { // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 16 // CHECK-128-NEXT: [[TMP0:%.*]] = load <16 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA6]] -// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v16i8( undef, <16 x i8> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v16i8( poison, <16 x i8> [[TMP0]], i64 0) // CHECK-128-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-128-NEXT: ret [[TMP1]] // @@ -195,7 +195,7 @@ void write_float64m1(struct struct_float64m1 *s, vfloat64m1_t x) { // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 32 // CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr [[Y]], align 8, !tbaa [[TBAA6]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v32i8( undef, <32 x i8> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v32i8( poison, <32 x i8> [[TMP0]], i64 0) // CHECK-256-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-256-NEXT: ret [[TMP1]] // diff --git a/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-cast.c b/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-cast.c index 3fa104b78f212..7992951346d54 100644 --- a/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-cast.c +++ b/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-cast.c @@ -120,7 +120,7 @@ vbool32_t to_vbool32_t(fixed_bool32_t type) { // CHECK-LABEL: @to_vint32m1_t__from_gnu_int32m1_t( // CHECK-NEXT: entry: // CHECK-NEXT: [[TYPE:%.*]] = load <8 x i32>, ptr [[TMP0:%.*]], align 32, !tbaa [[TBAA8]] -// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i32.v8i32( undef, <8 x i32> [[TYPE]], i64 0) +// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i32.v8i32( poison, <8 x i32> [[TYPE]], i64 0) // CHECK-NEXT: ret [[CAST_SCALABLE]] // vint32m1_t to_vint32m1_t__from_gnu_int32m1_t(gnu_int32m1_t type) { diff --git a/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-codegen.c b/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-codegen.c index bfdb39b6ac82d..d81855aea2e5e 100644 --- a/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-codegen.c +++ b/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-codegen.c @@ -57,14 +57,14 @@ fixed_bool32_t global_bool32; // CHECK-NEXT: store [[VEC:%.*]], ptr [[VEC_ADDR]], align 1 // CHECK-NEXT: [[TMP0:%.*]] = load , ptr [[M_ADDR]], align 1 // CHECK-NEXT: [[TMP1:%.*]] = load <32 x i8>, ptr @global_bool1, align 8 -// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv8i8.v32i8( undef, <32 x i8> [[TMP1]], i64 0) +// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv8i8.v32i8( poison, <32 x i8> [[TMP1]], i64 0) // CHECK-NEXT: [[TMP2:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-NEXT: [[TMP3:%.*]] = call @llvm.riscv.vmand.nxv64i1.i64( [[TMP0]], [[TMP2]], i64 256) // CHECK-NEXT: store [[TMP3]], ptr [[MASK]], align 1 // CHECK-NEXT: [[TMP4:%.*]] = load , ptr [[MASK]], align 1 // CHECK-NEXT: [[TMP5:%.*]] = load , ptr [[VEC_ADDR]], align 1 // CHECK-NEXT: [[TMP6:%.*]] = load <256 x i8>, ptr @global_vec_int8m8, align 8 -// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call @llvm.vector.insert.nxv64i8.v256i8( undef, <256 x i8> [[TMP6]], i64 0) +// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call @llvm.vector.insert.nxv64i8.v256i8( poison, <256 x i8> [[TMP6]], i64 0) // CHECK-NEXT: [[TMP7:%.*]] = call @llvm.riscv.vadd.mask.nxv64i8.nxv64i8.i64( poison, [[TMP5]], [[CAST_SCALABLE1]], [[TMP4]], i64 256, i64 3) // CHECK-NEXT: [[CAST_FIXED:%.*]] = call <256 x i8> @llvm.vector.extract.v256i8.nxv64i8( [[TMP7]], i64 0) // CHECK-NEXT: store <256 x i8> [[CAST_FIXED]], ptr [[RETVAL]], align 8 @@ -87,14 +87,14 @@ fixed_int8m8_t test_bool1(vbool1_t m, vint8m8_t vec) { // CHECK-NEXT: store [[VEC:%.*]], ptr [[VEC_ADDR]], align 2 // CHECK-NEXT: [[TMP0:%.*]] = load , ptr [[M_ADDR]], align 1 // CHECK-NEXT: [[TMP1:%.*]] = load <8 x i8>, ptr @global_bool4, align 8 -// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( undef, <8 x i8> [[TMP1]], i64 0) +// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( poison, <8 x i8> [[TMP1]], i64 0) // CHECK-NEXT: [[TMP2:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-NEXT: [[TMP3:%.*]] = call @llvm.riscv.vmand.nxv16i1.i64( [[TMP0]], [[TMP2]], i64 64) // CHECK-NEXT: store [[TMP3]], ptr [[MASK]], align 1 // CHECK-NEXT: [[TMP4:%.*]] = load , ptr [[MASK]], align 1 // CHECK-NEXT: [[TMP5:%.*]] = load , ptr [[VEC_ADDR]], align 2 // CHECK-NEXT: [[TMP6:%.*]] = load <64 x i16>, ptr @global_vec_int16m4, align 8 -// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call @llvm.vector.insert.nxv16i16.v64i16( undef, <64 x i16> [[TMP6]], i64 0) +// CHECK-NEXT: [[CAST_SCALABLE1:%.*]] = call @llvm.vector.insert.nxv16i16.v64i16( poison, <64 x i16> [[TMP6]], i64 0) // CHECK-NEXT: [[TMP7:%.*]] = call @llvm.riscv.vadd.mask.nxv16i16.nxv16i16.i64( poison, [[TMP5]], [[CAST_SCALABLE1]], [[TMP4]], i64 64, i64 3) // CHECK-NEXT: [[CAST_FIXED:%.*]] = call <64 x i16> @llvm.vector.extract.v64i16.nxv16i16( [[TMP7]], i64 0) // CHECK-NEXT: store <64 x i16> [[CAST_FIXED]], ptr [[RETVAL]], align 8 @@ -125,7 +125,7 @@ fixed_int16m4_t test_bool4(vbool4_t m, vint16m4_t vec) { // CHECK-NEXT: [[TMP4:%.*]] = load , ptr [[MASK]], align 1 // CHECK-NEXT: [[TMP5:%.*]] = load , ptr [[VEC_ADDR]], align 4 // CHECK-NEXT: [[TMP6:%.*]] = load <8 x i32>, ptr @global_vec, align 8 -// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv2i32.v8i32( undef, <8 x i32> [[TMP6]], i64 0) +// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv2i32.v8i32( poison, <8 x i32> [[TMP6]], i64 0) // CHECK-NEXT: [[TMP7:%.*]] = call @llvm.riscv.vadd.mask.nxv2i32.nxv2i32.i64( poison, [[TMP5]], [[CAST_SCALABLE]], [[TMP4]], i64 8, i64 3) // CHECK-NEXT: [[CAST_FIXED:%.*]] = call <8 x i32> @llvm.vector.extract.v8i32.nxv2i32( [[TMP7]], i64 0) // CHECK-NEXT: store <8 x i32> [[CAST_FIXED]], ptr [[RETVAL]], align 8 @@ -247,7 +247,7 @@ fixed_bool32_t address_of_array_idx_bool32() { // CHECK-NEXT: [[VEC_ADDR:%.*]] = alloca , align 4 // CHECK-NEXT: store [[VEC:%.*]], ptr [[VEC_ADDR]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = load <8 x i32>, ptr @global_vec, align 8 -// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv2i32.v8i32( undef, <8 x i32> [[TMP0]], i64 0) +// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv2i32.v8i32( poison, <8 x i32> [[TMP0]], i64 0) // CHECK-NEXT: [[TMP1:%.*]] = load , ptr [[VEC_ADDR]], align 4 // CHECK-NEXT: [[TMP2:%.*]] = call @llvm.riscv.vadd.nxv2i32.nxv2i32.i64( poison, [[CAST_SCALABLE]], [[TMP1]], i64 8) // CHECK-NEXT: [[CAST_FIXED:%.*]] = call <8 x i32> @llvm.vector.extract.v8i32.nxv2i32( [[TMP2]], i64 0) @@ -303,7 +303,7 @@ fixed_int32m2_t array_arg_m2(fixed_int32m2_t arr[]) { // CHECK-NEXT: [[VEC_ADDR:%.*]] = alloca , align 4 // CHECK-NEXT: store [[VEC:%.*]], ptr [[VEC_ADDR]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = load <16 x i32>, ptr @global_vec_m2, align 8 -// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv4i32.v16i32( undef, <16 x i32> [[TMP0]], i64 0) +// CHECK-NEXT: [[CAST_SCALABLE:%.*]] = call @llvm.vector.insert.nxv4i32.v16i32( poison, <16 x i32> [[TMP0]], i64 0) // CHECK-NEXT: [[TMP1:%.*]] = load , ptr [[VEC_ADDR]], align 4 // CHECK-NEXT: [[TMP2:%.*]] = call @llvm.riscv.vadd.nxv4i32.nxv4i32.i64( poison, [[CAST_SCALABLE]], [[TMP1]], i64 16) // CHECK-NEXT: [[CAST_FIXED:%.*]] = call <16 x i32> @llvm.vector.extract.v16i32.nxv4i32( [[TMP2]], i64 0) diff --git a/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-globals.c b/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-globals.c index 663e436b4dab6..4bd6311e05b03 100644 --- a/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-globals.c +++ b/clang/test/CodeGen/RISCV/attr-rvv-vector-bits-globals.c @@ -105,13 +105,13 @@ void write_global_bool32(vbool32_t v) { global_bool32 = v; } // CHECK-64-LABEL: @read_global_i64( // CHECK-64-NEXT: entry: // CHECK-64-NEXT: [[TMP0:%.*]] = load <1 x i64>, ptr @global_i64, align 8, !tbaa [[TBAA6]] -// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v1i64( undef, <1 x i64> [[TMP0]], i64 0) +// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v1i64( poison, <1 x i64> [[TMP0]], i64 0) // CHECK-64-NEXT: ret [[CAST_SCALABLE]] // // CHECK-256-LABEL: @read_global_i64( // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[TMP0:%.*]] = load <4 x i64>, ptr @global_i64, align 8, !tbaa [[TBAA6]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v4i64( undef, <4 x i64> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv1i64.v4i64( poison, <4 x i64> [[TMP0]], i64 0) // CHECK-256-NEXT: ret [[CAST_SCALABLE]] // vint64m1_t read_global_i64() { return global_i64; } @@ -119,14 +119,14 @@ vint64m1_t read_global_i64() { return global_i64; } // CHECK-64-LABEL: @read_global_bool1( // CHECK-64-NEXT: entry: // CHECK-64-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr @global_bool1, align 8, !tbaa [[TBAA6]] -// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v8i8( undef, <8 x i8> [[TMP0]], i64 0) +// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v8i8( poison, <8 x i8> [[TMP0]], i64 0) // CHECK-64-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-64-NEXT: ret [[TMP1]] // // CHECK-256-LABEL: @read_global_bool1( // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[TMP0:%.*]] = load <32 x i8>, ptr @global_bool1, align 8, !tbaa [[TBAA6]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v32i8( undef, <32 x i8> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8i8.v32i8( poison, <32 x i8> [[TMP0]], i64 0) // CHECK-256-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-256-NEXT: ret [[TMP1]] // @@ -135,14 +135,14 @@ vbool1_t read_global_bool1() { return global_bool1; } // CHECK-64-LABEL: @read_global_bool4( // CHECK-64-NEXT: entry: // CHECK-64-NEXT: [[TMP0:%.*]] = load <2 x i8>, ptr @global_bool4, align 2, !tbaa [[TBAA6]] -// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v2i8( undef, <2 x i8> [[TMP0]], i64 0) +// CHECK-64-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v2i8( poison, <2 x i8> [[TMP0]], i64 0) // CHECK-64-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-64-NEXT: ret [[TMP1]] // // CHECK-256-LABEL: @read_global_bool4( // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr @global_bool4, align 8, !tbaa [[TBAA6]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v8i8( undef, <8 x i8> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v8i8( poison, <8 x i8> [[TMP0]], i64 0) // CHECK-256-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-256-NEXT: ret [[TMP1]] // diff --git a/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c b/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c new file mode 100644 index 0000000000000..898891fa182ea --- /dev/null +++ b/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c @@ -0,0 +1,26 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple s390x-linux -emit-llvm -o - %s | FileCheck %s + +void *buf[20]; + +// CHECK-LABEL: define dso_local void @foo( +// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.eh.sjlj.setjmp(ptr @buf) +// CHECK-NEXT: ret void +// +void foo() +{ + __builtin_setjmp (buf); +} + +// CHECK-LABEL: define dso_local void @foo1( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: call void @llvm.eh.sjlj.longjmp(ptr @buf) +// CHECK-NEXT: unreachable +// +void foo1() +{ + __builtin_longjmp (buf, 1); +} diff --git a/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-malloc.c b/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-malloc.c index 1b05e8aa5052a..c0ca3dab51258 100644 --- a/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-malloc.c +++ b/clang/test/CodeGen/SystemZ/zos-mixed-ptr-sizes-malloc.c @@ -4,7 +4,7 @@ void *__malloc31(size_t); int test_1() { // X64-LABEL: define {{.*}} i32 @test_1() - // X64: ret i32 135 + // X64: ret i32 %add20 int *__ptr32 a; int *b; int i; diff --git a/clang/test/CodeGen/attr-arm-sve-vector-bits-bitcast.c b/clang/test/CodeGen/attr-arm-sve-vector-bits-bitcast.c index a7c87e32a58eb..c5a410193bfb7 100644 --- a/clang/test/CodeGen/attr-arm-sve-vector-bits-bitcast.c +++ b/clang/test/CodeGen/attr-arm-sve-vector-bits-bitcast.c @@ -32,21 +32,21 @@ DEFINE_STRUCT(bool) // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 16 // CHECK-128-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[Y]], align 16, !tbaa [[TBAA2:![0-9]+]] -// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v2i64( undef, <2 x i64> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v2i64( poison, <2 x i64> [[TMP0]], i64 0) // CHECK-128-NEXT: ret [[CAST_SCALABLE]] // // CHECK-256-LABEL: @read_int64( // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 32 // CHECK-256-NEXT: [[TMP0:%.*]] = load <4 x i64>, ptr [[Y]], align 16, !tbaa [[TBAA2:![0-9]+]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v4i64( undef, <4 x i64> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v4i64( poison, <4 x i64> [[TMP0]], i64 0) // CHECK-256-NEXT: ret [[CAST_SCALABLE]] // // CHECK-512-LABEL: @read_int64( // CHECK-512-NEXT: entry: // CHECK-512-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 64 // CHECK-512-NEXT: [[TMP0:%.*]] = load <8 x i64>, ptr [[Y]], align 16, !tbaa [[TBAA2:![0-9]+]] -// CHECK-512-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v8i64( undef, <8 x i64> [[TMP0]], i64 0) +// CHECK-512-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v8i64( poison, <8 x i64> [[TMP0]], i64 0) // CHECK-512-NEXT: ret [[CAST_SCALABLE]] // svint64_t read_int64(struct struct_int64 *s) { @@ -86,21 +86,21 @@ void write_int64(struct struct_int64 *s, svint64_t x) { // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 16 // CHECK-128-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[Y]], align 16, !tbaa [[TBAA2]] -// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2f64.v2f64( undef, <2 x double> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2f64.v2f64( poison, <2 x double> [[TMP0]], i64 0) // CHECK-128-NEXT: ret [[CAST_SCALABLE]] // // CHECK-256-LABEL: @read_float64( // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 32 // CHECK-256-NEXT: [[TMP0:%.*]] = load <4 x double>, ptr [[Y]], align 16, !tbaa [[TBAA2]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2f64.v4f64( undef, <4 x double> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2f64.v4f64( poison, <4 x double> [[TMP0]], i64 0) // CHECK-256-NEXT: ret [[CAST_SCALABLE]] // // CHECK-512-LABEL: @read_float64( // CHECK-512-NEXT: entry: // CHECK-512-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 64 // CHECK-512-NEXT: [[TMP0:%.*]] = load <8 x double>, ptr [[Y]], align 16, !tbaa [[TBAA2]] -// CHECK-512-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2f64.v8f64( undef, <8 x double> [[TMP0]], i64 0) +// CHECK-512-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2f64.v8f64( poison, <8 x double> [[TMP0]], i64 0) // CHECK-512-NEXT: ret [[CAST_SCALABLE]] // svfloat64_t read_float64(struct struct_float64 *s) { @@ -140,21 +140,21 @@ void write_float64(struct struct_float64 *s, svfloat64_t x) { // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 16 // CHECK-128-NEXT: [[TMP0:%.*]] = load <8 x bfloat>, ptr [[Y]], align 16, !tbaa [[TBAA2]] -// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v8bf16( undef, <8 x bfloat> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v8bf16( poison, <8 x bfloat> [[TMP0]], i64 0) // CHECK-128-NEXT: ret [[CAST_SCALABLE]] // // CHECK-256-LABEL: @read_bfloat16( // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 32 // CHECK-256-NEXT: [[TMP0:%.*]] = load <16 x bfloat>, ptr [[Y]], align 16, !tbaa [[TBAA2]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v16bf16( undef, <16 x bfloat> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v16bf16( poison, <16 x bfloat> [[TMP0]], i64 0) // CHECK-256-NEXT: ret [[CAST_SCALABLE]] // // CHECK-512-LABEL: @read_bfloat16( // CHECK-512-NEXT: entry: // CHECK-512-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 64 // CHECK-512-NEXT: [[TMP0:%.*]] = load <32 x bfloat>, ptr [[Y]], align 16, !tbaa [[TBAA2]] -// CHECK-512-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v32bf16( undef, <32 x bfloat> [[TMP0]], i64 0) +// CHECK-512-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v32bf16( poison, <32 x bfloat> [[TMP0]], i64 0) // CHECK-512-NEXT: ret [[CAST_SCALABLE]] // svbfloat16_t read_bfloat16(struct struct_bfloat16 *s) { @@ -194,7 +194,7 @@ void write_bfloat16(struct struct_bfloat16 *s, svbfloat16_t x) { // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 2 // CHECK-128-NEXT: [[TMP0:%.*]] = load <2 x i8>, ptr [[Y]], align 2, !tbaa [[TBAA2]] -// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v2i8( undef, <2 x i8> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v2i8( poison, <2 x i8> [[TMP0]], i64 0) // CHECK-128-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-128-NEXT: ret [[TMP1]] // @@ -202,7 +202,7 @@ void write_bfloat16(struct struct_bfloat16 *s, svbfloat16_t x) { // CHECK-256-NEXT: entry: // CHECK-256-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 4 // CHECK-256-NEXT: [[TMP0:%.*]] = load <4 x i8>, ptr [[Y]], align 2, !tbaa [[TBAA2]] -// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v4i8( undef, <4 x i8> [[TMP0]], i64 0) +// CHECK-256-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v4i8( poison, <4 x i8> [[TMP0]], i64 0) // CHECK-256-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-256-NEXT: ret [[TMP1]] // @@ -210,7 +210,7 @@ void write_bfloat16(struct struct_bfloat16 *s, svbfloat16_t x) { // CHECK-512-NEXT: entry: // CHECK-512-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[S:%.*]], i64 8 // CHECK-512-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr [[Y]], align 2, !tbaa [[TBAA2]] -// CHECK-512-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v8i8( undef, <8 x i8> [[TMP0]], i64 0) +// CHECK-512-NEXT: [[CAST_SCALABLE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v8i8( poison, <8 x i8> [[TMP0]], i64 0) // CHECK-512-NEXT: [[TMP1:%.*]] = bitcast [[CAST_SCALABLE]] to // CHECK-512-NEXT: ret [[TMP1]] // diff --git a/clang/test/CodeGen/attr-arm-sve-vector-bits-cast.c b/clang/test/CodeGen/attr-arm-sve-vector-bits-cast.c index cdfe6d5df848b..e1e2220f94d6d 100644 --- a/clang/test/CodeGen/attr-arm-sve-vector-bits-cast.c +++ b/clang/test/CodeGen/attr-arm-sve-vector-bits-cast.c @@ -75,7 +75,7 @@ svint64_t lax_cast(fixed_int32_t type) { // CHECK-LABEL: @to_svint32_t__from_gnu_int32_t( // CHECK-NEXT: entry: // CHECK-NEXT: [[TYPE:%.*]] = load <16 x i32>, ptr [[TMP0:%.*]], align 16, !tbaa [[TBAA6]] -// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv4i32.v16i32( undef, <16 x i32> [[TYPE]], i64 0) +// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv4i32.v16i32( poison, <16 x i32> [[TYPE]], i64 0) // CHECK-NEXT: ret [[CASTSCALABLESVE]] // svint32_t to_svint32_t__from_gnu_int32_t(gnu_int32_t type) { diff --git a/clang/test/CodeGen/attr-arm-sve-vector-bits-codegen.c b/clang/test/CodeGen/attr-arm-sve-vector-bits-codegen.c index c643bcf61455b..06fbb0027d7c1 100644 --- a/clang/test/CodeGen/attr-arm-sve-vector-bits-codegen.c +++ b/clang/test/CodeGen/attr-arm-sve-vector-bits-codegen.c @@ -24,16 +24,16 @@ fixed_int32_t global_vec; // CHECK-NEXT: store [[VEC:%.*]], ptr [[VEC_ADDR]], align 16 // CHECK-NEXT: [[TMP0:%.*]] = load , ptr [[PRED_ADDR]], align 2 // CHECK-NEXT: [[TMP1:%.*]] = load <8 x i8>, ptr @global_pred, align 2 -// CHECK-NEXT: [[CASTFIXEDSVE:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( undef, <8 x i8> [[TMP1]], i64 0) +// CHECK-NEXT: [[CASTFIXEDSVE:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( poison, <8 x i8> [[TMP1]], i64 0) // CHECK-NEXT: [[TMP2:%.*]] = bitcast [[CASTFIXEDSVE]] to // CHECK-NEXT: [[TMP3:%.*]] = load <8 x i8>, ptr @global_pred, align 2 -// CHECK-NEXT: [[CASTFIXEDSVE2:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( undef, <8 x i8> [[TMP3]], i64 0) +// CHECK-NEXT: [[CASTFIXEDSVE2:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( poison, <8 x i8> [[TMP3]], i64 0) // CHECK-NEXT: [[TMP4:%.*]] = bitcast [[CASTFIXEDSVE2]] to // CHECK-NEXT: [[TMP5:%.*]] = call @llvm.aarch64.sve.and.z.nxv16i1( [[TMP0]], [[TMP2]], [[TMP4]]) // CHECK-NEXT: store [[TMP5]], ptr [[PG]], align 2 // CHECK-NEXT: [[TMP6:%.*]] = load , ptr [[PG]], align 2 // CHECK-NEXT: [[TMP7:%.*]] = load <16 x i32>, ptr @global_vec, align 16 -// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = call @llvm.vector.insert.nxv4i32.v16i32( undef, <16 x i32> [[TMP7]], i64 0) +// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = call @llvm.vector.insert.nxv4i32.v16i32( poison, <16 x i32> [[TMP7]], i64 0) // CHECK-NEXT: [[TMP8:%.*]] = load , ptr [[VEC_ADDR]], align 16 // CHECK-NEXT: [[TMP9:%.*]] = call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[TMP6]]) // CHECK-NEXT: [[TMP10:%.*]] = call @llvm.aarch64.sve.add.nxv4i32( [[TMP9]], [[CASTSCALABLESVE]], [[TMP8]]) @@ -121,18 +121,18 @@ fixed_bool_t address_of_array_idx() { // CHECK-NEXT: store <8 x i8> , ptr [[YY]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load , ptr [[PRED_ADDR]], align 2 // CHECK-NEXT: [[TMP1:%.*]] = load <8 x i8>, ptr @global_pred, align 2 -// CHECK-NEXT: [[CASTFIXEDSVE:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( undef, <8 x i8> [[TMP1]], i64 0) +// CHECK-NEXT: [[CASTFIXEDSVE:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( poison, <8 x i8> [[TMP1]], i64 0) // CHECK-NEXT: [[TMP2:%.*]] = bitcast [[CASTFIXEDSVE]] to // CHECK-NEXT: [[TMP3:%.*]] = load <8 x i8>, ptr [[XX]], align 8 // CHECK-NEXT: [[TMP4:%.*]] = load <8 x i8>, ptr [[YY]], align 8 // CHECK-NEXT: [[ADD:%.*]] = add <8 x i8> [[TMP3]], [[TMP4]] -// CHECK-NEXT: [[CASTFIXEDSVE2:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( undef, <8 x i8> [[ADD]], i64 0) +// CHECK-NEXT: [[CASTFIXEDSVE2:%.*]] = call @llvm.vector.insert.nxv2i8.v8i8( poison, <8 x i8> [[ADD]], i64 0) // CHECK-NEXT: [[TMP5:%.*]] = bitcast [[CASTFIXEDSVE2]] to // CHECK-NEXT: [[TMP6:%.*]] = call @llvm.aarch64.sve.and.z.nxv16i1( [[TMP0]], [[TMP2]], [[TMP5]]) // CHECK-NEXT: store [[TMP6]], ptr [[PG]], align 2 // CHECK-NEXT: [[TMP7:%.*]] = load , ptr [[PG]], align 2 // CHECK-NEXT: [[TMP8:%.*]] = load <16 x i32>, ptr @global_vec, align 16 -// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = call @llvm.vector.insert.nxv4i32.v16i32( undef, <16 x i32> [[TMP8]], i64 0) +// CHECK-NEXT: [[CASTSCALABLESVE:%.*]] = call @llvm.vector.insert.nxv4i32.v16i32( poison, <16 x i32> [[TMP8]], i64 0) // CHECK-NEXT: [[TMP9:%.*]] = load , ptr [[VEC_ADDR]], align 16 // CHECK-NEXT: [[TMP10:%.*]] = call @llvm.aarch64.sve.convert.from.svbool.nxv4i1( [[TMP7]]) // CHECK-NEXT: [[TMP11:%.*]] = call @llvm.aarch64.sve.add.nxv4i32( [[TMP10]], [[CASTSCALABLESVE]], [[TMP9]]) diff --git a/clang/test/CodeGen/attr-arm-sve-vector-bits-globals.c b/clang/test/CodeGen/attr-arm-sve-vector-bits-globals.c index 7858a7bf0026e..011518c60f52f 100644 --- a/clang/test/CodeGen/attr-arm-sve-vector-bits-globals.c +++ b/clang/test/CodeGen/attr-arm-sve-vector-bits-globals.c @@ -71,13 +71,13 @@ void write_global_bool(svbool_t v) { global_bool = v; } // CHECK-128-LABEL: @read_global_i64( // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr @global_i64, align 16, !tbaa [[TBAA6]] -// CHECK-128-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v2i64( undef, <2 x i64> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v2i64( poison, <2 x i64> [[TMP0]], i64 0) // CHECK-128-NEXT: ret [[CASTSCALABLESVE]] // // CHECK-512-LABEL: @read_global_i64( // CHECK-512-NEXT: entry: // CHECK-512-NEXT: [[TMP0:%.*]] = load <8 x i64>, ptr @global_i64, align 16, !tbaa [[TBAA6]] -// CHECK-512-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v8i64( undef, <8 x i64> [[TMP0]], i64 0) +// CHECK-512-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv2i64.v8i64( poison, <8 x i64> [[TMP0]], i64 0) // CHECK-512-NEXT: ret [[CASTSCALABLESVE]] // svint64_t read_global_i64() { return global_i64; } @@ -85,13 +85,13 @@ svint64_t read_global_i64() { return global_i64; } // CHECK-128-LABEL: @read_global_bf16( // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[TMP0:%.*]] = load <8 x bfloat>, ptr @global_bf16, align 16, !tbaa [[TBAA6]] -// CHECK-128-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v8bf16( undef, <8 x bfloat> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v8bf16( poison, <8 x bfloat> [[TMP0]], i64 0) // CHECK-128-NEXT: ret [[CASTSCALABLESVE]] // // CHECK-512-LABEL: @read_global_bf16( // CHECK-512-NEXT: entry: // CHECK-512-NEXT: [[TMP0:%.*]] = load <32 x bfloat>, ptr @global_bf16, align 16, !tbaa [[TBAA6]] -// CHECK-512-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v32bf16( undef, <32 x bfloat> [[TMP0]], i64 0) +// CHECK-512-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv8bf16.v32bf16( poison, <32 x bfloat> [[TMP0]], i64 0) // CHECK-512-NEXT: ret [[CASTSCALABLESVE]] // svbfloat16_t read_global_bf16() { return global_bf16; } @@ -99,14 +99,14 @@ svbfloat16_t read_global_bf16() { return global_bf16; } // CHECK-128-LABEL: @read_global_bool( // CHECK-128-NEXT: entry: // CHECK-128-NEXT: [[TMP0:%.*]] = load <2 x i8>, ptr @global_bool, align 2, !tbaa [[TBAA6]] -// CHECK-128-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v2i8( undef, <2 x i8> [[TMP0]], i64 0) +// CHECK-128-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v2i8( poison, <2 x i8> [[TMP0]], i64 0) // CHECK-128-NEXT: [[TMP1:%.*]] = bitcast [[CASTSCALABLESVE]] to // CHECK-128-NEXT: ret [[TMP1]] // // CHECK-512-LABEL: @read_global_bool( // CHECK-512-NEXT: entry: // CHECK-512-NEXT: [[TMP0:%.*]] = load <8 x i8>, ptr @global_bool, align 2, !tbaa [[TBAA6]] -// CHECK-512-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v8i8( undef, <8 x i8> [[TMP0]], i64 0) +// CHECK-512-NEXT: [[CASTSCALABLESVE:%.*]] = tail call @llvm.vector.insert.nxv2i8.v8i8( poison, <8 x i8> [[TMP0]], i64 0) // CHECK-512-NEXT: [[TMP1:%.*]] = bitcast [[CASTSCALABLESVE]] to // CHECK-512-NEXT: ret [[TMP1]] // diff --git a/clang/test/CodeGen/attr-target-clones-aarch64.c b/clang/test/CodeGen/attr-target-clones-aarch64.c index 961279424754d..6b7acbbd4fc59 100644 --- a/clang/test/CodeGen/attr-target-clones-aarch64.c +++ b/clang/test/CodeGen/attr-target-clones-aarch64.c @@ -64,16 +64,16 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 32896 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 32896 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 33664 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 33664 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @ftc._MaesMlse // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 68719476736 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 68719476736 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 69793284352 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 69793284352 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: @@ -100,16 +100,16 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 17592186048512 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 17592186048512 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 17592186049280 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 17592186049280 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @ftc_def._MmemtagMsha2 // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 4096 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 4096 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 4864 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 4864 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: @@ -129,8 +129,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4096 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4096 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4864 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4864 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: @@ -157,8 +157,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1040 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1040 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1808 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1808 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: @@ -310,16 +310,16 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 549757911040 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 549757911040 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 619551195904 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 619551195904 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @ftc_inline2._MfcmaMsve2-bitperm // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 65536 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 65536 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 65792 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 65792 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: @@ -360,8 +360,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 18014673387388928 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 18014673387388928 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 18014743180706560 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 18014743180706560 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: @@ -376,8 +376,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: ret ptr @ftc_inline1._MpredresMrcpc // CHECK: resolver_else2: // CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 513 -// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 513 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 769 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 769 // CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] // CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] // CHECK: resolver_return3: @@ -411,8 +411,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 70369817919488 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 70369817919488 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 70369817985280 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 70369817985280 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: @@ -521,16 +521,16 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-MTE-BTI-NEXT: resolver_entry: // CHECK-MTE-BTI-NEXT: call void @__init_cpu_features_resolver() // CHECK-MTE-BTI-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 32896 -// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 32896 +// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 33664 +// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 33664 // CHECK-MTE-BTI-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK-MTE-BTI: resolver_return: // CHECK-MTE-BTI-NEXT: ret ptr @ftc._MaesMlse // CHECK-MTE-BTI: resolver_else: // CHECK-MTE-BTI-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 68719476736 -// CHECK-MTE-BTI-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 68719476736 +// CHECK-MTE-BTI-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 69793284352 +// CHECK-MTE-BTI-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 69793284352 // CHECK-MTE-BTI-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK-MTE-BTI: resolver_return1: @@ -557,16 +557,16 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-MTE-BTI-NEXT: resolver_entry: // CHECK-MTE-BTI-NEXT: call void @__init_cpu_features_resolver() // CHECK-MTE-BTI-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 17592186048512 -// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 17592186048512 +// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 17592186049280 +// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 17592186049280 // CHECK-MTE-BTI-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK-MTE-BTI: resolver_return: // CHECK-MTE-BTI-NEXT: ret ptr @ftc_def._MmemtagMsha2 // CHECK-MTE-BTI: resolver_else: // CHECK-MTE-BTI-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 4096 -// CHECK-MTE-BTI-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 4096 +// CHECK-MTE-BTI-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 4864 +// CHECK-MTE-BTI-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 4864 // CHECK-MTE-BTI-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK-MTE-BTI: resolver_return1: @@ -586,8 +586,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-MTE-BTI-NEXT: resolver_entry: // CHECK-MTE-BTI-NEXT: call void @__init_cpu_features_resolver() // CHECK-MTE-BTI-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4096 -// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4096 +// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4864 +// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4864 // CHECK-MTE-BTI-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK-MTE-BTI: resolver_return: @@ -614,8 +614,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-MTE-BTI-NEXT: resolver_entry: // CHECK-MTE-BTI-NEXT: call void @__init_cpu_features_resolver() // CHECK-MTE-BTI-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1040 -// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1040 +// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1808 +// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1808 // CHECK-MTE-BTI-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK-MTE-BTI: resolver_return: @@ -767,16 +767,16 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-MTE-BTI-NEXT: resolver_entry: // CHECK-MTE-BTI-NEXT: call void @__init_cpu_features_resolver() // CHECK-MTE-BTI-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 549757911040 -// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 549757911040 +// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 619551195904 +// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 619551195904 // CHECK-MTE-BTI-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK-MTE-BTI: resolver_return: // CHECK-MTE-BTI-NEXT: ret ptr @ftc_inline2._MfcmaMsve2-bitperm // CHECK-MTE-BTI: resolver_else: // CHECK-MTE-BTI-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 65536 -// CHECK-MTE-BTI-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 65536 +// CHECK-MTE-BTI-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 65792 +// CHECK-MTE-BTI-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 65792 // CHECK-MTE-BTI-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK-MTE-BTI: resolver_return1: @@ -817,8 +817,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-MTE-BTI-NEXT: resolver_entry: // CHECK-MTE-BTI-NEXT: call void @__init_cpu_features_resolver() // CHECK-MTE-BTI-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 18014673387388928 -// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 18014673387388928 +// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 18014743180706560 +// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 18014743180706560 // CHECK-MTE-BTI-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK-MTE-BTI: resolver_return: @@ -833,8 +833,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-MTE-BTI-NEXT: ret ptr @ftc_inline1._MpredresMrcpc // CHECK-MTE-BTI: resolver_else2: // CHECK-MTE-BTI-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 513 -// CHECK-MTE-BTI-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 513 +// CHECK-MTE-BTI-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 769 +// CHECK-MTE-BTI-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 769 // CHECK-MTE-BTI-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] // CHECK-MTE-BTI: resolver_return3: @@ -868,8 +868,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-MTE-BTI-NEXT: resolver_entry: // CHECK-MTE-BTI-NEXT: call void @__init_cpu_features_resolver() // CHECK-MTE-BTI-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 70369817919488 -// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 70369817919488 +// CHECK-MTE-BTI-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 70369817985280 +// CHECK-MTE-BTI-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 70369817985280 // CHECK-MTE-BTI-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-MTE-BTI-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK-MTE-BTI: resolver_return: diff --git a/clang/test/CodeGen/attr-target-version.c b/clang/test/CodeGen/attr-target-version.c index 4194ce2687050..428e7937d8d39 100644 --- a/clang/test/CodeGen/attr-target-version.c +++ b/clang/test/CodeGen/attr-target-version.c @@ -460,24 +460,24 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 11 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 11 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 66315 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 66315 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @fmv._MflagmMfp16fmlMrng // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 72057594037927940 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 72057594037927940 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 72061992218723078 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 72061992218723078 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: // CHECK-NEXT: ret ptr @fmv._Mflagm2Msme-i16i64 // CHECK: resolver_else2: // CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 9007199254741008 -// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 9007199254741008 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 9007199254741776 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 9007199254741776 // CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] // CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] // CHECK: resolver_return3: @@ -492,32 +492,32 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: ret ptr @fmv._McrcMls64 // CHECK: resolver_else6: // CHECK-NEXT: [[TMP16:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP17:%.*]] = and i64 [[TMP16]], 17592186044424 -// CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[TMP17]], 17592186044424 +// CHECK-NEXT: [[TMP17:%.*]] = and i64 [[TMP16]], 17592186110728 +// CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[TMP17]], 17592186110728 // CHECK-NEXT: [[TMP19:%.*]] = and i1 true, [[TMP18]] // CHECK-NEXT: br i1 [[TMP19]], label [[RESOLVER_RETURN7:%.*]], label [[RESOLVER_ELSE8:%.*]] // CHECK: resolver_return7: // CHECK-NEXT: ret ptr @fmv._Mfp16fmlMmemtag // CHECK: resolver_else8: // CHECK-NEXT: [[TMP20:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP21:%.*]] = and i64 [[TMP20]], 33024 -// CHECK-NEXT: [[TMP22:%.*]] = icmp eq i64 [[TMP21]], 33024 +// CHECK-NEXT: [[TMP21:%.*]] = and i64 [[TMP20]], 33536 +// CHECK-NEXT: [[TMP22:%.*]] = icmp eq i64 [[TMP21]], 33536 // CHECK-NEXT: [[TMP23:%.*]] = and i1 true, [[TMP22]] // CHECK-NEXT: br i1 [[TMP23]], label [[RESOLVER_RETURN9:%.*]], label [[RESOLVER_ELSE10:%.*]] // CHECK: resolver_return9: // CHECK-NEXT: ret ptr @fmv._MaesMfp // CHECK: resolver_else10: // CHECK-NEXT: [[TMP24:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP25:%.*]] = and i64 [[TMP24]], 4224 -// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i64 [[TMP25]], 4224 +// CHECK-NEXT: [[TMP25:%.*]] = and i64 [[TMP24]], 4992 +// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i64 [[TMP25]], 4992 // CHECK-NEXT: [[TMP27:%.*]] = and i1 true, [[TMP26]] // CHECK-NEXT: br i1 [[TMP27]], label [[RESOLVER_RETURN11:%.*]], label [[RESOLVER_ELSE12:%.*]] // CHECK: resolver_return11: // CHECK-NEXT: ret ptr @fmv._MlseMsha2 // CHECK: resolver_else12: // CHECK-NEXT: [[TMP28:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP29:%.*]] = and i64 [[TMP28]], 144115188075855872 -// CHECK-NEXT: [[TMP30:%.*]] = icmp eq i64 [[TMP29]], 144115188075855872 +// CHECK-NEXT: [[TMP29:%.*]] = and i64 [[TMP28]], 144119586256651008 +// CHECK-NEXT: [[TMP30:%.*]] = icmp eq i64 [[TMP29]], 144119586256651008 // CHECK-NEXT: [[TMP31:%.*]] = and i1 true, [[TMP30]] // CHECK-NEXT: br i1 [[TMP31]], label [[RESOLVER_RETURN13:%.*]], label [[RESOLVER_ELSE14:%.*]] // CHECK: resolver_return13: @@ -538,8 +538,8 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 9007199254741504 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 9007199254741504 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 9007199254741760 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 9007199254741760 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: @@ -560,16 +560,16 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 66048 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 66048 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 66304 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 66304 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @fmv_two._Mfp16Msimd // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 512 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 512 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 768 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 768 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: @@ -765,128 +765,128 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4398048673856 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4398048673856 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4398182892352 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4398182892352 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @fmv_inline._MfcmaMfp16MrdmMsme // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 864708720641179648 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 864708720641179648 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 864708720653762560 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 864708720653762560 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: // CHECK-NEXT: ret ptr @fmv_inline._MmemtagMmopsMrcpc3 // CHECK: resolver_else2: // CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 893353197568 -// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 893353197568 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 894427038464 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 894427038464 // CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] // CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] // CHECK: resolver_return3: // CHECK-NEXT: ret ptr @fmv_inline._Msve2Msve2-aesMsve2-bitperm // CHECK: resolver_else4: // CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP13:%.*]] = and i64 [[TMP12]], 34359775232 -// CHECK-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], 34359775232 +// CHECK-NEXT: [[TMP13:%.*]] = and i64 [[TMP12]], 35433583360 +// CHECK-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], 35433583360 // CHECK-NEXT: [[TMP15:%.*]] = and i1 true, [[TMP14]] // CHECK-NEXT: br i1 [[TMP15]], label [[RESOLVER_RETURN5:%.*]], label [[RESOLVER_ELSE6:%.*]] // CHECK: resolver_return5: // CHECK-NEXT: ret ptr @fmv_inline._MaesMf64mmMsha2 // CHECK: resolver_else6: // CHECK-NEXT: [[TMP16:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP17:%.*]] = and i64 [[TMP16]], 17246986240 -// CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[TMP17]], 17246986240 +// CHECK-NEXT: [[TMP17:%.*]] = and i64 [[TMP16]], 18320798464 +// CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[TMP17]], 18320798464 // CHECK-NEXT: [[TMP19:%.*]] = and i1 true, [[TMP18]] // CHECK-NEXT: br i1 [[TMP19]], label [[RESOLVER_RETURN7:%.*]], label [[RESOLVER_ELSE8:%.*]] // CHECK: resolver_return7: // CHECK-NEXT: ret ptr @fmv_inline._Mf32mmMi8mmMsha3 // CHECK: resolver_else8: // CHECK-NEXT: [[TMP20:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP21:%.*]] = and i64 [[TMP20]], 19791209299968 -// CHECK-NEXT: [[TMP22:%.*]] = icmp eq i64 [[TMP21]], 19791209299968 +// CHECK-NEXT: [[TMP21:%.*]] = and i64 [[TMP20]], 19861002584864 +// CHECK-NEXT: [[TMP22:%.*]] = icmp eq i64 [[TMP21]], 19861002584864 // CHECK-NEXT: [[TMP23:%.*]] = and i1 true, [[TMP22]] // CHECK-NEXT: br i1 [[TMP23]], label [[RESOLVER_RETURN9:%.*]], label [[RESOLVER_ELSE10:%.*]] // CHECK: resolver_return9: // CHECK-NEXT: ret ptr @fmv_inline._MmemtagMsve2-sm4 // CHECK: resolver_else10: // CHECK-NEXT: [[TMP24:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP25:%.*]] = and i64 [[TMP24]], 1374389534720 -// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i64 [[TMP25]], 1374389534720 +// CHECK-NEXT: [[TMP25:%.*]] = and i64 [[TMP24]], 1444182864640 +// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i64 [[TMP25]], 1444182864640 // CHECK-NEXT: [[TMP27:%.*]] = and i1 true, [[TMP26]] // CHECK-NEXT: br i1 [[TMP27]], label [[RESOLVER_RETURN11:%.*]], label [[RESOLVER_ELSE12:%.*]] // CHECK: resolver_return11: // CHECK-NEXT: ret ptr @fmv_inline._Msve2-aesMsve2-sha3 // CHECK: resolver_else12: // CHECK-NEXT: [[TMP28:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP29:%.*]] = and i64 [[TMP28]], 1207959552 -// CHECK-NEXT: [[TMP30:%.*]] = icmp eq i64 [[TMP29]], 1207959552 +// CHECK-NEXT: [[TMP29:%.*]] = and i64 [[TMP28]], 1208025856 +// CHECK-NEXT: [[TMP30:%.*]] = icmp eq i64 [[TMP29]], 1208025856 // CHECK-NEXT: [[TMP31:%.*]] = and i1 true, [[TMP30]] // CHECK-NEXT: br i1 [[TMP31]], label [[RESOLVER_RETURN13:%.*]], label [[RESOLVER_ELSE14:%.*]] // CHECK: resolver_return13: // CHECK-NEXT: ret ptr @fmv_inline._Mbf16Msve // CHECK: resolver_else14: // CHECK-NEXT: [[TMP32:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP33:%.*]] = and i64 [[TMP32]], 134348800 -// CHECK-NEXT: [[TMP34:%.*]] = icmp eq i64 [[TMP33]], 134348800 +// CHECK-NEXT: [[TMP33:%.*]] = and i64 [[TMP32]], 134349568 +// CHECK-NEXT: [[TMP34:%.*]] = icmp eq i64 [[TMP33]], 134349568 // CHECK-NEXT: [[TMP35:%.*]] = and i1 true, [[TMP34]] // CHECK-NEXT: br i1 [[TMP35]], label [[RESOLVER_RETURN15:%.*]], label [[RESOLVER_ELSE16:%.*]] // CHECK: resolver_return15: // CHECK-NEXT: ret ptr @fmv_inline._Mbf16Mdit // CHECK: resolver_else16: // CHECK-NEXT: [[TMP36:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP37:%.*]] = and i64 [[TMP36]], 20971520 -// CHECK-NEXT: [[TMP38:%.*]] = icmp eq i64 [[TMP37]], 20971520 +// CHECK-NEXT: [[TMP37:%.*]] = and i64 [[TMP36]], 20971776 +// CHECK-NEXT: [[TMP38:%.*]] = icmp eq i64 [[TMP37]], 20971776 // CHECK-NEXT: [[TMP39:%.*]] = and i1 true, [[TMP38]] // CHECK-NEXT: br i1 [[TMP39]], label [[RESOLVER_RETURN17:%.*]], label [[RESOLVER_ELSE18:%.*]] // CHECK: resolver_return17: // CHECK-NEXT: ret ptr @fmv_inline._MfrinttsMrcpc // CHECK: resolver_else18: // CHECK-NEXT: [[TMP40:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP41:%.*]] = and i64 [[TMP40]], 8650752 -// CHECK-NEXT: [[TMP42:%.*]] = icmp eq i64 [[TMP41]], 8650752 +// CHECK-NEXT: [[TMP41:%.*]] = and i64 [[TMP40]], 12845056 +// CHECK-NEXT: [[TMP42:%.*]] = icmp eq i64 [[TMP41]], 12845056 // CHECK-NEXT: [[TMP43:%.*]] = and i1 true, [[TMP42]] // CHECK-NEXT: br i1 [[TMP43]], label [[RESOLVER_RETURN19:%.*]], label [[RESOLVER_ELSE20:%.*]] // CHECK: resolver_return19: // CHECK-NEXT: ret ptr @fmv_inline._MdpbMrcpc2 // CHECK: resolver_else20: // CHECK-NEXT: [[TMP44:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP45:%.*]] = and i64 [[TMP44]], 1572864 -// CHECK-NEXT: [[TMP46:%.*]] = icmp eq i64 [[TMP45]], 1572864 +// CHECK-NEXT: [[TMP45:%.*]] = and i64 [[TMP44]], 1835264 +// CHECK-NEXT: [[TMP46:%.*]] = icmp eq i64 [[TMP45]], 1835264 // CHECK-NEXT: [[TMP47:%.*]] = and i1 true, [[TMP46]] // CHECK-NEXT: br i1 [[TMP47]], label [[RESOLVER_RETURN21:%.*]], label [[RESOLVER_ELSE22:%.*]] // CHECK: resolver_return21: // CHECK-NEXT: ret ptr @fmv_inline._Mdpb2Mjscvt // CHECK: resolver_else22: // CHECK-NEXT: [[TMP48:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP49:%.*]] = and i64 [[TMP48]], 520 -// CHECK-NEXT: [[TMP50:%.*]] = icmp eq i64 [[TMP49]], 520 +// CHECK-NEXT: [[TMP49:%.*]] = and i64 [[TMP48]], 66312 +// CHECK-NEXT: [[TMP50:%.*]] = icmp eq i64 [[TMP49]], 66312 // CHECK-NEXT: [[TMP51:%.*]] = and i1 true, [[TMP50]] // CHECK-NEXT: br i1 [[TMP51]], label [[RESOLVER_RETURN23:%.*]], label [[RESOLVER_ELSE24:%.*]] // CHECK: resolver_return23: // CHECK-NEXT: ret ptr @fmv_inline._Mfp16fmlMsimd // CHECK: resolver_else24: // CHECK-NEXT: [[TMP52:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP53:%.*]] = and i64 [[TMP52]], 32784 -// CHECK-NEXT: [[TMP54:%.*]] = icmp eq i64 [[TMP53]], 32784 +// CHECK-NEXT: [[TMP53:%.*]] = and i64 [[TMP52]], 33552 +// CHECK-NEXT: [[TMP54:%.*]] = icmp eq i64 [[TMP53]], 33552 // CHECK-NEXT: [[TMP55:%.*]] = and i1 true, [[TMP54]] // CHECK-NEXT: br i1 [[TMP55]], label [[RESOLVER_RETURN25:%.*]], label [[RESOLVER_ELSE26:%.*]] // CHECK: resolver_return25: // CHECK-NEXT: ret ptr @fmv_inline._MaesMdotprod // CHECK: resolver_else26: // CHECK-NEXT: [[TMP56:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP57:%.*]] = and i64 [[TMP56]], 192 -// CHECK-NEXT: [[TMP58:%.*]] = icmp eq i64 [[TMP57]], 192 +// CHECK-NEXT: [[TMP57:%.*]] = and i64 [[TMP56]], 960 +// CHECK-NEXT: [[TMP58:%.*]] = icmp eq i64 [[TMP57]], 960 // CHECK-NEXT: [[TMP59:%.*]] = and i1 true, [[TMP58]] // CHECK-NEXT: br i1 [[TMP59]], label [[RESOLVER_RETURN27:%.*]], label [[RESOLVER_ELSE28:%.*]] // CHECK: resolver_return27: // CHECK-NEXT: ret ptr @fmv_inline._MlseMrdm // CHECK: resolver_else28: // CHECK-NEXT: [[TMP60:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP61:%.*]] = and i64 [[TMP60]], 288 -// CHECK-NEXT: [[TMP62:%.*]] = icmp eq i64 [[TMP61]], 288 +// CHECK-NEXT: [[TMP61:%.*]] = and i64 [[TMP60]], 800 +// CHECK-NEXT: [[TMP62:%.*]] = icmp eq i64 [[TMP61]], 800 // CHECK-NEXT: [[TMP63:%.*]] = and i1 true, [[TMP62]] // CHECK-NEXT: br i1 [[TMP63]], label [[RESOLVER_RETURN29:%.*]], label [[RESOLVER_ELSE30:%.*]] // CHECK: resolver_return29: @@ -899,8 +899,8 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073741824 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073741824 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073807616 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073807616 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: @@ -913,8 +913,8 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 65536 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 65536 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 65792 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 65792 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: @@ -941,16 +941,16 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1048576 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048576 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1048832 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048832 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] // CHECK: resolver_return: // CHECK-NEXT: ret ptr @default_def_with_version_decls._Mjscvt // CHECK: resolver_else: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 64 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 64 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 832 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 832 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] // CHECK: resolver_return1: diff --git a/clang/test/CodeGen/memtag-globals.cpp b/clang/test/CodeGen/memtag-globals.cpp index ae2d32ae8a56d..0d7fe22a7b0f0 100644 --- a/clang/test/CodeGen/memtag-globals.cpp +++ b/clang/test/CodeGen/memtag-globals.cpp @@ -10,6 +10,7 @@ // RUN: FileCheck %s --check-prefix=IGNORELIST int global; +int __attribute__((__section__("my_section"))) section_global; int __attribute__((no_sanitize("memtag"))) attributed_global; int __attribute__((disable_sanitizer_instrumentation)) disable_instrumentation_global; int ignorelisted_global; @@ -24,6 +25,8 @@ void func() { // CHECK: @{{.*}}extra_global{{.*}} ={{.*}} sanitize_memtag // CHECK: @{{.*}}global{{.*}} ={{.*}} sanitize_memtag +// CHECK: @{{.*}}section_global{{.*}} = +// CHECK-NOT: sanitize_memtag // CHECK: @{{.*}}attributed_global{{.*}} = // CHECK-NOT: sanitize_memtag // CHECK: @{{.*}}disable_instrumentation_global{{.*}} = @@ -32,7 +35,7 @@ void func() { // CHECK-NOT: sanitize_memtag // CHECK: @{{.*}}static_var{{.*}} ={{.*}} sanitize_memtag -// CHECK: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}} sanitize_memtag +// CHECK: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}} // CHECK: @{{.*}}external_global{{.*}} ={{.*}} sanitize_memtag // IGNORELIST: @{{.*}}extra_global{{.*}} ={{.*}} sanitize_memtag diff --git a/clang/test/CodeGen/ptrauth-module-flags.c b/clang/test/CodeGen/ptrauth-module-flags.c index 5a7e9a7c2a36f..e441d52cb7c62 100644 --- a/clang/test/CodeGen/ptrauth-module-flags.c +++ b/clang/test/CodeGen/ptrauth-module-flags.c @@ -1,8 +1,13 @@ // RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=OFF // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-elf-got -emit-llvm %s -o - | FileCheck %s --check-prefix=ELFGOT +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefix=PERSONALITY // ELFGOT: !llvm.module.flags = !{ // ELFGOT-SAME: !1 // ELFGOT: !1 = !{i32 8, !"ptrauth-elf-got", i32 1} +// PERSONALITY: !llvm.module.flags = !{ +// PERSONALITY-SAME: !1 +// PERSONALITY: !1 = !{i32 8, !"ptrauth-sign-personality", i32 1} + // OFF-NOT: "ptrauth- diff --git a/clang/test/CodeGen/sanitize-type-attr.cpp b/clang/test/CodeGen/sanitize-type-attr.cpp new file mode 100644 index 0000000000000..eaae9aa98a47a --- /dev/null +++ b/clang/test/CodeGen/sanitize-type-attr.cpp @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type | FileCheck -check-prefix=TYSAN %s +// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type -fsanitize-blacklist=%t | FileCheck -check-prefix=BL %s + +// The sanitize_type attribute should be attached to functions +// when TypeSanitizer is enabled, unless no_sanitize("type") attribute +// is present. + +// WITHOUT: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]] +// BL: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]] +// TYSAN: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]] +__attribute__((no_sanitize("type"))) int NoTYSAN1(int *a) { return *a; } + +// WITHOUT: NoTYSAN2{{.*}}) [[NOATTR]] +// BL: NoTYSAN2{{.*}}) [[NOATTR]] +// TYSAN: NoTYSAN2{{.*}}) [[NOATTR]] +__attribute__((no_sanitize("type"))) int NoTYSAN2(int *a); +int NoTYSAN2(int *a) { return *a; } + +// WITHOUT: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]] +// BL: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]] +// TYSAN: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]] +__attribute__((no_sanitize("type"))) int NoTYSAN3(int *a) { return *a; } + +// WITHOUT: TYSANOk{{.*}}) [[NOATTR]] +// BL: TYSANOk{{.*}}) [[NOATTR]] +// TYSAN: TYSANOk{{.*}}) [[WITH:#[0-9]+]] +int TYSANOk(int *a) { return *a; } + +// WITHOUT: TemplateTYSANOk{{.*}}) [[NOATTR]] +// BL: TemplateTYSANOk{{.*}}) [[NOATTR]] +// TYSAN: TemplateTYSANOk{{.*}}) [[WITH]] +template +int TemplateTYSANOk() { return i; } + +// WITHOUT: TemplateNoTYSAN{{.*}}) [[NOATTR]] +// BL: TemplateNoTYSAN{{.*}}) [[NOATTR]] +// TYSAN: TemplateNoTYSAN{{.*}}) [[NOATTR]] +template +__attribute__((no_sanitize("type"))) int TemplateNoTYSAN() { return i; } + +int force_instance = TemplateTYSANOk<42>() + TemplateNoTYSAN<42>(); + +// Check that __cxx_global_var_init* get the sanitize_type attribute. +int global1 = 0; +int global2 = *(int *)((char *)&global1 + 1); +// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]] +// BL: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]] +// TYSAN: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]] + +// Make sure that we don't add globals to the list for which we don't have a +// specific type description. +// FIXME: We now have a type description for this type and a global is added. Should it? +struct SX { + int a, b; +}; +SX sx; + +void consumer(const char *); + +void char_caller() { + // TYSAN: void @_Z11char_callerv() + // TYSAN-NEXT: entry: + // TYSAN-NEXT: call void @_Z8consumerPKc(ptr noundef @.str) + // TYSAN-NEXT: ret void + + consumer("foo"); +} + +// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} } + +// BL: attributes [[NOATTR]] = { noinline nounwind{{.*}} } + +// TYSAN: attributes [[NOATTR]] = { mustprogress noinline nounwind{{.*}} } +// TYSAN: attributes [[WITH]] = { noinline nounwind sanitize_type{{.*}} } + +// TYSAN-DAG: !llvm.tysan.globals = !{[[G1MD:![0-9]+]], [[G2MD:![0-9]+]], [[G3MD:![0-9]+]], [[SXMD:![0-9]+]]} +// TYSAN-DAG: [[G1MD]] = !{ptr @force_instance, [[INTMD:![0-9]+]]} +// TYSAN-DAG: [[INTMD]] = !{!"int", +// TYSAN-DAG: [[G2MD]] = !{ptr @global1, [[INTMD]]} +// TYSAN-DAG: [[G3MD]] = !{ptr @global2, [[INTMD]]} +// TYSAN-DAG: [[SXMD]] = !{ptr @sx, [[SXTYMD:![0-9]+]]} +// TYSAN-DAG: [[SXTYMD]] = !{!"_ZTS2SX", [[INTMD]], i64 0, !1, i64 4} +// TYSAN-DAG: Simple C++ TBAA diff --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c index cb89fad941c83..71eb849433ed4 100644 --- a/clang/test/CodeGen/target-data.c +++ b/clang/test/CodeGen/target-data.c @@ -88,7 +88,7 @@ // RUN: %clang_cc1 -triple powerpc64-lv2 -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=PS3 -// PS3: target datalayout = "E-m:e-p:32:32-Fi64-i64:64-n32:64" +// PS3: target datalayout = "E-m:e-p:32:32-Fi64-i64:64-i128:128-n32:64" // RUN: %clang_cc1 -triple i686-nacl -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=I686-NACL @@ -108,11 +108,11 @@ // RUN: %clang_cc1 -triple wasm32-unknown-unknown -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=WEBASSEMBLY32 -// WEBASSEMBLY32: target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20" +// WEBASSEMBLY32: target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" // RUN: %clang_cc1 -triple wasm64-unknown-unknown -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=WEBASSEMBLY64 -// WEBASSEMBLY64: target datalayout = "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20" +// WEBASSEMBLY64: target datalayout = "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" // RUN: %clang_cc1 -triple lanai-unknown-unknown -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=LANAI @@ -128,35 +128,35 @@ // RUN: %clang_cc1 -triple powerpc64-freebsd -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=PPC64-FREEBSD -// PPC64-FREEBSD: target datalayout = "E-m:e-Fn32-i64:64-n32:64" +// PPC64-FREEBSD: target datalayout = "E-m:e-Fn32-i64:64-i128:128-n32:64" // RUN: %clang_cc1 -triple powerpc64le-freebsd -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=PPC64LE-FREEBSD -// PPC64LE-FREEBSD: target datalayout = "e-m:e-Fn32-i64:64-n32:64" +// PPC64LE-FREEBSD: target datalayout = "e-m:e-Fn32-i64:64-i128:128-n32:64" // RUN: %clang_cc1 -triple powerpc64-linux -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=PPC64-LINUX -// PPC64-LINUX: target datalayout = "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512" +// PPC64-LINUX: target datalayout = "E-m:e-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" // RUN: %clang_cc1 -triple powerpc64-linux -o - -emit-llvm -target-cpu future %s | \ // RUN: FileCheck %s -check-prefix=PPC64-FUTURE -// PPC64-FUTURE: target datalayout = "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512" +// PPC64-FUTURE: target datalayout = "E-m:e-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" // RUN: %clang_cc1 -triple powerpc64-linux -o - -emit-llvm -target-cpu pwr10 %s | \ // RUN: FileCheck %s -check-prefix=PPC64-P10 -// PPC64-P10: target datalayout = "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512" +// PPC64-P10: target datalayout = "E-m:e-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" // RUN: %clang_cc1 -triple powerpc64le-linux -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=PPC64LE-LINUX -// PPC64LE-LINUX: target datalayout = "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512" +// PPC64LE-LINUX: target datalayout = "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" // RUN: %clang_cc1 -triple powerpc64le-linux -o - -emit-llvm -target-cpu future %s | \ // RUN: FileCheck %s -check-prefix=PPC64LE-FUTURE -// PPC64LE-FUTURE: target datalayout = "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512" +// PPC64LE-FUTURE: target datalayout = "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" // RUN: %clang_cc1 -triple powerpc64le-linux -o - -emit-llvm -target-cpu pwr10 %s | \ // RUN: FileCheck %s -check-prefix=PPC64LE-P10 -// PPC64LE-P10: target datalayout = "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512" +// PPC64LE-P10: target datalayout = "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512" // RUN: %clang_cc1 -triple nvptx-unknown -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=NVPTX diff --git a/clang/test/CodeGen/ubsan-trap-debugloc.c b/clang/test/CodeGen/ubsan-trap-debugloc.c index 4cad708b0ca50..87cbfadec7d30 100644 --- a/clang/test/CodeGen/ubsan-trap-debugloc.c +++ b/clang/test/CodeGen/ubsan-trap-debugloc.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow %s -o - -debug-info-kind=line-tables-only | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -disable-llvm-passes -O -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -fsanitize-merge=signed-integer-overflow %s -o - -debug-info-kind=line-tables-only | FileCheck %s void foo(volatile int a) { diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c index dccce0ce4c56b..f211150a09cb6 100644 --- a/clang/test/CodeGen/ubsan-trap-merge.c +++ b/clang/test/CodeGen/ubsan-trap-merge.c @@ -1,67 +1,453 @@ // NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 -// The most important assertion is the attributes at the end of the file, which -// shows that -ubsan-unique-traps attaches 'nomerge' to each ubsantrap intrinsic. +// The most important assertions are the attributes at the end of the file, which +// show whether -ubsan-unique-traps and -fno-sanitize-merge attach 'nomerge' +// to each ubsan call. // -// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - \ -// RUN: | FileCheck %s +// N.B. although the clang driver defaults to -fsanitize-merge=undefined, +// clang_cc1 defaults to non-merge. (This is similar to -fsanitize-recover, for +// which the default is also applied at the driver level only.) +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefixes=TRAP-NOMERGE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 %s -o - | FileCheck %s --check-prefixes=HANDLER-NOMERGE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 %s -o - -fsanitize-minimal-runtime | FileCheck %s --check-prefixes=MINRT-NOMERGE +// +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefixes=TRAP-NOMERGE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - | FileCheck %s --check-prefixes=HANDLER-NOMERGE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-minimal-runtime | FileCheck %s --check-prefixes=MINRT-NOMERGE +// +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fno-sanitize-merge=signed-integer-overflow %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefixes=TRAP-NOMERGE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fno-sanitize-merge=signed-integer-overflow %s -o - | FileCheck %s --check-prefixes=HANDLER-NOMERGE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fno-sanitize-merge=signed-integer-overflow %s -o - -fsanitize-minimal-runtime | FileCheck %s --check-prefixes=MINRT-NOMERGE +// +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-merge=signed-integer-overflow %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefixes=TRAP-MERGE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-merge=signed-integer-overflow %s -o - | FileCheck %s --check-prefixes=HANDLER-MERGE +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-merge=signed-integer-overflow %s -o - -fsanitize-minimal-runtime | FileCheck %s --check-prefixes=MINRT-MERGE // // REQUIRES: x86-registered-target -// CHECK-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( -// CHECK-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] -// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] -// CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4:[0-9]+]], !nosanitize [[META2]] -// CHECK-NEXT: unreachable, !nosanitize [[META2]] -// CHECK: [[CONT]]: -// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] -// CHECK-NEXT: ret i32 [[TMP2]] +// TRAP-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// TRAP-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// TRAP-NEXT: [[ENTRY:.*:]] +// TRAP-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// TRAP-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP: [[TRAP]]: +// TRAP-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// TRAP-NEXT: unreachable, !nosanitize [[META2]] +// TRAP: [[CONT]]: +// TRAP-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-NEXT: ret i32 [[TMP2]] +// +// HANDLER-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// HANDLER-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// HANDLER-NEXT: [[ENTRY:.*:]] +// HANDLER-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// HANDLER-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// HANDLER: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP2]], i64 125) #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// HANDLER-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER: [[CONT]]: +// HANDLER-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-NEXT: ret i32 [[TMP3]] +// +// MINRT-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// MINRT-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// MINRT-NEXT: [[ENTRY:.*:]] +// MINRT-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// MINRT-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// MINRT: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// MINRT-NEXT: unreachable, !nosanitize [[META2]] +// MINRT: [[CONT]]: +// MINRT-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-NEXT: ret i32 [[TMP2]] +// TRAP-NOMERGE-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// TRAP-NOMERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// TRAP-NOMERGE-NEXT: [[ENTRY:.*:]] +// TRAP-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// TRAP-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP-NOMERGE: [[TRAP]]: +// TRAP-NOMERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-NOMERGE: [[CONT]]: +// TRAP-NOMERGE-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: ret i32 [[TMP2]] +// +// HANDLER-NOMERGE-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// HANDLER-NOMERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// HANDLER-NOMERGE-NEXT: [[ENTRY:.*:]] +// HANDLER-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// HANDLER-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// HANDLER-NOMERGE: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-NOMERGE-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP2]], i64 125) #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-NOMERGE: [[CONT]]: +// HANDLER-NOMERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: ret i32 [[TMP3]] +// +// MINRT-NOMERGE-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// MINRT-NOMERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// MINRT-NOMERGE-NEXT: [[ENTRY:.*:]] +// MINRT-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// MINRT-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// MINRT-NOMERGE: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-NOMERGE: [[CONT]]: +// MINRT-NOMERGE-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: ret i32 [[TMP2]] +// +// TRAP-MERGE-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// TRAP-MERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// TRAP-MERGE-NEXT: [[ENTRY:.*:]] +// TRAP-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// TRAP-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP-MERGE: [[TRAP]]: +// TRAP-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// TRAP-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-MERGE: [[CONT]]: +// TRAP-MERGE-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: ret i32 [[TMP2]] +// +// HANDLER-MERGE-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// HANDLER-MERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// HANDLER-MERGE-NEXT: [[ENTRY:.*:]] +// HANDLER-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// HANDLER-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// HANDLER-MERGE: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-MERGE-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP2]], i64 125) #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-MERGE: [[CONT]]: +// HANDLER-MERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: ret i32 [[TMP3]] +// +// MINRT-MERGE-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f( +// MINRT-MERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// MINRT-MERGE-NEXT: [[ENTRY:.*:]] +// MINRT-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]] +// MINRT-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// MINRT-MERGE: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4:[0-9]+]], !nosanitize [[META2]] +// MINRT-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-MERGE: [[CONT]]: +// MINRT-MERGE-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: ret i32 [[TMP2]] // int f(int x) { return x + 125; } -// CHECK-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( -// CHECK-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] -// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] -// CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] -// CHECK-NEXT: unreachable, !nosanitize [[META2]] -// CHECK: [[CONT]]: -// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] -// CHECK-NEXT: ret i32 [[TMP2]] +// TRAP-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// TRAP-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// TRAP-NEXT: [[ENTRY:.*:]] +// TRAP-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// TRAP-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP: [[TRAP]]: +// TRAP-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NEXT: unreachable, !nosanitize [[META2]] +// TRAP: [[CONT]]: +// TRAP-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-NEXT: ret i32 [[TMP2]] +// +// HANDLER-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// HANDLER-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-NEXT: [[ENTRY:.*:]] +// HANDLER-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP2]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER: [[CONT]]: +// HANDLER-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-NEXT: ret i32 [[TMP3]] +// +// MINRT-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// MINRT-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-NEXT: [[ENTRY:.*:]] +// MINRT-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// MINRT-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NEXT: unreachable, !nosanitize [[META2]] +// MINRT: [[CONT]]: +// MINRT-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-NEXT: ret i32 [[TMP2]] +// TRAP-NOMERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// TRAP-NOMERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// TRAP-NOMERGE-NEXT: [[ENTRY:.*:]] +// TRAP-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP-NOMERGE: [[TRAP]]: +// TRAP-NOMERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-NOMERGE: [[CONT]]: +// TRAP-NOMERGE-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: ret i32 [[TMP2]] +// +// HANDLER-NOMERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// HANDLER-NOMERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-NOMERGE-NEXT: [[ENTRY:.*:]] +// HANDLER-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-NOMERGE: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-NOMERGE-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP2]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-NOMERGE: [[CONT]]: +// HANDLER-NOMERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: ret i32 [[TMP3]] +// +// MINRT-NOMERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// MINRT-NOMERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-NOMERGE-NEXT: [[ENTRY:.*:]] +// MINRT-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-NOMERGE: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-NOMERGE: [[CONT]]: +// MINRT-NOMERGE-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: ret i32 [[TMP2]] +// +// TRAP-MERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// TRAP-MERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// TRAP-MERGE-NEXT: [[ENTRY:.*:]] +// TRAP-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP-MERGE: [[TRAP]]: +// TRAP-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-MERGE: [[CONT]]: +// TRAP-MERGE-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: ret i32 [[TMP2]] +// +// HANDLER-MERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// HANDLER-MERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-MERGE-NEXT: [[ENTRY:.*:]] +// HANDLER-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-MERGE: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-MERGE-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP2]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-MERGE: [[CONT]]: +// HANDLER-MERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: ret i32 [[TMP3]] +// +// MINRT-MERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g( +// MINRT-MERGE-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-MERGE-NEXT: [[ENTRY:.*:]] +// MINRT-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-MERGE: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-MERGE: [[CONT]]: +// MINRT-MERGE-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: ret i32 [[TMP2]] // int g(int x) { return x + 127; } -// CHECK-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( -// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] -// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] -// CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] -// CHECK-NEXT: unreachable, !nosanitize [[META2]] -// CHECK: [[CONT]]: -// CHECK-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] -// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] -// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP1:.*]], label %[[CONT2:.*]], !nosanitize [[META2]] -// CHECK: [[TRAP1]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] -// CHECK-NEXT: unreachable, !nosanitize [[META2]] -// CHECK: [[CONT2]]: -// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] -// CHECK-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP5]], i32 [[TMP4]]) -// CHECK-NEXT: ret i32 [[COND]] +// +// HANDLER-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( +// HANDLER-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-NEXT: [[ENTRY:.*:]] +// HANDLER-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[TMP2]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER: [[CONT]]: +// HANDLER-NEXT: [[TMP3:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1, !nosanitize [[META2]] +// HANDLER-NEXT: br i1 [[TMP4]], label %[[HANDLER_ADD_OVERFLOW1:.*]], label %[[CONT2:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER: [[HANDLER_ADD_OVERFLOW1]]: +// HANDLER-NEXT: [[TMP5:%.*]] = zext nneg i32 [[Y]] to i64, !nosanitize [[META2]] +// HANDLER-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[TMP5]], i64 129) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER: [[CONT2]]: +// HANDLER-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0, !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP7]], i32 [[TMP6]]) +// HANDLER-NEXT: ret i32 [[COND]] +// +// MINRT-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( +// MINRT-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-NEXT: [[ENTRY:.*:]] +// MINRT-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// MINRT-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NEXT: unreachable, !nosanitize [[META2]] +// MINRT: [[CONT]]: +// MINRT-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] +// MINRT-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// MINRT-NEXT: br i1 [[TMP3]], label %[[HANDLER_ADD_OVERFLOW1:.*]], label %[[CONT2:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT: [[HANDLER_ADD_OVERFLOW1]]: +// MINRT-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NEXT: unreachable, !nosanitize [[META2]] +// MINRT: [[CONT2]]: +// MINRT-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// MINRT-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP5]], i32 [[TMP4]]) +// MINRT-NEXT: ret i32 [[COND]] +// TRAP-NOMERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( +// TRAP-NOMERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// TRAP-NOMERGE-NEXT: [[ENTRY:.*:]] +// TRAP-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP-NOMERGE: [[TRAP]]: +// TRAP-NOMERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-NOMERGE: [[CONT]]: +// TRAP-NOMERGE-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: br i1 [[TMP3]], label %[[TRAP1:.*]], label %[[CONT2:.*]], !nosanitize [[META2]] +// TRAP-NOMERGE: [[TRAP1]]: +// TRAP-NOMERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-NOMERGE: [[CONT2]]: +// TRAP-NOMERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP5]], i32 [[TMP4]]) +// TRAP-NOMERGE-NEXT: ret i32 [[COND]] +// +// HANDLER-NOMERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( +// HANDLER-NOMERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-NOMERGE-NEXT: [[ENTRY:.*:]] +// HANDLER-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-NOMERGE: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-NOMERGE-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[TMP2]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-NOMERGE: [[CONT]]: +// HANDLER-NOMERGE-NEXT: [[TMP3:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: br i1 [[TMP4]], label %[[HANDLER_ADD_OVERFLOW1:.*]], label %[[CONT2:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-NOMERGE: [[HANDLER_ADD_OVERFLOW1]]: +// HANDLER-NOMERGE-NEXT: [[TMP5:%.*]] = zext nneg i32 [[Y]] to i64, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[TMP5]], i64 129) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-NOMERGE: [[CONT2]]: +// HANDLER-NOMERGE-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP7]], i32 [[TMP6]]) +// HANDLER-NOMERGE-NEXT: ret i32 [[COND]] +// +// MINRT-NOMERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( +// MINRT-NOMERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-NOMERGE-NEXT: [[ENTRY:.*:]] +// MINRT-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-NOMERGE: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-NOMERGE: [[CONT]]: +// MINRT-NOMERGE-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: br i1 [[TMP3]], label %[[HANDLER_ADD_OVERFLOW1:.*]], label %[[CONT2:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-NOMERGE: [[HANDLER_ADD_OVERFLOW1]]: +// MINRT-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-NOMERGE: [[CONT2]]: +// MINRT-NOMERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP5]], i32 [[TMP4]]) +// MINRT-NOMERGE-NEXT: ret i32 [[COND]] +// +// TRAP-MERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( +// TRAP-MERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// TRAP-MERGE-NEXT: [[ENTRY:.*:]] +// TRAP-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP-MERGE: [[TRAP]]: +// TRAP-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-MERGE: [[CONT]]: +// TRAP-MERGE-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: br i1 [[TMP3]], label %[[TRAP]], label %[[CONT1:.*]], !nosanitize [[META2]] +// TRAP-MERGE: [[CONT1]]: +// TRAP-MERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP5]], i32 [[TMP4]]) +// TRAP-MERGE-NEXT: ret i32 [[COND]] +// +// HANDLER-MERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( +// HANDLER-MERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-MERGE-NEXT: [[ENTRY:.*:]] +// HANDLER-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-MERGE: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-MERGE-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[TMP2]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-MERGE: [[CONT]]: +// HANDLER-MERGE-NEXT: [[TMP3:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 1, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: br i1 [[TMP4]], label %[[HANDLER_ADD_OVERFLOW1:.*]], label %[[CONT2:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-MERGE: [[HANDLER_ADD_OVERFLOW1]]: +// HANDLER-MERGE-NEXT: [[TMP5:%.*]] = zext nneg i32 [[Y]] to i64, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[TMP5]], i64 129) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-MERGE: [[CONT2]]: +// HANDLER-MERGE-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP7]], i32 [[TMP6]]) +// HANDLER-MERGE-NEXT: ret i32 [[COND]] +// +// MINRT-MERGE-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( +// MINRT-MERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-MERGE-NEXT: [[ENTRY:.*:]] +// MINRT-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-MERGE: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-MERGE: [[CONT]]: +// MINRT-MERGE-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: br i1 [[TMP3]], label %[[HANDLER_ADD_OVERFLOW1:.*]], label %[[CONT2:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-MERGE: [[HANDLER_ADD_OVERFLOW1]]: +// MINRT-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-MERGE: [[CONT2]]: +// MINRT-MERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP5]], i32 [[TMP4]]) +// MINRT-MERGE-NEXT: ret i32 [[COND]] // int h(int x, int y) { x += 127; @@ -69,37 +455,286 @@ int h(int x, int y) { return x < y ? x : y; } -// CHECK-LABEL: define dso_local noundef i32 @m( -// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] -// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP_I:.*]], label %[[F_EXIT:.*]], !nosanitize [[META2]] -// CHECK: [[TRAP_I]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] -// CHECK-NEXT: unreachable, !nosanitize [[META2]] -// CHECK: [[F_EXIT]]: -// CHECK-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] -// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] -// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP_I2:.*]], label %[[G_EXIT:.*]], !nosanitize [[META2]] -// CHECK: [[TRAP_I2]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] -// CHECK-NEXT: unreachable, !nosanitize [[META2]] -// CHECK: [[G_EXIT]]: -// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP6:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP4]], i32 [[TMP5]]), !nosanitize [[META2]] -// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META2]] -// CHECK-NEXT: br i1 [[TMP7]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] -// CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] -// CHECK-NEXT: unreachable, !nosanitize [[META2]] -// CHECK: [[CONT]]: -// CHECK-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META2]] -// CHECK-NEXT: ret i32 [[TMP8]] +// TRAP-LABEL: define dso_local noundef i32 @m( +// TRAP-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// TRAP-NEXT: [[ENTRY:.*:]] +// TRAP-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// TRAP-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-NEXT: br i1 [[TMP1]], label %[[TRAP_I:.*]], label %[[F_EXIT:.*]], !nosanitize [[META2]] +// TRAP: [[TRAP_I]]: +// TRAP-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NEXT: unreachable, !nosanitize [[META2]] +// TRAP: [[F_EXIT]]: +// TRAP-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// TRAP-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// TRAP-NEXT: br i1 [[TMP3]], label %[[TRAP_I2:.*]], label %[[G_EXIT:.*]], !nosanitize [[META2]] +// TRAP: [[TRAP_I2]]: +// TRAP-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NEXT: unreachable, !nosanitize [[META2]] +// TRAP: [[G_EXIT]]: +// TRAP-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// TRAP-NEXT: [[TMP6:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP4]], i32 [[TMP5]]), !nosanitize [[META2]] +// TRAP-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META2]] +// TRAP-NEXT: br i1 [[TMP7]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP: [[TRAP]]: +// TRAP-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NEXT: unreachable, !nosanitize [[META2]] +// TRAP: [[CONT]]: +// TRAP-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META2]] +// TRAP-NEXT: ret i32 [[TMP8]] +// +// HANDLER-LABEL: define dso_local noundef i32 @m( +// HANDLER-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-NEXT: [[ENTRY:.*:]] +// HANDLER-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW_I:.*]], label %[[F_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER: [[HANDLER_ADD_OVERFLOW_I]]: +// HANDLER-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB1]], i64 [[TMP2]], i64 125) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER: [[F_EXIT]]: +// HANDLER-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP4:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1, !nosanitize [[META2]] +// HANDLER-NEXT: br i1 [[TMP5]], label %[[HANDLER_ADD_OVERFLOW_I2:.*]], label %[[G_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER: [[HANDLER_ADD_OVERFLOW_I2]]: +// HANDLER-NEXT: [[TMP6:%.*]] = zext nneg i32 [[Y]] to i64, !nosanitize [[META2]] +// HANDLER-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB2]], i64 [[TMP6]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER: [[G_EXIT]]: +// HANDLER-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0, !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP8:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP3]], i32 [[TMP7]]), !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP9:%.*]] = extractvalue { i32, i1 } [[TMP8]], 1, !nosanitize [[META2]] +// HANDLER-NEXT: br i1 [[TMP9]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-NEXT: [[TMP10:%.*]] = zext i32 [[TMP3]] to i64, !nosanitize [[META2]] +// HANDLER-NEXT: [[TMP11:%.*]] = zext i32 [[TMP7]] to i64, !nosanitize [[META2]] +// HANDLER-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER: [[CONT]]: +// HANDLER-NEXT: [[TMP12:%.*]] = extractvalue { i32, i1 } [[TMP8]], 0, !nosanitize [[META2]] +// HANDLER-NEXT: ret i32 [[TMP12]] +// +// MINRT-LABEL: define dso_local noundef i32 @m( +// MINRT-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-NEXT: [[ENTRY:.*:]] +// MINRT-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// MINRT-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW_I:.*]], label %[[F_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT: [[HANDLER_ADD_OVERFLOW_I]]: +// MINRT-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NEXT: unreachable, !nosanitize [[META2]] +// MINRT: [[F_EXIT]]: +// MINRT-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// MINRT-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// MINRT-NEXT: br i1 [[TMP3]], label %[[HANDLER_ADD_OVERFLOW_I2:.*]], label %[[G_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT: [[HANDLER_ADD_OVERFLOW_I2]]: +// MINRT-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NEXT: unreachable, !nosanitize [[META2]] +// MINRT: [[G_EXIT]]: +// MINRT-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// MINRT-NEXT: [[TMP6:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP4]], i32 [[TMP5]]), !nosanitize [[META2]] +// MINRT-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META2]] +// MINRT-NEXT: br i1 [[TMP7]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NEXT: unreachable, !nosanitize [[META2]] +// MINRT: [[CONT]]: +// MINRT-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META2]] +// MINRT-NEXT: ret i32 [[TMP8]] +// TRAP-NOMERGE-LABEL: define dso_local noundef i32 @m( +// TRAP-NOMERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// TRAP-NOMERGE-NEXT: [[ENTRY:.*:]] +// TRAP-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: br i1 [[TMP1]], label %[[TRAP_I:.*]], label %[[F_EXIT:.*]], !nosanitize [[META2]] +// TRAP-NOMERGE: [[TRAP_I]]: +// TRAP-NOMERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-NOMERGE: [[F_EXIT]]: +// TRAP-NOMERGE-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: br i1 [[TMP3]], label %[[TRAP_I2:.*]], label %[[G_EXIT:.*]], !nosanitize [[META2]] +// TRAP-NOMERGE: [[TRAP_I2]]: +// TRAP-NOMERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-NOMERGE: [[G_EXIT]]: +// TRAP-NOMERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP6:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP4]], i32 [[TMP5]]), !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: br i1 [[TMP7]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP-NOMERGE: [[TRAP]]: +// TRAP-NOMERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-NOMERGE: [[CONT]]: +// TRAP-NOMERGE-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META2]] +// TRAP-NOMERGE-NEXT: ret i32 [[TMP8]] +// +// HANDLER-NOMERGE-LABEL: define dso_local noundef i32 @m( +// HANDLER-NOMERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-NOMERGE-NEXT: [[ENTRY:.*:]] +// HANDLER-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW_I:.*]], label %[[F_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-NOMERGE: [[HANDLER_ADD_OVERFLOW_I]]: +// HANDLER-NOMERGE-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB1]], i64 [[TMP2]], i64 125) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-NOMERGE: [[F_EXIT]]: +// HANDLER-NOMERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP4:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: br i1 [[TMP5]], label %[[HANDLER_ADD_OVERFLOW_I2:.*]], label %[[G_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-NOMERGE: [[HANDLER_ADD_OVERFLOW_I2]]: +// HANDLER-NOMERGE-NEXT: [[TMP6:%.*]] = zext nneg i32 [[Y]] to i64, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB2]], i64 [[TMP6]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-NOMERGE: [[G_EXIT]]: +// HANDLER-NOMERGE-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP8:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP3]], i32 [[TMP7]]), !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP9:%.*]] = extractvalue { i32, i1 } [[TMP8]], 1, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: br i1 [[TMP9]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-NOMERGE: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-NOMERGE-NEXT: [[TMP10:%.*]] = zext i32 [[TMP3]] to i64, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: [[TMP11:%.*]] = zext i32 [[TMP7]] to i64, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-NOMERGE: [[CONT]]: +// HANDLER-NOMERGE-NEXT: [[TMP12:%.*]] = extractvalue { i32, i1 } [[TMP8]], 0, !nosanitize [[META2]] +// HANDLER-NOMERGE-NEXT: ret i32 [[TMP12]] +// +// MINRT-NOMERGE-LABEL: define dso_local noundef i32 @m( +// MINRT-NOMERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-NOMERGE-NEXT: [[ENTRY:.*:]] +// MINRT-NOMERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW_I:.*]], label %[[F_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-NOMERGE: [[HANDLER_ADD_OVERFLOW_I]]: +// MINRT-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-NOMERGE: [[F_EXIT]]: +// MINRT-NOMERGE-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: br i1 [[TMP3]], label %[[HANDLER_ADD_OVERFLOW_I2:.*]], label %[[G_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-NOMERGE: [[HANDLER_ADD_OVERFLOW_I2]]: +// MINRT-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-NOMERGE: [[G_EXIT]]: +// MINRT-NOMERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP6:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP4]], i32 [[TMP5]]), !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: br i1 [[TMP7]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-NOMERGE: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-NOMERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-NOMERGE: [[CONT]]: +// MINRT-NOMERGE-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META2]] +// MINRT-NOMERGE-NEXT: ret i32 [[TMP8]] +// +// TRAP-MERGE-LABEL: define dso_local noundef i32 @m( +// TRAP-MERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// TRAP-MERGE-NEXT: [[ENTRY:.*:]] +// TRAP-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: br i1 [[TMP1]], label %[[TRAP_I:.*]], label %[[F_EXIT:.*]], !nosanitize [[META2]] +// TRAP-MERGE: [[TRAP_I]]: +// TRAP-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-MERGE: [[F_EXIT]]: +// TRAP-MERGE-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: br i1 [[TMP3]], label %[[TRAP_I2:.*]], label %[[G_EXIT:.*]], !nosanitize [[META2]] +// TRAP-MERGE: [[TRAP_I2]]: +// TRAP-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-MERGE: [[G_EXIT]]: +// TRAP-MERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP6:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP4]], i32 [[TMP5]]), !nosanitize [[META2]] +// TRAP-MERGE-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: br i1 [[TMP7]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TRAP-MERGE: [[TRAP]]: +// TRAP-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] +// TRAP-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// TRAP-MERGE: [[CONT]]: +// TRAP-MERGE-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META2]] +// TRAP-MERGE-NEXT: ret i32 [[TMP8]] +// +// HANDLER-MERGE-LABEL: define dso_local noundef i32 @m( +// HANDLER-MERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// HANDLER-MERGE-NEXT: [[ENTRY:.*:]] +// HANDLER-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW_I:.*]], label %[[F_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-MERGE: [[HANDLER_ADD_OVERFLOW_I]]: +// HANDLER-MERGE-NEXT: [[TMP2:%.*]] = zext nneg i32 [[X]] to i64, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB1]], i64 [[TMP2]], i64 125) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-MERGE: [[F_EXIT]]: +// HANDLER-MERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP4:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: br i1 [[TMP5]], label %[[HANDLER_ADD_OVERFLOW_I2:.*]], label %[[G_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-MERGE: [[HANDLER_ADD_OVERFLOW_I2]]: +// HANDLER-MERGE-NEXT: [[TMP6:%.*]] = zext nneg i32 [[Y]] to i64, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB2]], i64 [[TMP6]], i64 127) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-MERGE: [[G_EXIT]]: +// HANDLER-MERGE-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP8:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP3]], i32 [[TMP7]]), !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP9:%.*]] = extractvalue { i32, i1 } [[TMP8]], 1, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: br i1 [[TMP9]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// HANDLER-MERGE: [[HANDLER_ADD_OVERFLOW]]: +// HANDLER-MERGE-NEXT: [[TMP10:%.*]] = zext i32 [[TMP3]] to i64, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: [[TMP11:%.*]] = zext i32 [[TMP7]] to i64, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR4]], !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// HANDLER-MERGE: [[CONT]]: +// HANDLER-MERGE-NEXT: [[TMP12:%.*]] = extractvalue { i32, i1 } [[TMP8]], 0, !nosanitize [[META2]] +// HANDLER-MERGE-NEXT: ret i32 [[TMP12]] +// +// MINRT-MERGE-LABEL: define dso_local noundef i32 @m( +// MINRT-MERGE-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] { +// MINRT-MERGE-NEXT: [[ENTRY:.*:]] +// MINRT-MERGE-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: br i1 [[TMP1]], label %[[HANDLER_ADD_OVERFLOW_I:.*]], label %[[F_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-MERGE: [[HANDLER_ADD_OVERFLOW_I]]: +// MINRT-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-MERGE: [[F_EXIT]]: +// MINRT-MERGE-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: br i1 [[TMP3]], label %[[HANDLER_ADD_OVERFLOW_I2:.*]], label %[[G_EXIT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-MERGE: [[HANDLER_ADD_OVERFLOW_I2]]: +// MINRT-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-MERGE: [[G_EXIT]]: +// MINRT-MERGE-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP6:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP4]], i32 [[TMP5]]), !nosanitize [[META2]] +// MINRT-MERGE-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: br i1 [[TMP7]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// MINRT-MERGE: [[HANDLER_ADD_OVERFLOW]]: +// MINRT-MERGE-NEXT: tail call void @__ubsan_handle_add_overflow_minimal_abort() #[[ATTR4]], !nosanitize [[META2]] +// MINRT-MERGE-NEXT: unreachable, !nosanitize [[META2]] +// MINRT-MERGE: [[CONT]]: +// MINRT-MERGE-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META2]] +// MINRT-MERGE-NEXT: ret i32 [[TMP8]] // int m(int x, int y) { return f(x) + g(y); } -//. -// CHECK: attributes #[[ATTR4]] = { nomerge noreturn nounwind } + +// TRAP-MERGE: attributes #[[ATTR4]] = { noreturn nounwind } +// HANDLER-MERGE: attributes #[[ATTR4]] = { noreturn nounwind } +// MINRT-MERGE: attributes #[[ATTR4]] = { noreturn nounwind } + +// TRAP-NOMERGE: attributes #[[ATTR4]] = { nomerge noreturn nounwind } +// HANDLER-NOMERGE: attributes #[[ATTR4]] = { nomerge noreturn nounwind } +// MINRT-NOMERGE: attributes #[[ATTR4]] = { nomerge noreturn nounwind } diff --git a/clang/test/CodeGenCUDA/amdgpu-kernel-arg-pointer-type.cu b/clang/test/CodeGenCUDA/amdgpu-kernel-arg-pointer-type.cu index 334b33c872bbc..fab87aac18310 100644 --- a/clang/test/CodeGenCUDA/amdgpu-kernel-arg-pointer-type.cu +++ b/clang/test/CodeGenCUDA/amdgpu-kernel-arg-pointer-type.cu @@ -432,7 +432,7 @@ __global__ void kernel4(struct S s) { // CHECK-SPIRV-NEXT: ret void // // OPT-LABEL: define dso_local amdgpu_kernel void @_Z7kernel5P1S( -// OPT-SAME: ptr addrspace(1) nocapture noundef readonly [[S_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// OPT-SAME: ptr addrspace(1) nocapture noundef readonly [[S_COERCE:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] { // OPT-NEXT: [[ENTRY:.*:]] // OPT-NEXT: [[TMP0:%.*]] = load ptr, ptr addrspace(1) [[S_COERCE]], align 8 // OPT-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4 diff --git a/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp b/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp index 0cdc3b32521ff..a2cc9f30f026a 100644 --- a/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp +++ b/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp @@ -57,8 +57,8 @@ void run_foo_tml() { // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 9007199254806528 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 9007199254806528 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 9007199254806784 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 9007199254806784 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: @@ -77,8 +77,8 @@ void run_foo_tml() { // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 9007199254806528 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 9007199254806528 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 9007199254806784 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 9007199254806784 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: @@ -173,16 +173,16 @@ void run_foo_tml() { // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 36591746972385280 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 36591746972385280 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 36596145153180416 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 36596145153180416 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: // CHECK-NEXT: ret ptr @_ZN7MyClassIssE7foo_tmlEv._Msme-f64f64Mssbs // CHECK: [[RESOLVER_ELSE]]: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16777216 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16777216 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16777472 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16777472 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label %[[RESOLVER_RETURN1:.*]], label %[[RESOLVER_ELSE2:.*]] // CHECK: [[RESOLVER_RETURN1]]: @@ -222,16 +222,16 @@ void run_foo_tml() { // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 36591746972385280 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 36591746972385280 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 36596145153180416 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 36596145153180416 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: // CHECK-NEXT: ret ptr @_ZN7MyClassIisE7foo_tmlEv._Msme-f64f64Mssbs // CHECK: [[RESOLVER_ELSE]]: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16777216 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16777216 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16777472 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16777472 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label %[[RESOLVER_RETURN1:.*]], label %[[RESOLVER_ELSE2:.*]] // CHECK: [[RESOLVER_RETURN1]]: diff --git a/clang/test/CodeGenCXX/attr-target-version.cpp b/clang/test/CodeGenCXX/attr-target-version.cpp index 0fd9bc33df809..b6ba07ed29504 100644 --- a/clang/test/CodeGenCXX/attr-target-version.cpp +++ b/clang/test/CodeGenCXX/attr-target-version.cpp @@ -235,8 +235,8 @@ int bar() { // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 36028797153181696 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 36028797153181696 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 36033195199759104 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 36033195199759104 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: @@ -249,8 +249,8 @@ int bar() { // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 134217760 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 134217760 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 134218528 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 134218528 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: @@ -271,8 +271,8 @@ int bar() { // CHECK-NEXT: ret ptr @_ZN7MyClass3gooEi._Mcrc // CHECK: [[RESOLVER_ELSE]]: // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16 -// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 784 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 784 // CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] // CHECK-NEXT: br i1 [[TMP7]], label %[[RESOLVER_RETURN1:.*]], label %[[RESOLVER_ELSE2:.*]] // CHECK: [[RESOLVER_RETURN1]]: @@ -285,8 +285,8 @@ int bar() { // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073741824 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073741824 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073807616 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073807616 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: @@ -299,8 +299,8 @@ int bar() { // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 65536 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 65536 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 65792 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 65792 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: diff --git a/clang/test/CodeGenCXX/catch-undef-behavior.cpp b/clang/test/CodeGenCXX/catch-undef-behavior.cpp index a985183129911..419d1292551a0 100644 --- a/clang/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/clang/test/CodeGenCXX/catch-undef-behavior.cpp @@ -734,6 +734,6 @@ void ThisAlign::this_align_lambda_2() { p(); } -// CHECK: attributes [[NR_NUW]] = { noreturn nounwind } +// CHECK: attributes [[NR_NUW]] = { nomerge noreturn nounwind } // CHECK-FUNCSAN: ![[FUNCSAN]] = !{i32 -1056584962, i32 -1000226989} diff --git a/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp b/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp index 1c8835a3986ea..8a78463d3a495 100644 --- a/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp +++ b/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp @@ -31,7 +31,6 @@ void test_lambda() { //CHECK: define dso_local void @{{.*}}test_lambda{{.*}}() #0 { //CHECK: entry: //CHECK: %agg.tmp = alloca %class.anon, align 1 -//CHECK: %ref.tmp = alloca %class.anon, align 1 //CHECK: %call = call noundef i32 @"_ZZ11test_lambdavENH3$_0clIS_EEiT_"() //CHECK: ret void //CHECK: } diff --git a/clang/test/CodeGenCXX/default-arguments.cpp b/clang/test/CodeGenCXX/default-arguments.cpp index 215bcd882e962..2459ef1ad41fc 100644 --- a/clang/test/CodeGenCXX/default-arguments.cpp +++ b/clang/test/CodeGenCXX/default-arguments.cpp @@ -12,6 +12,17 @@ void g() { } } +namespace GH113324 { +struct S1 { + friend void f(S1, int = 42) {} +}; + +void test() { + S1 s1; + f(s1); +} +}; + struct A1 { A1(); ~A1(); diff --git a/clang/test/CodeGenCXX/ext-int.cpp b/clang/test/CodeGenCXX/ext-int.cpp index 97b5d6ce16b88..f470398ec2095 100644 --- a/clang/test/CodeGenCXX/ext-int.cpp +++ b/clang/test/CodeGenCXX/ext-int.cpp @@ -549,24 +549,6 @@ void Shift(_BitInt(28) Ext, _BitInt(65) LargeExt, int i) { // CHECK: ashr i65 {{.+}}, %[[PROMO]] } -void ComplexTest(_Complex _BitInt(12) first, _Complex _BitInt(33) second) { - // LIN: define{{.*}} void @_Z11ComplexTestCDB12_CDB33_ - // WIN: define dso_local void @"?ComplexTest@@YAXU?$_Complex@U?$_BitInt@$0M@@__clang@@@__clang@@U?$_Complex@U?$_BitInt@$0CB@@__clang@@@2@@Z" - first + second; - // CHECK: %[[FIRST_REALP:.+]] = getelementptr inbounds nuw { i12, i12 }, ptr %{{.+}}, i32 0, i32 0 - // CHECK: %[[FIRST_REAL:.+]] = load i12, ptr %[[FIRST_REALP]] - // CHECK: %[[FIRST_IMAGP:.+]] = getelementptr inbounds nuw { i12, i12 }, ptr %{{.+}}, i32 0, i32 1 - // CHECK: %[[FIRST_IMAG:.+]] = load i12, ptr %[[FIRST_IMAGP]] - // CHECK: %[[FIRST_REAL_CONV:.+]] = sext i12 %[[FIRST_REAL]] - // CHECK: %[[FIRST_IMAG_CONV:.+]] = sext i12 %[[FIRST_IMAG]] - // CHECK: %[[SECOND_REALP:.+]] = getelementptr inbounds nuw { i33, i33 }, ptr %{{.+}}, i32 0, i32 0 - // CHECK: %[[SECOND_REAL:.+]] = load i33, ptr %[[SECOND_REALP]] - // CHECK: %[[SECOND_IMAGP:.+]] = getelementptr inbounds nuw { i33, i33 }, ptr %{{.+}}, i32 0, i32 1 - // CHECK: %[[SECOND_IMAG:.+]] = load i33, ptr %[[SECOND_IMAGP]] - // CHECK: %[[REAL:.+]] = add i33 %[[FIRST_REAL_CONV]], %[[SECOND_REAL]] - // CHECK: %[[IMAG:.+]] = add i33 %[[FIRST_IMAG_CONV]], %[[SECOND_IMAG]] -} - typedef _BitInt(64) vint64_t16 __attribute__((vector_size(16))); void VectorTest(vint64_t16 first, vint64_t16 second) { // LIN: define{{.*}} void @_Z10VectorTestDv2_DB64_S0_(<2 x i64> %{{.+}}, <2 x i64> %{{.+}}) diff --git a/clang/test/CodeGenCXX/fmv-namespace.cpp b/clang/test/CodeGenCXX/fmv-namespace.cpp index d61f6dc9a7071..1a76ee0356524 100644 --- a/clang/test/CodeGenCXX/fmv-namespace.cpp +++ b/clang/test/CodeGenCXX/fmv-namespace.cpp @@ -76,8 +76,8 @@ __attribute((target_version("mops"))) int bar() { return 1; } // CHECK-NEXT: [[RESOLVER_ENTRY:.*:]] // CHECK-NEXT: call void @__init_cpu_features_resolver() // CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 -// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073741824 -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073741824 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073807616 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073807616 // CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]] // CHECK: [[RESOLVER_RETURN]]: diff --git a/clang/test/CodeGenCXX/matrix-type.cpp b/clang/test/CodeGenCXX/matrix-type.cpp index 1a5e5dba2978c..c3a299e7feee8 100644 --- a/clang/test/CodeGenCXX/matrix-type.cpp +++ b/clang/test/CodeGenCXX/matrix-type.cpp @@ -368,3 +368,36 @@ void test_use_matrix_2() { selector<2> r5 = use_matrix_3(m1); } + +// CHECK-LABEL: define void @_Z22test_pseudo_destructorv() +// CHECK-NEXT: entry: +// CHECK-NEXT: %a = alloca [25 x double], align 8 +// CHECK-NEXT: %b = alloca [12 x float], align 4 +// CHECK-NEXT: %0 = load <25 x double>, ptr %a, align 8 +// CHECK-NEXT: call void @_Z17pseudo_destructorIu11matrix_typeILm5ELm5EdEEvT_(<25 x double> %0) +// CHECK-NEXT: %1 = load <12 x float>, ptr %b, align 4 +// CHECK-NEXT: call void @_Z17pseudo_destructorIu11matrix_typeILm3ELm4EfEEvT_(<12 x float> %1) +// CHECK-NEXT: ret void + +// CHECK-LABEL: define linkonce_odr void @_Z17pseudo_destructorIu11matrix_typeILm5ELm5EdEEvT_(<25 x double> %t) +// CHECK-NEXT: entry: +// CHECK-NEXT: %t.addr = alloca [25 x double], align 8 +// CHECK-NEXT: store <25 x double> %t, ptr %t.addr, align 8 +// CHECK-NEXT: ret void + +// CHECK-LABEL: define linkonce_odr void @_Z17pseudo_destructorIu11matrix_typeILm3ELm4EfEEvT_(<12 x float> %t) +// CHECK-NEXT: entry: +// CHECK-NEXT: %t.addr = alloca [12 x float], align 4 +// CHECK-NEXT: store <12 x float> %t, ptr %t.addr, align 4 +// CHECK-NEXT: ret void +template +void pseudo_destructor(T t) { + t.~T(); +} + +void test_pseudo_destructor() { + dx5x5_t a; + fx3x4_t b; + pseudo_destructor(a); + pseudo_destructor(b); +} diff --git a/clang/test/CodeGenCXX/matrix-vector-bit-int.cpp b/clang/test/CodeGenCXX/matrix-vector-bit-int.cpp new file mode 100644 index 0000000000000..040615f417085 --- /dev/null +++ b/clang/test/CodeGenCXX/matrix-vector-bit-int.cpp @@ -0,0 +1,98 @@ +// RUN: %clang_cc1 -fenable-matrix %s -emit-llvm -triple x86_64-unknown-linux -disable-llvm-passes -o - -std=c++11 | FileCheck %s + +using i8x3 = _BitInt(8) __attribute__((ext_vector_type(3))); +using i8x3x3 = _BitInt(8) __attribute__((matrix_type(3, 3))); +using i32x3 = _BitInt(32) __attribute__((ext_vector_type(3))); +using i32x3x3 = _BitInt(32) __attribute__((matrix_type(3, 3))); +using i512x3 = _BitInt(512) __attribute__((ext_vector_type(3))); +using i512x3x3 = _BitInt(512) __attribute__((matrix_type(3, 3))); + +// CHECK-LABEL: define dso_local i32 @_Z2v1Dv3_DB8_(i32 %a.coerce) +i8x3 v1(i8x3 a) { + // CHECK-NEXT: entry: + // CHECK-NEXT: %retval = alloca <3 x i8>, align 4 + // CHECK-NEXT: %a = alloca <3 x i8>, align 4 + // CHECK-NEXT: %a.addr = alloca <3 x i8>, align 4 + // CHECK-NEXT: store i32 %a.coerce, ptr %a, align 4 + // CHECK-NEXT: %loadVec4 = load <4 x i8>, ptr %a, align 4 + // CHECK-NEXT: %a1 = shufflevector <4 x i8> %loadVec4, <4 x i8> poison, <3 x i32> + // CHECK-NEXT: %extractVec = shufflevector <3 x i8> %a1, <3 x i8> poison, <4 x i32> + // CHECK-NEXT: store <4 x i8> %extractVec, ptr %a.addr, align 4 + // CHECK-NEXT: %loadVec42 = load <4 x i8>, ptr %a.addr, align 4 + // CHECK-NEXT: %extractVec3 = shufflevector <4 x i8> %loadVec42, <4 x i8> poison, <3 x i32> + // CHECK-NEXT: %loadVec44 = load <4 x i8>, ptr %a.addr, align 4 + // CHECK-NEXT: %extractVec5 = shufflevector <4 x i8> %loadVec44, <4 x i8> poison, <3 x i32> + // CHECK-NEXT: %add = add <3 x i8> %extractVec3, %extractVec5 + // CHECK-NEXT: store <3 x i8> %add, ptr %retval, align 4 + // CHECK-NEXT: %0 = load i32, ptr %retval, align 4 + // CHECK-NEXT: ret i32 %0 + return a + a; +} + +// CHECK-LABEL: define dso_local noundef <3 x i32> @_Z2v2Dv3_DB32_(<3 x i32> noundef %a) +i32x3 v2(i32x3 a) { + // CHECK-NEXT: entry: + // CHECK-NEXT: %a.addr = alloca <3 x i32>, align 16 + // CHECK-NEXT: %extractVec = shufflevector <3 x i32> %a, <3 x i32> poison, <4 x i32> + // CHECK-NEXT: store <4 x i32> %extractVec, ptr %a.addr, align 16 + // CHECK-NEXT: %loadVec4 = load <4 x i32>, ptr %a.addr, align 16 + // CHECK-NEXT: %extractVec1 = shufflevector <4 x i32> %loadVec4, <4 x i32> poison, <3 x i32> + // CHECK-NEXT: %loadVec42 = load <4 x i32>, ptr %a.addr, align 16 + // CHECK-NEXT: %extractVec3 = shufflevector <4 x i32> %loadVec42, <4 x i32> poison, <3 x i32> + // CHECK-NEXT: %add = add <3 x i32> %extractVec1, %extractVec3 + // CHECK-NEXT: ret <3 x i32> %add + return a + a; +} + +// CHECK-LABEL: define dso_local noundef <3 x i512> @_Z2v3Dv3_DB512_(ptr noundef byval(<3 x i512>) align 256 %0) +i512x3 v3(i512x3 a) { + // CHECK-NEXT: entry: + // CHECK-NEXT: %a.addr = alloca <3 x i512>, align 256 + // CHECK-NEXT: %loadVec4 = load <4 x i512>, ptr %0, align 256 + // CHECK-NEXT: %a = shufflevector <4 x i512> %loadVec4, <4 x i512> poison, <3 x i32> + // CHECK-NEXT: %extractVec = shufflevector <3 x i512> %a, <3 x i512> poison, <4 x i32> + // CHECK-NEXT: store <4 x i512> %extractVec, ptr %a.addr, align 256 + // CHECK-NEXT: %loadVec41 = load <4 x i512>, ptr %a.addr, align 256 + // CHECK-NEXT: %extractVec2 = shufflevector <4 x i512> %loadVec41, <4 x i512> poison, <3 x i32> + // CHECK-NEXT: %loadVec43 = load <4 x i512>, ptr %a.addr, align 256 + // CHECK-NEXT: %extractVec4 = shufflevector <4 x i512> %loadVec43, <4 x i512> poison, <3 x i32> + // CHECK-NEXT: %add = add <3 x i512> %extractVec2, %extractVec4 + // CHECK-NEXT: ret <3 x i512> %add + return a + a; +} + +// CHECK-LABEL: define dso_local noundef <9 x i8> @_Z2m1u11matrix_typeILm3ELm3EDB8_E(<9 x i8> noundef %a) +i8x3x3 m1(i8x3x3 a) { + // CHECK-NEXT: entry: + // CHECK-NEXT: %a.addr = alloca [9 x i8], align 1 + // CHECK-NEXT: store <9 x i8> %a, ptr %a.addr, align 1 + // CHECK-NEXT: %0 = load <9 x i8>, ptr %a.addr, align 1 + // CHECK-NEXT: %1 = load <9 x i8>, ptr %a.addr, align 1 + // CHECK-NEXT: %2 = add <9 x i8> %0, %1 + // CHECK-NEXT: ret <9 x i8> %2 + return a + a; +} + +// CHECK-LABEL: define dso_local noundef <9 x i32> @_Z2m2u11matrix_typeILm3ELm3EDB32_E(<9 x i32> noundef %a) +i32x3x3 m2(i32x3x3 a) { + // CHECK-NEXT: entry: + // CHECK-NEXT: %a.addr = alloca [9 x i32], align 4 + // CHECK-NEXT: store <9 x i32> %a, ptr %a.addr, align 4 + // CHECK-NEXT: %0 = load <9 x i32>, ptr %a.addr, align 4 + // CHECK-NEXT: %1 = load <9 x i32>, ptr %a.addr, align 4 + // CHECK-NEXT: %2 = add <9 x i32> %0, %1 + // CHECK-NEXT: ret <9 x i32> %2 + return a + a; +} + +// CHECK-LABEL: define dso_local noundef <9 x i512> @_Z2m3u11matrix_typeILm3ELm3EDB512_E(<9 x i512> noundef %a) +i512x3x3 m3(i512x3x3 a) { + // CHECK-NEXT: entry: + // CHECK-NEXT: %a.addr = alloca [9 x i512], align 8 + // CHECK-NEXT: store <9 x i512> %a, ptr %a.addr, align 8 + // CHECK-NEXT: %0 = load <9 x i512>, ptr %a.addr, align 8 + // CHECK-NEXT: %1 = load <9 x i512>, ptr %a.addr, align 8 + // CHECK-NEXT: %2 = add <9 x i512> %0, %1 + // CHECK-NEXT: ret <9 x i512> %2 + return a + a; +} diff --git a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp index 2ac1961465d8a..fc8a31e0350e5 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -647,7 +647,7 @@ void (Multiple::*convertB2FuncToMultiple(void (B2::*mp)()))() { // CHECK: br i1 %{{.*}} label %{{.*}}, label %{{.*}} // // memptr.convert: ; preds = %entry -// CHECK: insertvalue { ptr, i32 } undef, ptr %[[mp]], 0 +// CHECK: insertvalue { ptr, i32 } poison, ptr %[[mp]], 0 // CHECK: insertvalue { ptr, i32 } %{{.*}}, i32 4, 1 // CHECK: br label // @@ -705,7 +705,7 @@ void (D::*convertCToD(void (C::*mp)()))() { // CHECK: %[[nv_adj:.*]] = select i1 %[[is_nvbase]], i32 %[[nv_disp]], i32 0 // CHECK: %[[dst_adj:.*]] = select i1 %[[is_nvbase]], i32 4, i32 0 // CHECK: %[[adj:.*]] = sub nsw i32 %[[nv_adj]], %[[dst_adj]] -// CHECK: insertvalue { ptr, i32, i32 } undef, ptr {{.*}}, 0 +// CHECK: insertvalue { ptr, i32, i32 } poison, ptr {{.*}}, 0 // CHECK: insertvalue { ptr, i32, i32 } {{.*}}, i32 %[[adj]], 1 // CHECK: insertvalue { ptr, i32, i32 } {{.*}}, i32 {{.*}}, 2 // CHECK: br label diff --git a/clang/test/CodeGenHLSL/builtins/AppendStructuredBuffer-elementtype.hlsl b/clang/test/CodeGenHLSL/builtins/AppendStructuredBuffer-elementtype.hlsl index 1e8aae588fc33..85face8eaeb6c 100644 --- a/clang/test/CodeGenHLSL/builtins/AppendStructuredBuffer-elementtype.hlsl +++ b/clang/test/CodeGenHLSL/builtins/AppendStructuredBuffer-elementtype.hlsl @@ -18,7 +18,8 @@ struct MyStruct { // DXIL: %"class.hlsl::AppendStructuredBuffer.9" = type { target("dx.RawBuffer", <3 x i32>, 1, 0) // DXIL: %"class.hlsl::AppendStructuredBuffer.10" = type { target("dx.RawBuffer", <2 x half>, 1, 0) // DXIL: %"class.hlsl::AppendStructuredBuffer.11" = type { target("dx.RawBuffer", <3 x float>, 1, 0) -// DXIL: %"class.hlsl::AppendStructuredBuffer.12" = type { target("dx.RawBuffer", %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] }, 1, 0) +// DXIL: %"class.hlsl::AppendStructuredBuffer.12" = type { target("dx.RawBuffer", %struct.MyStruct, 1, 0) +// DXIL: %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] } AppendStructuredBuffer BufI16; AppendStructuredBuffer BufU16; diff --git a/clang/test/CodeGenHLSL/builtins/ConsumeStructuredBuffer-elementtype.hlsl b/clang/test/CodeGenHLSL/builtins/ConsumeStructuredBuffer-elementtype.hlsl index f8574c6460d4e..5ed9e9ad8160f 100644 --- a/clang/test/CodeGenHLSL/builtins/ConsumeStructuredBuffer-elementtype.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ConsumeStructuredBuffer-elementtype.hlsl @@ -18,7 +18,8 @@ struct MyStruct { // DXIL: %"class.hlsl::ConsumeStructuredBuffer.9" = type { target("dx.RawBuffer", <3 x i32>, 1, 0) // DXIL: %"class.hlsl::ConsumeStructuredBuffer.10" = type { target("dx.RawBuffer", <2 x half>, 1, 0) // DXIL: %"class.hlsl::ConsumeStructuredBuffer.11" = type { target("dx.RawBuffer", <3 x float>, 1, 0) -// DXIL: %"class.hlsl::ConsumeStructuredBuffer.12" = type { target("dx.RawBuffer", %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] }, 1, 0) +// DXIL: %"class.hlsl::ConsumeStructuredBuffer.12" = type { target("dx.RawBuffer", %struct.MyStruct, 1, 0) +// DXIL: %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] } ConsumeStructuredBuffer BufI16; ConsumeStructuredBuffer BufU16; diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl new file mode 100644 index 0000000000000..d834a22917c1f --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -triple spirv-vulkan-compute -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV + +// CHECK-SPIRV: %"class.hlsl::RWBuffer" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 0) } +// CHECK-DXIL: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 0, 0) } +RWBuffer Buf : register(u5, space3); + +[shader("compute")] +[numthreads(1, 1, 1)] +void main() { +// CHECK: define void @main() +// CHECK-NEXT: entry: + +// CHECK-SPIRV-NEXT: %Buf_h.i = tail call target("spirv.Image", float, 5, 2, 0, 0, 2, 0) @llvm.spv.handle.fromBinding.tspirv.Image_f32_5_2_0_0_2_0t(i32 3, i32 5, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: store target("spirv.Image", float, 5, 2, 0, 0, 2, 0) %Buf_h.i, ptr @Buf, align 8 + +// CHECK-DXIL-NEXT: %Buf_h.i = tail call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h.i, ptr @Buf, align 4 + +// CHECK-NEXT: ret void +} diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-subscript.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-subscript.hlsl index 8ce8417772530..4428b77dd9ec8 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-subscript.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-subscript.hlsl @@ -6,9 +6,16 @@ RWBuffer Out; [numthreads(1,1,1)] void main(unsigned GI : SV_GroupIndex) { // CHECK: define void @main() + // CHECK: %[[INPTR:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) // CHECK: %[[LOAD:.*]] = load i32, ptr %[[INPTR]] // CHECK: %[[OUTPTR:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) // CHECK: store i32 %[[LOAD]], ptr %[[OUTPTR]] Out[GI] = In[GI]; + + // CHECK: %[[INPTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) + // CHECK: %[[LOAD:.*]] = load i32, ptr %[[INPTR]] + // CHECK: %[[OUTPTR:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) + // CHECK: store i32 %[[LOAD]], ptr %[[OUTPTR]] + Out[GI] = In.Load(GI); } diff --git a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedStructuredBuffer-elementtype.hlsl b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedStructuredBuffer-elementtype.hlsl index 7057988de24b3..68d626de689f2 100644 --- a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedStructuredBuffer-elementtype.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedStructuredBuffer-elementtype.hlsl @@ -18,7 +18,7 @@ struct MyStruct { // DXIL: %"class.hlsl::RasterizerOrderedStructuredBuffer.9" = type { target("dx.RawBuffer", <3 x i32>, 1, 1) } // DXIL: %"class.hlsl::RasterizerOrderedStructuredBuffer.10" = type { target("dx.RawBuffer", <2 x half>, 1, 1) } // DXIL: %"class.hlsl::RasterizerOrderedStructuredBuffer.11" = type { target("dx.RawBuffer", <3 x float>, 1, 1) } -// DXIL: %"class.hlsl::RasterizerOrderedStructuredBuffer.12" = type { target("dx.RawBuffer", %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] }, 1, 1) } +// DXIL: %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] } RasterizerOrderedStructuredBuffer BufI16; RasterizerOrderedStructuredBuffer BufU16; diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl index b7986ae7dda1c..53abdc71bdd4b 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl @@ -5,21 +5,45 @@ RWStructuredBuffer RWSB1 : register(u0); RWStructuredBuffer RWSB2 : register(u1); +AppendStructuredBuffer ASB : register(u2); +ConsumeStructuredBuffer CSB : register(u3); // CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } -export void TestIncrementCounter() { - RWSB1.IncrementCounter(); +export int TestIncrementCounter() { + return RWSB1.IncrementCounter(); } -// CHECK: define void @_Z20TestIncrementCounterv() -// CHECK-DXIL: call i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i8 1) +// CHECK: define noundef i32 @_Z20TestIncrementCounterv() +// CHECK-DXIL: %[[INDEX:.*]] = call i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i8 1) +// CHECK-DXIL: ret i32 %[[INDEX]] +export int TestDecrementCounter() { + return RWSB2.DecrementCounter(); +} + +// CHECK: define noundef i32 @_Z20TestDecrementCounterv() +// CHECK-DXIL: %[[INDEX:.*]] = call i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i8 -1) +// CHECK-DXIL: ret i32 %[[INDEX]] + +export void TestAppend(float value) { + ASB.Append(value); +} + +// CHECK: define void @_Z10TestAppendf(float noundef %value) +// CHECK-DXIL: %[[VALUE:.*]] = load float, ptr %value.addr, align 4 +// CHECK-DXIL: %[[INDEX:.*]] = call i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i8 1) +// CHECK-DXIL: %[[RESPTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i32 %[[INDEX]]) +// CHECK-DXIL: store float %[[VALUE]], ptr %[[RESPTR]], align 4 -export void TestDecrementCounter() { - RWSB2.DecrementCounter(); +export float TestConsume() { + return CSB.Consume(); } -// CHECK: define void @_Z20TestDecrementCounterv() -// CHECK-DXIL: call i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i8 -1) +// CHECK: define noundef float @_Z11TestConsumev() +// CHECK-DXIL: %[[INDEX:.*]] = call i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %1, i8 -1) +// CHECK-DXIL: %[[RESPTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %0, i32 %[[INDEX]]) +// CHECK-DXIL: %[[VALUE:.*]] = load float, ptr %[[RESPTR]], align 4 +// CHECK-DXIL: ret float %[[VALUE]] // CHECK: declare i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8) +// CHECK: declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i32) diff --git a/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl b/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl new file mode 100644 index 0000000000000..df530a9cee561 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/WaveActiveAllTrue.hlsl @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -finclude-default-header -fnative-half-type -triple \ +// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN: %clang_cc1 -finclude-default-header -fnative-half-type -triple \ +// RUN: spirv-pc-vulkan-compute %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV + +// Test basic lowering to runtime function call for int values. + +// CHECK-LABEL: define {{.*}}test +bool test(bool p1) { + // CHECK-SPIRV: %[[#entry_tok0:]] = call token @llvm.experimental.convergence.entry() + // CHECK-SPIRV: %[[RET:.*]] = call spir_func i1 @llvm.spv.wave.all(i1 %{{[a-zA-Z0-9]+}}) [ "convergencectrl"(token %[[#entry_tok0]]) ] + // CHECK-DXIL: %[[RET:.*]] = call i1 @llvm.dx.wave.all(i1 %{{[a-zA-Z0-9]+}}) + // CHECK: ret i1 %[[RET]] + return WaveActiveAllTrue(p1); +} diff --git a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl index 7de62a363eedb..fda034ce7f203 100644 --- a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl +++ b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl @@ -3,7 +3,8 @@ using handle_float_t = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]]; // CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", <4 x float>, 1, 0, 0) -// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] }, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", %struct.MyStruct, 0, 0) +// CHECK: %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] } // CHECK: define void @_Z2faU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a) // CHECK: call void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %0) diff --git a/clang/test/CodeGenHLSL/resource-bindings.hlsl b/clang/test/CodeGenHLSL/resource-bindings.hlsl index bfec90e1871f8..d4e6308210653 100644 --- a/clang/test/CodeGenHLSL/resource-bindings.hlsl +++ b/clang/test/CodeGenHLSL/resource-bindings.hlsl @@ -15,5 +15,5 @@ struct S { int i; }; -// CHECK: %T3S0_h = call target("dx.RawBuffer", %struct.S = type { <4 x float>, i32, [12 x i8] }, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 3, i32 1, i32 0, i1 false) +// CHECK: %T3S0_h = call target("dx.RawBuffer", %struct.S, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 3, i32 1, i32 0, i1 false) StructuredBuffer T3S0 : register(t3); diff --git a/clang/test/CodeGenHLSL/semantics/SV_GroupThreadID.hlsl b/clang/test/CodeGenHLSL/semantics/SV_GroupThreadID.hlsl new file mode 100644 index 0000000000000..3d347b973f39c --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/SV_GroupThreadID.hlsl @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv + +// Make sure SV_GroupThreadID translated into dx.thread.id.in.group for directx target and spv.thread.id.in.group for spirv target. + +// CHECK: define void @foo() +// CHECK: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0) +// CHECK-DXIL: call void @{{.*}}foo{{.*}}(i32 %[[#ID]]) +// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(i32 %[[#ID]]) +[shader("compute")] +[numthreads(8,8,1)] +void foo(uint Idx : SV_GroupThreadID) {} + +// CHECK: define void @bar() +// CHECK: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0) +// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0 +// CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1) +// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 +// CHECK-DXIL: call void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]]) +// CHECK-SPIRV: call spir_func void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]]) +[shader("compute")] +[numthreads(8,8,1)] +void bar(uint2 Idx : SV_GroupThreadID) {} + +// CHECK: define void @test() +// CHECK: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0) +// CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0 +// CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1) +// CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 +// CHECK: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 2) +// CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2 +// CHECK-DXIL: call void @{{.*}}test{{.*}}(<3 x i32> %[[#ID_XYZ]]) +// CHECK-SPIRV: call spir_func void @{{.*}}test{{.*}}(<3 x i32> %[[#ID_XYZ]]) +[shader("compute")] +[numthreads(8,8,1)] +void test(uint3 Idx : SV_GroupThreadID) {} diff --git a/clang/test/CodeGenObjC/arc-ternary-op.m b/clang/test/CodeGenObjC/arc-ternary-op.m index d633851ac7617..4a3c00c9807a9 100644 --- a/clang/test/CodeGenObjC/arc-ternary-op.m +++ b/clang/test/CodeGenObjC/arc-ternary-op.m @@ -67,7 +67,7 @@ void test1(int cond) { // CHECK: [[T0:%.*]] = load ptr, ptr [[ARG]] // CHECK-NEXT: store ptr [[T0]], ptr [[TEMP1]] // CHECK-NEXT: br label - // CHECK: [[W:%.*]] = phi ptr [ [[T0]], {{%.*}} ], [ undef, {{%.*}} ] + // CHECK: [[W:%.*]] = phi ptr [ [[T0]], {{%.*}} ], [ poison, {{%.*}} ] // CHECK-NEXT: call void @test1_sink(ptr noundef [[T1]]) // CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[ARG]], null // CHECK-NEXT: br i1 [[T0]], diff --git a/clang/test/CodeGenObjCXX/arc.mm b/clang/test/CodeGenObjCXX/arc.mm index 7a6de17e2baa0..7883378b33828 100644 --- a/clang/test/CodeGenObjCXX/arc.mm +++ b/clang/test/CodeGenObjCXX/arc.mm @@ -75,7 +75,7 @@ void test34(int cond) { // CHECK: [[T0:%.*]] = load ptr, ptr [[ARG]] // CHECK-NEXT: store ptr [[T0]], ptr [[TEMP1]] // CHECK-NEXT: br label - // CHECK: [[W0:%.*]] = phi ptr [ [[T0]], {{%.*}} ], [ undef, {{%.*}} ] + // CHECK: [[W0:%.*]] = phi ptr [ [[T0]], {{%.*}} ], [ poison, {{%.*}} ] // CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(ptr noundef [[T1]]) // CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[ARG]], null // CHECK-NEXT: br i1 [[T0]], diff --git a/clang/test/CodeGenOpenCL/opencl_types.cl b/clang/test/CodeGenOpenCL/opencl_types.cl index 7cab853c76d9a..aac3492b7a9e8 100644 --- a/clang/test/CodeGenOpenCL/opencl_types.cl +++ b/clang/test/CodeGenOpenCL/opencl_types.cl @@ -64,12 +64,90 @@ kernel void foo(image1d_t img) { kernel void foo_ro_pipe(read_only pipe int p) {} // CHECK-SPIR: @foo_ro_pipe(target("spirv.Pipe", 0) %p) -// CHECK_AMDGCN: @foo_ro_pipe(ptr addrspace(1) %p) +// CHECK-AMDGCN: @foo_ro_pipe(ptr addrspace(1) %p) kernel void foo_wo_pipe(write_only pipe int p) {} // CHECK-SPIR: @foo_wo_pipe(target("spirv.Pipe", 1) %p) -// CHECK_AMDGCN: @foo_wo_pipe(ptr addrspace(1) %p) +// CHECK-AMDGCN: @foo_wo_pipe(ptr addrspace(1) %p) void __attribute__((overloadable)) bad1(image1d_t b, image2d_t c, image2d_t d) {} // CHECK-SPIR-LABEL: @{{_Z4bad114ocl_image1d_ro14ocl_image2d_roS0_|"\\01\?bad1@@\$\$J0YAXPAUocl_image1d_ro@@PAUocl_image2d_ro@@1@Z"}} // CHECK-AMDGCN-LABEL: @{{_Z4bad114ocl_image1d_ro14ocl_image2d_roS0_|"\\01\?bad1@@\$\$J0YAXPAUocl_image1d_ro@@PAUocl_image2d_ro@@1@Z"}}(ptr addrspace(4){{.*}}ptr addrspace(4){{.*}}ptr addrspace(4){{.*}}) + + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test20ocl_image1d_array_ro(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_only image1d_array_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test20ocl_image1d_array_wo(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(write_only image1d_array_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test20ocl_image1d_array_rw(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_write image1d_array_t img) {} + + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test21ocl_image1d_buffer_ro(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_only image1d_buffer_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test21ocl_image1d_buffer_wo(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(write_only image1d_buffer_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test21ocl_image1d_buffer_rw(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_write image1d_buffer_t img) {} + + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test20ocl_image2d_array_ro(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_only image2d_array_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test20ocl_image2d_array_wo(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(write_only image2d_array_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test20ocl_image2d_array_rw(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_write image2d_array_t img) {} + + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image1d_ro(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_only image1d_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image1d_wo(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(write_only image1d_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image1d_rw(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_write image1d_t img) {} + + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image2d_ro(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_only image2d_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image2d_wo(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(write_only image2d_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image2d_rw(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_write image2d_t img) {} + + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image3d_ro(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_only image3d_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image3d_wo(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(write_only image3d_t img) {} + +// CHECK-AMDGCN: define dso_local void @_Z20img_type_mangle_test14ocl_image3d_rw(ptr addrspace(4) %img) +__attribute__((overloadable)) +void img_type_mangle_test(read_write image3d_t img) {} diff --git a/clang/test/CoverageMapping/switch.cpp b/clang/test/CoverageMapping/switch.cpp index a1fee644faaf0..db4cddbc6b941 100644 --- a/clang/test/CoverageMapping/switch.cpp +++ b/clang/test/CoverageMapping/switch.cpp @@ -2,13 +2,13 @@ // CHECK: foo void foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+11]]:2 = #0 - switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = 0, ((#0 - #2) - #3) + switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#2 + #3), ((#0 - #2) - #3) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+5]]:10 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = #2 - return; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, 0 + return; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE+1]]:3 = 0 case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #3 - break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, 0 + break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = #1 int x = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = #1 @@ -28,14 +28,14 @@ void bar(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+21]]:2 = #0 nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = 0, #2 // CHECK-NEXT: File 0, [[@LINE-1]]:5 -> [[@LINE-1]]:10 = 0 switch (i) // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+11]]:2 = #3 - case 1: // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = 0, (#3 - #5) + case 1: // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:11 -> [[@LINE-1]]:12 = #5, (#3 - #5) // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE+1]]:10 = #5 - nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #5, 0 + nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #5, (#3 - #5) // CHECK-NEXT: File 0, [[@LINE+1]]:3 -> [[@LINE+7]]:2 = #4 - switch (i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = 0, (#4 - #7) + switch (i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:11 -> [[@LINE]]:12 = #7, (#4 - #7) nop(); // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+2]]:10 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #7 - nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, 0 + nop(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, (#4 - #7) } nop(); // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = #6 } @@ -53,35 +53,35 @@ int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+39]]:2 = #0 int i = 0; switch(i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:13 -> [[@LINE+8]]:10 = 0 case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #2 - i = 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, 0 + i = 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #3 - i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, 0 + i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #4 - break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #4, 0 + break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #4, (#0 - #4) } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = #1 switch(i) { // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+27]]:2 = #1 case 0: // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+7]]:10 = 0 i = 1; // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE+1]]:10 = #6 - break; // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #6, 0 + break; // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #6, (#1 - #6) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:10 = #7 - i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, 0 + i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, (#1 - #7) default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = (#7 + #8) - break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #8, 0 + break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #8, (#1 - #8) } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = #5 // CHECK-NEXT: File 0, [[@LINE+1]]:3 -> [[@LINE+17]]:2 = #5 - switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = 0, ((((#5 - #10) - #11) - #12) - #13) + switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (((#10 + #11) + #12) + #13), ((((#5 - #10) - #11) - #12) - #13) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+8]]:11 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+7]]:11 = #10 - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #10, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #10, (#5 - #10) case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+5]]:11 = (#10 + #11) - i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #11, 0 + i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #11, (#5 - #11) case 3: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:11 = ((#10 + #11) + #12) - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #12, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #12, (#5 - #12) case 4: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = (((#10 + #11) + #12) + #13) - i = 99; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #13, 0 + i = 99; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #13, (#5 - #13) } foo(1); // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:11 = #9 @@ -95,10 +95,10 @@ int pr44011(int i) { // CHECK-NEXT: File 0, [[@LINE]]:20 -> {{.*}}:2 = #0 switch (i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+6]]:13 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 = #2 - return 0; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, 0 + return 0; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 = #3 - return 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #3, 0 + return 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #3, (#0 - #3) } } // A region for counter #1 is missing due to the missing return. @@ -106,17 +106,17 @@ int pr44011(int i) { // CHECK-NEXT: File 0, [[@LINE]]:20 -> {{.*}}:2 = #0 // FIXME: End location for "case 1" shouldn't point at the end of the switch. // CHECK: fallthrough int fallthrough(int i) { // CHECK-NEXT: File 0, [[@LINE]]:24 -> [[@LINE+14]]:2 = #0 - // CHECK-NEXT: Branch,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:11 = 0, ((((#0 - #2) - #3) - #4) - #5) + // CHECK-NEXT: Branch,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:11 = (((#2 + #3) + #4) + #5), ((((#0 - #2) - #3) - #4) - #5) switch(i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:13 -> [[@LINE+10]]:10 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+9]]:10 = #2 - i = 23; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, 0 + i = 23; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = (#2 + #3) - i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, 0 + i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0 case 3: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+4]]:10 = #4 - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4) case 4: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = (#4 + #5) - i = 99; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #5, 0 + i = 99; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #5, (#0 - #5) break; } } @@ -126,12 +126,12 @@ void abort(void) __attribute((noreturn)); int noret(int x) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+11]]:2 switch (x) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+8]]:14 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:12 - abort(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, 0 + abort(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, (#0 - #2) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:3 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 - return 5; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, 0 + return 5; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = 0 case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:14 - return 10; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, 0 + return 10; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4) } } diff --git a/clang/test/CoverageMapping/switchmacro.c b/clang/test/CoverageMapping/switchmacro.c index 0696e7490cdf9..4c98cc7d9403a 100644 --- a/clang/test/CoverageMapping/switchmacro.c +++ b/clang/test/CoverageMapping/switchmacro.c @@ -6,7 +6,7 @@ int foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> {{[0-9]+}}:2 = #0 switch (i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> {{[0-9]+}}:11 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> {{[0-9]+}}:11 = #2 - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, (#0 - #2) if (i == 1) // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:15 = #2 // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:9 -> [[@LINE-1]]:15 = #3, (#2 - #3) return 0; // CHECK: File 0, [[@LINE]]:7 -> [[@LINE]]:15 = #3 @@ -15,7 +15,7 @@ int foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> {{[0-9]+}}:2 = #0 // CHECK-NEXT: File 0, [[@LINE+1]]:8 -> {{[0-9]+}}:11 = (#2 - #3) FOO(1); case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:13 = ((#2 + #4) - #3) - // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, 0 + // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4) return 2; // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+4]]:3 = 0 // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:6 = 0 diff --git a/clang/test/Driver/config-file.c b/clang/test/Driver/config-file.c index e9a8555bcc8e4..e84d6dfca373a 100644 --- a/clang/test/Driver/config-file.c +++ b/clang/test/Driver/config-file.c @@ -85,9 +85,9 @@ //--- The linker input flags should be moved to the end of input list and appear only when linking. // RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg %s -lmylib -Wl,foo.a -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING -// RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -fopenmp %s -lmylib -Wl,foo.a -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING-LIBOMP-GOES-AFTER +// RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -fopenmp=libomp %s -lmylib -Wl,foo.a -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING-LIBOMP-GOES-AFTER // RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING -// RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -fopenmp -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING-OPENMP +// RUN: %clang --target=aarch64-unknown-linux-gnu --config %S/Inputs/config-l.cfg -fopenmp=libomp -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING-OPENMP // RUN: %clang --target=x86_64-pc-windows-msvc --config %S/Inputs/config-l.cfg %s -lmylib -Wl,foo.lib -### 2>&1 | FileCheck %s -check-prefix CHECK-LINKING-MSVC // RUN: %clang --target=x86_64-pc-windows-msvc --config %S/Inputs/config-l.cfg -S %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NOLINKING-MSVC // CHECK-LINKING: Configuration file: {{.*}}Inputs{{.}}config-l.cfg diff --git a/clang/test/Driver/config-file3.c b/clang/test/Driver/config-file3.c index a0b8062c60ce5..395c31ce04b6b 100644 --- a/clang/test/Driver/config-file3.c +++ b/clang/test/Driver/config-file3.c @@ -226,3 +226,26 @@ // // RUN: HOME=%S/Inputs/config %clang -### --config-user-dir=~ -v 2>&1 | FileCheck %s --check-prefix=CHECK-TILDE // CHECK-TILDE: User configuration file directory: {{.*}}/Inputs/config + +//--- Fallback to stripping OS versions +// +// RUN: touch %t/testdmode/x86_64-apple-darwin23.6.0-clang.cfg +// RUN: touch %t/testdmode/x86_64-apple-darwin23-clang.cfg +// RUN: touch %t/testdmode/x86_64-apple-darwin-clang.cfg +// RUN: %clang -target x86_64-apple-darwin23.6.0 --config-system-dir=%t/testdmode --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix DARWIN --implicit-check-not 'Configuration file:' +// +// DARWIN: Configuration file: {{.*}}/testdmode/x86_64-apple-darwin23.6.0-clang.cfg + +//--- DARWIN + no full version +// +// RUN: rm %t/testdmode/x86_64-apple-darwin23.6.0-clang.cfg +// RUN: %clang -target x86_64-apple-darwin23.6.0 --config-system-dir=%t/testdmode --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix DARWIN-MAJOR --implicit-check-not 'Configuration file:' +// +// DARWIN-MAJOR: Configuration file: {{.*}}/testdmode/x86_64-apple-darwin23-clang.cfg + +//--- DARWIN + no version +// +// RUN: rm %t/testdmode/x86_64-apple-darwin23-clang.cfg +// RUN: %clang -target x86_64-apple-darwin23.6.0 --config-system-dir=%t/testdmode --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix DARWIN-VERSIONLESS --implicit-check-not 'Configuration file:' +// +// DARWIN-VERSIONLESS: Configuration file: {{.*}}/testdmode/x86_64-apple-darwin-clang.cfg diff --git a/clang/test/Driver/freebsd.c b/clang/test/Driver/freebsd.c index 10fe155fee874..a0787bab4feb8 100644 --- a/clang/test/Driver/freebsd.c +++ b/clang/test/Driver/freebsd.c @@ -77,6 +77,21 @@ // RUN: | FileCheck --check-prefix=CHECK-RV64I-LD %s // CHECK-RV64I-LD: ld{{.*}}" {{.*}} "-m" "elf64lriscv" // +// Check that LoongArch passes the correct linker emulation. +// +// RUN: %clang --target=loongarch32-freebsd -### %s %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-LA32-LD %s +// CHECK-LA32-LD: ld{{.*}}" {{.*}} "-m" "elf32loongarch" +// RUN: %clang --target=loongarch64-freebsd -### %s %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-LA64-LD %s +// CHECK-LA64-LD: ld{{.*}}" {{.*}} "-m" "elf64loongarch" +// +// Check options passed to the linker on LoongArch +// +// RUN: %clang --target=loongarch64-freebsd -mno-relax -### %s %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-LA64-LD-OPTS %s +// CHECK-LA64-LD-OPTS: ld{{.*}}" {{.*}} "-X" "--no-relax" +// // Check that the new linker flags are passed to FreeBSD // RUN: %clang --target=x86_64-pc-freebsd10.0 -m32 %s \ // RUN: --sysroot=%S/Inputs/multiarch_freebsd64_tree -### 2>&1 \ diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 15f190165a7d7..aeae15aada70c 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -9,6 +9,59 @@ // CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound" // CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound" +// The trailing -fsanitize-merge takes precedence +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge -fsanitize-merge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge -fsanitize-merge=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=undefined -fsanitize-merge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=undefined -fsanitize-merge=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow -fsanitize-merge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=bool -fsanitize-merge=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=undefined -fsanitize-merge=bool %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE +// CHECK-UNDEFINED-MERGE: "-fsanitize-merge=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound" + +// The trailing arguments (-fsanitize-merge -fno-sanitize-merge=signed-integer-overflow) take precedence +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge -fno-sanitize-merge=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=undefined -fno-sanitize-merge=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge -fsanitize-merge -fno-sanitize-merge=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge -fsanitize-merge=undefined -fno-sanitize-merge=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow -fsanitize-merge -fno-sanitize-merge=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow -fsanitize-merge=undefined -fno-sanitize-merge=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2 +// CHECK-UNDEFINED-MERGE2: "-fsanitize-merge=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound" + +// The trailing -fno-sanitize-merge takes precedence +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE3 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=undefined %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE3 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge -fno-sanitize-merge=bool %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE3 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=undefined -fno-sanitize-merge=bool %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE3 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge -fno-sanitize-merge %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE3 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge -fno-sanitize-merge=undefined %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE3 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=undefined -fno-sanitize-merge %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE3 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=undefined -fno-sanitize-merge=undefined %s -### 2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE3 +// CHECK-UNDEFINED-MERGE3: "-fsanitize-merge" + +// The trailing arguments (-fsanitize-merge -fno-sanitize-merge=alignment,null) take precedence +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge -fno-sanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=undefined -fno-sanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge -fsanitize-merge -fno-sanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge -fsanitize-merge=undefined -fno-sanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow -fsanitize-merge -fno-sanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow -fsanitize-merge=undefined -fno-sanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4 +// CHECK-UNDEFINED-MERGE4: "-fsanitize-merge=array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound" + +// The trailing arguments (-fno-sanitize-merge -fsanitize-merge=alignment,null) take precedence +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge -fsanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE5 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize-merge=undefined -fsanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE5 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge -fno-sanitize-merge -fsanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE5 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge -fno-sanitize-merge=undefined -fsanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE5 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=signed-integer-overflow -fno-sanitize-merge -fsanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE5 +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-merge=signed-integer-overflow -fno-sanitize-merge=undefined -fsanitize-merge=alignment,null %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE5 +// CHECK-UNDEFINED-MERGE5: "-fsanitize-merge=alignment,null" + // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED // CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}} @@ -989,19 +1042,25 @@ // RUN: not %clang --target=x86_64-linux-gnu -fsanitize=undefined,function -mcmodel=large %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION-CODE-MODEL // CHECK-UBSAN-FUNCTION-CODE-MODEL: error: invalid argument '-fsanitize=function' only allowed with '-mcmodel=small' -// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION -// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=undefined -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION -// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI -// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=function -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI --check-prefix=CHECK-UBSAN-FUNCTION +// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION-TARGET +// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=undefined -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION-TARGET +// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI-TARGET +// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=function -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI-TARGET --check-prefix=CHECK-UBSAN-FUNCTION-TARGET // RUN: %clang --target=x86_64-sie-ps5 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-UNDEFINED // CHECK-UBSAN-UNDEFINED: "-fsanitize={{((alignment|array-bounds|bool|builtin|enum|float-cast-overflow|integer-divide-by-zero|nonnull-attribute|null|pointer-overflow|return|returns-nonnull-attribute|shift-base|shift-exponent|signed-integer-overflow|unreachable|vla-bound),?){17}"}} -// RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION -// RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI +// RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION-MEXECUTE-ONLY +// RUN: not %clang --target=armv6t2-eabi -mpure-code -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION-MPURE-CODE +// RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI-MEXECUTE-ONLY +// RUN: not %clang --target=armv6t2-eabi -mpure-code -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI-MPURE-CODE // RUN: %clang --target=armv6t2-eabi -mexecute-only -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-UNDEFINED-VPTR -// CHECK-UBSAN-KCFI-DAG: error: invalid argument '-fsanitize=kcfi' not allowed with {{('x86_64-sie-ps5'|'armv6t2-unknown-unknown-eabi')}} -// CHECK-UBSAN-FUNCTION-DAG: error: invalid argument '-fsanitize=function' not allowed with {{('x86_64-sie-ps5'|'armv6t2-unknown-unknown-eabi')}} +// CHECK-UBSAN-KCFI-TARGET-DAG: error: unsupported option '-fsanitize=kcfi' for target 'x86_64-sie-ps5' +// CHECK-UBSAN-KCFI-MEXECUTE-ONLY-DAG: error: invalid argument '-fsanitize=kcfi' not allowed with '-mexecute-only' +// CHECK-UBSAN-KCFI-MPURE-CODE-DAG: error: invalid argument '-fsanitize=kcfi' not allowed with '-mpure-code' +// CHECK-UBSAN-FUNCTION-TARGET-DAG: error: unsupported option '-fsanitize=function' for target 'x86_64-sie-ps5' +// CHECK-UBSAN-FUNCTION-MEXECUTE-ONLY-DAG: error: invalid argument '-fsanitize=function' not allowed with '-mexecute-only' +// CHECK-UBSAN-FUNCTION-MPURE-CODE-DAG: error: invalid argument '-fsanitize=function' not allowed with '-mpure-code' // CHECK-UBSAN-UNDEFINED-VPTR: "-fsanitize={{((alignment|array-bounds|bool|builtin|enum|float-cast-overflow|integer-divide-by-zero|nonnull-attribute|null|pointer-overflow|return|returns-nonnull-attribute|shift-base|shift-exponent|signed-integer-overflow|unreachable|vla-bound|vptr),?){18}"}} // * Test BareMetal toolchain sanitizer support * diff --git a/clang/test/Driver/fveclib.c b/clang/test/Driver/fveclib.c index 09a12c2327137..7d0985c4dd4f4 100644 --- a/clang/test/Driver/fveclib.c +++ b/clang/test/Driver/fveclib.c @@ -112,3 +112,20 @@ /* Verify no warning when math-errno is re-enabled for a different veclib (that does not imply -fno-math-errno). */ // RUN: %clang -### --target=aarch64-linux-gnu -fveclib=ArmPL -fmath-errno -fveclib=LIBMVEC %s 2>&1 | FileCheck --check-prefix=CHECK-REPEAT-VECLIB %s // CHECK-REPEAT-VECLIB-NOT: math errno enabled + +/// Verify that vectorized routines library is being linked in. +// RUN: %clang -### --target=aarch64-pc-windows-msvc -fveclib=ArmPL %s 2>&1 | FileCheck --check-prefix=CHECK-LINKING-ARMPL-MSVC %s +// RUN: %clang -### --target=aarch64-linux-gnu -fveclib=ArmPL %s 2>&1 | FileCheck --check-prefix=CHECK-LINKING-ARMPL-LINUX %s +// RUN: %clang -### --target=aarch64-linux-gnu -fveclib=ArmPL %s -lamath 2>&1 | FileCheck --check-prefix=CHECK-LINKING-AMATH-BEFORE-ARMPL-LINUX %s +// RUN: %clang -### --target=arm64-apple-darwin -fveclib=ArmPL %s 2>&1 | FileCheck --check-prefix=CHECK-LINKING-ARMPL-DARWIN %s +// RUN: %clang -### --target=arm64-apple-darwin -fveclib=ArmPL %s -lamath 2>&1 | FileCheck --check-prefix=CHECK-LINKING-AMATH-BEFORE-ARMPL-DARWIN %s +// CHECK-LINKING-ARMPL-LINUX: "--push-state" "--as-needed" "-lm" "-lamath" "-lm" "--pop-state" +// CHECK-LINKING-ARMPL-DARWIN: "-lm" "-lamath" "-lm" +// CHECK-LINKING-ARMPL-MSVC: "--dependent-lib=amath" +// CHECK-LINKING-AMATH-BEFORE-ARMPL-LINUX: "-lamath" {{.*}}"--push-state" "--as-needed" "-lm" "-lamath" "-lm" "--pop-state" +// CHECK-LINKING-AMATH-BEFORE-ARMPL-DARWIN: "-lamath" {{.*}}"-lm" "-lamath" "-lm" + +/// Verify that the RPATH is being set when needed. +// RUN: %clang -### --target=aarch64-linux-gnu -resource-dir=%S/../../../clang/test/Driver/Inputs/resource_dir_with_arch_subdir -frtlib-add-rpath -fveclib=ArmPL %s 2>&1 | FileCheck --check-prefix=CHECK-RPATH-ARMPL %s +// CHECK-RPATH-ARMPL: "--push-state" "--as-needed" "-lm" "-lamath" "-lm" "--pop-state" +// CHECK-RPATH-ARMPL-SAME: "-rpath" diff --git a/clang/test/Driver/module-fgen-reduced-bmi.cppm b/clang/test/Driver/module-fgen-reduced-bmi.cppm index 1223189fb49b7..7329c12941d73 100644 --- a/clang/test/Driver/module-fgen-reduced-bmi.cppm +++ b/clang/test/Driver/module-fgen-reduced-bmi.cppm @@ -29,13 +29,41 @@ // // RUN: %clang -std=c++20 Hello.cc -fexperimental-modules-reduced-bmi -Wall -Werror \ // RUN: -c -o Hello.o -### 2>&1 | FileCheck Hello.cc +// +// RUN: %clang -std=c++20 Hello.cppm -fmodule-output=Hello.pcm \ +// RUN: -fmodules-reduced-bmi -c -o Hello.o -### 2>&1 | FileCheck Hello.cppm +// +// RUN: %clang -std=c++20 Hello.cppm \ +// RUN: -fmodules-reduced-bmi -c -o Hello.o -### 2>&1 | \ +// RUN: FileCheck Hello.cppm --check-prefix=CHECK-UNSPECIFIED +// +// RUN: %clang -std=c++20 Hello.cppm \ +// RUN: -fmodules-reduced-bmi -c -### 2>&1 | \ +// RUN: FileCheck Hello.cppm --check-prefix=CHECK-NO-O +// +// RUN: %clang -std=c++20 Hello.cppm \ +// RUN: -fmodules-reduced-bmi -c -o AnotherName.o -### 2>&1 | \ +// RUN: FileCheck Hello.cppm --check-prefix=CHECK-ANOTHER-NAME +// +// RUN: %clang -std=c++20 Hello.cppm --precompile -fmodules-reduced-bmi \ +// RUN: -o Hello.full.pcm -### 2>&1 | FileCheck Hello.cppm \ +// RUN: --check-prefix=CHECK-EMIT-MODULE-INTERFACE +// +// RUN: %clang -std=c++20 Hello.cc -fmodules-reduced-bmi -Wall -Werror \ +// RUN: -c -o Hello.o -### 2>&1 | FileCheck Hello.cc +// +// RUN: %clang -std=c++20 Hello.cppm -fmodule-output=Hello.pcm -c -o Hello.o \ +// RUN: -Wno-missing-reduced-bmi -### 2>&1 | FileCheck Hello.cppm -check-prefix=NO_WARN +// +// RUN: %clang -std=c++20 Hello.cppm --precompile -o Hello.pcm \ +// RUN: -Wno-missing-reduced-bmi -### 2>&1 | FileCheck Hello.cppm -check-prefix=NO_WARN //--- Hello.cppm export module Hello; // Test that we won't generate the emit-module-interface as 2 phase compilation model. // CHECK-NOT: -emit-module-interface -// CHECK: "-fexperimental-modules-reduced-bmi" +// CHECK: "-fmodules-reduced-bmi" // CHECK-UNSPECIFIED: -fmodule-output=Hello.pcm @@ -46,6 +74,8 @@ export module Hello; // flag. // CHECK-EMIT-MODULE-INTERFACE: -emit-module-interface +// NO_WARN-NOT: warning + //--- Hello.cc -// CHECK-NOT: "-fexperimental-modules-reduced-bmi" +// CHECK-NOT: "-fmodules-reduced-bmi" diff --git a/clang/test/Driver/print-enabled-extensions/riscv-rocket-rv64.c b/clang/test/Driver/print-enabled-extensions/riscv-rocket-rv64.c index f8dd58cd74d6d..bc99f7775b7e0 100644 --- a/clang/test/Driver/print-enabled-extensions/riscv-rocket-rv64.c +++ b/clang/test/Driver/print-enabled-extensions/riscv-rocket-rv64.c @@ -4,10 +4,10 @@ // Simple litmus test to check the frontend handling of this option is // enabled. -// CHECK: Extensions enabled for the given RISC-V target +// CHECK: Extensions enabled for the given RISC-V target // CHECK-EMPTY: -// CHECK-NEXT: Name Version Description -// CHECK-NEXT: i 2.1 'I' (Base Integer Instruction Set) -// CHECK-NEXT: zicsr 2.0 'zicsr' (CSRs) -// CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) +// CHECK-NEXT: Name Version Description +// CHECK-NEXT: i 2.1 'I' (Base Integer Instruction Set) +// CHECK-NEXT: zicsr 2.0 'Zicsr' (CSRs) +// CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) // CHECK-EMPTY: diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c index 9df903115b57c..8344c1aa39973 100644 --- a/clang/test/Driver/print-supported-extensions-riscv.c +++ b/clang/test/Driver/print-supported-extensions-riscv.c @@ -5,7 +5,7 @@ // CHECK-EMPTY: // CHECK-NEXT: Name Version Description // CHECK-NEXT: i 2.1 'I' (Base Integer Instruction Set) -// CHECK-NEXT: e 2.0 Implements RV{32,64}E (provides 16 rather than 32 GPRs) +// CHECK-NEXT: e 2.0 'E' (Embedded Instruction Set with 16 GPRs) // CHECK-NEXT: m 2.0 'M' (Integer Multiplication and Division) // CHECK-NEXT: a 2.1 'A' (Atomic Instructions) // CHECK-NEXT: f 2.2 'F' (Single-Precision Floating-Point) @@ -24,7 +24,7 @@ // CHECK-NEXT: ziccrse 1.0 'Ziccrse' (Main Memory Supports Forward Progress on LR/SC Sequences) // CHECK-NEXT: zicntr 2.0 'Zicntr' (Base Counters and Timers) // CHECK-NEXT: zicond 1.0 'Zicond' (Integer Conditional Operations) -// CHECK-NEXT: zicsr 2.0 'zicsr' (CSRs) +// CHECK-NEXT: zicsr 2.0 'Zicsr' (CSRs) // CHECK-NEXT: zifencei 2.0 'Zifencei' (fence.i) // CHECK-NEXT: zihintntl 1.0 'Zihintntl' (Non-Temporal Locality Hints) // CHECK-NEXT: zihintpause 2.0 'Zihintpause' (Pause Hint) @@ -78,7 +78,7 @@ // CHECK-NEXT: zve64d 1.0 'Zve64d' (Vector Extensions for Embedded Processors with maximal 64 EEW, F and D extension) // CHECK-NEXT: zve64f 1.0 'Zve64f' (Vector Extensions for Embedded Processors with maximal 64 EEW and F extension) // CHECK-NEXT: zve64x 1.0 'Zve64x' (Vector Extensions for Embedded Processors with maximal 64 EEW) -// CHECK-NEXT: zvfbfmin 1.0 'Zvbfmin' (Vector BF16 Converts) +// CHECK-NEXT: zvfbfmin 1.0 'Zvfbfmin' (Vector BF16 Converts) // CHECK-NEXT: zvfbfwma 1.0 'Zvfbfwma' (Vector BF16 widening mul-add) // CHECK-NEXT: zvfh 1.0 'Zvfh' (Vector Half-Precision Floating-Point) // CHECK-NEXT: zvfhmin 1.0 'Zvfhmin' (Vector Half-Precision Floating-Point Minimal) @@ -87,7 +87,7 @@ // CHECK-NEXT: zvkn 1.0 'Zvkn' (shorthand for 'Zvkned', 'Zvknhb', 'Zvkb', and 'Zvkt') // CHECK-NEXT: zvknc 1.0 'Zvknc' (shorthand for 'Zvknc' and 'Zvbc') // CHECK-NEXT: zvkned 1.0 'Zvkned' (Vector AES Encryption & Decryption (Single Round)) -// CHECK-NEXT: zvkng 1.0 'zvkng' (shorthand for 'Zvkn' and 'Zvkg') +// CHECK-NEXT: zvkng 1.0 'Zvkng' (shorthand for 'Zvkn' and 'Zvkg') // CHECK-NEXT: zvknha 1.0 'Zvknha' (Vector SHA-2 (SHA-256 only)) // CHECK-NEXT: zvknhb 1.0 'Zvknhb' (Vector SHA-2 (SHA-256 and SHA-512)) // CHECK-NEXT: zvks 1.0 'Zvks' (shorthand for 'Zvksed', 'Zvksh', 'Zvkb', and 'Zvkt') @@ -96,25 +96,25 @@ // CHECK-NEXT: zvksg 1.0 'Zvksg' (shorthand for 'Zvks' and 'Zvkg') // CHECK-NEXT: zvksh 1.0 'Zvksh' (SM3 Hash Function Instructions) // CHECK-NEXT: zvkt 1.0 'Zvkt' (Vector Data-Independent Execution Latency) -// CHECK-NEXT: zvl1024b 1.0 'Zvl' (Minimum Vector Length) 1024 -// CHECK-NEXT: zvl128b 1.0 'Zvl' (Minimum Vector Length) 128 -// CHECK-NEXT: zvl16384b 1.0 'Zvl' (Minimum Vector Length) 16384 -// CHECK-NEXT: zvl2048b 1.0 'Zvl' (Minimum Vector Length) 2048 -// CHECK-NEXT: zvl256b 1.0 'Zvl' (Minimum Vector Length) 256 -// CHECK-NEXT: zvl32768b 1.0 'Zvl' (Minimum Vector Length) 32768 -// CHECK-NEXT: zvl32b 1.0 'Zvl' (Minimum Vector Length) 32 -// CHECK-NEXT: zvl4096b 1.0 'Zvl' (Minimum Vector Length) 4096 -// CHECK-NEXT: zvl512b 1.0 'Zvl' (Minimum Vector Length) 512 -// CHECK-NEXT: zvl64b 1.0 'Zvl' (Minimum Vector Length) 64 -// CHECK-NEXT: zvl65536b 1.0 'Zvl' (Minimum Vector Length) 65536 -// CHECK-NEXT: zvl8192b 1.0 'Zvl' (Minimum Vector Length) 8192 +// CHECK-NEXT: zvl1024b 1.0 'Zvl1024b' (Minimum Vector Length 1024) +// CHECK-NEXT: zvl128b 1.0 'Zvl128b' (Minimum Vector Length 128) +// CHECK-NEXT: zvl16384b 1.0 'Zvl16384b' (Minimum Vector Length 16384) +// CHECK-NEXT: zvl2048b 1.0 'Zvl2048b' (Minimum Vector Length 2048) +// CHECK-NEXT: zvl256b 1.0 'Zvl256b' (Minimum Vector Length 256) +// CHECK-NEXT: zvl32768b 1.0 'Zvl32768b' (Minimum Vector Length 32768) +// CHECK-NEXT: zvl32b 1.0 'Zvl32b' (Minimum Vector Length 32) +// CHECK-NEXT: zvl4096b 1.0 'Zvl4096b' (Minimum Vector Length 4096) +// CHECK-NEXT: zvl512b 1.0 'Zvl512b' (Minimum Vector Length 512) +// CHECK-NEXT: zvl64b 1.0 'Zvl64b' (Minimum Vector Length 64) +// CHECK-NEXT: zvl65536b 1.0 'Zvl65536b' (Minimum Vector Length 65536) +// CHECK-NEXT: zvl8192b 1.0 'Zvl8192b' (Minimum Vector Length 8192) // CHECK-NEXT: zhinx 1.0 'Zhinx' (Half Float in Integer) // CHECK-NEXT: zhinxmin 1.0 'Zhinxmin' (Half Float in Integer Minimal) // CHECK-NEXT: sha 1.0 'Sha' (Augmented Hypervisor) // CHECK-NEXT: shcounterenw 1.0 'Shcounterenw' (Support writeable hcounteren enable bit for any hpmcounter that is not read-only zero) -// CHECK-NEXT: shgatpa 1.0 'Sgatpa' (SvNNx4 mode supported for all modes supported by satp, as well as Bare) +// CHECK-NEXT: shgatpa 1.0 'Shgatpa' (SvNNx4 mode supported for all modes supported by satp, as well as Bare) // CHECK-NEXT: shtvala 1.0 'Shtvala' (htval provides all needed values) -// CHECK-NEXT: shvsatpa 1.0 'Svsatpa' (vsatp supports all modes supported by satp) +// CHECK-NEXT: shvsatpa 1.0 'Shvsatpa' (vsatp supports all modes supported by satp) // CHECK-NEXT: shvstvala 1.0 'Shvstvala' (vstval provides all needed values) // CHECK-NEXT: shvstvecd 1.0 'Shvstvecd' (vstvec supports Direct mode) // CHECK-NEXT: smaia 1.0 'Smaia' (Advanced Interrupt Architecture Machine Level) @@ -145,11 +145,11 @@ // CHECK-NEXT: supm 1.0 'Supm' (Indicates User-mode Pointer Masking) // CHECK-NEXT: svade 1.0 'Svade' (Raise exceptions on improper A/D bits) // CHECK-NEXT: svadu 1.0 'Svadu' (Hardware A/D updates) -// CHECK-NEXT: svbare 1.0 'Svbare' $(satp mode Bare supported) +// CHECK-NEXT: svbare 1.0 'Svbare' (satp mode Bare supported) // CHECK-NEXT: svinval 1.0 'Svinval' (Fine-Grained Address-Translation Cache Invalidation) // CHECK-NEXT: svnapot 1.0 'Svnapot' (NAPOT Translation Contiguity) // CHECK-NEXT: svpbmt 1.0 'Svpbmt' (Page-Based Memory Types) -// CHECK-NEXT: svvptc 1.0 'svvptc' (Obviating Memory-Management Instructions after Marking PTEs Valid) +// CHECK-NEXT: svvptc 1.0 'Svvptc' (Obviating Memory-Management Instructions after Marking PTEs Valid) // CHECK-NEXT: xcvalu 1.0 'XCValu' (CORE-V ALU Operations) // CHECK-NEXT: xcvbi 1.0 'XCVbi' (CORE-V Immediate Branching) // CHECK-NEXT: xcvbitmanip 1.0 'XCVbitmanip' (CORE-V Bit Manipulation) @@ -189,7 +189,9 @@ // CHECK-NEXT: ssctr 1.0 'Ssctr' (Control Transfer Records Supervisor Level) // CHECK-NEXT: svukte 0.3 'Svukte' (Address-Independent Latency of User-Mode Faults to Supervisor Addresses) // CHECK-NEXT: xqcia 0.2 'Xqcia' (Qualcomm uC Arithmetic Extension) +// CHECK-NEXT: xqcics 0.2 'Xqcics' (Qualcomm uC Conditional Select Extension) // CHECK-NEXT: xqcicsr 0.2 'Xqcicsr' (Qualcomm uC CSR Extension) +// CHECK-NEXT: xqcilsm 0.2 'Xqcilsm' (Qualcomm uC Load Store Multiple Extension) // CHECK-NEXT: xqcisls 0.2 'Xqcisls' (Qualcomm uC Scaled Load Store Extension) // CHECK-EMPTY: // CHECK-NEXT: Supported Profiles diff --git a/clang/test/Driver/riscv-cpus.c b/clang/test/Driver/riscv-cpus.c index 249216612f7ee..1b09945620f8c 100644 --- a/clang/test/Driver/riscv-cpus.c +++ b/clang/test/Driver/riscv-cpus.c @@ -98,6 +98,23 @@ // RUN: %clang --target=riscv64 -### -c %s 2>&1 -mtune=rocket-rv64 | FileCheck -check-prefix=MTUNE-ROCKET64 %s // MTUNE-ROCKET64: "-tune-cpu" "rocket-rv64" +// RUN: %clang --target=riscv64 -### -c %s 2>&1 -mtune=mips-p8700 | FileCheck -check-prefix=MTUNE-MIPS-P8700 %s +// MTUNE-MIPS-P8700: "-tune-cpu" "mips-p8700" + +// RUN: %clang --target=riscv64 -### -c %s 2>&1 -mcpu=mips-p8700 | FileCheck -check-prefix=MCPU-MIPS-P8700 %s +// MCPU-MIPS-P8700: "-target-cpu" "mips-p8700" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+m" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+a" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+f" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+d" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+c" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+zicsr" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+zifencei" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+zaamo" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+zalrsc" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+zba" +// MCPU-MIPS-P8700-SAME: "-target-feature" "+zbb" + // RUN: %clang --target=riscv32 -### -c %s 2>&1 -mtune=syntacore-scr1-base | FileCheck -check-prefix=MTUNE-SYNTACORE-SCR1-BASE %s // MTUNE-SYNTACORE-SCR1-BASE: "-tune-cpu" "syntacore-scr1-base" diff --git a/clang/test/Driver/sanitizer-ld.c b/clang/test/Driver/sanitizer-ld.c index 877a01c3de304..60d60a6047b0f 100644 --- a/clang/test/Driver/sanitizer-ld.c +++ b/clang/test/Driver/sanitizer-ld.c @@ -15,7 +15,7 @@ // CHECK-ASAN-LINUX: "-lpthread" // CHECK-ASAN-LINUX: "-lrt" // CHECK-ASAN-LINUX: "-ldl" -// CHECK-ASAN-LINUX-NOT: "-lresolv" +// CHECK-ASAN-LINUX: "-lresolv" // RUN: %clang -fsanitize=address -fno-sanitize-link-runtime -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -143,7 +143,7 @@ // CHECK-ASAN-LINUX-CXX: "-lpthread" // CHECK-ASAN-LINUX-CXX: "-lrt" // CHECK-ASAN-LINUX-CXX: "-ldl" -// CHECK-ASAN-LINUX-CXX-NOT: "-lresolv" +// CHECK-ASAN-LINUX-CXX: "-lresolv" // RUN: %clang -### %s -o /dev/null -fsanitize=address \ // RUN: --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform \ @@ -274,6 +274,29 @@ // CHECK-ASAN-ANDROID-SHARED-NOT: "-lpthread" // CHECK-ASAN-ANDROID-SHARED-NOT: "-lresolv" + +// RUN: %clangxx %s -### -o %t.o 2>&1 \ +// RUN: --target=x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \ +// RUN: -fsanitize=type \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-TYSAN-LINUX-CXX %s +// +// CHECK-TYSAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}" +// CHECK-TYSAN-LINUX-CXX-NOT: stdc++ +// CHECK-TYSAN-LINUX-CXX: "--whole-archive" "{{.*}}libclang_rt.tysan{{[^.]*}}.a" "--no-whole-archive" +// CHECK-TYSAN-LINUX-CXX: stdc++ + +// RUN: %clangxx -fsanitize=type -### %s 2>&1 \ +// RUN: -mmacosx-version-min=10.6 \ +// RUN: --target=x86_64-apple-darwin13.4.0 -fuse-ld=ld -stdlib=platform \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-TYSAN-DARWIN-CXX %s +// CHECK-TYSAN-DARWIN-CXX: "{{.*}}ld{{(.exe)?}}" +// CHECK-TYSAN-DARWIN-CXX: libclang_rt.tysan_osx_dynamic.dylib +// CHECK-TYSAN-DARWIN-CXX-NOT: -lc++abi + // RUN: %clangxx -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \ // RUN: -fsanitize=thread \ @@ -292,7 +315,7 @@ // CHECK-TSAN-LINUX-CXX: "-lpthread" // CHECK-TSAN-LINUX-CXX: "-lrt" // CHECK-TSAN-LINUX-CXX: "-ldl" -// CHECK-TSAN-LINUX-CXX-NOT: "-lresolv" +// CHECK-TSAN-LINUX-CXX: "-lresolv" // RUN: %clang -fsanitize=thread -fno-sanitize-link-runtime -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -365,7 +388,7 @@ // CHECK-UBSAN-LINUX-NOT: libclang_rt.ubsan_standalone_cxx // CHECK-UBSAN-LINUX-NOT: "-lstdc++" // CHECK-UBSAN-LINUX: "-lpthread" -// CHECK-UBSAN-LINUX-NOT: "-lresolv" +// CHECK-UBSAN-LINUX: "-lresolv" // RUN: %clang -fsanitize=undefined -fno-sanitize-link-runtime -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -438,7 +461,7 @@ // CHECK-UBSAN-LINUX-CXX: "-lstdc++" // CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan // CHECK-UBSAN-LINUX-CXX: "-lpthread" -// CHECK-UBSAN-LINUX-CXX-NOT: "-lresolv" +// CHECK-UBSAN-LINUX-CXX: "-lresolv" // RUN: %clang -fsanitize=undefined -fsanitize-minimal-runtime -### %s 2>&1 \ // RUN: --target=i386-unknown-linux -fuse-ld=ld \ @@ -448,7 +471,7 @@ // CHECK-UBSAN-MINIMAL-LINUX: "{{.*}}ld{{(.exe)?}}" // CHECK-UBSAN-MINIMAL-LINUX: "--whole-archive" "{{.*}}libclang_rt.ubsan_minimal.a" "--no-whole-archive" // CHECK-UBSAN-MINIMAL-LINUX: "-lpthread" -// CHECK-UBSAN-MINIMAL-LINUX-NOT: "-lresolv" +// CHECK-UBSAN-MINIMAL-LINUX: "-lresolv" // RUN: %clang -fsanitize=undefined -fsanitize-minimal-runtime -### %s 2>&1 \ // RUN: --target=x86_64-apple-darwin -fuse-ld=ld \ @@ -485,7 +508,7 @@ // CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.ubsan // CHECK-ASAN-UBSAN-LINUX-NOT: "-lstdc++" // CHECK-ASAN-UBSAN-LINUX: "-lpthread" -// CHECK-ASAN-UBSAN-LINUX-NOT: "-lresolv" +// CHECK-ASAN-UBSAN-LINUX: "-lresolv" // RUN: %clangxx -fsanitize=address,undefined -### %s 2>&1 \ // RUN: --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform \ @@ -498,7 +521,7 @@ // CHECK-ASAN-UBSAN-LINUX-CXX-NOT: libclang_rt.ubsan // CHECK-ASAN-UBSAN-LINUX-CXX: "-lstdc++" // CHECK-ASAN-UBSAN-LINUX-CXX: "-lpthread" -// CHECK-ASAN-UBSAN-LINUX-CXX-NOT: "-lresolv" +// CHECK-ASAN-UBSAN-LINUX-CXX: "-lresolv" // RUN: %clangxx -fsanitize=memory,undefined -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -541,7 +564,7 @@ // CHECK-LSAN-LINUX: libclang_rt.lsan.a" // CHECK-LSAN-LINUX: "-lpthread" // CHECK-LSAN-LINUX: "-ldl" -// CHECK-LSAN-LINUX-NOT: "-lresolv" +// CHECK-LSAN-LINUX: "-lresolv" // RUN: %clang -fsanitize=leak -fno-sanitize-link-runtime -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -564,7 +587,7 @@ // CHECK-LSAN-COV-LINUX-NOT: libclang_rt.ubsan // CHECK-LSAN-COV-LINUX: "-lpthread" // CHECK-LSAN-COV-LINUX: "-ldl" -// CHECK-LSAN-COV-LINUX-NOT: "-lresolv" +// CHECK-LSAN-COV-LINUX: "-lresolv" // RUN: %clang -fsanitize=leak,address -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -586,7 +609,7 @@ // CHECK-ASAN-COV-LINUX-NOT: libclang_rt.ubsan // CHECK-ASAN-COV-LINUX-NOT: "-lstdc++" // CHECK-ASAN-COV-LINUX: "-lpthread" -// CHECK-ASAN-COV-LINUX-NOT: "-lresolv" +// CHECK-ASAN-COV-LINUX: "-lresolv" // RUN: %clang -fsanitize=memory -fsanitize-coverage=func -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -610,7 +633,7 @@ // CHECK-DFSAN-COV-LINUX-NOT: libclang_rt.ubsan // CHECK-DFSAN-COV-LINUX-NOT: "-lstdc++" // CHECK-DFSAN-COV-LINUX: "-lpthread" -// CHECK-DFSAN-COV-LINUX-NOT: "-lresolv" +// CHECK-DFSAN-COV-LINUX: "-lresolv" // RUN: %clang -fsanitize=undefined -fsanitize-coverage=func -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -621,7 +644,7 @@ // CHECK-UBSAN-COV-LINUX: "--whole-archive" "{{.*}}libclang_rt.ubsan_standalone.a" "--no-whole-archive" // CHECK-UBSAN-COV-LINUX-NOT: "-lstdc++" // CHECK-UBSAN-COV-LINUX: "-lpthread" -// CHECK-UBSAN-COV-LINUX-NOT: "-lresolv" +// CHECK-UBSAN-COV-LINUX: "-lresolv" // RUN: %clang -fsanitize-coverage=func -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -632,7 +655,7 @@ // CHECK-COV-LINUX: "--whole-archive" "{{.*}}libclang_rt.ubsan_standalone.a" "--no-whole-archive" // CHECK-COV-LINUX-NOT: "-lstdc++" // CHECK-COV-LINUX: "-lpthread" -// CHECK-COV-LINUX-NOT: "-lresolv" +// CHECK-COV-LINUX: "-lresolv" // RUN: %clang -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld -fsanitize=numerical \ @@ -644,8 +667,7 @@ // CHECK-NSAN-LINUX-NOT: "-lc" // CHECK-NSAN-LINUX-NOT: libclang_rt.ubsan // CHECK-NSAN-LINUX: libclang_rt.nsan.a" -// CHECK-NSAN-LINUX: "-lpthread" "-lrt" "-lm" "-ldl" -// CHECK-NSAN-LINUX-NOT: "-lresolv" +// CHECK-NSAN-LINUX: "-lpthread" "-lrt" "-lm" "-ldl" "-lresolv" // RUN: %clang -### %s 2>&1 --target=x86_64-unknown-linux -fuse-ld=ld -fsanitize=numerical -shared-libsan \ // RUN: -resource-dir=%S/Inputs/resource_dir \ @@ -758,7 +780,7 @@ // CHECK-SAFESTACK-LINUX: libclang_rt.safestack.a" // CHECK-SAFESTACK-LINUX: "-lpthread" // CHECK-SAFESTACK-LINUX: "-ldl" -// CHECK-SAFESTACK-LINUX-NOT: "-lresolv" +// CHECK-SAFESTACK-LINUX: "-lresolv" // RUN: %clang -fsanitize=shadow-call-stack -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld \ @@ -958,7 +980,7 @@ // CHECK-SCUDO-LINUX-NOT: "-lstdc++" // CHECK-SCUDO-LINUX: "-lpthread" // CHECK-SCUDO-LINUX: "-ldl" -// CHECK-SCUDO-LINUX-NOT: "-lresolv" +// CHECK-SCUDO-LINUX: "-lresolv" // RUN: %clang -### %s -o %t.so -shared 2>&1 \ // RUN: --target=i386-unknown-linux -fuse-ld=ld -fsanitize=scudo -shared-libsan \ @@ -1019,7 +1041,7 @@ // CHECK-HWASAN-X86-64-LINUX: "-lpthread" // CHECK-HWASAN-X86-64-LINUX: "-lrt" // CHECK-HWASAN-X86-64-LINUX: "-ldl" -// CHECK-HWASAN-X86-64-LINUX-NOT: "-lresolv" +// CHECK-HWASAN-X86-64-LINUX: "-lresolv" // RUN: %clang -### %s 2>&1 \ // RUN: --target=x86_64-unknown-linux -fuse-ld=ld -fsanitize=hwaddress \ @@ -1068,7 +1090,7 @@ // CHECK-HWASAN-AARCH64-LINUX: "-lpthread" // CHECK-HWASAN-AARCH64-LINUX: "-lrt" // CHECK-HWASAN-AARCH64-LINUX: "-ldl" -// CHECK-HWASAN-AARCH64-LINUX-NOT: "-lresolv" +// CHECK-HWASAN-AARCH64-LINUX: "-lresolv" // RUN: %clang -### %s 2>&1 \ // RUN: --target=aarch64-unknown-linux -fuse-ld=ld -fsanitize=hwaddress \ diff --git a/clang/test/Driver/stack-clash-protection.c b/clang/test/Driver/stack-clash-protection.c index 222452f7897a6..3b0476db9d3cb 100644 --- a/clang/test/Driver/stack-clash-protection.c +++ b/clang/test/Driver/stack-clash-protection.c @@ -22,6 +22,11 @@ // SCP-ll-win64-NOT: attributes {{.*}} "probe-stack"="inline-asm" // SCP-ll-win64: argument unused during compilation: '-fstack-clash-protection' +// RUN: %clang -target x86_64-unknown-fuchsia -fstack-clash-protection -### %s 2>&1 | FileCheck %s -check-prefix=SCP-FUCHSIA +// RUN: %clang -target aarch64-unknown-fuchsia -fstack-clash-protection -### %s 2>&1 | FileCheck %s -check-prefix=SCP-FUCHSIA +// RUN: %clang -target riscv64-unknown-fuchsia -fstack-clash-protection -### %s 2>&1 | FileCheck %s -check-prefix=SCP-FUCHSIA +// SCP-FUCHSIA: "-fstack-clash-protection" + int foo(int c) { int r; __asm__("sub %0, %%rsp" diff --git a/clang/test/Driver/sysroot.c b/clang/test/Driver/sysroot.c index 85da2499090af..3080f76e03168 100644 --- a/clang/test/Driver/sysroot.c +++ b/clang/test/Driver/sysroot.c @@ -4,10 +4,9 @@ // CHECK-SYSROOTEQ: "-cc1"{{.*}} "-isysroot" "{{[^"]*}}/FOO" // Apple Darwin uses -isysroot as the syslib root, too. -// We pass --sysroot="" to defeat any -DDEFAULT_SYSROOT parameter. // RUN: touch %t2.o // RUN: %clang -target i386-apple-darwin10 \ -// RUN: -isysroot /FOO --sysroot="" -### %t2.o 2> %t2 +// RUN: -isysroot /FOO -### %t2.o 2> %t2 // RUN: FileCheck --check-prefix=CHECK-APPLE-ISYSROOT < %t2 %s // CHECK-APPLE-ISYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "{{[^"]*}}/FOO" diff --git a/clang/test/Driver/unknown-arg-drivermodes.test b/clang/test/Driver/unknown-arg-drivermodes.test new file mode 100644 index 0000000000000..a7ea73af345e0 --- /dev/null +++ b/clang/test/Driver/unknown-arg-drivermodes.test @@ -0,0 +1,55 @@ +// RUN: %clang_cl \ +// RUN: --config \ +// RUN: -fdiagnostics-color=auto \ +// RUN: -fno-record-command-line \ +// RUN: -frecord-command-line \ +// RUN: -nodefaultlibs \ +// RUN: -nostdlib \ +// RUN: -rpath \ +// RUN: -shared \ +// RUN: -static \ +// RUN: -stdlib \ +// RUN: -Xoffload-linker \ +// RUN: -### -x c++ -c - < /dev/null 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CL --implicit-check-not="warning:" + +// RUN: not %clang_dxc \ +// RUN: --config \ +// RUN: -fdiagnostics-color=auto \ +// RUN: -fno-record-command-line \ +// RUN: -frecord-command-line \ +// RUN: -nodefaultlibs \ +// RUN: -nostdlib \ +// RUN: -rpath \ +// RUN: -shared \ +// RUN: -static \ +// RUN: -stdlib \ +// RUN: -Xlinker \ +// RUN: -Xoffload-linker \ +// RUN: -### -T lib_6_3 -Vd - < /dev/null 2>&1 \ +// RUN: | FileCheck %s --check-prefix=DXC --implicit-check-not="error:" + +// CL: warning: unknown argument ignored in clang-cl: '--config' +// CL: warning: unknown argument ignored in clang-cl: '-fdiagnostics-color=auto' +// CL: warning: unknown argument ignored in clang-cl: '-fno-record-command-line' +// CL: warning: unknown argument ignored in clang-cl: '-frecord-command-line' +// CL: warning: unknown argument ignored in clang-cl: '-nodefaultlibs' +// CL: warning: unknown argument ignored in clang-cl: '-nostdlib' +// CL: warning: unknown argument ignored in clang-cl: '-rpath' +// CL: warning: unknown argument ignored in clang-cl: '-shared' +// CL: warning: unknown argument ignored in clang-cl: '-static' +// CL: warning: unknown argument ignored in clang-cl: '-stdlib' +// CL: warning: unknown argument ignored in clang-cl: '-Xoffload-linker' + +// DXC: error: unknown argument: '--config' +// DXC: error: unknown argument: '-fdiagnostics-color=auto' +// DXC: error: unknown argument: '-fno-record-command-line' +// DXC: error: unknown argument: '-frecord-command-line' +// DXC: error: unknown argument: '-nodefaultlibs' +// DXC: error: unknown argument: '-nostdlib' +// DXC: error: unknown argument: '-rpath' +// DXC: error: unknown argument: '-shared' +// DXC: error: unknown argument: '-static' +// DXC: error: unknown argument: '-stdlib' +// DXC: error: unknown argument: '-Xlinker' +// DXC: error: unknown argument: '-Xoffload-linker' diff --git a/clang/test/ExtractAPI/objc_external_category.m b/clang/test/ExtractAPI/objc_external_category.m index 8afc92489f28b..1947237d088e8 100644 --- a/clang/test/ExtractAPI/objc_external_category.m +++ b/clang/test/ExtractAPI/objc_external_category.m @@ -46,7 +46,7 @@ @interface ExtInterface // Symbol graph from the build without extension SGFs should be identical to main symbol graph with extension SGFs // RUN: diff %t/symbols/Module.symbols.json %t/ModuleNoExt.symbols.json -// RUN: FileCheck %s --input-file %t/symbols/ExternalModule@Module.symbols.json --check-prefix EXT +// RUN: FileCheck %s --input-file %t/symbols/Module@ExternalModule.symbols.json --check-prefix EXT // EXT-DAG: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(py)Property $ c:objc(cs)ExtInterface" // EXT-DAG: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(im)InstanceMethod $ c:objc(cs)ExtInterface" // EXT-DAG: "!testRelLabel": "memberOf $ c:objc(cs)ExtInterface(cm)ClassMethod $ c:objc(cs)ExtInterface" @@ -55,3 +55,10 @@ @interface ExtInterface // EXT-DAG: "!testLabel": "c:objc(cs)ExtInterface(cm)ClassMethod" // EXT-NOT: "!testLabel": "c:objc(cs)ExtInterface" // EXT-NOT: "!testLabel": "c:objc(cs)ModInterface" + +// Ensure that the 'module' metadata for the extension symbol graph should still reference the +// declaring module + +// RUN: FileCheck %s --input-file %t/symbols/Module@ExternalModule.symbols.json --check-prefix META +// META: "module": { +// META-NEXT: "name": "Module", diff --git a/clang/test/Format/docs_updated.test b/clang/test/Format/docs_updated.test index 17066650a1267..98d330e37ef45 100644 --- a/clang/test/Format/docs_updated.test +++ b/clang/test/Format/docs_updated.test @@ -1,5 +1,6 @@ // RUN: %python %S/../../docs/tools/dump_format_style.py -o %t.style -// RUN: diff %t.style %S/../../docs/ClangFormatStyleOptions.rst +// RUN: diff --strip-trailing-cr %t.style \ +// RUN: %S/../../docs/ClangFormatStyleOptions.rst // RUN: %python %S/../../docs/tools/dump_format_help.py -o %t.help -// RUN: diff %t.help %S/../../docs/ClangFormat.rst +// RUN: diff --strip-trailing-cr %t.help %S/../../docs/ClangFormat.rst diff --git a/clang/test/Format/lit.local.cfg b/clang/test/Format/lit.local.cfg index 8acf02725d701..b060c79226cbd 100644 --- a/clang/test/Format/lit.local.cfg +++ b/clang/test/Format/lit.local.cfg @@ -1,3 +1,6 @@ +import platform +import lit.formats + # Suffixes supported by clang-format. config.suffixes = [ ".c", @@ -19,3 +22,8 @@ config.suffixes = [ ".td", ".test" ] + +# AIX 'diff' command doesn't support --strip-trailing-cr, but the internal +# python implementation does, so use that for cross platform compatibility +if platform.system() == "AIX": + config.test_format = lit.formats.ShTest() diff --git a/clang/test/Headers/crash-instantiated-in-scope-cxx-modules4.cpp b/clang/test/Headers/crash-instantiated-in-scope-cxx-modules4.cpp new file mode 100644 index 0000000000000..087eb135dc5f5 --- /dev/null +++ b/clang/test/Headers/crash-instantiated-in-scope-cxx-modules4.cpp @@ -0,0 +1,110 @@ +// RUN: rm -fR %t +// RUN: split-file %s %t +// RUN: cd %t +// RUN: %clang_cc1 -verify -std=c++20 -x c++ -fmodule-map-file=modules.map -fmodule-name=foo1 -emit-module modules.map -o foo1.pcm +// RUN: %clang_cc1 -verify -std=c++20 -x c++ -fmodule-map-file=modules.map -fmodule-name=foo2 -emit-module modules.map -o foo2.pcm +// RUN: %clang_cc1 -verify -std=c++20 -x c++ -fmodule-map-file=modules.map -fmodule-file=foo1.pcm -fmodule-file=foo2.pcm server.cc + +//--- functional +#pragma once + +namespace std { +template class function {}; +} // namespace std + +//--- foo.h +#pragma once + +class MethodHandler { + public: + virtual ~MethodHandler() {} + struct HandlerParameter { + HandlerParameter(); + }; + virtual void RunHandler(const HandlerParameter ¶m); +}; + +template +class CallbackUnaryHandler : public MethodHandler { + public: + explicit CallbackUnaryHandler(); + + void RunHandler(const HandlerParameter ¶m) final { + void *call = nullptr; + (void)[call](bool){}; + } +}; + +//--- foo1.h +// expected-no-diagnostics +#pragma once + +#include "functional" + +#include "foo.h" + +class A; + +class ClientAsyncResponseReaderHelper { + public: + using t = std::function; + static void SetupRequest(t finish); +}; + +//--- foo2.h +// expected-no-diagnostics +#pragma once + +#include "foo.h" + +template +class a : public BaseClass { + public: + a() { [[maybe_unused]] CallbackUnaryHandler a; } +}; + +//--- modules.map +module "foo" { + export * + module "foo.h" { + export * + textual header "foo.h" + } +} + +module "foo1" { + export * + module "foo1.h" { + export * + header "foo1.h" + } + + use "foo" +} + +module "foo2" { + export * + module "foo2.h" { + export * + header "foo2.h" + } + + use "foo" +} + +//--- server.cc +// expected-no-diagnostics +#include "functional" + +#include "foo1.h" +#include "foo2.h" + +std::function on_emit; + +template +class CallbackUnaryHandler; + +class s {}; +class hs final : public a { + explicit hs() {} +}; diff --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp index 5b88e00b71508..3a60318d3f231 100644 --- a/clang/test/Lexer/cxx-features.cpp +++ b/clang/test/Lexer/cxx-features.cpp @@ -81,7 +81,7 @@ #error "wrong value for __cpp_named_character_escapes" #endif -#if check(explicit_this_parameter, 0, 0, 0, 0, 0, 0, 0) +#if check(explicit_this_parameter, 0, 0, 0, 0, 0, 202110L, 202110L) #error "wrong value for __cpp_explicit_this_parameter" #endif diff --git a/clang/test/Misc/target-invalid-cpu-note/riscv.c b/clang/test/Misc/target-invalid-cpu-note/riscv.c index 8c5df5884cd79..fc8536d99cb80 100644 --- a/clang/test/Misc/target-invalid-cpu-note/riscv.c +++ b/clang/test/Misc/target-invalid-cpu-note/riscv.c @@ -25,6 +25,7 @@ // RISCV64: error: unknown target CPU 'not-a-cpu' // RISCV64-NEXT: note: valid target CPU values are: // RISCV64-SAME: {{^}} generic-rv64 +// RISCV64-SAME: {{^}}, mips-p8700 // RISCV64-SAME: {{^}}, rocket-rv64 // RISCV64-SAME: {{^}}, sifive-p450 // RISCV64-SAME: {{^}}, sifive-p470 @@ -72,6 +73,7 @@ // TUNE-RISCV64: error: unknown target CPU 'not-a-cpu' // TUNE-RISCV64-NEXT: note: valid target CPU values are: // TUNE-RISCV64-SAME: {{^}} generic-rv64 +// TUNE-RISCV64-SAME: {{^}}, mips-p8700 // TUNE-RISCV64-SAME: {{^}}, rocket-rv64 // TUNE-RISCV64-SAME: {{^}}, sifive-p450 // TUNE-RISCV64-SAME: {{^}}, sifive-p470 diff --git a/clang/test/Modules/ExtDebugInfo.m b/clang/test/Modules/ExtDebugInfo.m index b6a8b2676e5ba..e2611ae530063 100644 --- a/clang/test/Modules/ExtDebugInfo.m +++ b/clang/test/Modules/ExtDebugInfo.m @@ -75,7 +75,8 @@ int foo(ObjCClass *c) { // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass", // CHECK-SAME: scope: ![[MOD]], -// CHECK-SAME: flags: DIFlagFwdDecl) +// CHECK-SAME: flags: DIFlagFwdDecl, +// CHECK-SAME: runtimeLang: DW_LANG_ObjC) // CHECK-NOT: !DICompositeType(tag: DW_TAG_structure_type, // CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, diff --git a/clang/test/Modules/ModuleDebugInfo.m b/clang/test/Modules/ModuleDebugInfo.m index 62c6fd68dd854..c527c43a0f4a2 100644 --- a/clang/test/Modules/ModuleDebugInfo.m +++ b/clang/test/Modules/ModuleDebugInfo.m @@ -39,6 +39,7 @@ // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "FwdDecl", // CHECK-SAME: scope: ![[MODULE]], +// CHECK-SAME: runtimeLang: DW_LANG_ObjC // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass", // CHECK-SAME: scope: ![[MODULE]], diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index b7d5741e69af6..7b41a0b0bfb2c 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -251,7 +251,7 @@ namespace Std { // CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate -// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]' +// CHECK-DUMP-NEXT: TemplateArgument type 'char[{{1|2}}]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition // CHECK-DUMP-NEXT: DefinitionData // CHECK-DUMP-NEXT: DefaultConstructor @@ -260,9 +260,9 @@ namespace Std { // CHECK-DUMP-NEXT: CopyAssignment // CHECK-DUMP-NEXT: MoveAssignment // CHECK-DUMP-NEXT: Destructor -// CHECK-DUMP-NEXT: TemplateArgument type 'char[2]' +// CHECK-DUMP-NEXT: TemplateArgument type 'char[{{1|2}}]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate -// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]' +// CHECK-DUMP-NEXT: TemplateArgument type 'char[{{1|2}}]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition // CHECK-DUMP-NEXT: DefinitionData // CHECK-DUMP-NEXT: DefaultConstructor @@ -271,4 +271,4 @@ namespace Std { // CHECK-DUMP-NEXT: CopyAssignment // CHECK-DUMP-NEXT: MoveAssignment // CHECK-DUMP-NEXT: Destructor -// CHECK-DUMP-NEXT: TemplateArgument type 'char[1]' +// CHECK-DUMP-NEXT: TemplateArgument type 'char[{{1|2}}]' diff --git a/clang/test/Modules/friend-inline-function-body.cpp b/clang/test/Modules/friend-inline-function-body.cpp new file mode 100644 index 0000000000000..478125a795554 --- /dev/null +++ b/clang/test/Modules/friend-inline-function-body.cpp @@ -0,0 +1,111 @@ +// RUN: rm -fR %t +// RUN: split-file %s %t +// RUN: cd %t +// RUN: %clang_cc1 -std=c++20 -fmodule-map-file=modules.map -xc++ -emit-module -fmodule-name=internal modules.map -o internal.pcm +// RUN: %clang_cc1 -std=c++20 -fmodule-map-file=modules.map -xc++ -emit-module -fmodule-name=interface modules.map -o interface.pcm +// RUN: %clang_cc1 -std=c++20 -fmodule-map-file=modules.map -xc++ -emit-module -fmodule-name=foo modules.map -o foo.pcm -fmodule-file=interface.pcm -fmodule-file=internal.pcm +// RUN: %clang_cc1 -std=c++20 -fmodule-map-file=modules.map -O1 -emit-obj main.cc -verify -fmodule-file=foo.pcm + +//--- modules.map +module "interface" { + export * + module "interface.h" { + export * + header "interface.h" + } +} + +module "internal" { + export * + module "internal.h" { + export * + header "internal.h" + } +} + +module "foo" { + export * + module "foo.h" { + export * + header "foo.h" + } +} + +//--- foo.h +#ifndef FOO_H +#define FOO_H + +#include "strong_int.h" + +DEFINE_STRONG_INT_TYPE(CallbackId, int); + +#define CALL_HASH(id) \ + (void)[&]() { AbslHashValue(0, id); }; + +void test(CallbackId id) { + CALL_HASH(id); +} + +#include "internal.h" +#include "interface.h" + +#endif + +//--- interface.h +#ifndef INTERFACE_H +#define INTERFACE_H + +#include "strong_int.h" + +DEFINE_STRONG_INT_TYPE(EndpointToken, int); + +#endif + +//--- internal.h +#ifndef INTERNAL_H +#define INTERNAL_H + +#include "strong_int.h" + +DEFINE_STRONG_INT_TYPE(OrderedListSortKey, int); +DEFINE_STRONG_INT_TYPE(OrderedListId, int); + +#endif + +//--- strong_int.h +#ifndef STRONG_INT_H +#define STRONG_INT_H + +namespace util_intops { + +template +class StrongInt2; + +template +class StrongInt2 { + public: + template + friend H AbslHashValue(H h, const StrongInt2& i) { + return h; + } +}; + +} // namespace util_intops + +#define DEFINE_STRONG_INT_TYPE(type_name, value_type) \ + struct type_name##_strong_int_tag_ {}; \ + typedef ::util_intops::StrongInt2 \ + type_name; + +#endif + +//--- main.cc +// expected-no-diagnostics +#include "foo.h" + +#include "strong_int.h" + +DEFINE_STRONG_INT_TYPE(ArchiveId2, int); +void partial(ArchiveId2 id) { + CALL_HASH(id); +} diff --git a/clang/test/Modules/initializer-list-recognition-through-export-and-linkage-issue-118218.cpp b/clang/test/Modules/initializer-list-recognition-through-export-and-linkage-issue-118218.cpp new file mode 100644 index 0000000000000..e2c796fb103f6 --- /dev/null +++ b/clang/test/Modules/initializer-list-recognition-through-export-and-linkage-issue-118218.cpp @@ -0,0 +1,39 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/std.cppm -emit-module-interface -o %t/std.pcm +// RUN: %clang_cc1 -std=c++20 %t/mod.cppm -fprebuilt-module-path=%t -emit-module-interface -o %t/mod.pcm +// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -verify %t/main.cpp + +//--- std.cppm +export module std; + +extern "C++" { + namespace std { + export template + class initializer_list { + const E* _1; + const E* _2; + }; + } +} + +//--- mod.cppm +export module mod; + +import std; + +export struct A { + void func(std::initializer_list) {} +}; + +//--- main.cpp +// expected-no-diagnostics +import std; +import mod; + +int main() { + A{}.func({1,1}); + return 0; +} diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index f1de6b3d433ed..4de0e50dbc0eb 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -3084,8 +3084,8 @@ struct S5 { }; #else S5 s5; -// expected-error@second.h:* {{'PointersAndReferences::S5::x' from module 'SecondModule' is not present in definition of 'PointersAndReferences::S5' in module 'FirstModule'}} -// expected-note@first.h:* {{declaration of 'x' does not match}} +// expected-error@first.h:* {{'PointersAndReferences::S5::x' from module 'FirstModule' is not present in definition of 'PointersAndReferences::S5' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} #endif #if defined(FIRST) diff --git a/clang/test/Modules/recursive-instantiations.cppm b/clang/test/Modules/recursive-instantiations.cppm new file mode 100644 index 0000000000000..d5854b0e647e3 --- /dev/null +++ b/clang/test/Modules/recursive-instantiations.cppm @@ -0,0 +1,40 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/type_traits.cppm -emit-module-interface -o %t/type_traits.pcm +// RUN: %clang_cc1 -std=c++20 %t/test.cpp -fprebuilt-module-path=%t -verify + +//--- type_traits.cppm +export module type_traits; + +export template +constexpr bool is_pod_v = __is_pod(T); + +//--- test.cpp +// expected-no-diagnostics +import type_traits; +// Base is either void or wrapper. +template struct wrapper : Base {}; +template <> struct wrapper {}; + +// wrap<0>::type is wrapper, wrap<1>::type is wrapper>, +// and so on. +template +struct wrap { + template + using type = wrapper::template type>; +}; + +template <> +struct wrap<0> { + template + using type = wrapper; +}; + +inline constexpr int kMaxRank = 40; +template +using rank = typename wrap::template type; +using rank_selector_t = rank; + +static_assert(is_pod_v, "Must be POD"); diff --git a/clang/test/OpenMP/amdgpu_threadprivate.cpp b/clang/test/OpenMP/amdgpu_threadprivate.cpp new file mode 100644 index 0000000000000..f7061f42bbe7c --- /dev/null +++ b/clang/test/OpenMP/amdgpu_threadprivate.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-linux-gnu -target-cpu gfx906 -fopenmp -nogpulib -fopenmp-is-target-device -emit-llvm %s -o - | FileCheck %s + +// Don't crash with assertions build. + +// CHECK: @MyGlobVar = external thread_local addrspace(1) global i32, align 4 +// CHECK: define weak_odr hidden noundef ptr @_ZTW9MyGlobVar() #0 comdat { +// CHECK-NEXT: %1 = call align 4 ptr addrspace(1) @llvm.threadlocal.address.p1(ptr addrspace(1) align 4 @MyGlobVar) +// CHECK-NEXT: %2 = addrspacecast ptr addrspace(1) %1 to ptr +// CHECK-NEXT: ret ptr %2 +// CHECK-NEXT: } +int MyGlobVar; +#pragma omp threadprivate(MyGlobVar) +int main() { + MyGlobVar = 1; +} + diff --git a/clang/test/OpenMP/declare_mapper_codegen.cpp b/clang/test/OpenMP/declare_mapper_codegen.cpp index d2954b7a74821..f9da3d97766d9 100644 --- a/clang/test/OpenMP/declare_mapper_codegen.cpp +++ b/clang/test/OpenMP/declare_mapper_codegen.cpp @@ -86,19 +86,9 @@ class C { #pragma omp declare mapper(id: C s) map(s.a, s.b[0:2]) -// CK0: define {{.*}}void [[MPRFUNC:@[.]omp_mapper[.].*C[.]id]](ptr{{.*}}, ptr{{.*}}, ptr{{.*}}, i64{{.*}}, i64{{.*}}, ptr{{.*}}) -// CK0: store ptr %{{[^,]+}}, ptr [[HANDLEADDR:%[^,]+]] -// CK0: store ptr %{{[^,]+}}, ptr [[BPTRADDR:%[^,]+]] -// CK0: store ptr %{{[^,]+}}, ptr [[VPTRADDR:%[^,]+]] -// CK0: store i64 %{{[^,]+}}, ptr [[SIZEADDR:%[^,]+]] -// CK0: store i64 %{{[^,]+}}, ptr [[TYPEADDR:%[^,]+]] -// CK0-DAG: [[BYTESIZE:%.+]] = load i64, ptr [[SIZEADDR]] +// CK0: define {{.*}}void [[MPRFUNC:@[.]omp_mapper[.].*C[.]id]](ptr noundef [[HANDLE:%.+]], ptr noundef [[BPTR:%.+]], ptr noundef [[BEGIN:%.+]], i64 noundef [[BYTESIZE:%.+]], i64 noundef [[TYPE:%.+]], ptr{{.*}}) // CK0-64-DAG: [[SIZE:%.+]] = udiv exact i64 [[BYTESIZE]], 16 // CK0-32-DAG: [[SIZE:%.+]] = udiv exact i64 [[BYTESIZE]], 8 -// CK0-DAG: [[TYPE:%.+]] = load i64, ptr [[TYPEADDR]] -// CK0-DAG: [[HANDLE:%.+]] = load ptr, ptr [[HANDLEADDR]] -// CK0-DAG: [[BPTR:%.+]] = load ptr, ptr [[BPTRADDR]] -// CK0-DAG: [[BEGIN:%.+]] = load ptr, ptr [[VPTRADDR]] // CK0-DAG: [[ISARRAY:%.+]] = icmp sgt i64 [[SIZE]], 1 // CK0-DAG: [[PTREND:%.+]] = getelementptr %class.C, ptr [[BEGIN]], i64 [[SIZE]] // CK0-DAG: [[PTRSNE:%.+]] = icmp ne ptr [[BPTR]], [[BEGIN]] @@ -597,18 +587,8 @@ class C { #pragma omp declare mapper(id: C s) map(s.a) -// CK1-LABEL: define {{.*}}void @.omp_mapper.{{.*}}C{{.*}}.id{{.*}}(ptr{{.*}}, ptr{{.*}}, ptr{{.*}}, i64{{.*}}, i64{{.*}}, ptr{{.*}}) -// CK1: store ptr %{{[^,]+}}, ptr [[HANDLEADDR:%[^,]+]] -// CK1: store ptr %{{[^,]+}}, ptr [[BPTRADDR:%[^,]+]] -// CK1: store ptr %{{[^,]+}}, ptr [[VPTRADDR:%[^,]+]] -// CK1: store i64 %{{[^,]+}}, ptr [[SIZEADDR:%[^,]+]] -// CK1: store i64 %{{[^,]+}}, ptr [[TYPEADDR:%[^,]+]] -// CK1-DAG: [[BYTESIZE:%.+]] = load i64, ptr [[SIZEADDR]] +// CK1: define {{.*}}void @.omp_mapper.{{.*}}C{{.*}}.id{{.*}}(ptr noundef [[HANDLE:%.+]], ptr noundef [[BPTR:%.+]], ptr noundef [[BEGIN:%.+]], i64 noundef [[BYTESIZE:%.+]], i64 noundef [[TYPE:%.+]], ptr{{.*}}) // CK1-DAG: [[SIZE:%.+]] = udiv exact i64 [[BYTESIZE]], 4 -// CK1-DAG: [[TYPE:%.+]] = load i64, ptr [[TYPEADDR]] -// CK1-DAG: [[HANDLE:%.+]] = load ptr, ptr [[HANDLEADDR]] -// CK1-DAG: [[BPTR:%.+]] = load ptr, ptr [[BPTRADDR]] -// CK1-DAG: [[BEGIN:%.+]] = load ptr, ptr [[VPTRADDR]] // CK1-DAG: [[PTREND:%.+]] = getelementptr %class.C, ptr [[BEGIN]], i64 [[SIZE]] // CK1-DAG: [[ISARRAY:%.+]] = icmp sgt i64 [[SIZE]], 1 // CK1-DAG: [[PTRSNE:%.+]] = icmp ne ptr [[BPTR]], [[BEGIN]] @@ -717,18 +697,8 @@ class C { // CK2: define {{.*}}void [[BMPRFUNC:@[.]omp_mapper[.].*B[.]default]](ptr{{.*}}, ptr{{.*}}, ptr{{.*}}, i64{{.*}}, i64{{.*}}, ptr{{.*}}) -// CK2-LABEL: define {{.*}}void @.omp_mapper.{{.*}}C{{.*}}.id(ptr{{.*}}, ptr{{.*}}, ptr{{.*}}, i64{{.*}}, i64{{.*}}, ptr{{.*}}) -// CK2: store ptr %{{[^,]+}}, ptr [[HANDLEADDR:%[^,]+]] -// CK2: store ptr %{{[^,]+}}, ptr [[BPTRADDR:%[^,]+]] -// CK2: store ptr %{{[^,]+}}, ptr [[VPTRADDR:%[^,]+]] -// CK2: store i64 %{{[^,]+}}, ptr [[SIZEADDR:%[^,]+]] -// CK2: store i64 %{{[^,]+}}, ptr [[TYPEADDR:%[^,]+]] -// CK2-DAG: [[BYTESIZE:%.+]] = load i64, ptr [[SIZEADDR]] +// CK2: define {{.*}}void @.omp_mapper.{{.*}}C{{.*}}.id(ptr noundef [[HANDLE:%.+]], ptr noundef [[BPTR:%.+]], ptr noundef [[BEGIN:%.+]], i64 noundef [[BYTESIZE:%.+]], i64 noundef [[TYPE:%.+]], ptr{{.*}}) // CK2-DAG: [[SIZE:%.+]] = udiv exact i64 [[BYTESIZE]], 16 -// CK2-DAG: [[TYPE:%.+]] = load i64, ptr [[TYPEADDR]] -// CK2-DAG: [[HANDLE:%.+]] = load ptr, ptr [[HANDLEADDR]] -// CK2-DAG: [[BPTR:%.+]] = load ptr, ptr [[BPTRADDR]] -// CK2-DAG: [[BEGIN:%.+]] = load ptr, ptr [[VPTRADDR]] // CK2-DAG: [[PTREND:%.+]] = getelementptr %class.C, ptr [[BEGIN]], i64 [[SIZE]] // CK2-DAG: [[ISARRAY:%.+]] = icmp sgt i64 [[SIZE]], 1 // CK2-DAG: [[PTRSNE:%.+]] = icmp ne ptr [[BPTR]], [[BEGIN]] @@ -921,19 +891,9 @@ class C { #pragma omp declare mapper(id: C s) map(s.a, s.b[0:2]) -// CK4: define {{.*}}void [[MPRFUNC:@[.]omp_mapper[.].*C[.]id]](ptr{{.*}}, ptr{{.*}}, ptr{{.*}}, i64{{.*}}, i64{{.*}}, ptr{{.*}}) -// CK4: store ptr %{{[^,]+}}, ptr [[HANDLEADDR:%[^,]+]] -// CK4: store ptr %{{[^,]+}}, ptr [[BPTRADDR:%[^,]+]] -// CK4: store ptr %{{[^,]+}}, ptr [[VPTRADDR:%[^,]+]] -// CK4: store i64 %{{[^,]+}}, ptr [[SIZEADDR:%[^,]+]] -// CK4: store i64 %{{[^,]+}}, ptr [[TYPEADDR:%[^,]+]] -// CK4-DAG: [[BYTESIZE:%.+]] = load i64, ptr [[SIZEADDR]] +// CK4: define {{.*}}void [[MPRFUNC:@[.]omp_mapper[.].*C[.]id]](ptr noundef [[HANDLE:%.+]], ptr noundef [[BPTR:%.+]], ptr noundef [[BEGIN:%.+]], i64 noundef [[BYTESIZE:%.+]], i64 noundef [[TYPE:%.+]], ptr{{.*}}) // CK4-64-DAG: [[SIZE:%.+]] = udiv exact i64 [[BYTESIZE]], 16 // CK4-32-DAG: [[SIZE:%.+]] = udiv exact i64 [[BYTESIZE]], 8 -// CK4-DAG: [[TYPE:%.+]] = load i64, ptr [[TYPEADDR]] -// CK4-DAG: [[HANDLE:%.+]] = load ptr, ptr [[HANDLEADDR]] -// CK4-DAG: [[BPTR:%.+]] = load ptr, ptr [[BPTRADDR]] -// CK4-DAG: [[BEGIN:%.+]] = load ptr, ptr [[VPTRADDR]] // CK4-DAG: [[PTREND:%.+]] = getelementptr %class.C, ptr [[BEGIN]], i64 [[SIZE]] // CK4-DAG: [[ISARRAY:%.+]] = icmp sgt i64 [[SIZE]], 1 // CK4-DAG: [[PTRSNE:%.+]] = icmp ne ptr [[BPTR]], [[BEGIN]] diff --git a/clang/test/OpenMP/target_map_names.cpp b/clang/test/OpenMP/target_map_names.cpp index c1c2015609fb7..3ee28d3ce5ce9 100644 --- a/clang/test/OpenMP/target_map_names.cpp +++ b/clang/test/OpenMP/target_map_names.cpp @@ -201,9 +201,7 @@ void secondMapNameInClause() { // DEBUG: store ptr @[[NAME:.offload_mapnames.[0-9]+]], ptr %[[ARG:.+]] // CHECK-NOT: store ptr @[[NAME:.offload_mapnames.[0-9]+]], ptr %[[ARG:.+]] -// DEBUG: void @.omp_mapper._ZTS2S3.id(ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}, ptr noundef [[NAME_ARG:%.+]]) -// DEBUG: store ptr [[NAME_ARG]], ptr [[NAME_STACK:%.+]] -// DEBUG: [[MAPPER_NAME:%.+]] = load ptr, ptr [[NAME_STACK]] +// DEBUG: void @.omp_mapper._ZTS2S3.id(ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}, ptr noundef [[MAPPER_NAME:%.+]]) // DEBUG: call void @__tgt_push_mapper_component(ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, i64 %{{.*}}, i64 %{{.*}}, ptr [[MAPPER_NAME]]) #endif diff --git a/clang/test/OpenMP/target_map_names_attr.cpp b/clang/test/OpenMP/target_map_names_attr.cpp index cb108474b3561..e6b0e1beb5bd5 100644 --- a/clang/test/OpenMP/target_map_names_attr.cpp +++ b/clang/test/OpenMP/target_map_names_attr.cpp @@ -186,9 +186,7 @@ void secondMapNameInClause() { // DEBUG: store ptr @[[NAME:.offload_mapnames.[0-9]+]], ptr %[[ARG:.+]] // CHECK-NOT: store ptr @[[NAME:.offload_mapnames.[0-9]+]], ptr %[[ARG:.+]] -// DEBUG: void @.omp_mapper._ZTS2S3.id(ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}, ptr noundef [[NAME_ARG:%.+]]) -// DEBUG: store ptr [[NAME_ARG]], ptr [[NAME_STACK:%.+]] -// DEBUG: [[MAPPER_NAME:%.+]] = load ptr, ptr [[NAME_STACK]] +// DEBUG: void @.omp_mapper._ZTS2S3.id(ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}, ptr noundef [[MAPPER_NAME:%.+]]) // DEBUG: call void @__tgt_push_mapper_component(ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, i64 %{{.*}}, i64 %{{.*}}, ptr [[MAPPER_NAME]]) #endif diff --git a/clang/test/OpenMP/target_map_nest_defalut_mapper_codegen.cpp b/clang/test/OpenMP/target_map_nest_defalut_mapper_codegen.cpp index 775f0b296b1b6..0fc6de0e4279a 100644 --- a/clang/test/OpenMP/target_map_nest_defalut_mapper_codegen.cpp +++ b/clang/test/OpenMP/target_map_nest_defalut_mapper_codegen.cpp @@ -109,30 +109,12 @@ void foo() { // CHECK-LABEL: define {{[^@]+}}@.omp_mapper._ZTS1D.default // CHECK-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]], ptr noundef [[TMP2:%.*]], i64 noundef [[TMP3:%.*]], i64 noundef [[TMP4:%.*]], ptr noundef [[TMP5:%.*]]) #[[ATTR2:[0-9]+]] { // CHECK-NEXT: entry: -// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[DOTADDR2:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[DOTADDR3:%.*]] = alloca i64, align 8 -// CHECK-NEXT: [[DOTADDR4:%.*]] = alloca i64, align 8 -// CHECK-NEXT: [[DOTADDR5:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 -// CHECK-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK-NEXT: store ptr [[TMP2]], ptr [[DOTADDR2]], align 8 -// CHECK-NEXT: store i64 [[TMP3]], ptr [[DOTADDR3]], align 8 -// CHECK-NEXT: store i64 [[TMP4]], ptr [[DOTADDR4]], align 8 -// CHECK-NEXT: store ptr [[TMP5]], ptr [[DOTADDR5]], align 8 -// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr [[DOTADDR3]], align 8 -// CHECK-NEXT: [[TMP7:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 -// CHECK-NEXT: [[TMP9:%.*]] = load ptr, ptr [[DOTADDR2]], align 8 -// CHECK-NEXT: [[TMP10:%.*]] = udiv exact i64 [[TMP6]], 12 -// CHECK-NEXT: [[TMP11:%.*]] = getelementptr [[STRUCT_D:%.*]], ptr [[TMP9]], i64 [[TMP10]] -// CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTADDR4]], align 8 -// CHECK-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTADDR5]], align 8 +// CHECK-NEXT: [[TMP10:%.*]] = udiv exact i64 [[TMP3]], 12 +// CHECK-NEXT: [[TMP11:%.*]] = getelementptr [[STRUCT_D:%.*]], ptr [[TMP2]], i64 [[TMP10]] // CHECK-NEXT: [[OMP_ARRAYINIT_ISARRAY:%.*]] = icmp sgt i64 [[TMP10]], 1 -// CHECK-NEXT: [[TMP14:%.*]] = and i64 [[TMP12]], 8 -// CHECK-NEXT: [[TMP15:%.*]] = icmp ne ptr [[TMP8]], [[TMP9]] -// CHECK-NEXT: [[TMP16:%.*]] = and i64 [[TMP12]], 16 +// CHECK-NEXT: [[TMP14:%.*]] = and i64 [[TMP4]], 8 +// CHECK-NEXT: [[TMP15:%.*]] = icmp ne ptr [[TMP1]], [[TMP2]] +// CHECK-NEXT: [[TMP16:%.*]] = and i64 [[TMP4]], 16 // CHECK-NEXT: [[TMP17:%.*]] = icmp ne i64 [[TMP16]], 0 // CHECK-NEXT: [[TMP18:%.*]] = and i1 [[TMP15]], [[TMP17]] // CHECK-NEXT: [[TMP19:%.*]] = or i1 [[OMP_ARRAYINIT_ISARRAY]], [[TMP18]] @@ -141,15 +123,15 @@ void foo() { // CHECK-NEXT: br i1 [[TMP20]], label [[DOTOMP_ARRAY__INIT:%.*]], label [[OMP_ARRAYMAP_HEAD:%.*]] // CHECK: .omp.array..init: // CHECK-NEXT: [[TMP21:%.*]] = mul nuw i64 [[TMP10]], 12 -// CHECK-NEXT: [[TMP22:%.*]] = and i64 [[TMP12]], -4 +// CHECK-NEXT: [[TMP22:%.*]] = and i64 [[TMP4]], -4 // CHECK-NEXT: [[TMP23:%.*]] = or i64 [[TMP22]], 512 -// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP7]], ptr [[TMP8]], ptr [[TMP9]], i64 [[TMP21]], i64 [[TMP23]], ptr [[TMP13]]) +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[TMP1]], ptr [[TMP2]], i64 [[TMP21]], i64 [[TMP23]], ptr [[TMP5]]) // CHECK-NEXT: br label [[OMP_ARRAYMAP_HEAD]] // CHECK: omp.arraymap.head: -// CHECK-NEXT: [[OMP_ARRAYMAP_ISEMPTY:%.*]] = icmp eq ptr [[TMP9]], [[TMP11]] +// CHECK-NEXT: [[OMP_ARRAYMAP_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP11]] // CHECK-NEXT: br i1 [[OMP_ARRAYMAP_ISEMPTY]], label [[OMP_DONE:%.*]], label [[OMP_ARRAYMAP_BODY:%.*]] // CHECK: omp.arraymap.body: -// CHECK-NEXT: [[OMP_ARRAYMAP_PTRCURRENT:%.*]] = phi ptr [ [[TMP9]], [[OMP_ARRAYMAP_HEAD]] ], [ [[OMP_ARRAYMAP_NEXT:%.*]], [[OMP_TYPE_END25:%.*]] ] +// CHECK-NEXT: [[OMP_ARRAYMAP_PTRCURRENT:%.*]] = phi ptr [ [[TMP2]], [[OMP_ARRAYMAP_HEAD]] ], [ [[OMP_ARRAYMAP_NEXT:%.*]], [[OMP_TYPE_END25:%.*]] ] // CHECK-NEXT: [[E:%.*]] = getelementptr inbounds nuw [[STRUCT_D]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], i32 0, i32 0 // CHECK-NEXT: [[F:%.*]] = getelementptr inbounds nuw [[STRUCT_D]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], i32 0, i32 1 // CHECK-NEXT: [[H:%.*]] = getelementptr inbounds nuw [[STRUCT_D]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], i32 0, i32 2 @@ -158,10 +140,10 @@ void foo() { // CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[E]] to i64 // CHECK-NEXT: [[TMP27:%.*]] = sub i64 [[TMP25]], [[TMP26]] // CHECK-NEXT: [[TMP28:%.*]] = sdiv exact i64 [[TMP27]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -// CHECK-NEXT: [[TMP29:%.*]] = call i64 @__tgt_mapper_num_components(ptr [[TMP7]]) +// CHECK-NEXT: [[TMP29:%.*]] = call i64 @__tgt_mapper_num_components(ptr [[TMP0]]) // CHECK-NEXT: [[TMP30:%.*]] = shl i64 [[TMP29]], 48 // CHECK-NEXT: [[TMP31:%.*]] = add nuw i64 0, [[TMP30]] -// CHECK-NEXT: [[TMP32:%.*]] = and i64 [[TMP12]], 3 +// CHECK-NEXT: [[TMP32:%.*]] = and i64 [[TMP4]], 3 // CHECK-NEXT: [[TMP33:%.*]] = icmp eq i64 [[TMP32]], 0 // CHECK-NEXT: br i1 [[TMP33]], label [[OMP_TYPE_ALLOC:%.*]], label [[OMP_TYPE_ALLOC_ELSE:%.*]] // CHECK: omp.type.alloc: @@ -181,87 +163,87 @@ void foo() { // CHECK-NEXT: br label [[OMP_TYPE_END]] // CHECK: omp.type.end: // CHECK-NEXT: [[OMP_MAPTYPE:%.*]] = phi i64 [ [[TMP34]], [[OMP_TYPE_ALLOC]] ], [ [[TMP36]], [[OMP_TYPE_TO]] ], [ [[TMP38]], [[OMP_TYPE_FROM]] ], [ [[TMP31]], [[OMP_TYPE_TO_ELSE]] ] -// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP7]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[E]], i64 [[TMP28]], i64 [[OMP_MAPTYPE]], ptr null) +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[E]], i64 [[TMP28]], i64 [[OMP_MAPTYPE]], ptr null) // CHECK-NEXT: [[TMP39:%.*]] = add nuw i64 281474976711171, [[TMP30]] -// CHECK-NEXT: [[TMP40:%.*]] = and i64 [[TMP12]], 3 +// CHECK-NEXT: [[TMP40:%.*]] = and i64 [[TMP4]], 3 // CHECK-NEXT: [[TMP41:%.*]] = icmp eq i64 [[TMP40]], 0 // CHECK-NEXT: br i1 [[TMP41]], label [[OMP_TYPE_ALLOC6:%.*]], label [[OMP_TYPE_ALLOC_ELSE7:%.*]] -// CHECK: omp.type.alloc6: +// CHECK: omp.type.alloc1: // CHECK-NEXT: [[TMP42:%.*]] = and i64 [[TMP39]], -4 // CHECK-NEXT: br label [[OMP_TYPE_END11:%.*]] -// CHECK: omp.type.alloc.else7: +// CHECK: omp.type.alloc.else2: // CHECK-NEXT: [[TMP43:%.*]] = icmp eq i64 [[TMP40]], 1 // CHECK-NEXT: br i1 [[TMP43]], label [[OMP_TYPE_TO8:%.*]], label [[OMP_TYPE_TO_ELSE9:%.*]] -// CHECK: omp.type.to8: +// CHECK: omp.type.to3: // CHECK-NEXT: [[TMP44:%.*]] = and i64 [[TMP39]], -3 // CHECK-NEXT: br label [[OMP_TYPE_END11]] -// CHECK: omp.type.to.else9: +// CHECK: omp.type.to.else4: // CHECK-NEXT: [[TMP45:%.*]] = icmp eq i64 [[TMP40]], 2 // CHECK-NEXT: br i1 [[TMP45]], label [[OMP_TYPE_FROM10:%.*]], label [[OMP_TYPE_END11]] -// CHECK: omp.type.from10: +// CHECK: omp.type.from5: // CHECK-NEXT: [[TMP46:%.*]] = and i64 [[TMP39]], -2 // CHECK-NEXT: br label [[OMP_TYPE_END11]] -// CHECK: omp.type.end11: +// CHECK: omp.type.end6: // CHECK-NEXT: [[OMP_MAPTYPE12:%.*]] = phi i64 [ [[TMP42]], [[OMP_TYPE_ALLOC6]] ], [ [[TMP44]], [[OMP_TYPE_TO8]] ], [ [[TMP46]], [[OMP_TYPE_FROM10]] ], [ [[TMP39]], [[OMP_TYPE_TO_ELSE9]] ] -// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP7]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[E]], i64 4, i64 [[OMP_MAPTYPE12]], ptr null) +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[E]], i64 4, i64 [[OMP_MAPTYPE12]], ptr null) // CHECK-NEXT: [[TMP47:%.*]] = add nuw i64 281474976711171, [[TMP30]] -// CHECK-NEXT: [[TMP48:%.*]] = and i64 [[TMP12]], 3 +// CHECK-NEXT: [[TMP48:%.*]] = and i64 [[TMP4]], 3 // CHECK-NEXT: [[TMP49:%.*]] = icmp eq i64 [[TMP48]], 0 // CHECK-NEXT: br i1 [[TMP49]], label [[OMP_TYPE_ALLOC13:%.*]], label [[OMP_TYPE_ALLOC_ELSE14:%.*]] -// CHECK: omp.type.alloc13: +// CHECK: omp.type.alloc8: // CHECK-NEXT: [[TMP50:%.*]] = and i64 [[TMP47]], -4 // CHECK-NEXT: br label [[OMP_TYPE_END18:%.*]] -// CHECK: omp.type.alloc.else14: +// CHECK: omp.type.alloc.else9: // CHECK-NEXT: [[TMP51:%.*]] = icmp eq i64 [[TMP48]], 1 // CHECK-NEXT: br i1 [[TMP51]], label [[OMP_TYPE_TO15:%.*]], label [[OMP_TYPE_TO_ELSE16:%.*]] -// CHECK: omp.type.to15: +// CHECK: omp.type.to10: // CHECK-NEXT: [[TMP52:%.*]] = and i64 [[TMP47]], -3 // CHECK-NEXT: br label [[OMP_TYPE_END18]] -// CHECK: omp.type.to.else16: +// CHECK: omp.type.to.else11: // CHECK-NEXT: [[TMP53:%.*]] = icmp eq i64 [[TMP48]], 2 // CHECK-NEXT: br i1 [[TMP53]], label [[OMP_TYPE_FROM17:%.*]], label [[OMP_TYPE_END18]] -// CHECK: omp.type.from17: +// CHECK: omp.type.from12: // CHECK-NEXT: [[TMP54:%.*]] = and i64 [[TMP47]], -2 // CHECK-NEXT: br label [[OMP_TYPE_END18]] -// CHECK: omp.type.end18: +// CHECK: omp.type.end13: // CHECK-NEXT: [[OMP_MAPTYPE19:%.*]] = phi i64 [ [[TMP50]], [[OMP_TYPE_ALLOC13]] ], [ [[TMP52]], [[OMP_TYPE_TO15]] ], [ [[TMP54]], [[OMP_TYPE_FROM17]] ], [ [[TMP47]], [[OMP_TYPE_TO_ELSE16]] ] -// CHECK-NEXT: call void @.omp_mapper._ZTS1C.default(ptr [[TMP7]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[F]], i64 4, i64 [[OMP_MAPTYPE19]], ptr null) #[[ATTR3]] +// CHECK-NEXT: call void @.omp_mapper._ZTS1C.default(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[F]], i64 4, i64 [[OMP_MAPTYPE19]], ptr null) #[[ATTR3]] // CHECK-NEXT: [[TMP55:%.*]] = add nuw i64 281474976711171, [[TMP30]] -// CHECK-NEXT: [[TMP56:%.*]] = and i64 [[TMP12]], 3 +// CHECK-NEXT: [[TMP56:%.*]] = and i64 [[TMP4]], 3 // CHECK-NEXT: [[TMP57:%.*]] = icmp eq i64 [[TMP56]], 0 // CHECK-NEXT: br i1 [[TMP57]], label [[OMP_TYPE_ALLOC20:%.*]], label [[OMP_TYPE_ALLOC_ELSE21:%.*]] -// CHECK: omp.type.alloc20: +// CHECK: omp.type.alloc15: // CHECK-NEXT: [[TMP58:%.*]] = and i64 [[TMP55]], -4 // CHECK-NEXT: br label [[OMP_TYPE_END25]] -// CHECK: omp.type.alloc.else21: +// CHECK: omp.type.alloc.else16: // CHECK-NEXT: [[TMP59:%.*]] = icmp eq i64 [[TMP56]], 1 // CHECK-NEXT: br i1 [[TMP59]], label [[OMP_TYPE_TO22:%.*]], label [[OMP_TYPE_TO_ELSE23:%.*]] -// CHECK: omp.type.to22: +// CHECK: omp.type.to17: // CHECK-NEXT: [[TMP60:%.*]] = and i64 [[TMP55]], -3 // CHECK-NEXT: br label [[OMP_TYPE_END25]] -// CHECK: omp.type.to.else23: +// CHECK: omp.type.to.else18: // CHECK-NEXT: [[TMP61:%.*]] = icmp eq i64 [[TMP56]], 2 // CHECK-NEXT: br i1 [[TMP61]], label [[OMP_TYPE_FROM24:%.*]], label [[OMP_TYPE_END25]] -// CHECK: omp.type.from24: +// CHECK: omp.type.from19: // CHECK-NEXT: [[TMP62:%.*]] = and i64 [[TMP55]], -2 // CHECK-NEXT: br label [[OMP_TYPE_END25]] -// CHECK: omp.type.end25: +// CHECK: omp.type.end20: // CHECK-NEXT: [[OMP_MAPTYPE26:%.*]] = phi i64 [ [[TMP58]], [[OMP_TYPE_ALLOC20]] ], [ [[TMP60]], [[OMP_TYPE_TO22]] ], [ [[TMP62]], [[OMP_TYPE_FROM24]] ], [ [[TMP55]], [[OMP_TYPE_TO_ELSE23]] ] -// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP7]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[H]], i64 4, i64 [[OMP_MAPTYPE26]], ptr null) +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[H]], i64 4, i64 [[OMP_MAPTYPE26]], ptr null) // CHECK-NEXT: [[OMP_ARRAYMAP_NEXT]] = getelementptr [[STRUCT_D]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], i32 1 // CHECK-NEXT: [[OMP_ARRAYMAP_ISDONE:%.*]] = icmp eq ptr [[OMP_ARRAYMAP_NEXT]], [[TMP11]] // CHECK-NEXT: br i1 [[OMP_ARRAYMAP_ISDONE]], label [[OMP_ARRAYMAP_EXIT:%.*]], label [[OMP_ARRAYMAP_BODY]] // CHECK: omp.arraymap.exit: // CHECK-NEXT: [[OMP_ARRAYINIT_ISARRAY27:%.*]] = icmp sgt i64 [[TMP10]], 1 -// CHECK-NEXT: [[TMP63:%.*]] = and i64 [[TMP12]], 8 +// CHECK-NEXT: [[TMP63:%.*]] = and i64 [[TMP4]], 8 // CHECK-NEXT: [[DOTOMP_ARRAY__DEL__DELETE:%.*]] = icmp ne i64 [[TMP63]], 0 // CHECK-NEXT: [[TMP64:%.*]] = and i1 [[OMP_ARRAYINIT_ISARRAY27]], [[DOTOMP_ARRAY__DEL__DELETE]] // CHECK-NEXT: br i1 [[TMP64]], label [[DOTOMP_ARRAY__DEL:%.*]], label [[OMP_DONE]] // CHECK: .omp.array..del: // CHECK-NEXT: [[TMP65:%.*]] = mul nuw i64 [[TMP10]], 12 -// CHECK-NEXT: [[TMP66:%.*]] = and i64 [[TMP12]], -4 +// CHECK-NEXT: [[TMP66:%.*]] = and i64 [[TMP4]], -4 // CHECK-NEXT: [[TMP67:%.*]] = or i64 [[TMP66]], 512 -// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP7]], ptr [[TMP8]], ptr [[TMP9]], i64 [[TMP65]], i64 [[TMP67]], ptr [[TMP13]]) +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[TMP1]], ptr [[TMP2]], i64 [[TMP65]], i64 [[TMP67]], ptr [[TMP5]]) // CHECK-NEXT: br label [[OMP_DONE]] // CHECK: omp.done: // CHECK-NEXT: ret void @@ -270,30 +252,12 @@ void foo() { // CHECK-LABEL: define {{[^@]+}}@.omp_mapper._ZTS1C.default // CHECK-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]], ptr noundef [[TMP2:%.*]], i64 noundef [[TMP3:%.*]], i64 noundef [[TMP4:%.*]], ptr noundef [[TMP5:%.*]]) #[[ATTR2]] { // CHECK-NEXT: entry: -// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[DOTADDR2:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: [[DOTADDR3:%.*]] = alloca i64, align 8 -// CHECK-NEXT: [[DOTADDR4:%.*]] = alloca i64, align 8 -// CHECK-NEXT: [[DOTADDR5:%.*]] = alloca ptr, align 8 -// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 -// CHECK-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8 -// CHECK-NEXT: store ptr [[TMP2]], ptr [[DOTADDR2]], align 8 -// CHECK-NEXT: store i64 [[TMP3]], ptr [[DOTADDR3]], align 8 -// CHECK-NEXT: store i64 [[TMP4]], ptr [[DOTADDR4]], align 8 -// CHECK-NEXT: store ptr [[TMP5]], ptr [[DOTADDR5]], align 8 -// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr [[DOTADDR3]], align 8 -// CHECK-NEXT: [[TMP7:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTADDR1]], align 8 -// CHECK-NEXT: [[TMP9:%.*]] = load ptr, ptr [[DOTADDR2]], align 8 -// CHECK-NEXT: [[TMP10:%.*]] = udiv exact i64 [[TMP6]], 4 -// CHECK-NEXT: [[TMP11:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[TMP9]], i64 [[TMP10]] -// CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTADDR4]], align 8 -// CHECK-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTADDR5]], align 8 +// CHECK-NEXT: [[TMP10:%.*]] = udiv exact i64 [[TMP3]], 4 +// CHECK-NEXT: [[TMP11:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[TMP2]], i64 [[TMP10]] // CHECK-NEXT: [[OMP_ARRAYINIT_ISARRAY:%.*]] = icmp sgt i64 [[TMP10]], 1 -// CHECK-NEXT: [[TMP14:%.*]] = and i64 [[TMP12]], 8 -// CHECK-NEXT: [[TMP15:%.*]] = icmp ne ptr [[TMP8]], [[TMP9]] -// CHECK-NEXT: [[TMP16:%.*]] = and i64 [[TMP12]], 16 +// CHECK-NEXT: [[TMP14:%.*]] = and i64 [[TMP4]], 8 +// CHECK-NEXT: [[TMP15:%.*]] = icmp ne ptr [[TMP1]], [[TMP2]] +// CHECK-NEXT: [[TMP16:%.*]] = and i64 [[TMP4]], 16 // CHECK-NEXT: [[TMP17:%.*]] = icmp ne i64 [[TMP16]], 0 // CHECK-NEXT: [[TMP18:%.*]] = and i1 [[TMP15]], [[TMP17]] // CHECK-NEXT: [[TMP19:%.*]] = or i1 [[OMP_ARRAYINIT_ISARRAY]], [[TMP18]] @@ -302,20 +266,20 @@ void foo() { // CHECK-NEXT: br i1 [[TMP20]], label [[DOTOMP_ARRAY__INIT:%.*]], label [[OMP_ARRAYMAP_HEAD:%.*]] // CHECK: .omp.array..init: // CHECK-NEXT: [[TMP21:%.*]] = mul nuw i64 [[TMP10]], 4 -// CHECK-NEXT: [[TMP22:%.*]] = and i64 [[TMP12]], -4 +// CHECK-NEXT: [[TMP22:%.*]] = and i64 [[TMP4]], -4 // CHECK-NEXT: [[TMP23:%.*]] = or i64 [[TMP22]], 512 -// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP7]], ptr [[TMP8]], ptr [[TMP9]], i64 [[TMP21]], i64 [[TMP23]], ptr [[TMP13]]) +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[TMP1]], ptr [[TMP2]], i64 [[TMP21]], i64 [[TMP23]], ptr [[TMP5]]) // CHECK-NEXT: br label [[OMP_ARRAYMAP_HEAD]] // CHECK: omp.arraymap.head: -// CHECK-NEXT: [[OMP_ARRAYMAP_ISEMPTY:%.*]] = icmp eq ptr [[TMP9]], [[TMP11]] +// CHECK-NEXT: [[OMP_ARRAYMAP_ISEMPTY:%.*]] = icmp eq ptr [[TMP2]], [[TMP11]] // CHECK-NEXT: br i1 [[OMP_ARRAYMAP_ISEMPTY]], label [[OMP_DONE:%.*]], label [[OMP_ARRAYMAP_BODY:%.*]] // CHECK: omp.arraymap.body: -// CHECK-NEXT: [[OMP_ARRAYMAP_PTRCURRENT:%.*]] = phi ptr [ [[TMP9]], [[OMP_ARRAYMAP_HEAD]] ], [ [[OMP_ARRAYMAP_NEXT:%.*]], [[OMP_TYPE_END:%.*]] ] +// CHECK-NEXT: [[OMP_ARRAYMAP_PTRCURRENT:%.*]] = phi ptr [ [[TMP2]], [[OMP_ARRAYMAP_HEAD]] ], [ [[OMP_ARRAYMAP_NEXT:%.*]], [[OMP_TYPE_END:%.*]] ] // CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_C]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], i32 0, i32 0 -// CHECK-NEXT: [[TMP24:%.*]] = call i64 @__tgt_mapper_num_components(ptr [[TMP7]]) +// CHECK-NEXT: [[TMP24:%.*]] = call i64 @__tgt_mapper_num_components(ptr [[TMP0]]) // CHECK-NEXT: [[TMP25:%.*]] = shl i64 [[TMP24]], 48 // CHECK-NEXT: [[TMP26:%.*]] = add nuw i64 1, [[TMP25]] -// CHECK-NEXT: [[TMP27:%.*]] = and i64 [[TMP12]], 3 +// CHECK-NEXT: [[TMP27:%.*]] = and i64 [[TMP4]], 3 // CHECK-NEXT: [[TMP28:%.*]] = icmp eq i64 [[TMP27]], 0 // CHECK-NEXT: br i1 [[TMP28]], label [[OMP_TYPE_ALLOC:%.*]], label [[OMP_TYPE_ALLOC_ELSE:%.*]] // CHECK: omp.type.alloc: @@ -335,21 +299,21 @@ void foo() { // CHECK-NEXT: br label [[OMP_TYPE_END]] // CHECK: omp.type.end: // CHECK-NEXT: [[OMP_MAPTYPE:%.*]] = phi i64 [ [[TMP29]], [[OMP_TYPE_ALLOC]] ], [ [[TMP31]], [[OMP_TYPE_TO]] ], [ [[TMP33]], [[OMP_TYPE_FROM]] ], [ [[TMP26]], [[OMP_TYPE_TO_ELSE]] ] -// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP7]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[A]], i64 4, i64 [[OMP_MAPTYPE]], ptr null) +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], ptr [[A]], i64 4, i64 [[OMP_MAPTYPE]], ptr null) // CHECK-NEXT: [[OMP_ARRAYMAP_NEXT]] = getelementptr [[STRUCT_C]], ptr [[OMP_ARRAYMAP_PTRCURRENT]], i32 1 // CHECK-NEXT: [[OMP_ARRAYMAP_ISDONE:%.*]] = icmp eq ptr [[OMP_ARRAYMAP_NEXT]], [[TMP11]] // CHECK-NEXT: br i1 [[OMP_ARRAYMAP_ISDONE]], label [[OMP_ARRAYMAP_EXIT:%.*]], label [[OMP_ARRAYMAP_BODY]] // CHECK: omp.arraymap.exit: // CHECK-NEXT: [[OMP_ARRAYINIT_ISARRAY6:%.*]] = icmp sgt i64 [[TMP10]], 1 -// CHECK-NEXT: [[TMP34:%.*]] = and i64 [[TMP12]], 8 +// CHECK-NEXT: [[TMP34:%.*]] = and i64 [[TMP4]], 8 // CHECK-NEXT: [[DOTOMP_ARRAY__DEL__DELETE:%.*]] = icmp ne i64 [[TMP34]], 0 // CHECK-NEXT: [[TMP35:%.*]] = and i1 [[OMP_ARRAYINIT_ISARRAY6]], [[DOTOMP_ARRAY__DEL__DELETE]] // CHECK-NEXT: br i1 [[TMP35]], label [[DOTOMP_ARRAY__DEL:%.*]], label [[OMP_DONE]] // CHECK: .omp.array..del: // CHECK-NEXT: [[TMP36:%.*]] = mul nuw i64 [[TMP10]], 4 -// CHECK-NEXT: [[TMP37:%.*]] = and i64 [[TMP12]], -4 +// CHECK-NEXT: [[TMP37:%.*]] = and i64 [[TMP4]], -4 // CHECK-NEXT: [[TMP38:%.*]] = or i64 [[TMP37]], 512 -// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP7]], ptr [[TMP8]], ptr [[TMP9]], i64 [[TMP36]], i64 [[TMP38]], ptr [[TMP13]]) +// CHECK-NEXT: call void @__tgt_push_mapper_component(ptr [[TMP0]], ptr [[TMP1]], ptr [[TMP2]], i64 [[TMP36]], i64 [[TMP38]], ptr [[TMP5]]) // CHECK-NEXT: br label [[OMP_DONE]] // CHECK: omp.done: // CHECK-NEXT: ret void diff --git a/clang/test/OpenMP/target_parallel_ast_print.cpp b/clang/test/OpenMP/target_parallel_ast_print.cpp index 7e27ac7b92ca4..3ee98bc525c1b 100644 --- a/clang/test/OpenMP/target_parallel_ast_print.cpp +++ b/clang/test/OpenMP/target_parallel_ast_print.cpp @@ -38,10 +38,6 @@ struct S { // CHECK: static int TS; // CHECK-NEXT: #pragma omp threadprivate(S::TS) // CHECK-NEXT: } -// CHECK: template<> struct S { -// CHECK: static char TS; -// CHECK-NEXT: #pragma omp threadprivate(S::TS) -// CHECK-NEXT: } template T tmain(T argc, T *argv) { diff --git a/clang/test/OpenMP/target_teams_ast_print.cpp b/clang/test/OpenMP/target_teams_ast_print.cpp index 8338f2a68f922..cc47ae92efac0 100644 --- a/clang/test/OpenMP/target_teams_ast_print.cpp +++ b/clang/test/OpenMP/target_teams_ast_print.cpp @@ -40,10 +40,6 @@ struct S { // CHECK: static int TS; // CHECK-NEXT: #pragma omp threadprivate(S::TS) // CHECK-NEXT: } -// CHECK: template<> struct S { -// CHECK: static long TS; -// CHECK-NEXT: #pragma omp threadprivate(S::TS) -// CHECK-NEXT: } template T tmain(T argc, T *argv) { diff --git a/clang/test/OpenMP/task_ast_print.cpp b/clang/test/OpenMP/task_ast_print.cpp index 2a6b8908a1e2d..30fb7ab75cc87 100644 --- a/clang/test/OpenMP/task_ast_print.cpp +++ b/clang/test/OpenMP/task_ast_print.cpp @@ -87,10 +87,6 @@ struct S { // CHECK: static int TS; // CHECK-NEXT: #pragma omp threadprivate(S::TS) // CHECK-NEXT: } -// CHECK: template<> struct S { -// CHECK: static long TS; -// CHECK-NEXT: #pragma omp threadprivate(S::TS) -// CHECK-NEXT: } template T tmain(T argc, T *argv) { diff --git a/clang/test/OpenMP/teams_ast_print.cpp b/clang/test/OpenMP/teams_ast_print.cpp index 0087f71ac9f74..597a9b2bdbdc5 100644 --- a/clang/test/OpenMP/teams_ast_print.cpp +++ b/clang/test/OpenMP/teams_ast_print.cpp @@ -27,10 +27,6 @@ struct S { // CHECK: static int TS; // CHECK-NEXT: #pragma omp threadprivate(S::TS) // CHECK-NEXT: } -// CHECK: template<> struct S { -// CHECK: static long TS; -// CHECK-NEXT: #pragma omp threadprivate(S::TS) -// CHECK-NEXT: } template T tmain(T argc, T *argv) { diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp index a0b3266c738ff..6d4f16c6f533e 100644 --- a/clang/test/Parser/cxx0x-decl.cpp +++ b/clang/test/Parser/cxx0x-decl.cpp @@ -214,6 +214,7 @@ struct MemberComponentOrder : Base { void NoMissingSemicolonHere(struct S [3]); template void NoMissingSemicolonHereEither(struct S... [N]); +// expected-warning@-1 {{'S...[N]' is no longer a pack expansion but a pack indexing type; add a name to specify a pack expansion}} \ // expected-error@-1 {{'S' does not refer to the name of a parameter pack}} \ // expected-error@-1 {{declaration of anonymous struct must be a definition}} \ // expected-error@-1 {{expected parameter declarator}} \ diff --git a/clang/test/Parser/cxx2c-pack-indexing.cpp b/clang/test/Parser/cxx2c-pack-indexing.cpp index 99347a2f8f157..72e286322fa97 100644 --- a/clang/test/Parser/cxx2c-pack-indexing.cpp +++ b/clang/test/Parser/cxx2c-pack-indexing.cpp @@ -12,8 +12,7 @@ struct S { // expected-note {{to match this '['}} \ // expected-warning{{declaration does not declare anything}} - T...[]; // expected-error{{expected expression}} \ - // expected-warning{{declaration does not declare anything}} + T...[]; // expected-error{{expected member name or ';' after declaration specifiers}} void f(auto... v) { decltype(v...[1]) a = v...[1]; @@ -65,7 +64,7 @@ int main() { } -namespace GH11460 { +namespace GH111460 { template requires( ); // expected-error {{expected expression}} struct SS { diff --git a/clang/test/Parser/gh110231.cpp b/clang/test/Parser/gh110231.cpp new file mode 100644 index 0000000000000..b1405517505ff --- /dev/null +++ b/clang/test/Parser/gh110231.cpp @@ -0,0 +1,12 @@ +// RUN: seq 100 | xargs -Ifoo %clang_cc1 -std=c++20 -fsyntax-only -verify %s +// expected-no-diagnostics +// This is a regression test for a non-deterministic stack-overflow. + +template < typename > +concept C1 = true; + +template < typename , auto > +concept C2 = true; + +template < C1 auto V, C2< V > auto> +struct S; diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c index 656b31444a9ee..2e884c472c2ec 100644 --- a/clang/test/ParserOpenACC/parse-clauses.c +++ b/clang/test/ParserOpenACC/parse-clauses.c @@ -4,37 +4,27 @@ void func() { - // expected-warning@+2{{OpenACC clause 'finalize' not yet implemented, clause ignored}} - // expected-warning@+1{{OpenACC construct 'enter data' not yet implemented, pragma ignored}} -#pragma acc enter data finalize - - // expected-warning@+3{{OpenACC clause 'finalize' not yet implemented, clause ignored}} - // expected-warning@+2{{OpenACC clause 'finalize' not yet implemented, clause ignored}} - // expected-warning@+1{{OpenACC construct 'enter data' not yet implemented, pragma ignored}} -#pragma acc enter data finalize finalize - - // expected-warning@+3{{OpenACC clause 'finalize' not yet implemented, clause ignored}} - // expected-error@+2{{invalid OpenACC clause 'invalid'}} - // expected-warning@+1{{OpenACC construct 'enter data' not yet implemented, pragma ignored}} -#pragma acc enter data finalize invalid - - // expected-warning@+3{{OpenACC clause 'finalize' not yet implemented, clause ignored}} - // expected-error@+2{{invalid OpenACC clause 'invalid'}} - // expected-warning@+1{{OpenACC construct 'enter data' not yet implemented, pragma ignored}} -#pragma acc enter data finalize invalid invalid finalize - - // expected-warning@+3{{OpenACC clause 'wait' not yet implemented, clause ignored}} - // expected-warning@+2{{OpenACC clause 'finalize' not yet implemented, clause ignored}} - // expected-warning@+1{{OpenACC construct 'enter data' not yet implemented, pragma ignored}} -#pragma acc enter data wait finalize + // expected-error@+1{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} +#pragma acc exit data finalize - // expected-warning@+2{{OpenACC clause 'if_present' not yet implemented, clause ignored}} - // expected-warning@+1{{OpenACC construct 'host_data' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} +#pragma acc exit data finalize finalize + + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{invalid OpenACC clause 'invalid'}} +#pragma acc exit data finalize invalid + + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{invalid OpenACC clause 'invalid'}} +#pragma acc exit data finalize invalid invalid finalize + + // expected-error@+1{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} +#pragma acc exit data wait finalize + + // expected-error@+1{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} #pragma acc host_data if_present - // expected-warning@+3{{OpenACC clause 'if_present' not yet implemented, clause ignored}} - // expected-warning@+2{{OpenACC clause 'if_present' not yet implemented, clause ignored}} - // expected-warning@+1{{OpenACC construct 'host_data' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} #pragma acc host_data if_present, if_present // expected-error@+4{{OpenACC clause 'independent' on 'loop' construct conflicts with previous data dependence clause}} @@ -460,13 +450,16 @@ void VarListClauses() { #pragma acc serial present_or_copy(HasMem.MemArr[3:]) for(int i = 0; i < 5;++i) {} - // expected-error@+2{{expected ','}} - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented, clause ignored}} -#pragma acc serial use_device(s.array[s.value] s.array[s.value :5] ), self + // expected-error@+2 2{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} + // expected-error@+1{{expected ','}} +#pragma acc host_data use_device(s.array[s.value] s.array[s.value :5] ), if_present + for(int i = 0; i < 5;++i) {} + + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(s.array[s.value : 5]), if_present for(int i = 0; i < 5;++i) {} - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented, clause ignored}} -#pragma acc serial use_device(s.array[s.value : 5]), self +#pragma acc host_data use_device(HasMem), if_present for(int i = 0; i < 5;++i) {} // expected-error@+1{{expected ','}} @@ -505,14 +498,13 @@ void VarListClauses() { #pragma acc serial attach(IsPointer), self for(int i = 0; i < 5;++i) {} - // expected-error@+2{{expected ','}} - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented, clause ignored}} -#pragma acc serial detach(s.array[s.value] s.array[s.value :5] ), self - for(int i = 0; i < 5;++i) {} + // expected-error@+4{{expected ','}} + // expected-error@+3{{expected pointer in 'detach' clause, type is 'char'}} + // expected-error@+2{{OpenACC sub-array is not allowed here}} + // expected-note@+1{{expected variable of pointer type}} +#pragma acc exit data copyout(s) detach(s.array[s.value] s.array[s.value :5]) - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented, clause ignored}} -#pragma acc serial detach(s.array[s.value : 5], s.value), self - for(int i = 0; i < 5;++i) {} +#pragma acc exit data copyout(s) detach(IsPointer) // expected-error@+1{{expected ','}} #pragma acc serial private(s.array[s.value] s.array[s.value :5] ), self @@ -528,22 +520,11 @@ void VarListClauses() { #pragma acc serial firstprivate(s.array[s.value : 5], s.value), self for(int i = 0; i < 5;++i) {} - // expected-error@+2{{expected ','}} - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented, clause ignored}} -#pragma acc serial delete(s.array[s.value] s.array[s.value :5] ), self - for(int i = 0; i < 5;++i) {} - - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented, clause ignored}} -#pragma acc serial delete(s.array[s.value : 5], s.value), self - for(int i = 0; i < 5;++i) {} - - // expected-error@+2{{expected ','}} - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented, clause ignored}} -#pragma acc serial use_device(s.array[s.value] s.array[s.value :5] ), self + // expected-error@+1{{expected ','}} +#pragma acc exit data delete(s.array[s.value] s.array[s.value :5] ) async for(int i = 0; i < 5;++i) {} - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented, clause ignored}} -#pragma acc serial use_device(s.array[s.value : 5], s.value), self +#pragma acc exit data delete(s.array[s.value : 5], s.value),async for(int i = 0; i < 5;++i) {} // expected-error@+2{{expected ','}} diff --git a/clang/test/ParserOpenACC/parse-clauses.cpp b/clang/test/ParserOpenACC/parse-clauses.cpp index dc985826a4efe..770bc3b976c96 100644 --- a/clang/test/ParserOpenACC/parse-clauses.cpp +++ b/clang/test/ParserOpenACC/parse-clauses.cpp @@ -34,6 +34,11 @@ void templ() { #pragma acc parallel async for(;;){} + + + T t; +#pragma acc exit data delete(t) + ; } struct S { diff --git a/clang/test/ParserOpenACC/parse-constructs.c b/clang/test/ParserOpenACC/parse-constructs.c index 27b9a6993fd3e..4a6c31cc9b0a9 100644 --- a/clang/test/ParserOpenACC/parse-constructs.c +++ b/clang/test/ParserOpenACC/parse-constructs.c @@ -54,16 +54,16 @@ void func() { // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc kernels clause list for(;;){} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'data' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc data clause list for(;;){} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'enter data' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc enter data clause list for(;;){} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'exit data' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc exit data clause list for(;;){} // expected-error@+1{{invalid OpenACC directive 'enter invalid'}} @@ -78,8 +78,8 @@ void func() { // expected-error@+1{{expected identifier}} #pragma acc exit } for(;;){} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'host_data' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc host_data clause list for(;;){} // expected-error@+1{{invalid OpenACC clause 'clause'}} diff --git a/clang/test/ParserOpenACC/parse-wait-construct.c b/clang/test/ParserOpenACC/parse-wait-construct.c index 8f7ea8efd5766..17b7ecbde7856 100644 --- a/clang/test/ParserOpenACC/parse-wait-construct.c +++ b/clang/test/ParserOpenACC/parse-wait-construct.c @@ -3,171 +3,135 @@ void func() { int i, j; - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} #pragma acc wait - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait clause-list - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait ( - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} #pragma acc wait () - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait () clause-list - // expected-error@+4{{expected expression}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{expected expression}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (devnum: - // expected-error@+2{{expected expression}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{expected expression}} #pragma acc wait (devnum:) - // expected-error@+3{{expected expression}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected expression}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (devnum:) clause-list - // expected-error@+4{{expected ':'}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{expected ':'}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (devnum: i + j - // expected-error@+2{{expected ':'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{expected ':'}} #pragma acc wait (devnum: i + j) - // expected-error@+3{{expected ':'}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ':'}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (devnum: i + j) clause-list - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (queues: - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} #pragma acc wait (queues:) - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (queues:) clause-list - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (devnum: i + j:queues: - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} #pragma acc wait (devnum: i + j:queues:) - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (devnum: i + j:queues:) clause-list - // expected-error@+5{{use of undeclared identifier 'devnum'}} - // expected-error@+4{{expected ','}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+4{{use of undeclared identifier 'devnum'}} + // expected-error@+3{{expected ','}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait (queues:devnum: i + j - // expected-error@+3{{use of undeclared identifier 'devnum'}} - // expected-error@+2{{expected ','}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{use of undeclared identifier 'devnum'}} + // expected-error@+1{{expected ','}} #pragma acc wait (queues:devnum: i + j) - // expected-error@+4{{use of undeclared identifier 'devnum'}} - // expected-error@+3{{expected ','}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{use of undeclared identifier 'devnum'}} + // expected-error@+2{{expected ','}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait (queues:devnum: i + j) clause-list - // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(i, j, 1+1, 3.3 - // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} #pragma acc wait(i, j, 1+1, 3.3) - // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(i, j, 1+1, 3.3) clause-list - // expected-error@+4{{expected expression}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{expected expression}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(, - // expected-error@+2{{expected expression}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{expected expression}} #pragma acc wait(,) - // expected-error@+3{{expected expression}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{expected expression}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(,) clause-list - // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(queues:i, j, 1+1, 3.3 - // expected-error@+5{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+4{{expected expression}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+3{{expected expression}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(queues:i, j, 1+1, 3.3, - // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} #pragma acc wait(queues:i, j, 1+1, 3.3) - // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(queues:i, j, 1+1, 3.3) clause-list - // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(devnum:3:i, j, 1+1, 3.3 - // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} #pragma acc wait(devnum:3:i, j, 1+1, 3.3) - // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(devnum:3:i, j, 1+1, 3.3) clause-list - // expected-error@+4{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3 - // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3) - // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('double' invalid)}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc wait(devnum:3:queues:i, j, 1+1, 3.3) clause-list } diff --git a/clang/test/Preprocessor/predefined-arch-macros.c b/clang/test/Preprocessor/predefined-arch-macros.c index 20aa2d4e0a54c..43f3454ed3c35 100644 --- a/clang/test/Preprocessor/predefined-arch-macros.c +++ b/clang/test/Preprocessor/predefined-arch-macros.c @@ -1953,6 +1953,8 @@ // CHECK_GNR_M32: #define __SSSE3__ 1 // CHECK_GNR_M32: #define __TSXLDTRK__ 1 // CHECK_GNR_M32: #define __UINTR__ 1 +// CHECK_GNR_M32-NOT: #define __USERMSR__ 1 +// CHECK_DMR_M32: #define __USERMSR__ 1 // CHECK_GNR_M32: #define __VAES__ 1 // CHECK_GNR_M32: #define __VPCLMULQDQ__ 1 // CHECK_GNR_M32: #define __WAITPKG__ 1 @@ -2061,6 +2063,8 @@ // CHECK_GNR_M64: #define __SSSE3__ 1 // CHECK_GNR_M64: #define __TSXLDTRK__ 1 // CHECK_GNR_M64: #define __UINTR__ 1 +// CHECK_GNR_M64-NOT: #define __USERMSR__ 1 +// CHECK_DMR_M64: #define __USERMSR__ 1 // CHECK_GNR_M64: #define __VAES__ 1 // CHECK_GNR_M64: #define __VPCLMULQDQ__ 1 // CHECK_GNR_M64: #define __WAITPKG__ 1 diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h b/clang/test/Sema/Inputs/lifetime-analysis.h index 5c151385b1fe5..f888e6ab94bb6 100644 --- a/clang/test/Sema/Inputs/lifetime-analysis.h +++ b/clang/test/Sema/Inputs/lifetime-analysis.h @@ -128,6 +128,11 @@ struct reference_wrapper { template reference_wrapper ref(T& t) noexcept; +template +struct [[gsl::Pointer]] iterator { + T& operator*() const; +}; + struct false_type { static constexpr bool value = false; constexpr operator bool() const noexcept { return value; } diff --git a/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_cvt.c b/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_cvt.c index af1ef46ea6972..c5f03b27016ba 100644 --- a/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_cvt.c +++ b/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_cvt.c @@ -5,7 +5,8 @@ #include -void test_features_sme2_fp8(svmfloat8_t zn, fpm_t fpmr) __arm_streaming { +void test_features_sme2_fp8(svmfloat8_t zn, svfloat16x2_t znf16, svbfloat16x2_t znbf16, + svfloat32x4_t znf32, fpm_t fpmr) __arm_streaming { // expected-error@+1 {{'svcvtl1_f16_mf8_x2_fpm' needs target feature sme,sme2,fp8}} svcvtl1_f16_mf8_x2_fpm(zn, fpmr); // expected-error@+1 {{'svcvtl2_f16_mf8_x2_fpm' needs target feature sme,sme2,fp8}} @@ -23,4 +24,13 @@ void test_features_sme2_fp8(svmfloat8_t zn, fpm_t fpmr) __arm_streaming { svcvt1_bf16_mf8_x2_fpm(zn, fpmr); // expected-error@+1 {{'svcvt2_bf16_mf8_x2_fpm' needs target feature sme,sme2,fp8}} svcvt2_bf16_mf8_x2_fpm(zn, fpmr); + + // expected-error@+1 {{'svcvt_mf8_f16_x2_fpm' needs target feature sme,sme2,fp8}} + svcvt_mf8_f16_x2_fpm(znf16, fpmr); + // expected-error@+1 {{'svcvt_mf8_bf16_x2_fpm' needs target feature sme,sme2,fp8}} + svcvt_mf8_bf16_x2_fpm(znbf16, fpmr); + // expected-error@+1 {{'svcvt_mf8_f32_x4_fpm' needs target feature sme,sme2,fp8}} + svcvt_mf8_f32_x4_fpm(znf32, fpmr); + // expected-error@+1 {{'svcvtn_mf8_f32_x4_fpm' needs target feature sme,sme2,fp8}} + svcvtn_mf8_f32_x4_fpm(znf32, fpmr); } \ No newline at end of file diff --git a/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_imm.c b/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_imm.c index 62cad9cfa4c8f..bea0b29bcc70a 100644 --- a/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_imm.c +++ b/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_imm.c @@ -16,3 +16,37 @@ void test_svmopa(svbool_t pn, svbool_t pm, svmfloat8_t zn, svmfloat8_t zm, // expected-error@+1 {{argument value 4 is outside the valid range [0, 3]}} svmopa_za32_mf8_m_fpm(4, pn, pm, zn, zm, fpmr); } + +void test_svmla(uint32_t slice, svmfloat8_t zn, svmfloat8x2_t znx2, svmfloat8x4_t znx4, + fpm_t fpmr) __arm_streaming __arm_inout("za") { + // expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svmla_lane_za16_mf8_vg2x1_fpm(slice, zn, zn, -1, fpmr); + // expected-error@+1 {{argument value 16 is outside the valid range [0, 15]}} + svmla_lane_za16_mf8_vg2x1_fpm(slice, zn, zn, 16, fpmr); + + // expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svmla_lane_za16_mf8_vg2x2_fpm(slice, znx2, zn, -1, fpmr); + // expected-error@+1 {{argument value 16 is outside the valid range [0, 15]}} + svmla_lane_za16_mf8_vg2x2_fpm(slice, znx2, zn, 16, fpmr); + + // expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svmla_lane_za16_mf8_vg2x4_fpm(slice, znx4, zn, -1, fpmr); + // expected-error@+1 {{argument value 16 is outside the valid range [0, 15]}} + svmla_lane_za16_mf8_vg2x4_fpm(slice, znx4, zn, 16, fpmr); + + // expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svmla_lane_za32_mf8_vg4x1_fpm(slice, zn, zn, -1, fpmr); + // expected-error@+1 {{argument value 16 is outside the valid range [0, 15]}} + svmla_lane_za32_mf8_vg4x1_fpm(slice, zn, zn, 16, fpmr); + + // expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svmla_lane_za32_mf8_vg4x2_fpm(slice, znx2, zn, -1, fpmr); + // expected-error@+1 {{argument value 16 is outside the valid range [0, 15]}} + svmla_lane_za32_mf8_vg4x2_fpm(slice, znx2, zn, 16, fpmr); + + // expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svmla_lane_za32_mf8_vg4x4_fpm(slice, znx4, zn, -1, fpmr); + // expected-error@+1 {{argument value 16 is outside the valid range [0, 15]}} + svmla_lane_za32_mf8_vg4x4_fpm(slice, znx4, zn, 16, fpmr); + +} \ No newline at end of file diff --git a/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_mla.c b/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_mla.c new file mode 100644 index 0000000000000..1dbc30196a554 --- /dev/null +++ b/clang/test/Sema/aarch64-fp8-intrinsics/acle_sme2_fp8_mla.c @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -verify -emit-llvm-only %s + +// REQUIRES: aarch64-registered-target + +#include + +void test_svmla(uint32_t slice, svmfloat8_t zn, svmfloat8x2_t znx2, svmfloat8x4_t znx4, + fpm_t fpmr) __arm_streaming __arm_inout("za") { + // expected-error@+1 {{'svmla_lane_za16_mf8_vg2x1_fpm' needs target feature sme,sme-f8f16}} + svmla_lane_za16_mf8_vg2x1_fpm(slice, zn, zn, 0, fpmr); + + // expected-error@+1 {{'svmla_lane_za16_mf8_vg2x2_fpm' needs target feature sme,sme-f8f16}} + svmla_lane_za16_mf8_vg2x2_fpm(slice, znx2, zn, 0, fpmr); + + // expected-error@+1 {{'svmla_lane_za16_mf8_vg2x4_fpm' needs target feature sme,sme-f8f16}} + svmla_lane_za16_mf8_vg2x4_fpm(slice, znx4, zn, 0, fpmr); + + // expected-error@+1 {{'svmla_lane_za32_mf8_vg4x1_fpm' needs target feature sme,sme-f8f32}} + svmla_lane_za32_mf8_vg4x1_fpm(slice, zn, zn, 0, fpmr); + + // expected-error@+1 {{'svmla_lane_za32_mf8_vg4x2_fpm' needs target feature sme,sme-f8f32}} + svmla_lane_za32_mf8_vg4x2_fpm(slice, znx2, zn, 0, fpmr); + + // expected-error@+1 {{'svmla_lane_za32_mf8_vg4x4_fpm' needs target feature sme,sme-f8f32}} + svmla_lane_za32_mf8_vg4x4_fpm(slice, znx4, zn, 0, fpmr); + + // expected-error@+1 {{'svmla_single_za16_mf8_vg2x1_fpm' needs target feature sme,sme-f8f16}} + svmla_single_za16_mf8_vg2x1_fpm(slice, zn, zn, fpmr); + + // expected-error@+1 {{'svmla_single_za16_mf8_vg2x2_fpm' needs target feature sme,sme-f8f16}} + svmla_single_za16_mf8_vg2x2_fpm(slice, znx2, zn, fpmr); + + // expected-error@+1 {{'svmla_single_za16_mf8_vg2x4_fpm' needs target feature sme,sme-f8f16}} + svmla_single_za16_mf8_vg2x4_fpm(slice, znx4, zn, fpmr); + + // expected-error@+1 {{'svmla_single_za32_mf8_vg4x1_fpm' needs target feature sme,sme-f8f32}} + svmla_single_za32_mf8_vg4x1_fpm(slice, zn, zn, fpmr); + + // expected-error@+1 {{'svmla_single_za32_mf8_vg4x2_fpm' needs target feature sme,sme-f8f32}} + svmla_single_za32_mf8_vg4x2_fpm(slice, znx2, zn, fpmr); + + // expected-error@+1 {{'svmla_single_za32_mf8_vg4x4_fpm' needs target feature sme,sme-f8f32}} + svmla_single_za32_mf8_vg4x4_fpm(slice, znx4, zn, fpmr); + + // expected-error@+1 {{'svmla_za16_mf8_vg2x2_fpm' needs target feature sme,sme-f8f16}} + svmla_za16_mf8_vg2x2_fpm(slice, znx2, znx2, fpmr); + + // expected-error@+1 {{'svmla_za16_mf8_vg2x4_fpm' needs target feature sme,sme-f8f16}} + svmla_za16_mf8_vg2x4_fpm(slice, znx4, znx4, fpmr); + + // expected-error@+1 {{'svmla_za32_mf8_vg4x2_fpm' needs target feature sme,sme-f8f32}} + svmla_za32_mf8_vg4x2_fpm(slice, znx2, znx2, fpmr); + + // expected-error@+1 {{'svmla_za32_mf8_vg4x4_fpm' needs target feature sme,sme-f8f32}} + svmla_za32_mf8_vg4x4_fpm(slice, znx4, znx4, fpmr); +} \ No newline at end of file diff --git a/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_fp8_fdot.c b/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_fp8_fdot.c new file mode 100644 index 0000000000000..bbcd0335ff555 --- /dev/null +++ b/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_fp8_fdot.c @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -verify -emit-llvm -o - %s + +// REQUIRES: aarch64-registered-target + +#include + +void test_features(uint32_t slice, svmfloat8_t f8, svmfloat8x2_t f8x2, + svmfloat8x4_t f8x4, uint64_t fpmr) __arm_streaming __arm_inout("za") { + // expected-error@+1 {{'svdot_lane_za32_mf8_vg1x2_fpm' needs target feature sme,sme-f8f32}} + svdot_lane_za32_mf8_vg1x2_fpm(slice, f8x2, f8, 3, fpmr); + // expected-error@+1 {{'svdot_lane_za32_mf8_vg1x4_fpm' needs target feature sme,sme-f8f32}} + svdot_lane_za32_mf8_vg1x4_fpm(slice, f8x4, f8, 3, fpmr); + // expected-error@+1 {{'svdot_lane_za16_mf8_vg1x2_fpm' needs target feature sme,sme-f8f16}} + svdot_lane_za16_mf8_vg1x2_fpm(slice, f8x2, f8, 3, fpmr); + // expected-error@+1 {{'svdot_lane_za16_mf8_vg1x4_fpm' needs target feature sme,sme-f8f16}} + svdot_lane_za16_mf8_vg1x4_fpm(slice, f8x4, f8, 3, fpmr); + // expected-error@+1 {{'svdot_single_za32_mf8_vg1x2_fpm' needs target feature sme,sme-f8f32}} + svdot_single_za32_mf8_vg1x2_fpm(slice, f8x2, f8, fpmr); + // expected-error@+1 {{'svdot_single_za32_mf8_vg1x4_fpm' needs target feature sme,sme-f8f32}} + svdot_single_za32_mf8_vg1x4_fpm(slice, f8x4, f8, fpmr); + // expected-error@+1 {{'svdot_za32_mf8_vg1x2_fpm' needs target feature sme,sme-f8f32}} + svdot_za32_mf8_vg1x2_fpm(slice, f8x2, f8x2, fpmr); + // expected-error@+1 {{'svdot_za32_mf8_vg1x4_fpm' needs target feature sme,sme-f8f32}} + svdot_za32_mf8_vg1x4_fpm(slice, f8x4, f8x4, fpmr); + // expected-error@+1 {{'svdot_single_za16_mf8_vg1x2_fpm' needs target feature sme,sme-f8f16}} + svdot_single_za16_mf8_vg1x2_fpm(slice, f8x2, f8, fpmr); + // expected-error@+1 {{'svdot_single_za16_mf8_vg1x4_fpm' needs target feature sme,sme-f8f16}} + svdot_single_za16_mf8_vg1x4_fpm(slice, f8x4, f8, fpmr); + // expected-error@+1 {{'svdot_za16_mf8_vg1x2_fpm' needs target feature sme,sme-f8f16}} + svdot_za16_mf8_vg1x2_fpm(slice, f8x2, f8x2, fpmr); + // expected-error@+1 {{'svdot_za16_mf8_vg1x4_fpm' needs target feature sme,sme-f8f16}} + svdot_za16_mf8_vg1x4_fpm(slice, f8x4, f8x4, fpmr); +} + +void test_imm(uint32_t slice, svmfloat8_t f8, svmfloat8x2_t f8x2, + svmfloat8x4_t f8x4, uint64_t fpmr) __arm_streaming __arm_inout("za") { +// expected-error@+1{{argument value 18446744073709551615 is outside the valid range [0, 3]}} + svdot_lane_za32_mf8_vg1x2_fpm(slice, f8x2, f8, -1, fpmr); +// expected-error@+1{{argument value 18446744073709551615 is outside the valid range [0, 3]}} + svdot_lane_za32_mf8_vg1x4_fpm(slice, f8x4, f8, -1, fpmr); +// expected-error@+1{{argument value 18446744073709551615 is outside the valid range [0, 7]}} + svdot_lane_za16_mf8_vg1x2_fpm(slice, f8x2, f8, -1, fpmr); +// expected-error@+1{{argument value 18446744073709551615 is outside the valid range [0, 7]}} + svdot_lane_za16_mf8_vg1x4_fpm(slice, f8x4, f8, -1, fpmr); + +// expected-error@+1{{argument value 4 is outside the valid range [0, 3]}} + svdot_lane_za32_mf8_vg1x2_fpm(slice, f8x2, f8, 4, fpmr); +// expected-error@+1{{argument value 4 is outside the valid range [0, 3]}} + svdot_lane_za32_mf8_vg1x4_fpm(slice, f8x4, f8, 4, fpmr); +// expected-error@+1{{argument value 8 is outside the valid range [0, 7]}} + svdot_lane_za16_mf8_vg1x2_fpm(slice, f8x2, f8, 8, fpmr); +// expected-error@+1{{argument value 8 is outside the valid range [0, 7]}} + svdot_lane_za16_mf8_vg1x4_fpm(slice, f8x4, f8, 8, fpmr); +} diff --git a/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_fp8_fvdot.c b/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_fp8_fvdot.c new file mode 100644 index 0000000000000..3dc4c93457104 --- /dev/null +++ b/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_fp8_fvdot.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -verify -emit-llvm -o - %s + +// REQUIRES: aarch64-registered-target + +#include + +void test_features(uint32_t slice, fpm_t fpmr, svmfloat8x2_t zn, + svmfloat8_t zm) __arm_streaming __arm_inout("za") { +// expected-error@+1 {{'svvdot_lane_za16_mf8_vg1x2_fpm' needs target feature sme,sme-f8f16}} + svvdot_lane_za16_mf8_vg1x2_fpm(slice, zn, zm, 7, fpmr); +// expected-error@+1 {{'svvdotb_lane_za32_mf8_vg1x4_fpm' needs target feature sme,sme-f8f32}} + svvdotb_lane_za32_mf8_vg1x4_fpm(slice, zn, zm, 3, fpmr); +// expected-error@+1 {{'svvdott_lane_za32_mf8_vg1x4_fpm' needs target feature sme,sme-f8f32}} + svvdott_lane_za32_mf8_vg1x4_fpm(slice, zn, zm, 3, fpmr); +} + +void test_imm(uint32_t slice, fpm_t fpmr, svmfloat8x2_t zn, + svmfloat8_t zm) __arm_streaming __arm_inout("za") { +// expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 7]}} + svvdot_lane_za16_mf8_vg1x2_fpm(slice, zn, zm, -1, fpmr); +// expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 3]}} + svvdotb_lane_za32_mf8_vg1x4_fpm(slice, zn, zm, -1, fpmr); +// expected-error@+1 {{argument value 18446744073709551615 is outside the valid range [0, 3]}} + svvdott_lane_za32_mf8_vg1x4_fpm(slice, zn, zm, -1, fpmr); + +// expected-error@+1{{argument value 8 is outside the valid range [0, 7]}} + svvdot_lane_za16_mf8_vg1x2_fpm(slice, zn, zm, 8, fpmr); +// expected-error@+1{{argument value 4 is outside the valid range [0, 3]}} + svvdotb_lane_za32_mf8_vg1x4_fpm(slice, zn, zm, 4, fpmr); +// expected-error@+1{{argument value 4 is outside the valid range [0, 3]}} + svvdott_lane_za32_mf8_vg1x4_fpm(slice, zn, zm, 4, fpmr); +} diff --git a/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_fp8.c b/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_fp8.c new file mode 100644 index 0000000000000..192d200eb4910 --- /dev/null +++ b/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_fp8.c @@ -0,0 +1,103 @@ +// REQUIRES: aarch64-registered-target + +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -verify -emit-llvm -o - %s + +#include + +void test_features(svmfloat8_t zn, svmfloat8_t zm, mfloat8_t x, fpm_t fpm) { + svcvt1_bf16_mf8_fpm(zn, fpm); + // expected-error@-1 {{'svcvt1_bf16_mf8_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvt2_bf16_mf8_fpm(zn, fpm); + // expected-error@-1 {{'svcvt2_bf16_mf8_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvtlt1_bf16_mf8_fpm(zn, fpm); + // expected-error@-1 {{'svcvtlt1_bf16_mf8_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvtlt2_bf16_mf8_fpm(zn, fpm); + // expected-error@-1 {{'svcvtlt2_bf16_mf8_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvt1_f16_mf8_fpm(zn, fpm); + // expected-error@-1 {{'svcvt1_f16_mf8_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvt2_f16_mf8_fpm(zn, fpm); + // expected-error@-1 {{'svcvt2_f16_mf8_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvtlt1_f16_mf8_fpm(zn, fpm); + // expected-error@-1 {{'svcvtlt1_f16_mf8_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvtlt2_f16_mf8_fpm(zn, fpm); + // expected-error@-1 {{'svcvtlt2_f16_mf8_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + + svcvtn_mf8_bf16_x2_fpm(svcreate2(svundef_bf16(), svundef_bf16()), fpm); + // expected-error@-1 {{'svcvtn_mf8_bf16_x2_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvtn_mf8_f16_x2_fpm(svcreate2(svundef_f16(), svundef_f16()), fpm); + // expected-error@-1 {{'svcvtn_mf8_f16_x2_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvtnb_mf8_f32_x2_fpm(svcreate2(svundef_f32(), svundef_f32()), fpm); + // expected-error@-1 {{'svcvtnb_mf8_f32_x2_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + svcvtnt_mf8_f32_x2_fpm(zn, svcreate2(svundef_f32(), svundef_f32()), fpm); + // expected-error@-1 {{'svcvtnt_mf8_f32_x2_fpm' needs target feature (sve,sve2,fp8)|(sme,sme2,fp8)}} + + svdot_f32_mf8_fpm(svundef_f32(), zn, zm, fpm); +// expected-error@-1 {{'svdot_f32_mf8_fpm' needs target feature (sve,sve2,fp8dot4)|(sme,ssve-fp8dot4)}} + svdot_n_f32_mf8_fpm(svundef_f32(), zn, x, fpm); +// expected-error@-1 {{'svdot_n_f32_mf8_fpm' needs target feature (sve,sve2,fp8dot4)|(sme,ssve-fp8dot4)}} + svdot_f16_mf8_fpm(svundef_f16(), zn, zm, fpm); +// expected-error@-1 {{'svdot_f16_mf8_fpm' needs target feature (sve,sve2,fp8dot2)|(sme,ssve-fp8dot2)}} + svdot_n_f16_mf8_fpm(svundef_f16(), zn, x, fpm); +// expected-error@-1 {{'svdot_n_f16_mf8_fpm' needs target feature (sve,sve2,fp8dot2)|(sme,ssve-fp8dot2)}} + svdot_lane_f32_mf8_fpm(svundef_f32(), zn, zm, 3, fpm); +// expected-error@-1 {{'svdot_lane_f32_mf8_fpm' needs target feature (sve,sve2,fp8dot4)|(sme,ssve-fp8dot4)}} + svdot_lane_f16_mf8_fpm(svundef_f16(), zn, zm, 7, fpm); +// expected-error@-1 {{'svdot_lane_f16_mf8_fpm' needs target feature (sve,sve2,fp8dot2)|(sme,ssve-fp8dot2)}} + + svmlalb_f16_mf8_fpm(svundef_f16(), zn, zm, fpm); + // expected-error@-1 {{'svmlalb_f16_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalb_n_f16_mf8_fpm(svundef_f16(), zn, x, fpm); + // expected-error@-1 {{'svmlalb_n_f16_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalt_f16_mf8_fpm(svundef_f16(), zn, zm, fpm); + // expected-error@-1 {{'svmlalt_f16_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalt_n_f16_mf8_fpm(svundef_f16(), zn, x, fpm); + // expected-error@-1 {{'svmlalt_n_f16_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalb_lane_f16_mf8_fpm(svundef_f16(), zn, zm, 7, fpm); + // expected-error@-1 {{'svmlalb_lane_f16_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalt_lane_f16_mf8_fpm(svundef_f16(), zn, zm, 7, fpm); + // expected-error@-1 {{'svmlalt_lane_f16_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlallbb_f32_mf8_fpm(svundef_f32(), zn, zm, fpm); + // expected-error@-1 {{'svmlallbb_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlallbb_n_f32_mf8_fpm(svundef_f32(), zn, x, fpm); + // expected-error@-1 {{'svmlallbb_n_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlallbt_f32_mf8_fpm(svundef_f32(), zn, zm, fpm); + // expected-error@-1 {{'svmlallbt_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlallbt_n_f32_mf8_fpm(svundef_f32(), zn, x, fpm); + // expected-error@-1 {{'svmlallbt_n_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalltb_f32_mf8_fpm(svundef_f32(), zn, zm, fpm); + // expected-error@-1 {{'svmlalltb_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalltb_n_f32_mf8_fpm(svundef_f32(), zn, x, fpm); + // expected-error@-1 {{'svmlalltb_n_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalltt_f32_mf8_fpm(svundef_f32(), zn, zm, fpm); + // expected-error@-1 {{'svmlalltt_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalltt_n_f32_mf8_fpm(svundef_f32(), zn, x, fpm); + // expected-error@-1 {{'svmlalltt_n_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlallbb_lane_f32_mf8_fpm(svundef_f32(), zn, zm, 7, fpm); + // expected-error@-1 {{'svmlallbb_lane_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlallbt_lane_f32_mf8_fpm(svundef_f32(), zn, zm, 7, fpm); + // expected-error@-1 {{'svmlallbt_lane_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalltb_lane_f32_mf8_fpm(svundef_f32(), zn, zm, 7, fpm); + // expected-error@-1 {{'svmlalltb_lane_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} + svmlalltt_lane_f32_mf8_fpm(svundef_f32(), zn, zm, 7, fpm); + // expected-error@-1 {{'svmlalltt_lane_f32_mf8_fpm' needs target feature (sve,sve2,fp8fma)|(sme,ssve-fp8fma)}} +} + +void test_imm_range(svmfloat8_t zn, svmfloat8_t zm, fpm_t fpm) { + svdot_lane_f32_mf8_fpm(svundef_f32(), zn, zm, -1, fpm); +// expected-error@-1 {{argument value 18446744073709551615 is outside the valid range [0, 3]}} + svdot_lane_f16_mf8_fpm(svundef_f16(), zn, zm, -1, fpm); +// expected-error@-1 {{argument value 18446744073709551615 is outside the valid range [0, 7]}} + + svmlalb_lane_f16_mf8_fpm(svundef_f16(), zn, zm, -1, fpm); + // expected-error@-1 {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svmlalt_lane_f16_mf8_fpm(svundef_f16(), zn, zm, -1, fpm); + // expected-error@-1 {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svmlallbb_lane_f32_mf8_fpm(svundef_f32(), zn, zm, -1, fpm); + // expected-error@-1 {{argument value 18446744073709551615 is outside the valid range [0, 7]}} + svmlallbt_lane_f32_mf8_fpm(svundef_f32(), zn, zm, -1, fpm); + // expected-error@-1 {{argument value 18446744073709551615 is outside the valid range [0, 7]}} + svmlalltb_lane_f32_mf8_fpm(svundef_f32(), zn, zm, -1, fpm); + // expected-error@-1 {{argument value 18446744073709551615 is outside the valid range [0, 7]}} + svmlalltt_lane_f32_mf8_fpm(svundef_f32(), zn, zm, -1, fpm); + // expected-error@-1 {{argument value 18446744073709551615 is outside the valid range [0, 7]}} +} diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c index a9cff5947ef5d..a666b45b3150c 100644 --- a/clang/test/Sema/asm.c +++ b/clang/test/Sema/asm.c @@ -365,3 +365,24 @@ void test19(long long x) // FIXME: This case should be supported by codegen, but it fails now. asm ("" : "=rm" (x): "0" (e)); // expected-error {{unsupported inline asm: input with type 'st_size128' (aka 'struct _st_size128') matching output with type 'long long'}} } + +typedef int int2 __attribute__((ext_vector_type(2))); + +// GH118892 +void test20(char x) { + double d; + float f; + + asm ("fabs" : "=t" (d): "0" (x)); // expected-error {{unsupported inline asm: input with type 'char' matching output with type 'double'}} + asm ("fabs" : "=t" (x): "0" (d)); // expected-error {{unsupported inline asm: input with type 'double' matching output with type 'char'}} + asm ("fabs" : "=t" (f): "0" (d)); // no-error + asm ("fabs" : "=t" (d): "0" (f)); // no-error + + st_size64 a; + asm ("fabs" : "=t" (d): "0" (a)); // expected-error {{unsupported inline asm: input with type 'st_size64' (aka 'struct _st_size64') matching output with type 'double'}} + asm ("fabs" : "=t" (a): "0" (d)); // expected-error {{unsupported inline asm: input with type 'double' matching output with type 'st_size64' (aka 'struct _st_size64')}} + + int2 v; + asm ("fabs" : "=t" (d): "0" (v)); // expected-error {{unsupported inline asm: input with type 'int2' (vector of 2 'int' values) matching output with type 'double'}} + asm ("fabs" : "=t" (v): "0" (d)); // expected-error {{unsupported inline asm: input with type 'double' matching output with type 'int2' (vector of 2 'int' values)}} +} diff --git a/clang/test/Sema/tautological-pointer-comparison.c b/clang/test/Sema/tautological-pointer-comparison.c new file mode 100644 index 0000000000000..19cd20e5f7d21 --- /dev/null +++ b/clang/test/Sema/tautological-pointer-comparison.c @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +int add_ptr_idx_ult_ptr(const char *ptr, unsigned index) { + return ptr + index < ptr; // expected-warning {{pointer comparison always evaluates to false}} +} + +int add_idx_ptr_ult_ptr(const char *ptr, unsigned index) { + return index + ptr < ptr; // expected-warning {{pointer comparison always evaluates to false}} +} + +int ptr_ugt_add_ptr_idx(const char *ptr, unsigned index) { + return ptr > ptr + index; // expected-warning {{pointer comparison always evaluates to false}} +} + +int ptr_ugt_add_idx_ptr(const char *ptr, unsigned index) { + return ptr > index + ptr; // expected-warning {{pointer comparison always evaluates to false}} +} + +int add_ptr_idx_uge_ptr(const char *ptr, unsigned index) { + return ptr + index >= ptr; // expected-warning {{pointer comparison always evaluates to true}} +} + +int add_idx_ptr_uge_ptr(const char *ptr, unsigned index) { + return index + ptr >= ptr; // expected-warning {{pointer comparison always evaluates to true}} +} + +int ptr_ule_add_ptr_idx(const char *ptr, unsigned index) { + return ptr <= ptr + index; // expected-warning {{pointer comparison always evaluates to true}} +} + +int ptr_ule_add_idx_ptr(const char *ptr, unsigned index) { + return ptr <= index + ptr; // expected-warning {{pointer comparison always evaluates to true}} +} + +int add_ptr_idx_ult_ptr_array(unsigned index) { + char ptr[10]; + return ptr + index < ptr; // expected-warning {{pointer comparison always evaluates to false}} +} + +// Negative tests with wrong predicate. + +int add_ptr_idx_ule_ptr(const char *ptr, unsigned index) { + return ptr + index <= ptr; +} + +int add_ptr_idx_ugt_ptr(const char *ptr, unsigned index) { + return ptr + index > ptr; +} + +int ptr_uge_add_idx_ptr(const char *ptr, unsigned index) { + return ptr >= index + ptr; +} + +int ptr_ult_add_idx_ptr(const char *ptr, unsigned index) { + return ptr < index + ptr; +} + +// Negative test with signed index. + +int add_ptr_idx_ult_ptr_signed(const char *ptr, int index) { + return ptr + index < ptr; +} + +// Negative test with unrelated pointers. + +int add_ptr_idx_ult_ptr2(const char *ptr, const char *ptr2, unsigned index) { + return ptr + index < ptr2; +} + +// Negative test with non-pointer operands. + +int add_ptr_idx_ult_ptr_not_pointer(unsigned ptr, unsigned index) { + return ptr + index < ptr; +} diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp index fc876926ba2e6..45b4dc838f44e 100644 --- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp +++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp @@ -604,8 +604,9 @@ struct [[gsl::Pointer]] Span { // Pointer from Owner std::string_view test5() { - std::string_view a = StatusOr().valueLB(); // expected-warning {{object backing the pointer will be dest}} - return StatusOr().valueLB(); // expected-warning {{returning address of local temporary}} + // The Owner doesn't own the object which its inner pointer points to. + std::string_view a = StatusOr().valueLB(); // OK + return StatusOr().valueLB(); // OK // No dangling diagnostics on non-lifetimebound methods. std::string_view b = StatusOr().valueNoLB(); @@ -652,7 +653,7 @@ Span test10(StatusOr> aa) { // Pointer> from Owner> Span test11(StatusOr> aa) { - return aa.valueLB(); // expected-warning {{address of stack memory}} + return aa.valueLB(); // OK return aa.valueNoLB(); // OK. } @@ -693,3 +694,86 @@ void test() { auto y = std::set{}.begin(); // expected-warning {{object backing the pointer}} } } // namespace GH118064 + +namespace LifetimeboundInterleave { + +const std::string& Ref(const std::string& abc [[clang::lifetimebound]]); + +std::string_view TakeSv(std::string_view abc [[clang::lifetimebound]]); +std::string_view TakeStrRef(const std::string& abc [[clang::lifetimebound]]); +std::string_view TakeStr(std::string abc [[clang::lifetimebound]]); + +std::string_view test1() { + std::string_view t1 = Ref(std::string()); // expected-warning {{object backing}} + t1 = Ref(std::string()); // expected-warning {{object backing}} + return Ref(std::string()); // expected-warning {{returning address}} + + std::string_view t2 = TakeSv(std::string()); // expected-warning {{object backing}} + t2 = TakeSv(std::string()); // expected-warning {{object backing}} + return TakeSv(std::string()); // expected-warning {{returning address}} + + std::string_view t3 = TakeStrRef(std::string()); // expected-warning {{temporary}} + t3 = TakeStrRef(std::string()); // expected-warning {{object backing}} + return TakeStrRef(std::string()); // expected-warning {{returning address}} + + + std::string_view t4 = TakeStr(std::string()); + t4 = TakeStr(std::string()); + return TakeStr(std::string()); +} + +template +struct Foo { + const T& get() const [[clang::lifetimebound]]; + const T& getNoLB() const; +}; +std::string_view test2(Foo r1, Foo r2) { + std::string_view t1 = Foo().get(); // expected-warning {{object backing}} + t1 = Foo().get(); // expected-warning {{object backing}} + return r1.get(); // expected-warning {{address of stack}} + + std::string_view t2 = Foo().get(); + t2 = Foo().get(); + return r2.get(); + + // no warning on no-LB-annotated method. + std::string_view t3 = Foo().getNoLB(); + t3 = Foo().getNoLB(); + return r1.getNoLB(); +} + +struct Bar {}; +struct [[gsl::Pointer]] Pointer { + Pointer(const Bar & bar [[clang::lifetimebound]]); +}; +Pointer test3(Bar bar) { + Pointer p = Pointer(Bar()); // expected-warning {{temporary}} + p = Pointer(Bar()); // expected-warning {{object backing}} + return bar; // expected-warning {{address of stack}} +} + +template +struct MySpan { + MySpan(const std::vector& v); + using iterator = std::iterator; + iterator begin() const [[clang::lifetimebound]]; +}; +template +typename MySpan::iterator ReturnFirstIt(const MySpan& v [[clang::lifetimebound]]); + +void test4() { + std::vector v{1}; + // MySpan doesn't own any underlying T objects, the pointee object of + // the MySpan iterator is still alive when the whole span is destroyed, thus + // no diagnostic. + const int& t1 = *MySpan(v).begin(); + const int& t2 = *ReturnFirstIt(MySpan(v)); + // Ideally, we would diagnose the following case, but due to implementation + // constraints, we do not. + const int& t4 = *MySpan(std::vector{}).begin(); + + auto it1 = MySpan(v).begin(); // expected-warning {{temporary whose address is use}} + auto it2 = ReturnFirstIt(MySpan(v)); // expected-warning {{temporary whose address is used}} +} + +} // namespace LifetimeboundInterleave diff --git a/clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp index 03a6800898d18..8360b8fd7d8ee 100644 --- a/clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp +++ b/clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp @@ -115,3 +115,14 @@ namespace nested_union { // of Test3, or we should exclude f(Test3) as a candidate. static_assert(f({1}) == 2, ""); // expected-error {{call to 'f' is ambiguous}} } + +// Fix crash issue https://github.com/llvm/llvm-project/issues/112560. +// Make sure clang compiles the following code without crashing: +namespace GH112560 { +union U { + int f = ; // expected-error {{expected expression}} +}; +void foo() { + U g{}; +} +} // namespace GH112560 diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index 520052a89d184..6f17ce7275456 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -437,6 +437,10 @@ namespace std { constexpr strong_ordering strong_ordering::equal = {0}; constexpr strong_ordering strong_ordering::greater = {1}; constexpr strong_ordering strong_ordering::less = {-1}; + + template constexpr __remove_reference_t(T)&& move(T&& t) noexcept { + return static_cast<__remove_reference_t(T)&&>(t); + } } namespace operators_deduction { @@ -965,6 +969,22 @@ void f(); void a::f(this auto) {} // expected-error {{an explicit object parameter cannot appear in a non-member function}} } +namespace GH100341 { +struct X { + X() = default; + X(X&&) = default; + void operator()(this X); +}; + +void fail() { + X()(); + [x = X{}](this auto) {}(); +} +void pass() { + std::move(X())(); + std::move([x = X{}](this auto) {})(); +} +} // namespace GH100341 struct R { void f(this auto &&self, int &&r_value_ref) {} // expected-note {{candidate function template not viable: expects an rvalue for 2nd argument}} void g(int &&r_value_ref) { diff --git a/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp b/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp index 80dfeb9b6a8bf..118af8e867f5f 100644 --- a/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp +++ b/clang/test/SemaCXX/cxx2c-pack-indexing-ext-diags.cpp @@ -19,3 +19,35 @@ void f(T... t) { // cxx11-warning@+1 {{pack indexing is a C++2c extension}} T...[0] c; } + +template +void g(T... [1]); // cxx11-warning {{'T...[1]' is no longer a pack expansion but a pack indexing type; add a name to specify a pack expansion}} \ + // cxx11-warning {{pack indexing is a C++2c extension}} \ + // cxx11-note {{candidate function template not viable}} \ + // cxx26-warning {{pack indexing is incompatible with C++ standards before C++2c}} \ + // cxx26-note {{candidate function template not viable}} + +template +void h(T... param[1]); + +template +struct S { + using type = T; +}; + +template +void h(typename T... [1]::type); // cxx11-warning {{pack indexing is a C++2c extension}} \ + // cxx26-warning {{pack indexing is incompatible with C++ standards before C++2c}} + +template +void x(T... [0]); // cxx11-warning {{'T...[0]' is no longer a pack expansion but a pack indexing type; add a name to specify a pack expansion}} \ + // cxx11-warning {{pack indexing is a C++2c extension}} \ + // cxx26-warning {{pack indexing is incompatible with C++ standards before C++2c}} + +void call() { + g(nullptr, nullptr); // cxx26-error {{no matching function for call to 'g'}} \ + // cxx11-error {{no matching function for call to 'g'}} + h(nullptr, nullptr); + h, S>("hello"); + x(nullptr); +} diff --git a/clang/test/SemaCXX/ext-int.cpp b/clang/test/SemaCXX/ext-int.cpp index 000b871ccd343..d974221e774a7 100644 --- a/clang/test/SemaCXX/ext-int.cpp +++ b/clang/test/SemaCXX/ext-int.cpp @@ -101,8 +101,10 @@ typedef _BitInt(37) __attribute__((vector_size(16))) VecTy4; // expected-error@+1{{'_BitInt' vector element width must be a power of 2}} typedef _BitInt(37) __attribute__((ext_vector_type(32))) OtherVecTy4; -// Allow _Complex: +// expected-error@+1{{'_Complex _BitInt' is invalid}} _Complex _BitInt(3) Cmplx; +// expected-error@+1{{'_Complex _BitInt' is invalid}} +typedef _Complex _BitInt(3) Cmp; // Reject cases of _Atomic: // expected-error@+1{{_Atomic cannot be applied to integer type '_BitInt(4)'}} diff --git a/clang/test/SemaCXX/matrix-type.cpp b/clang/test/SemaCXX/matrix-type.cpp index af31e267fdcae..bb7a8421ca9e3 100644 --- a/clang/test/SemaCXX/matrix-type.cpp +++ b/clang/test/SemaCXX/matrix-type.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -pedantic -fenable-matrix -std=c++11 -verify -triple x86_64-apple-darwin %s +// RUN: %clang_cc1 -fsyntax-only -fenable-matrix -std=c++11 -verify -triple x86_64-apple-darwin %s using matrix_double_t = double __attribute__((matrix_type(6, 6))); using matrix_float_t = float __attribute__((matrix_type(6, 6))); @@ -29,3 +29,13 @@ void matrix_unsupported_element_type() { using matrix3_t = bool __attribute__((matrix_type(1, 1))); // expected-error{{invalid matrix element type 'bool'}} using matrix4_t = TestEnum __attribute__((matrix_type(1, 1))); // expected-error{{invalid matrix element type 'TestEnum'}} } + +void matrix_unsupported_bit_int() { + using m1 = _BitInt(2) __attribute__((matrix_type(4, 4))); // expected-error{{'_BitInt' matrix element width must be at least as wide as 'CHAR_BIT'}} + using m2 = _BitInt(7) __attribute__((matrix_type(4, 4))); // expected-error{{'_BitInt' matrix element width must be at least as wide as 'CHAR_BIT'}} + using m3 = _BitInt(9) __attribute__((matrix_type(4, 4))); // expected-error{{'_BitInt' matrix element width must be a power of 2}} + using m4 = _BitInt(12) __attribute__((matrix_type(4, 4))); // expected-error{{'_BitInt' matrix element width must be a power of 2}} + using m5 = _BitInt(8) __attribute__((matrix_type(4, 4))); + using m6 = _BitInt(64) __attribute__((matrix_type(4, 4))); + using m7 = _BitInt(256) __attribute__((matrix_type(4, 4))); +} diff --git a/clang/test/SemaCXX/matrix-types-pseudo-destructor.cpp b/clang/test/SemaCXX/matrix-types-pseudo-destructor.cpp new file mode 100644 index 0000000000000..b5a1b8c8a452a --- /dev/null +++ b/clang/test/SemaCXX/matrix-types-pseudo-destructor.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -fenable-matrix -verify %s +// expected-no-diagnostics + +template +void f() { + T().~T(); +} + +template +void f1(T *f) { + f->~T(); + (*f).~T(); +} + +using mat4 = float __attribute__((matrix_type(4, 4))); +using mat4i = int __attribute__((matrix_type(4, 4))); + +template +using mat4_t = T __attribute__((matrix_type(4, 4))); + +void g() { + f(); + f(); + f>(); +} + +void g2(mat4* m1, mat4i* m2, mat4_t* m3) { + f1(m1); + f1(m2); + f1(m3); +} diff --git a/clang/test/SemaCXX/ms-property.cpp b/clang/test/SemaCXX/ms-property.cpp index 168987b246223..d5799a8a4d363 100644 --- a/clang/test/SemaCXX/ms-property.cpp +++ b/clang/test/SemaCXX/ms-property.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -ast-print -verify -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s -// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s -// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -ast-print -o - | FileCheck %s -// expected-no-diagnostics +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t %s -ast-print -o - | FileCheck %s +// RUN: %clang_cc1 -fdeclspec -fsyntax-only -verify %s -std=c++23 #ifndef HEADER #define HEADER @@ -85,4 +85,40 @@ int main(int argc, char **argv) { // CHECK-NEXT: return Test1::GetTest1()->X; return Test1::GetTest1()->X; } + +struct X { + int implicit_object_member_function() { return 0; } + static int static_member_function() { return 0; } + + __declspec(property(get=implicit_object_member_function)) int imp; + __declspec(property(get=static_member_function)) int st; + +#if __cplusplus >= 202302L + int explicit_object_member_function(this X self) { return 0; } + __declspec(property(get=explicit_object_member_function)) int exp; +#endif +}; + +[[nodiscard]] X get_x(); +void f() { + (void) get_x().imp; + (void) get_x().st; + // expected-warning@-1 {{ignoring return value of function declared with 'nodiscard' attribute}} +#if __cplusplus >= 202302L + (void) get_x().exp; +#endif +} + +#if __cplusplus >= 202302L +struct Y { + Y() = default; + Y(const Y&) = delete; + int explicit_object_member_function(this Y) { return 0; } + __declspec(property(get = explicit_object_member_function)) int prop; +}; +void g() { + (void) Y().prop; +} +#endif + #endif // HEADER diff --git a/clang/test/SemaCXX/msvc-pragma-function-no-builtin-attr.cpp b/clang/test/SemaCXX/msvc-pragma-function-no-builtin-attr.cpp new file mode 100644 index 0000000000000..7262ffd079a92 --- /dev/null +++ b/clang/test/SemaCXX/msvc-pragma-function-no-builtin-attr.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cl -fms-compatibility -Xclang -ast-dump -fsyntax-only -- %s | FileCheck %s + +extern "C" __inline float __cdecl fabsf( float _X); +// CHECK: FunctionDecl {{.*}} fabsf +#pragma function(fabsf) + __inline float __cdecl fabsf( float _X) +{ + return 0; +} +// CHECK: FunctionDecl {{.*}} fabsf +// CHECK: NoBuiltinAttr {{.*}} <> Implicit fabsf + +int bar() { + return 0; +} +// CHECK: FunctionDecl {{.*}} bar +// CHECK: NoBuiltinAttr {{.*}} <> Implicit fabsf + +struct A { + int foo() = delete; + // CHECK: CXXMethodDecl {{.*}} foo {{.*}} delete + // CHECK-NOT: NoBuiltinAttr + A() = default; + // CHECK: CXXConstructorDecl {{.*}} A {{.*}} default + // CHECK-NOT: NoBuiltinAttr +}; + +int main() { + return 0; +} +// CHECK: FunctionDecl {{.*}} main +// CHECK: NoBuiltinAttr {{.*}} <> Implicit fabsf diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp index 8b3a5d8dd3327..069a9004927a9 100644 --- a/clang/test/SemaCXX/source_location.cpp +++ b/clang/test/SemaCXX/source_location.cpp @@ -1012,3 +1012,21 @@ int h = Var; } + +namespace GH119129 { +struct X{ + constexpr int foo(std::source_location loc = std::source_location::current()) { + return loc.line(); + } +}; +static_assert(X{}.foo() == __LINE__); +static_assert(X{}. + foo() == __LINE__); +static_assert(X{}. + + + foo() == __LINE__); +#line 10000 +static_assert(X{}. + foo() == 10001); +} diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp index 8477200456d98..3c52c8165d852 100644 --- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -1593,8 +1593,12 @@ namespace substitution_test { void unlockData() UNLOCK_FUNCTION(mu); void doSomething() EXCLUSIVE_LOCKS_REQUIRED(mu) { } + void operator()() EXCLUSIVE_LOCKS_REQUIRED(mu) { } + + MyData operator+(const MyData& other) const SHARED_LOCKS_REQUIRED(mu, other.mu); }; + MyData operator-(const MyData& a, const MyData& b) SHARED_LOCKS_REQUIRED(a.mu, b.mu); class DataLocker { public: @@ -1607,6 +1611,27 @@ namespace substitution_test { public: void foo(MyData* d) EXCLUSIVE_LOCKS_REQUIRED(d->mu) { } + void subst(MyData& d) { + d.doSomething(); // expected-warning {{calling function 'doSomething' requires holding mutex 'd.mu' exclusively}} + d(); // expected-warning {{calling function 'operator()' requires holding mutex 'd.mu' exclusively}} + d.operator()(); // expected-warning {{calling function 'operator()' requires holding mutex 'd.mu' exclusively}} + + d.lockData(); + d.doSomething(); + d(); + d.operator()(); + d.unlockData(); + } + + void binop(MyData& a, MyData& b) EXCLUSIVE_LOCKS_REQUIRED(a.mu) { + a + b; // expected-warning {{calling function 'operator+' requires holding mutex 'b.mu'}} + // expected-note@-1 {{found near match 'a.mu'}} + b + a; // expected-warning {{calling function 'operator+' requires holding mutex 'b.mu'}} + // expected-note@-1 {{found near match 'a.mu'}} + a - b; // expected-warning {{calling function 'operator-' requires holding mutex 'b.mu'}} + // expected-note@-1 {{found near match 'a.mu'}} + } + void bar1(MyData* d) { d->lockData(); foo(d); @@ -5172,9 +5197,13 @@ class Foo { }; func1(); // expected-warning {{calling function 'operator()' requires holding mutex 'mu_' exclusively}} + func1.operator()(); // expected-warning {{calling function 'operator()' requires holding mutex 'mu_' exclusively}} func2(); + func2.operator()(); func3(); mu_.Unlock(); + func3.operator()(); + mu_.Unlock(); } }; diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp index c6c93a27e4b96..7dd6c83dbba2a 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp @@ -52,3 +52,43 @@ void constant_id_string(unsigned idx) { unsafe_char = ""[1]; //expected-warning{{unsafe buffer access}} unsafe_char = ""[idx]; //expected-warning{{unsafe buffer access}} } + +typedef float Float4x4[4][4]; + +// expected-warning@+1 {{'matrix' is an unsafe buffer that does not perform bounds checks}} +float two_dimension_array(Float4x4& matrix, unsigned idx) { + // expected-warning@+1{{unsafe buffer access}} + float a = matrix[0][4]; + + a = matrix[0][3]; + + // expected-note@+1{{used in buffer access here}} + a = matrix[4][0]; + + a = matrix[idx][0]; // expected-note{{used in buffer access here}} + + a = matrix[0][idx]; //expected-warning{{unsafe buffer access}} + + a = matrix[idx][idx]; //expected-warning{{unsafe buffer access}} // expected-note{{used in buffer access here}} + + return matrix[1][1]; +} + +typedef float Float2x3x4[2][3][4]; +float multi_dimension_array(Float2x3x4& matrix) { + float *f = matrix[0][2]; + return matrix[1][2][3]; +} + +char array_strings[][11] = { + "Apple", "Banana", "Cherry", "Date", "Elderberry" +}; + +char array_string[] = "123456"; + +char access_strings() { + char c = array_strings[0][4]; + c = array_strings[3][10]; + c = array_string[5]; + return c; +} diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp index 0ba605475925b..1636c948da075 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp @@ -96,7 +96,6 @@ void test_attribute_multiple_fields (D d) { int v = d.buf[0]; //expected-warning{{field 'buf' prone to unsafe buffer manipulation}} - //expected-warning@+1{{unsafe buffer access}} v = d.buf[5]; //expected-warning{{field 'buf' prone to unsafe buffer manipulation}} } diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp index 71350098613d1..0c80da63f8291 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp @@ -118,7 +118,7 @@ void isArrayDecayToPointerUPC(int a[][10], int (*b)[10]) { // expected-warning@-2{{'b' is an unsafe pointer used for buffer access}} int tmp; - tmp = a[5][5] + b[5][5]; // expected-warning2{{unsafe buffer access}} expected-note2{{used in buffer access here}} + tmp = a[5][5] + b[5][5]; // expected-note2{{used in buffer access here}} } // parameter having default values: diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp index 642db0e9d3c63..41d38ada48788 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp @@ -109,7 +109,6 @@ void testQualifiedParameters(const int * p, const int * const q, const int a[10] q[1], 1[q], q[-1], // expected-note3{{used in buffer access here}} a[1], // expected-note{{used in buffer access here}} `a` is of pointer type b[1][2] // expected-note{{used in buffer access here}} `b[1]` is of array type - // expected-warning@-1{{unsafe buffer access}} ); } @@ -128,29 +127,41 @@ T_t funRetT(); T_t * funRetTStar(); void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) { - foo(sp->a[1], // expected-warning{{unsafe buffer access}} + foo(sp->a[1], sp->b[1], // expected-warning{{unsafe buffer access}} - sp->c.a[1], // expected-warning{{unsafe buffer access}} + sp->c.a[1], sp->c.b[1], // expected-warning{{unsafe buffer access}} - s.a[1], // expected-warning{{unsafe buffer access}} + s.a[1], s.b[1], // expected-warning{{unsafe buffer access}} - s.c.a[1], // expected-warning{{unsafe buffer access}} + s.c.a[1], s.c.b[1], // expected-warning{{unsafe buffer access}} - sp2->a[1], // expected-warning{{unsafe buffer access}} + sp2->a[1], sp2->b[1], // expected-warning{{unsafe buffer access}} - sp2->c.a[1], // expected-warning{{unsafe buffer access}} + sp2->c.a[1], sp2->c.b[1], // expected-warning{{unsafe buffer access}} - s2.a[1], // expected-warning{{unsafe buffer access}} + s2.a[1], s2.b[1], // expected-warning{{unsafe buffer access}} - s2.c.a[1], // expected-warning{{unsafe buffer access}} + s2.c.a[1], s2.c.b[1], // expected-warning{{unsafe buffer access}} - funRetT().a[1], // expected-warning{{unsafe buffer access}} + funRetT().a[1], funRetT().b[1], // expected-warning{{unsafe buffer access}} - funRetTStar()->a[1], // expected-warning{{unsafe buffer access}} + funRetTStar()->a[1], funRetTStar()->b[1] // expected-warning{{unsafe buffer access}} ); } +union Foo { + bool b; + int arr[10]; +}; + +int testUnionMembers(Foo f) { + int a = f.arr[0]; + a = f.arr[5]; + a = f.arr[10]; // expected-warning{{unsafe buffer access}} + return a; +} + int garray[10]; // expected-warning{{'garray' is an unsafe buffer that does not perform bounds checks}} int * gp = garray; // expected-warning{{'gp' is an unsafe pointer used for buffer access}} int gvar = gp[1]; // FIXME: file scope unsafe buffer access is not warned @@ -213,7 +224,6 @@ void testTypedefs(T_ptr_t p) { // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} foo(p[1], // expected-note{{used in buffer access here}} p[1].a[1], // expected-note{{used in buffer access here}} - // expected-warning@-1{{unsafe buffer access}} p[1].b[1] // expected-note{{used in buffer access here}} // expected-warning@-1{{unsafe buffer access}} ); @@ -223,10 +233,9 @@ template T f(T t, T * pt, T a[N], T (&b)[N]) { // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} // expected-warning@-2{{'pt' is an unsafe pointer used for buffer access}} // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}} - // expected-warning@-4{{'b' is an unsafe buffer that does not perform bounds checks}} foo(pt[1], // expected-note{{used in buffer access here}} a[1], // expected-note{{used in buffer access here}} - b[1]); // expected-note{{used in buffer access here}} + b[1]); return &t[1]; // expected-note{{used in buffer access here}} } @@ -376,7 +385,7 @@ int testArrayAccesses(int n, int idx) { typedef int A[3]; const A tArr = {4, 5, 6}; foo(tArr[0], tArr[1]); - return cArr[0][1]; // expected-warning{{unsafe buffer access}} + return cArr[0][1]; } void testArrayPtrArithmetic(int x[]) { // expected-warning{{'x' is an unsafe pointer used for buffer access}} diff --git a/clang/test/SemaHLSL/BuiltIns/WaveActiveAllTrue-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/WaveActiveAllTrue-errors.hlsl new file mode 100644 index 0000000000000..b0d0fdfca5e18 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/WaveActiveAllTrue-errors.hlsl @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify + +bool test_too_few_arg() { + return __builtin_hlsl_wave_active_all_true(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +bool test_too_many_arg(bool p0) { + return __builtin_hlsl_wave_active_all_true(p0, p0); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +struct Foo +{ + int a; +}; + +bool test_type_check(Foo p0) { + return __builtin_hlsl_wave_active_all_true(p0); + // expected-error@-1 {{no viable conversion from 'Foo' to 'bool'}} +} diff --git a/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl index 13c07038d2e4a..393d7300605c0 100644 --- a/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl +++ b/clang/test/SemaHLSL/Semantics/entry_parameter.hlsl @@ -1,16 +1,14 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -hlsl-entry CSMain -x hlsl -finclude-default-header -ast-dump -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-mesh -hlsl-entry CSMain -x hlsl -finclude-default-header -verify -o - %s [numthreads(8,8,1)] -// expected-error@+3 {{attribute 'SV_GroupIndex' is unsupported in 'mesh' shaders, requires compute}} -// expected-error@+2 {{attribute 'SV_DispatchThreadID' is unsupported in 'mesh' shaders, requires compute}} -// expected-error@+1 {{attribute 'SV_GroupID' is unsupported in 'mesh' shaders, requires compute}} -void CSMain(int GI : SV_GroupIndex, uint ID : SV_DispatchThreadID, uint GID : SV_GroupID) { -// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain 'void (int, uint, uint)' +void CSMain(int GI : SV_GroupIndex, uint ID : SV_DispatchThreadID, uint GID : SV_GroupID, uint GThreadID : SV_GroupThreadID) { +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain 'void (int, uint, uint, uint)' // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:17 GI 'int' // CHECK-NEXT: HLSLSV_GroupIndexAttr // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:42 ID 'uint' // CHECK-NEXT: HLSLSV_DispatchThreadIDAttr // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:73 GID 'uint' // CHECK-NEXT: HLSLSV_GroupIDAttr +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:96 GThreadID 'uint' +// CHECK-NEXT: HLSLSV_GroupThreadIDAttr } diff --git a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl index 4e1f88aa2294b..1bb4ee5182d62 100644 --- a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl +++ b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl @@ -49,3 +49,33 @@ struct ST2_GID { static uint GID : SV_GroupID; uint s_gid : SV_GroupID; }; + +[numthreads(8,8,1)] +// expected-error@+1 {{attribute 'SV_GroupThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}} +void CSMain_GThreadID(float ID : SV_GroupThreadID) { +} + +[numthreads(8,8,1)] +// expected-error@+1 {{attribute 'SV_GroupThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}} +void CSMain2_GThreadID(ST GID : SV_GroupThreadID) { + +} + +void foo_GThreadID() { +// expected-warning@+1 {{'SV_GroupThreadID' attribute only applies to parameters and non-static data members}} + uint GThreadIS : SV_GroupThreadID; +} + +struct ST2_GThreadID { +// expected-warning@+1 {{'SV_GroupThreadID' attribute only applies to parameters and non-static data members}} + static uint GThreadID : SV_GroupThreadID; + uint s_gthreadid : SV_GroupThreadID; +}; + + +[shader("vertex")] +// expected-error@+4 {{attribute 'SV_GroupIndex' is unsupported in 'vertex' shaders, requires compute}} +// expected-error@+3 {{attribute 'SV_DispatchThreadID' is unsupported in 'vertex' shaders, requires compute}} +// expected-error@+2 {{attribute 'SV_GroupID' is unsupported in 'vertex' shaders, requires compute}} +// expected-error@+1 {{attribute 'SV_GroupThreadID' is unsupported in 'vertex' shaders, requires compute}} +void vs_main(int GI : SV_GroupIndex, uint ID : SV_DispatchThreadID, uint GID : SV_GroupID, uint GThreadID : SV_GroupThreadID) {} diff --git a/clang/test/SemaHLSL/Semantics/valid_entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/valid_entry_parameter.hlsl index 10a5e5dabac87..6781f9241df24 100644 --- a/clang/test/SemaHLSL/Semantics/valid_entry_parameter.hlsl +++ b/clang/test/SemaHLSL/Semantics/valid_entry_parameter.hlsl @@ -49,3 +49,28 @@ void CSMain3_GID(uint3 : SV_GroupID) { // CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:24 'uint3' // CHECK-NEXT: HLSLSV_GroupIDAttr } + +[numthreads(8,8,1)] +void CSMain_GThreadID(uint ID : SV_GroupThreadID) { +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain_GThreadID 'void (uint)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:28 ID 'uint' +// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +} +[numthreads(8,8,1)] +void CSMain1_GThreadID(uint2 ID : SV_GroupThreadID) { +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain1_GThreadID 'void (uint2)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:30 ID 'uint2' +// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +} +[numthreads(8,8,1)] +void CSMain2_GThreadID(uint3 ID : SV_GroupThreadID) { +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain2_GThreadID 'void (uint3)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:30 ID 'uint3' +// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +} +[numthreads(8,8,1)] +void CSMain3_GThreadID(uint3 : SV_GroupThreadID) { +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:6 CSMain3_GThreadID 'void (uint3)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:30 'uint3' +// CHECK-NEXT: HLSLSV_GroupThreadIDAttr +} diff --git a/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c b/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c index 45eede2e30f1f..a71d25ce61bed 100644 --- a/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c +++ b/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c @@ -1,8 +1,5 @@ // RUN: %clang_cc1 %s -fopenacc -verify -// TODO: OpenACC: A number of the 'not yet implemented' diagnostics interfere -// with the diagnostics we want to make here, so as we implement these, we need -// to replace the errors we should have. void uses() { #pragma acc parallel loop auto for(unsigned i = 0; i < 5; ++i); @@ -40,10 +37,10 @@ void uses() { int *VarPtr; // 'auto' can combine with any other clause. - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop auto finalize for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop auto if_present for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop auto worker @@ -67,15 +64,15 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_copy' is a deprecated clause name and is now an alias for 'copy'}} #pragma acc parallel loop auto present_or_copy(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop auto use_device(Var) for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop auto attach(VarPtr) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop auto delete(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop auto detach(Var) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -124,7 +121,6 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_create' is a deprecated clause name and is now an alias for 'create'}} #pragma acc parallel loop auto present_or_create(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc parallel loop auto reduction(+:Var) for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop auto collapse(1) @@ -158,10 +154,10 @@ void uses() { #pragma acc parallel loop auto wait for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop finalize auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop if_present auto for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop worker auto @@ -185,15 +181,15 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_copy' is a deprecated clause name and is now an alias for 'copy'}} #pragma acc parallel loop present_or_copy(Var) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop use_device(Var) auto for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop attach(VarPtr) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop delete(Var) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop detach(Var) auto for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -242,7 +238,6 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_create' is a deprecated clause name and is now an alias for 'create'}} #pragma acc parallel loop present_or_create(Var) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc parallel loop reduction(+:Var) auto for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop collapse(1) auto @@ -277,10 +272,10 @@ void uses() { for(unsigned i = 0; i < 5; ++i); // 'independent' can also be combined with any clauses - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop independent finalize for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop independent if_present for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop independent worker @@ -304,15 +299,15 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_copy' is a deprecated clause name and is now an alias for 'copy'}} #pragma acc parallel loop independent present_or_copy(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop independent use_device(Var) for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop independent attach(VarPtr) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop independent delete(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop independent detach(Var) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -361,7 +356,6 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_create' is a deprecated clause name and is now an alias for 'create'}} #pragma acc parallel loop independent present_or_create(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc parallel loop independent reduction(+:Var) for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop independent collapse(1) @@ -395,10 +389,10 @@ void uses() { #pragma acc parallel loop independent wait for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop finalize independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop if_present independent for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop worker independent @@ -422,15 +416,15 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_copy' is a deprecated clause name and is now an alias for 'copy'}} #pragma acc parallel loop present_or_copy(Var) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop use_device(Var) independent for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop attach(VarPtr) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop delete(Var) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop detach(Var) independent for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -479,7 +473,6 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_create' is a deprecated clause name and is now an alias for 'create'}} #pragma acc parallel loop present_or_create(Var) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc parallel loop reduction(+:Var) independent for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop collapse(1) independent @@ -526,10 +519,10 @@ void uses() { // expected-note@+1{{previous clause is here}} #pragma acc parallel loop seq vector for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop seq finalize for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop seq if_present for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'nohost' not yet implemented}} @@ -549,15 +542,15 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_copy' is a deprecated clause name and is now an alias for 'copy'}} #pragma acc parallel loop seq present_or_copy(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop seq use_device(Var) for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop seq attach(VarPtr) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop seq delete(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop seq detach(Var) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -606,7 +599,6 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_create' is a deprecated clause name and is now an alias for 'create'}} #pragma acc parallel loop seq present_or_create(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc parallel loop seq reduction(+:Var) for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop seq collapse(1) @@ -650,10 +642,10 @@ void uses() { // expected-note@+1{{previous clause is here}} #pragma acc parallel loop vector seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop finalize seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop if_present seq for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'nohost' not yet implemented}} @@ -673,15 +665,15 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_copy' is a deprecated clause name and is now an alias for 'copy'}} #pragma acc parallel loop present_or_copy(Var) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop use_device(Var) seq for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop attach(VarPtr) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop delete(Var) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop detach(Var) seq for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -730,7 +722,6 @@ void uses() { // expected-warning@+1{{OpenACC clause name 'present_or_create' is a deprecated clause name and is now an alias for 'create'}} #pragma acc parallel loop present_or_create(Var) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc parallel loop reduction(+:Var) seq for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop collapse(1) seq diff --git a/clang/test/SemaOpenACC/combined-construct-collapse-clause.cpp b/clang/test/SemaOpenACC/combined-construct-collapse-clause.cpp index c7db9669a9879..f2be6622007c3 100644 --- a/clang/test/SemaOpenACC/combined-construct-collapse-clause.cpp +++ b/clang/test/SemaOpenACC/combined-construct-collapse-clause.cpp @@ -214,14 +214,17 @@ void no_other_directives() { #pragma acc serial loop collapse(2) for(unsigned i = 0; i < 5; ++i) { for(unsigned j = 0; j < 5; ++j) { -#pragma acc data // expected-warning{{OpenACC construct 'data' not yet implemented}} + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} +#pragma acc data + ; } } // expected-note@+1{{active 'collapse' clause defined here}} #pragma acc kernels loop collapse(2) for(unsigned i = 0; i < 5; ++i) { + // expected-error@+2{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} // expected-error@+1{{OpenACC 'data' construct cannot appear in intervening code of a 'kernels loop' with a 'collapse' clause}} -#pragma acc data // expected-warning{{OpenACC construct 'data' not yet implemented}} +#pragma acc data for(unsigned j = 0; j < 5; ++j) { } } diff --git a/clang/test/SemaOpenACC/combined-construct-default-ast.cpp b/clang/test/SemaOpenACC/combined-construct-default-ast.cpp index 2ff24b32afe7b..8f09e74907318 100644 --- a/clang/test/SemaOpenACC/combined-construct-default-ast.cpp +++ b/clang/test/SemaOpenACC/combined-construct-default-ast.cpp @@ -1,4 +1,3 @@ - // RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s // Test this with PCH. diff --git a/clang/test/SemaOpenACC/combined-construct-default-clause.c b/clang/test/SemaOpenACC/combined-construct-default-clause.c index a9c90240cb122..2d77faa442a62 100644 --- a/clang/test/SemaOpenACC/combined-construct-default-clause.c +++ b/clang/test/SemaOpenACC/combined-construct-default-clause.c @@ -28,8 +28,6 @@ void SingleOnly() { #pragma acc kernels loop default(none) for(int i = 0; i < 5; ++i); - // expected-warning@+2{{OpenACC construct 'data' not yet implemented}} - // expected-warning@+1{{OpenACC clause 'default' not yet implemented}} #pragma acc data default(none) while(0); @@ -37,7 +35,6 @@ void SingleOnly() { #pragma acc loop default(none) for(int i = 5; i < 10;++i); - // expected-warning@+2{{OpenACC construct 'wait' not yet implemented}} // expected-error@+1{{OpenACC 'default' clause is not valid on 'wait' directive}} #pragma acc wait default(none) while(0); diff --git a/clang/test/SemaOpenACC/combined-construct-device_type-clause.c b/clang/test/SemaOpenACC/combined-construct-device_type-clause.c index 11bb342a2f638..40339941f51a9 100644 --- a/clang/test/SemaOpenACC/combined-construct-device_type-clause.c +++ b/clang/test/SemaOpenACC/combined-construct-device_type-clause.c @@ -42,12 +42,10 @@ void uses() { #pragma acc parallel loop device_type(*) vector for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'finalize' may not follow a 'device_type' clause in a 'serial loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'serial loop' directive}} #pragma acc serial loop device_type(*) finalize for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'if_present' may not follow a 'device_type' clause in a 'kernels loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'kernels loop' directive}} #pragma acc kernels loop device_type(*) if_present for(int i = 0; i < 5; ++i); #pragma acc parallel loop device_type(*) seq @@ -89,20 +87,17 @@ void uses() { // expected-note@+1{{previous clause is here}} #pragma acc serial loop device_type(*) present_or_copy(Var) for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'use_device' may not follow a 'device_type' clause in a 'kernels loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'kernels loop' directive}} #pragma acc kernels loop device_type(*) use_device(Var) for(int i = 0; i < 5; ++i); // expected-error@+2{{OpenACC clause 'attach' may not follow a 'device_type' clause in a 'parallel loop' construct}} // expected-note@+1{{previous clause is here}} #pragma acc parallel loop device_type(*) attach(Var) for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'delete' may not follow a 'device_type' clause in a 'serial loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'serial loop' directive}} #pragma acc serial loop device_type(*) delete(Var) for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'detach' may not follow a 'device_type' clause in a 'kernels loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'kernels loop' directive}} #pragma acc kernels loop device_type(*) detach(Var) for(int i = 0; i < 5; ++i); // expected-error@+2{{OpenACC clause 'device' may not follow a 'device_type' clause in a 'parallel loop' construct}} diff --git a/clang/test/SemaOpenACC/combined-construct-if-clause.c b/clang/test/SemaOpenACC/combined-construct-if-clause.c index 563f1cd25377b..5580fdfe22b7b 100644 --- a/clang/test/SemaOpenACC/combined-construct-if-clause.c +++ b/clang/test/SemaOpenACC/combined-construct-if-clause.c @@ -43,8 +43,7 @@ void BoolExpr(int *I, float *F) { #pragma acc kernels loop if (*I < *F) for (unsigned i = 0; i < 5; ++i); - // expected-warning@+2{{OpenACC construct 'data' not yet implemented}} - // expected-warning@+1{{OpenACC clause 'if' not yet implemented}} + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} #pragma acc data if (*I < *F) for (unsigned i = 0; i < 5; ++i); #pragma acc parallel loop if (*I < *F) diff --git a/clang/test/SemaOpenACC/combined-construct-reduction-ast.cpp b/clang/test/SemaOpenACC/combined-construct-reduction-ast.cpp new file mode 100644 index 0000000000000..502b7a2613e40 --- /dev/null +++ b/clang/test/SemaOpenACC/combined-construct-reduction-ast.cpp @@ -0,0 +1,129 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +void NormalFunc(int i, float f) { + // CHECK: FunctionDecl{{.*}}NormalFunc + // CHECK-NEXT: ParmVarDecl + // CHECK-NEXT: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc parallel loop reduction(+: i) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} parallel loop + // CHECK-NEXT: reduction clause Operator: + + // CHECK-NEXT: DeclRefExpr{{.*}} 'int' lvalue ParmVar{{.*}} 'i' 'int' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + +#pragma acc serial loop reduction(*: f) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} serial loop + // CHECK-NEXT: reduction clause Operator: * + // CHECK-NEXT: DeclRefExpr{{.*}} 'float' lvalue ParmVar{{.*}} 'f' 'float' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + +#pragma acc kernels loop reduction(max: i) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} kernels loop + // CHECK-NEXT: reduction clause Operator: max + // CHECK-NEXT: DeclRefExpr{{.*}} 'int' lvalue ParmVar{{.*}} 'i' 'int' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + } + +template +void TemplFunc() { + // CHECK: FunctionTemplateDecl{{.*}}TemplFunc + // CHECK-NEXT: TemplateTypeParmDecl + + // Match the prototype: + // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc + // CHECK-NEXT: CompoundStmt + + T t; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl{{.*}} t 'T' + +#pragma acc parallel loop reduction(+: t) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} parallel loop + // CHECK-NEXT: reduction clause Operator: + + // CHECK-NEXT: DeclRefExpr{{.*}} 'T' lvalue Var{{.*}} 't' 'T' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + +#pragma acc serial loop reduction(*: T::SomeFloat) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} serial loop + // CHECK-NEXT: reduction clause Operator: * + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + typename T::IntTy i; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl{{.*}} i 'typename T::IntTy' + +#pragma acc kernels loop reduction(max: i) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} kernels loop + // CHECK-NEXT: reduction clause Operator: max + // CHECK-NEXT: DeclRefExpr{{.*}} 'typename T::IntTy' lvalue Var{{.*}} 'i' 'typename T::IntTy' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + // Match the instantiation: + + // CHECK: FunctionDecl{{.*}}TemplFunc 'void ()' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'InstTy' + // CHECK-NEXT: RecordType{{.*}} 'InstTy' + // CHECK-NEXT: CXXRecord{{.*}} 'InstTy' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl{{.*}} used t 'InstTy' + // CHECK-NEXT: CXXConstructExpr{{.*}} 'InstTy' 'void () noexcept' + + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} parallel loop + // CHECK-NEXT: reduction clause Operator: + + // CHECK-NEXT: DeclRefExpr{{.*}} 'InstTy' lvalue Var{{.*}} 't' 'InstTy' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} serial loop + // CHECK-NEXT: reduction clause Operator: * + // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl{{.*}} i 'typename InstTy::IntTy':'int' + + // CHECK-NEXT: OpenACCCombinedConstruct{{.*}} kernels loop + // CHECK-NEXT: reduction clause Operator: max + // CHECK-NEXT: DeclRefExpr{{.*}} 'typename InstTy::IntTy':'int' lvalue Var{{.*}} 'i' 'typename InstTy::IntTy':'int' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + +} + +struct InstTy { + using IntTy = int; + static constexpr float SomeFloat = 5.0; +}; + +void Instantiate() { + TemplFunc(); +} +#endif // PCH_HELPER diff --git a/clang/test/SemaOpenACC/combined-construct-reduction-clause.cpp b/clang/test/SemaOpenACC/combined-construct-reduction-clause.cpp new file mode 100644 index 0000000000000..082f1ed67a86f --- /dev/null +++ b/clang/test/SemaOpenACC/combined-construct-reduction-clause.cpp @@ -0,0 +1,169 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct CompositeOfScalars { + int I; + float F; + short J; + char C; + double D; + _Complex float CF; + _Complex double CD; +}; + +struct CompositeHasComposite { + int I; + float F; + short J; + char C; + double D; + _Complex float CF; + _Complex double CD; + struct CompositeOfScalars COS; // #COS_FIELD +}; + + // All of the type checking is done for compute and loop constructs, so only check the basics + the parts that are combined specific. +void uses(unsigned Parm) { + struct CompositeOfScalars CoS; + struct CompositeHasComposite ChC; + int I; + float F; + int Array[5]; + + // legal on all 3 kinds of combined constructs +#pragma acc parallel loop reduction(+:Parm) + for(int i = 0; i < 5; ++i); + +#pragma acc serial loop reduction(&: CoS, I, F) + for(int i = 0; i < 5; ++i); + +#pragma acc kernels loop reduction(min: CoS, Array[I], Array[0:I]) + for(int i = 0; i < 5; ++i); + + // expected-error@+2{{OpenACC 'reduction' composite variable must not have non-scalar field}} + // expected-note@#COS_FIELD{{invalid field is here}} +#pragma acc parallel loop reduction(&: ChC) + for(int i = 0; i < 5; ++i); + +#pragma acc kernels loop reduction(+:Parm) num_gangs(I) + for(int i = 0; i < 5; ++i); + // expected-error@+2{{OpenACC 'num_gangs' clause with more than 1 argument may not appear on a 'parallel loop' construct with a 'reduction' clause}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop reduction(+:Parm) num_gangs(I, I) + for(int i = 0; i < 5; ++i); + +#pragma acc kernels loop num_gangs(I) reduction(+:Parm) + for(int i = 0; i < 5; ++i); + // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel loop' construct with a 'num_gangs' clause with more than 1 argument}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop num_gangs(I, I) reduction(+:Parm) + for(int i = 0; i < 5; ++i); + + // Reduction cannot appear on a loop with a 'gang' of dim>1. +#pragma acc parallel loop gang(dim:1) reduction(+:Parm) + for(int i = 0; i < 5; ++i); + // expected-error@+2{{OpenACC 'reduction' clause cannot appear on the same 'parallel loop' construct as a 'gang' clause with a 'dim' value greater than 1}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop gang(dim:2) reduction(+:Parm) + for(int i = 0; i < 5; ++i); +#pragma acc parallel loop reduction(+:Parm) gang(dim:1) + for(int i = 0; i < 5; ++i); + // expected-error@+2{{OpenACC 'gang' clause with a 'dim' value greater than 1 cannot appear on the same 'parallel loop' construct as a 'reduction' clause}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop reduction(+:Parm) gang(dim:2) + for(int i = 0; i < 5; ++i); + + // Reduction cannot appear on a loop with a gang and a num_gangs with >1 + // explicit argument. +#pragma acc kernels loop num_gangs(I) reduction(+:Parm) gang + for(int i = 0; i < 5; ++i); +#pragma acc kernels loop num_gangs(I) gang reduction(+:Parm) + for(int i = 0; i < 5; ++i); +#pragma acc kernels loop reduction(+:Parm) num_gangs(I) gang + for(int i = 0; i < 5; ++i); +#pragma acc kernels loop reduction(+:Parm) gang num_gangs(I) + for(int i = 0; i < 5; ++i); +#pragma acc kernels loop gang num_gangs(I) reduction(+:Parm) + for(int i = 0; i < 5; ++i); +#pragma acc kernels loop gang reduction(+:Parm) num_gangs(I) + for(int i = 0; i < 5; ++i); + + // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel loop' construct with a 'num_gangs' clause with more than 1 argument}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop num_gangs(I, I) reduction(+:Parm) gang + for(int i = 0; i < 5; ++i); + // expected-error@+3{{OpenACC 'reduction' clause cannot appear on the same 'parallel loop' construct as a 'gang' clause and a 'num_gangs' clause with more than one argument}} + // expected-note@+2{{previous clause is here}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop num_gangs(I, I) gang reduction(+:Parm) + for(int i = 0; i < 5; ++i); + // expected-error@+2{{OpenACC 'num_gangs' clause with more than 1 argument may not appear on a 'parallel loop' construct with a 'reduction' clause}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop reduction(+:Parm) num_gangs(I, I) gang + for(int i = 0; i < 5; ++i); + // expected-error@+3{{OpenACC 'reduction' clause cannot appear on the same 'parallel loop' construct as a 'gang' clause and a 'num_gangs' clause with more than one argument}} + // expected-note@+2{{previous clause is here}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop reduction(+:Parm) gang num_gangs(I, I) + for(int i = 0; i < 5; ++i); + // expected-error@+3{{OpenACC 'reduction' clause cannot appear on the same 'parallel loop' construct as a 'gang' clause and a 'num_gangs' clause with more than one argument}} + // expected-note@+2{{previous clause is here}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop gang num_gangs(I, I) reduction(+:Parm) + for(int i = 0; i < 5; ++i); + // expected-error@+3{{OpenACC 'reduction' clause cannot appear on the same 'parallel loop' construct as a 'gang' clause and a 'num_gangs' clause with more than one argument}} + // expected-note@+2{{previous clause is here}} + // expected-note@+1{{previous clause is here}} +#pragma acc parallel loop gang reduction(+:Parm) num_gangs(I, I) + for(int i = 0; i < 5; ++i); + +#pragma acc parallel loop num_gangs(I) reduction(+:Parm) gang + for(int i = 0; i < 5; ++i); +#pragma acc parallel loop num_gangs(I) gang reduction(+:Parm) + for(int i = 0; i < 5; ++i); +#pragma acc parallel loop reduction(+:Parm) num_gangs(I) gang + for(int i = 0; i < 5; ++i); +#pragma acc parallel loop reduction(+:Parm) gang num_gangs(I) + for(int i = 0; i < 5; ++i); +#pragma acc parallel loop gang num_gangs(I) reduction(+:Parm) + for(int i = 0; i < 5; ++i); +#pragma acc parallel loop gang reduction(+:Parm) num_gangs(I) + for(int i = 0; i < 5; ++i); + +#pragma acc parallel loop reduction(+:I) + for(int i = 0; i < 5; ++i) { + // expected-error@+2{{OpenACC 'reduction' variable must have the same operator in all nested constructs (& vs +)}} + // expected-note@-3{{previous clause is here}} +#pragma acc loop reduction(&:I) + for(int i = 0; i < 5; ++i); + } +#pragma acc parallel loop reduction(+:I) + for(int i = 0; i < 5; ++i) { + // expected-error@+2{{OpenACC 'reduction' variable must have the same operator in all nested constructs (& vs +)}} + // expected-note@-3{{previous clause is here}} +#pragma acc parallel reduction(&:I) + for(int i = 0; i < 5; ++i); + } + +#pragma acc parallel loop reduction(+:I) + for(int i = 0; i < 5; ++i) { + // expected-error@+2{{OpenACC 'reduction' variable must have the same operator in all nested constructs (& vs +)}} + // expected-note@-3{{previous clause is here}} +#pragma acc parallel loop reduction(&:I) + for(int i = 0; i < 5; ++i); + } +#pragma acc loop reduction(+:I) + for(int i = 0; i < 5; ++i) { + // expected-error@+2{{OpenACC 'reduction' variable must have the same operator in all nested constructs (& vs +)}} + // expected-note@-3{{previous clause is here}} +#pragma acc parallel loop reduction(&:I) + for(int i = 0; i < 5; ++i); + } + +#pragma acc parallel reduction(+:I) + for(int i = 0; i < 5; ++i) { + // expected-error@+2{{OpenACC 'reduction' variable must have the same operator in all nested constructs (& vs +)}} + // expected-note@-3{{previous clause is here}} +#pragma acc parallel loop reduction(&:I) + for(int i = 0; i < 5; ++i); + } +} diff --git a/clang/test/SemaOpenACC/compute-construct-default-clause.c b/clang/test/SemaOpenACC/compute-construct-default-clause.c index 70e29f3e8ac05..86a758779fdf6 100644 --- a/clang/test/SemaOpenACC/compute-construct-default-clause.c +++ b/clang/test/SemaOpenACC/compute-construct-default-clause.c @@ -28,8 +28,6 @@ void SingleOnly() { #pragma acc kernels default(none) for(int i = 0; i < 5; ++i); - // expected-warning@+2{{OpenACC construct 'data' not yet implemented}} - // expected-warning@+1{{OpenACC clause 'default' not yet implemented}} #pragma acc data default(none) while(0); @@ -37,7 +35,6 @@ void SingleOnly() { #pragma acc loop default(none) for(int i = 5; i < 10;++i); - // expected-warning@+2{{OpenACC construct 'wait' not yet implemented}} // expected-error@+1{{OpenACC 'default' clause is not valid on 'wait' directive}} #pragma acc wait default(none) while(0); diff --git a/clang/test/SemaOpenACC/compute-construct-device_type-clause.c b/clang/test/SemaOpenACC/compute-construct-device_type-clause.c index 0ae972d2a99ff..c1a77abf5c3f1 100644 --- a/clang/test/SemaOpenACC/compute-construct-device_type-clause.c +++ b/clang/test/SemaOpenACC/compute-construct-device_type-clause.c @@ -34,22 +34,20 @@ void uses() { #pragma acc kernels dtype(MACRO) while(1); - // expected-error@+2{{OpenACC 'device_type' clause is not valid on 'enter data' directive}} - // expected-warning@+1{{OpenACC construct 'enter data' not yet implemented}} + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{OpenACC 'device_type' clause is not valid on 'enter data' directive}} #pragma acc enter data device_type(I) - // expected-error@+2{{OpenACC 'dtype' clause is not valid on 'enter data' directive}} - // expected-warning@+1{{OpenACC construct 'enter data' not yet implemented}} + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{OpenACC 'dtype' clause is not valid on 'enter data' directive}} #pragma acc enter data dtype(I) // Only 'async', 'wait', num_gangs', 'num_workers', 'vector_length' allowed after 'device_type'. - // expected-error@+2{{OpenACC clause 'finalize' may not follow a 'device_type' clause in a 'kernels' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'kernels' directive}} #pragma acc kernels device_type(*) finalize while(1); - // expected-error@+2{{OpenACC clause 'if_present' may not follow a 'device_type' clause in a 'kernels' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'kernels' directive}} #pragma acc kernels device_type(*) if_present while(1); // expected-error@+1{{OpenACC 'seq' clause is not valid on 'kernels' directive}} @@ -95,20 +93,17 @@ void uses() { // expected-note@+1{{previous clause is here}} #pragma acc kernels device_type(*) present_or_copy(Var) while(1); - // expected-error@+2{{OpenACC clause 'use_device' may not follow a 'device_type' clause in a 'kernels' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'kernels' directive}} #pragma acc kernels device_type(*) use_device(Var) while(1); // expected-error@+2{{OpenACC clause 'attach' may not follow a 'device_type' clause in a 'kernels' construct}} // expected-note@+1{{previous clause is here}} #pragma acc kernels device_type(*) attach(Var) while(1); - // expected-error@+2{{OpenACC clause 'delete' may not follow a 'device_type' clause in a 'kernels' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'kernels' directive}} #pragma acc kernels device_type(*) delete(Var) while(1); - // expected-error@+2{{OpenACC clause 'detach' may not follow a 'device_type' clause in a 'kernels' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'kernels' directive}} #pragma acc kernels device_type(*) detach(Var) while(1); // expected-error@+2{{OpenACC clause 'device' may not follow a 'device_type' clause in a 'kernels' construct}} diff --git a/clang/test/SemaOpenACC/compute-construct-if-clause.c b/clang/test/SemaOpenACC/compute-construct-if-clause.c index 7cdc35275acce..c0ea88f06284d 100644 --- a/clang/test/SemaOpenACC/compute-construct-if-clause.c +++ b/clang/test/SemaOpenACC/compute-construct-if-clause.c @@ -43,8 +43,7 @@ void BoolExpr(int *I, float *F) { #pragma acc kernels if (*I < *F) while(0); - // expected-warning@+2{{OpenACC construct 'data' not yet implemented}} - // expected-warning@+1{{OpenACC clause 'if' not yet implemented}} + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} #pragma acc data if (*I < *F) while(0); #pragma acc parallel loop if (*I < *F) diff --git a/clang/test/SemaOpenACC/compute-construct-reduction-clause.c b/clang/test/SemaOpenACC/compute-construct-reduction-clause.c index 80310f0e7afc6..fcc4ca2655c20 100644 --- a/clang/test/SemaOpenACC/compute-construct-reduction-clause.c +++ b/clang/test/SemaOpenACC/compute-construct-reduction-clause.c @@ -41,12 +41,12 @@ void uses(unsigned Parm) { #pragma acc parallel num_gangs(IVar) reduction(+:IVar) while (1); - // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument, have 2}} + // expected-error@+2{{OpenACC 'num_gangs' clause with more than 1 argument may not appear on a 'parallel' construct with a 'reduction' clause}} // expected-note@+1{{previous clause is here}} #pragma acc parallel reduction(+:Parm) num_gangs(Parm, IVar) while (1); - // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument, have 2}} + // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument}} // expected-note@+1{{previous clause is here}} #pragma acc parallel num_gangs(Parm, IVar) reduction(+:Var) while (1); diff --git a/clang/test/SemaOpenACC/compute-construct-reduction-clause.cpp b/clang/test/SemaOpenACC/compute-construct-reduction-clause.cpp index 532dbb2387165..7372f683e2eb3 100644 --- a/clang/test/SemaOpenACC/compute-construct-reduction-clause.cpp +++ b/clang/test/SemaOpenACC/compute-construct-reduction-clause.cpp @@ -41,12 +41,12 @@ void uses(unsigned Parm) { #pragma acc parallel num_gangs(IVar) reduction(+:Var) while (1); - // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument, have 2}} + // expected-error@+2{{OpenACC 'num_gangs' clause with more than 1 argument may not appear on a 'parallel' construct with a 'reduction' clause}} // expected-note@+1{{previous clause is here}} #pragma acc parallel reduction(+:Parm) num_gangs(Parm, IVar) while (1); - // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument, have 2}} + // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument}} // expected-note@+1{{previous clause is here}} #pragma acc parallel num_gangs(Parm, IVar) reduction(+:Var) while (1); @@ -116,12 +116,12 @@ void TemplUses(T Parm, U CoS, V ChC) { #pragma acc parallel num_gangs(Var) reduction(+:Var) while (1); - // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument, have 2}} + // expected-error@+2{{OpenACC 'num_gangs' clause with more than 1 argument may not appear on a 'parallel' construct with a 'reduction' clause}} // expected-note@+1{{previous clause is here}} #pragma acc parallel reduction(+:Parm) num_gangs(Parm, Var) while (1); - // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument, have 2}} + // expected-error@+2{{OpenACC 'reduction' clause may not appear on a 'parallel' construct with a 'num_gangs' clause with more than 1 argument}} // expected-note@+1{{previous clause is here}} #pragma acc parallel num_gangs(Parm, Var) reduction(+:Var) while (1); diff --git a/clang/test/SemaOpenACC/data-construct-ast.cpp b/clang/test/SemaOpenACC/data-construct-ast.cpp new file mode 100644 index 0000000000000..5abd142b237a2 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-ast.cpp @@ -0,0 +1,109 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +void NormalFunc() { + // CHECK-LABEL: NormalFunc + // CHECK-NEXT: CompoundStmt + + int Var; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + + // TODO OpenACC: these constructs require the clauses to be legal, but we + // don't have the clauses implemented yet. As we implement them, they needed + // to be added to the 'check' lines. + +#pragma acc data default(none) + while (Var); + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: default(none) + // CHECK-NEXT: WhileStmt + // CHECK: NullStmt +#pragma acc enter data copyin(Var) + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'int' +#pragma acc exit data copyout(Var) + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'int' +#pragma acc host_data use_device(Var) + while (Var); + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}} host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'int' + // CHECK-NEXT: WhileStmt + // CHECK: NullStmt +} + +template +void TemplFunc() { + // CHECK-LABEL: FunctionTemplateDecl {{.*}}TemplFunc + // CHECK-NEXT: TemplateTypeParmDecl + // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc + // CHECK-NEXT: CompoundStmt + + T Var; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + +#pragma acc data default(none) + while (Var); + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: default(none) + // CHECK-NEXT: WhileStmt + // CHECK: NullStmt +#pragma acc enter data copyin(Var) + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'T' +#pragma acc exit data copyout(Var) + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'T' +#pragma acc host_data use_device(Var) + while (Var); + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}} host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'T' + // CHECK-NEXT: WhileStmt + // CHECK: NullStmt + + // Instantiation: + // CHECK-NEXT: FunctionDecl{{.*}} TemplFunc 'void ()' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: default(none) + // CHECK-NEXT: WhileStmt + // CHECK: NullStmt + + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'int' + + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'int' + + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}} host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Var' 'int' + // CHECK-NEXT: WhileStmt + // CHECK: NullStmt +} +void use() { + TemplFunc(); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-async-ast.cpp b/clang/test/SemaOpenACC/data-construct-async-ast.cpp new file mode 100644 index 0000000000000..fb6a37108ae4e --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-async-ast.cpp @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s +#ifndef PCH_HELPER +#define PCH_HELPER + +int some_int(); + +template +void TemplUses() { + // CHECK: FunctionTemplateDecl{{.*}}TemplUses + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}T + // CHECK-NEXT: FunctionDecl{{.*}}TemplUses + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + T t; + +#pragma acc data default(none) async(some_int()) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: default(none) + // CHECK-NEXT: async clause + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' + // CHECK-NEXT: NullStmt +#pragma acc enter data copyin(t) async(T{}) + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'t' 'T' + // CHECK-NEXT: async clause + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'T' 'T' list + // CHECK-NEXT: InitListExpr{{.*}}'void' +#pragma acc exit data copyout(t) async + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'t' 'T' + // CHECK-NEXT: async clause + + // Instantiations + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void ()' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: default(none) + // CHECK-NEXT: async clause + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' + // CHECK-NEXT: NullStmt + + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'t' 'int' + // CHECK-NEXT: async clause + // CHECK-NEXT: CXXFunctionalCastExpr + // CHECK-NEXT: InitListExpr{{.*}}'int' + + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'t' 'int' + // CHECK-NEXT: async clause +} +void Inst() { + TemplUses(); +} + + +#endif // PCH_HELPER diff --git a/clang/test/SemaOpenACC/data-construct-async-clause.c b/clang/test/SemaOpenACC/data-construct-async-clause.c new file mode 100644 index 0000000000000..3c9fbae0d9875 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-async-clause.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +void Test() { + int I; + struct NotConvertible{} NC; + // No special rules for this clause on the data constructs, so not much to + // test that isn't covered by combined/compute. +#pragma acc data copyin(I) async(I) + ; +#pragma acc enter data copyin(I) async(I) +#pragma acc exit data copyout(I) async(I) + // expected-error@+1{{OpenACC 'async' clause is not valid on 'host_data' directive}} +#pragma acc host_data use_device(I) async(I) + ; + + // expected-error@+1{{OpenACC clause 'async' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc data copyin(NC) async(NC) + ; + // expected-error@+1{{OpenACC clause 'async' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc enter data copyin(NC) async(NC) + // expected-error@+1{{OpenACC clause 'async' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc exit data copyout(NC) async(NC) + // expected-error@+1{{OpenACC clause 'async' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc host_data use_device(NC) async(NC) + ; + + // expected-error@+2{{OpenACC 'async' clause cannot appear more than once on a 'data' directive}} + // expected-note@+1{{previous clause is here}} +#pragma acc data copyin(I) async(I) async(I) + ; + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} +#pragma acc enter data copyin(I) async(I, I) +} diff --git a/clang/test/SemaOpenACC/data-construct-attach-ast.cpp b/clang/test/SemaOpenACC/data-construct-attach-ast.cpp new file mode 100644 index 0000000000000..f480e8bb61a70 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-attach-ast.cpp @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; + +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc data default(present) attach(PointerParam) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(present) + // CHECK-NEXT: attach clause + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}} 'PointerParam' 'float *' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt +} + +template +void TemplUses(T *t) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 0 T + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T *)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T *' + // CHECK-NEXT: CompoundStmt + +#pragma acc data default(present) attach(t) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(present) + // CHECK-NEXT: attach clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T *' lvalue ParmVar{{.*}} 't' 'T *' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int *)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int *' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(present) + // CHECK-NEXT: attach clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 't' 'int *' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + +} + +void Inst() { + int i; + TemplUses(&i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-attach-clause.c b/clang/test/SemaOpenACC/data-construct-attach-clause.c new file mode 100644 index 0000000000000..0bc02563ff695 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-attach-clause.c @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct S { + int IntMem; + int *PtrMem; +}; + +void uses() { + int LocalInt; + int *LocalPtr; + int Array[5]; + int *PtrArray[5]; + struct S s; + + // expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}} +#pragma acc data default(none) attach(LocalInt) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data default(none) attach(&LocalInt) + ; + + + // expected-error@+1{{expected pointer in 'attach' clause, type is 'int[5]'}} +#pragma acc enter data copyin(LocalInt) attach(Array) + + // expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}} +#pragma acc data default(none) attach(Array[0]) + ; + + // expected-error@+2{{OpenACC sub-array is not allowed here}} + // expected-note@+1{{expected variable of pointer type}} +#pragma acc data default(none) attach(Array[0:1]) + ; + + // expected-error@+1{{expected pointer in 'attach' clause, type is 'int *[5]'}} +#pragma acc data default(none) attach(PtrArray) + ; + +#pragma acc data default(none) attach(PtrArray[0]) + ; + + // expected-error@+2{{OpenACC sub-array is not allowed here}} + // expected-note@+1{{expected variable of pointer type}} +#pragma acc data default(none) attach(PtrArray[0:1]) + ; + + // expected-error@+1{{expected pointer in 'attach' clause, type is 'struct S'}} +#pragma acc data default(none) attach(s) + ; + + // expected-error@+1{{expected pointer in 'attach' clause, type is 'int'}} +#pragma acc data default(none) attach(s.IntMem) + ; + +#pragma acc data default(none) attach(s.PtrMem) + ; + + // expected-error@+1{{OpenACC 'attach' clause is not valid on 'exit data' directive}} +#pragma acc exit data copyout(LocalInt) attach(PtrArray[0]) + // expected-error@+1{{OpenACC 'attach' clause is not valid on 'host_data' directive}} +#pragma acc host_data use_device(LocalInt) attach(PtrArray[0]) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-copy-ast.cpp b/clang/test/SemaOpenACC/data-construct-copy-ast.cpp new file mode 100644 index 0000000000000..de067f00a2b29 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-copy-ast.cpp @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; + +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt +#pragma acc data copy(GlobalArray) pcopy(PointerParam[Global]) present_or_copy(Global) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copy clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: pcopy clause + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: present_or_copy clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: NullStmt +} +template +void TemplUses(T t, U u) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: NonTypeTemplateParmDecl {{.*}}referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 1 T + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 2 U + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T, U)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced u 'U' + // CHECK-NEXT: CompoundStmt + +#pragma acc data copy(t) pcopy(NTTP, u) present_or_copy(u[0:t]) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copy clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: pcopy clause + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: present_or_copy clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: NullStmt + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int, int *)' implicit_instantiation + // CHECK-NEXT: TemplateArgument decl + // CHECK-NEXT: Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: TemplateArgument type 'int *' + // CHECK-NEXT: PointerType{{.*}} 'int *' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used u 'int *' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copy clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: pcopy clause + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: present_or_copy clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int *' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: NullStmt +} +void Inst() { + static constexpr unsigned CEVar = 1; + int i; + TemplUses(i, &i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-copy-clause.c b/clang/test/SemaOpenACC/data-construct-copy-clause.c new file mode 100644 index 0000000000000..882a0bc87e003 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-copy-clause.c @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +typedef struct IsComplete { + struct S { int A; } CompositeMember; + int ScalarMember; + float ArrayMember[5]; + void *PointerMember; +} Complete; +void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete CompositeParam) { + int LocalInt; + short *LocalPointer; + float LocalArray[5]; + Complete LocalComposite; + // Check Appertainment: +#pragma acc data copy(LocalInt) + ; + + // expected-warning@+1{{OpenACC clause name 'pcopy' is a deprecated clause name and is now an alias for 'copy'}} +#pragma acc data pcopy(LocalInt) + ; + + // expected-warning@+1{{OpenACC clause name 'present_or_copy' is a deprecated clause name and is now an alias for 'copy'}} +#pragma acc data present_or_copy(LocalInt) + ; + + // Valid cases: +#pragma acc data copy(LocalInt, LocalPointer, LocalArray) + ; +#pragma acc data copy(LocalArray[2:1]) + ; + +#pragma acc data copy(LocalComposite.ScalarMember, LocalComposite.ScalarMember) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copy(1 + IntParam) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copy(+IntParam) + ; + + // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}} +#pragma acc data copy(PointerParam[2:]) + ; + + // expected-error@+1{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} +#pragma acc data copy(ArrayParam[2:5]) + ; + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copy((float*)ArrayParam[2:5]) + ; + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copy((float)ArrayParam[2]) + ; + + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{OpenACC 'copy' clause is not valid on 'enter data' directive}} +#pragma acc enter data copy(LocalInt) + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{OpenACC 'pcopy' clause is not valid on 'exit data' directive}} +#pragma acc exit data pcopy(LocalInt) + // expected-error@+2{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+1{{OpenACC 'present_or_copy' clause is not valid on 'host_data' directive}} +#pragma acc host_data present_or_copy(LocalInt) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-copyin-ast.cpp b/clang/test/SemaOpenACC/data-construct-copyin-ast.cpp new file mode 100644 index 0000000000000..fd21d60c84431 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-copyin-ast.cpp @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc data copyin(GlobalArray) pcopyin(readonly:PointerParam[Global]) present_or_copyin(Global) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: pcopyin clause : readonly + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: present_or_copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: NullStmt + +#pragma acc enter data copyin(GlobalArray) pcopyin(readonly:PointerParam[Global]) present_or_copyin(Global) + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: pcopyin clause : readonly + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: present_or_copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' +} + +template +void TemplUses(T t, U u) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: NonTypeTemplateParmDecl {{.*}}referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 1 T + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 2 U + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T, U)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced u 'U' + // CHECK-NEXT: CompoundStmt + +#pragma acc data copyin(t) pcopyin(readonly: NTTP, u) present_or_copyin(u[0:t]) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: pcopyin clause : readonly + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: present_or_copyin clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: NullStmt + +#pragma acc enter data copyin(t) pcopyin(readonly: NTTP, u) present_or_copyin(u[0:t]) + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: pcopyin clause : readonly + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: present_or_copyin clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int, int *)' implicit_instantiation + // CHECK-NEXT: TemplateArgument decl + // CHECK-NEXT: Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: TemplateArgument type 'int *' + // CHECK-NEXT: PointerType{{.*}} 'int *' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used u 'int *' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: pcopyin clause : readonly + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: present_or_copyin clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int *' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: NullStmt + + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: pcopyin clause : readonly + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: present_or_copyin clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int *' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' +} + +void Inst() { + static constexpr unsigned CEVar = 1; + int i; + TemplUses(i, &i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-copyin-clause.c b/clang/test/SemaOpenACC/data-construct-copyin-clause.c new file mode 100644 index 0000000000000..370cc7000f8d8 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-copyin-clause.c @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +typedef struct IsComplete { + struct S { int A; } CompositeMember; + int ScalarMember; + float ArrayMember[5]; + void *PointerMember; +} Complete; +void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete CompositeParam) { + int LocalInt; + short *LocalPointer; + float LocalArray[5]; + Complete LocalComposite; + // Check Appertainment: +#pragma acc data copyin(LocalInt) + ; +#pragma acc enter data copyin(LocalInt) + + // expected-warning@+1{{OpenACC clause name 'pcopyin' is a deprecated clause name and is now an alias for 'copyin'}} +#pragma acc data pcopyin(LocalInt) + ; + + // expected-warning@+1{{OpenACC clause name 'present_or_copyin' is a deprecated clause name and is now an alias for 'copyin'}} +#pragma acc data present_or_copyin(LocalInt) + ; + + // Valid cases: +#pragma acc data copyin(LocalInt, LocalPointer, LocalArray) + ; +#pragma acc data copyin(LocalArray[2:1]) + ; +#pragma acc data copyin(readonly:LocalArray[2:1]) + ; + +#pragma acc data copyin(LocalComposite.ScalarMember, LocalComposite.ScalarMember) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyin(1 + IntParam) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyin(+IntParam) + ; + + // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}} +#pragma acc data copyin(PointerParam[2:]) + ; + + // expected-error@+1{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} +#pragma acc data copyin(ArrayParam[2:5]) + ; + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyin((float*)ArrayParam[2:5]) + ; + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyin((float)ArrayParam[2]) + ; + // expected-error@+2{{invalid tag 'invalid' on 'copyin' clause}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyin(invalid:(float)ArrayParam[2]) + ; + + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{OpenACC 'copyin' clause is not valid on 'exit data' directive}} +#pragma acc exit data copyin(LocalInt) + // expected-error@+2{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+1{{OpenACC 'pcopyin' clause is not valid on 'host_data' directive}} +#pragma acc host_data pcopyin(LocalInt) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-copyout-ast.cpp b/clang/test/SemaOpenACC/data-construct-copyout-ast.cpp new file mode 100644 index 0000000000000..38e6e7b476fe5 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-copyout-ast.cpp @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc data copyout(GlobalArray) pcopyout(zero:PointerParam[Global]) present_or_copyout(Global) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: pcopyout clause : zero + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: present_or_copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: NullStmt + +#pragma acc exit data copyout(GlobalArray) pcopyout(zero:PointerParam[Global]) present_or_copyout(Global) + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: pcopyout clause : zero + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: present_or_copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' +} + +template +void TemplUses(T t, U u) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: NonTypeTemplateParmDecl {{.*}}referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 1 T + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 2 U + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T, U)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced u 'U' + // CHECK-NEXT: CompoundStmt + +#pragma acc data copyout(t) pcopyout(zero: NTTP, u) present_or_copyout(u[0:t]) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: pcopyout clause : zero + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: present_or_copyout clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: NullStmt + +#pragma acc exit data copyout(t) pcopyout(zero: NTTP, u) present_or_copyout(u[0:t]) + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: pcopyout clause : zero + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: present_or_copyout clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int, int *)' implicit_instantiation + // CHECK-NEXT: TemplateArgument decl + // CHECK-NEXT: Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: TemplateArgument type 'int *' + // CHECK-NEXT: PointerType{{.*}} 'int *' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used u 'int *' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: pcopyout clause : zero + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: present_or_copyout clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int *' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: NullStmt + + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: pcopyout clause : zero + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: present_or_copyout clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int *' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' +} + +void Inst() { + static constexpr unsigned CEVar = 1; + int i; + TemplUses(i, &i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-copyout-clause.c b/clang/test/SemaOpenACC/data-construct-copyout-clause.c new file mode 100644 index 0000000000000..0f9d5f2ad5c83 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-copyout-clause.c @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +typedef struct IsComplete { + struct S { int A; } CompositeMember; + int ScalarMember; + float ArrayMember[5]; + void *PointerMember; +} Complete; +void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete CompositeParam) { + int LocalInt; + short *LocalPointer; + float LocalArray[5]; + Complete LocalComposite; + // Check Appertainment: +#pragma acc data copyout(LocalInt) + ; +#pragma acc exit data copyout(LocalInt) + + // expected-warning@+1{{OpenACC clause name 'pcopyout' is a deprecated clause name and is now an alias for 'copyout'}} +#pragma acc data pcopyout(LocalInt) + ; + + // expected-warning@+1{{OpenACC clause name 'present_or_copyout' is a deprecated clause name and is now an alias for 'copyout'}} +#pragma acc data present_or_copyout(LocalInt) + ; + + // Valid cases: +#pragma acc data copyout(LocalInt, LocalPointer, LocalArray) + ; +#pragma acc data copyout(LocalArray[2:1]) + ; +#pragma acc data copyout(zero:LocalArray[2:1]) + ; + +#pragma acc data copyout(LocalComposite.ScalarMember, LocalComposite.ScalarMember) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyout(1 + IntParam) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyout(+IntParam) + ; + + // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}} +#pragma acc data copyout(PointerParam[2:]) + ; + + // expected-error@+1{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} +#pragma acc data copyout(ArrayParam[2:5]) + ; + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyout((float*)ArrayParam[2:5]) + ; + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyout((float)ArrayParam[2]) + ; + // expected-error@+2{{invalid tag 'invalid' on 'copyout' clause}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data copyout(invalid:(float)ArrayParam[2]) + ; + + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{OpenACC 'copyout' clause is not valid on 'enter data' directive}} +#pragma acc enter data copyout(LocalInt) + // expected-error@+2{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+1{{OpenACC 'pcopyout' clause is not valid on 'host_data' directive}} +#pragma acc host_data pcopyout(LocalInt) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-create-ast.cpp b/clang/test/SemaOpenACC/data-construct-create-ast.cpp new file mode 100644 index 0000000000000..623d44aac43f9 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-create-ast.cpp @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -Wno-openacc-deprecated-clause-alias -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc data create(GlobalArray) pcreate(zero:PointerParam[Global]) present_or_create(Global) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: pcreate clause : zero + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: present_or_create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: NullStmt + +#pragma acc enter data create(GlobalArray) pcreate(zero:PointerParam[Global]) present_or_create(Global) + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: pcreate clause : zero + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: present_or_create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' +} + +template +void TemplUses(T t, U u) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: NonTypeTemplateParmDecl {{.*}}referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 1 T + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 2 U + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T, U)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced u 'U' + // CHECK-NEXT: CompoundStmt + +#pragma acc data create(t) pcreate(zero: NTTP, u) present_or_create(u[0:t]) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: pcreate clause : zero + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: present_or_create clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: NullStmt + +#pragma acc enter data create(t) pcreate(zero: NTTP, u) present_or_create(u[0:t]) + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: pcreate clause : zero + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: present_or_create clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int, int *)' implicit_instantiation + // CHECK-NEXT: TemplateArgument decl + // CHECK-NEXT: Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: TemplateArgument type 'int *' + // CHECK-NEXT: PointerType{{.*}} 'int *' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used u 'int *' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: pcreate clause : zero + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: present_or_create clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int *' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: NullStmt + + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}} enter data + // CHECK-NEXT: create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: pcreate clause : zero + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: present_or_create clause + // CHECK-NEXT: ArraySectionExpr + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int *' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 0 + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' +} + +void Inst() { + static constexpr unsigned CEVar = 1; + int i; + TemplUses(i, &i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-create-clause.c b/clang/test/SemaOpenACC/data-construct-create-clause.c new file mode 100644 index 0000000000000..4972bdca4b85d --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-create-clause.c @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +typedef struct IsComplete { + struct S { int A; } CompositeMember; + int ScalarMember; + float ArrayMember[5]; + void *PointerMember; +} Complete; +void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete CompositeParam) { + int LocalInt; + short *LocalPointer; + float LocalArray[5]; + Complete LocalComposite; + // Check Appertainment: +#pragma acc data create(LocalInt) + ; +#pragma acc enter data create(LocalInt) + + // expected-warning@+1{{OpenACC clause name 'pcreate' is a deprecated clause name and is now an alias for 'create'}} +#pragma acc data pcreate(LocalInt) + ; + + // expected-warning@+1{{OpenACC clause name 'present_or_create' is a deprecated clause name and is now an alias for 'create'}} +#pragma acc data present_or_create(LocalInt) + ; + + // Valid cases: +#pragma acc data create(LocalInt, LocalPointer, LocalArray) + ; +#pragma acc data create(LocalArray[2:1]) + ; +#pragma acc data create(zero:LocalArray[2:1]) + ; + +#pragma acc data create(LocalComposite.ScalarMember, LocalComposite.ScalarMember) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data create(1 + IntParam) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data create(+IntParam) + ; + + // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}} +#pragma acc data create(PointerParam[2:]) + ; + + // expected-error@+1{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} +#pragma acc data create(ArrayParam[2:5]) + ; + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data create((float*)ArrayParam[2:5]) + ; + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data create((float)ArrayParam[2]) + ; + // expected-error@+2{{invalid tag 'invalid' on 'create' clause}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data create(invalid:(float)ArrayParam[2]) + ; + + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{OpenACC 'create' clause is not valid on 'exit data' directive}} +#pragma acc exit data create(LocalInt) + // expected-error@+2{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+1{{OpenACC 'pcreate' clause is not valid on 'host_data' directive}} +#pragma acc host_data pcreate(LocalInt) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-default-ast.cpp b/clang/test/SemaOpenACC/data-construct-default-ast.cpp new file mode 100644 index 0000000000000..ef9b1348c6709 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-default-ast.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER +void NormalFunc() { + // CHECK-LABEL: NormalFunc + // CHECK-NEXT: CompoundStmt + // CHECK-NEXT: OpenACCDataConstruct {{.*}}data + // CHECK-NEXT: default(none) +#pragma acc data default(none) + // CHECK: OpenACCDataConstruct {{.*}}data + // CHECK-NEXT: default(present) +#pragma acc data default(present) + ; +} +template +void TemplFunc() { +#pragma acc data default(none) + for (unsigned i = 0; i < 5; ++i) { + typename T::type I; + } + +#pragma acc data default(present) + for (unsigned i = 0; i < 5; ++i) { + typename T::type I; + } + + // CHECK-LABEL: FunctionTemplateDecl {{.*}}TemplFunc + // CHECK-NEXT: TemplateTypeParmDecl + + // Template Pattern: + // CHECK-NEXT: FunctionDecl + // CHECK-NEXT: CompoundStmt + // CHECK-NEXT: OpenACCDataConstruct {{.*}}data + // CHECK-NEXT: default(none) + // CHECK: VarDecl{{.*}} I 'typename T::type' + + // CHECK-NEXT: OpenACCDataConstruct {{.*}}data + // CHECK-NEXT: default(present) + // CHECK: VarDecl{{.*}} I 'typename T::type' + + // Check instantiation. + // CHECK-LABEL: FunctionDecl{{.*}} used TemplFunc 'void ()' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'S' + // CHECK-NEXT: RecordType + // CHECK-NEXT: CXXRecord + // CHECK-NEXT: CompoundStmt + // CHECK-NEXT: OpenACCDataConstruct {{.*}}data + // CHECK-NEXT: default(none) + // CHECK: VarDecl{{.*}} I 'typename S::type':'int' + // CHECK-NEXT: OpenACCDataConstruct {{.*}}data + // CHECK-NEXT: default(present) + // CHECK: VarDecl{{.*}} I 'typename S::type':'int' + +} +struct S { + using type = int; +}; + +void use() { + TemplFunc(); +} + +#endif diff --git a/clang/test/SemaOpenACC/data-construct-default-clause.c b/clang/test/SemaOpenACC/data-construct-default-clause.c new file mode 100644 index 0000000000000..150d3ec22dcda --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-default-clause.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +void use() { + // expected-error@+2{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} + // expected-error@+1{{invalid value for 'default' clause; expected 'present' or 'none'}} +#pragma acc data default(garbage) + ; +#pragma acc data default(present) + ; +#pragma acc data default(none) + ; + // expected-error@+2{{OpenACC 'default' clause cannot appear more than once on a 'data' directive}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) default(present) + ; + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{OpenACC 'default' clause is not valid on 'enter data' directive}} +#pragma acc enter data default(present) + ; + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{OpenACC 'default' clause is not valid on 'exit data' directive}} +#pragma acc exit data default(none) + ; + // expected-error@+2{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+1{{OpenACC 'default' clause is not valid on 'host_data' directive}} +#pragma acc host_data default(present) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-delete-ast.cpp b/clang/test/SemaOpenACC/data-construct-delete-ast.cpp new file mode 100644 index 0000000000000..b61fdc900928d --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-delete-ast.cpp @@ -0,0 +1,58 @@ + +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc exit data delete(GlobalArray, PointerParam[Global]) + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: delete clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' +} + +template +void TemplUses(T t) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 0 T + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T' + // CHECK-NEXT: CompoundStmt + +#pragma acc exit data delete(t) + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: delete clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: delete clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' +} + +void Inst() { + int i; + TemplUses(i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-delete-clause.c b/clang/test/SemaOpenACC/data-construct-delete-clause.c new file mode 100644 index 0000000000000..05093dbc4e01b --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-delete-clause.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +typedef struct IsComplete { + struct S { int A; } CompositeMember; + int ScalarMember; + float ArrayMember[5]; + void *PointerMember; +} Complete; +void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete CompositeParam) { + int LocalInt; + short *LocalPointer; + float LocalArray[5]; + Complete LocalComposite; + // Check Appertainment: +#pragma acc exit data delete(LocalInt) + + // Valid cases: +#pragma acc exit data delete(LocalInt, LocalPointer, LocalArray) +#pragma acc exit data delete(LocalArray[2:1]) +#pragma acc exit data delete(LocalComposite.ScalarMember, LocalComposite.ScalarMember) + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc exit data delete(1 + IntParam) + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc exit data delete(+IntParam) + + // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}} +#pragma acc exit data delete(PointerParam[2:]) + + // expected-error@+1{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} +#pragma acc exit data delete(ArrayParam[2:5]) + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc exit data delete((float*)ArrayParam[2:5]) + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc exit data delete((float)ArrayParam[2]) + + // expected-error@+2{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'data' directive}} +#pragma acc data delete(LocalInt) + ; + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'enter data' directive}} +#pragma acc enter data delete(LocalInt) + // expected-error@+2{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'host_data' directive}} +#pragma acc host_data delete(LocalInt) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-detach-ast.cpp b/clang/test/SemaOpenACC/data-construct-detach-ast.cpp new file mode 100644 index 0000000000000..d5096cdc868d0 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-detach-ast.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; + +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc exit data copyout(Global) detach(PointerParam) + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: detach clause + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}} 'PointerParam' 'float *' +} + +template +void TemplUses(T *t) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 0 T + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T *)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T *' + // CHECK-NEXT: CompoundStmt + +#pragma acc exit data copyout(Global) detach(t) + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: detach clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T *' lvalue ParmVar{{.*}} 't' 'T *' + + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int *)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int *' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}} exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: detach clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 't' 'int *' + +} + +void Inst() { + int i; + TemplUses(&i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-detach-clause.c b/clang/test/SemaOpenACC/data-construct-detach-clause.c new file mode 100644 index 0000000000000..edcc80ac36236 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-detach-clause.c @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct S { + int IntMem; + int *PtrMem; +}; + +void uses() { + int LocalInt; + int *LocalPtr; + int Array[5]; + int *PtrArray[5]; + struct S s; + + // expected-error@+1{{expected pointer in 'detach' clause, type is 'int'}} +#pragma acc exit data copyout(LocalInt) detach(LocalInt) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc exit data copyout(LocalInt) detach(&LocalInt) + ; + + + // expected-error@+1{{expected pointer in 'detach' clause, type is 'int[5]'}} +#pragma acc exit data copyout(LocalInt) detach(Array) + + // expected-error@+1{{expected pointer in 'detach' clause, type is 'int'}} +#pragma acc exit data copyout(LocalInt) detach(Array[0]) + ; + + // expected-error@+2{{OpenACC sub-array is not allowed here}} + // expected-note@+1{{expected variable of pointer type}} +#pragma acc exit data copyout(LocalInt) detach(Array[0:1]) + ; + + // expected-error@+1{{expected pointer in 'detach' clause, type is 'int *[5]'}} +#pragma acc exit data copyout(LocalInt) detach(PtrArray) + ; + +#pragma acc exit data copyout(LocalInt) detach(PtrArray[0]) + ; + + // expected-error@+2{{OpenACC sub-array is not allowed here}} + // expected-note@+1{{expected variable of pointer type}} +#pragma acc exit data copyout(LocalInt) detach(PtrArray[0:1]) + ; + + // expected-error@+1{{expected pointer in 'detach' clause, type is 'struct S'}} +#pragma acc exit data copyout(LocalInt) detach(s) + ; + + // expected-error@+1{{expected pointer in 'detach' clause, type is 'int'}} +#pragma acc exit data copyout(LocalInt) detach(s.IntMem) + ; + +#pragma acc exit data copyout(LocalInt) detach(s.PtrMem) + ; + + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'data' directive}} +#pragma acc data copyin(LocalInt) detach(PtrArray[0]) + ; + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'enter data' directive}} +#pragma acc enter data copyin(LocalInt) detach(PtrArray[0]) + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'host_data' directive}} +#pragma acc host_data use_device(LocalInt) detach(PtrArray[0]) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-device_type-ast.cpp b/clang/test/SemaOpenACC/data-construct-device_type-ast.cpp new file mode 100644 index 0000000000000..1f497bb7afcc4 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-device_type-ast.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s +#ifndef PCH_HELPER +#define PCH_HELPER + +template +void TemplUses() { + // CHECK: FunctionTemplateDecl{{.*}}TemplUses + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}T + // CHECK-NEXT: FunctionDecl{{.*}}TemplUses + // CHECK-NEXT: CompoundStmt + +#pragma acc data default(none) device_type(T) dtype(T) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(none) + // CHECK-NEXT: device_type(T) + // CHECK-NEXT: dtype(T) + // CHECK-NEXT: NullStmt + + // Instantiations + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void ()' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: CompoundStmt + + // Argument to 'device-type' is just an identifier, so we don't transform it. + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(none) + // CHECK-NEXT: device_type(T) + // CHECK-NEXT: dtype(T) + // CHECK-NEXT: NullStmt +} +void Inst() { + TemplUses(); +} + +#endif // PCH_HELPER diff --git a/clang/test/SemaOpenACC/data-construct-device_type-clause.c b/clang/test/SemaOpenACC/data-construct-device_type-clause.c new file mode 100644 index 0000000000000..a467287b93e0c --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-device_type-clause.c @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +void uses() { + int Var; +#pragma acc data default(none) device_type(foo) async + ; +#pragma acc data default(none) device_type(foo) wait + ; +#pragma acc data default(none) device_type(foo) dtype(false) + ; +#pragma acc data default(none) dtype(foo) device_type(false) + ; + + // expected-error@+2{{OpenACC clause 'if' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) if(1) + ; + // expected-error@+2{{OpenACC clause 'copy' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) copy(Var) + ; + // expected-error@+2{{OpenACC clause 'copyin' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) copyin(Var) + ; + // expected-error@+2{{OpenACC clause 'copyout' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) copyout(Var) + ; + // expected-error@+2{{OpenACC clause 'create' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) create(Var) + ; + // expected-error@+2{{OpenACC clause 'no_create' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) no_create(Var) + ; + // expected-error@+2{{OpenACC clause 'present' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) present(Var) + ; + // expected-error@+2{{OpenACC clause 'deviceptr' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) deviceptr(Var) + ; + // expected-error@+2{{OpenACC clause 'attach' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(foo) attach(Var) + ; + // expected-error@+3{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} + // expected-error@+2{{OpenACC clause 'default' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data device_type(foo) default(none) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-deviceptr-ast.cpp b/clang/test/SemaOpenACC/data-construct-deviceptr-ast.cpp new file mode 100644 index 0000000000000..a4ac289ab4827 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-deviceptr-ast.cpp @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; + +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc data default(present) deviceptr(PointerParam) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(present) + // CHECK-NEXT: deviceptr clause + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}} 'PointerParam' 'float *' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt +} + +template +void TemplUses(T *t) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 0 T + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T *)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T *' + // CHECK-NEXT: CompoundStmt + +#pragma acc data default(present) deviceptr(t) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(present) + // CHECK-NEXT: deviceptr clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T *' lvalue ParmVar{{.*}} 't' 'T *' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int *)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int *' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(present) + // CHECK-NEXT: deviceptr clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 't' 'int *' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + +} + +void Inst() { + int i; + TemplUses(&i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-deviceptr-clause.c b/clang/test/SemaOpenACC/data-construct-deviceptr-clause.c new file mode 100644 index 0000000000000..70ccd3b7aec95 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-deviceptr-clause.c @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct S { + int IntMem; + int *PtrMem; +}; + +void uses() { + int LocalInt; + int *LocalPtr; + int Array[5]; + int *PtrArray[5]; + struct S s; + + // expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}} +#pragma acc data default(none) deviceptr(LocalInt) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data default(none) deviceptr(&LocalInt) + ; + + + // expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int[5]'}} +#pragma acc data default(none) deviceptr(Array) + ; + + // expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}} +#pragma acc data default(none) deviceptr(Array[0]) + ; + + // expected-error@+2{{OpenACC sub-array is not allowed here}} + // expected-note@+1{{expected variable of pointer type}} +#pragma acc data default(none) deviceptr(Array[0:1]) + ; + + // expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int *[5]'}} +#pragma acc data default(none) deviceptr(PtrArray) + ; + +#pragma acc data default(none) deviceptr(PtrArray[0]) + ; + + // expected-error@+2{{OpenACC sub-array is not allowed here}} + // expected-note@+1{{expected variable of pointer type}} +#pragma acc data default(none) deviceptr(PtrArray[0:1]) + ; + + // expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'struct S'}} +#pragma acc data default(none) deviceptr(s) + ; + + // expected-error@+1{{expected pointer in 'deviceptr' clause, type is 'int'}} +#pragma acc data default(none) deviceptr(s.IntMem) + ; + +#pragma acc data default(none) deviceptr(s.PtrMem) + ; + + // expected-error@+1{{OpenACC 'deviceptr' clause is not valid on 'enter data' directive}} +#pragma acc enter data copyin(LocalInt) deviceptr(LocalInt) + // expected-error@+1{{OpenACC 'deviceptr' clause is not valid on 'exit data' directive}} +#pragma acc exit data copyout(LocalInt) deviceptr(LocalInt) + // expected-error@+1{{OpenACC 'deviceptr' clause is not valid on 'host_data' directive}} +#pragma acc host_data use_device(LocalInt) deviceptr(LocalInt) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-finalize-ast.cpp b/clang/test/SemaOpenACC/data-construct-finalize-ast.cpp new file mode 100644 index 0000000000000..0dc6605cc6042 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-finalize-ast.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s +#ifndef PCH_HELPER +#define PCH_HELPER + +void Uses() { + // CHECK: FunctionDecl{{.*}}Uses + // CHECK-NEXT: CompoundStmt + + int I; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + +#pragma acc exit data copyout(I) finalize + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'int' + // CHECK-NEXT: finalize clause +} + +template +void TemplUses() { + // CHECK: FunctionTemplateDecl{{.*}}TemplUses + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}T + // CHECK-NEXT: FunctionDecl{{.*}}TemplUses + // CHECK-NEXT: CompoundStmt + + T I; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + +#pragma acc exit data copyout(I) finalize + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'T' + // CHECK-NEXT: finalize clause + + // Instantiations + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void ()' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'int' + // CHECK-NEXT: finalize clause +} +void Inst() { + TemplUses(); +} + + +#endif // PCH_HELPER diff --git a/clang/test/SemaOpenACC/data-construct-finalize-clause.c b/clang/test/SemaOpenACC/data-construct-finalize-clause.c new file mode 100644 index 0000000000000..252b26708cd81 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-finalize-clause.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +void Test() { + int I; + + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'data' directive}} +#pragma acc data copyin(I) finalize + ; + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'enter data' directive}} +#pragma acc enter data copyin(I) finalize + ; + + // finalize is valid only on exit data, otherwise has no other rules. +#pragma acc exit data copyout(I) finalize + ; + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'host_data' directive}} +#pragma acc host_data use_device(I) finalize + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-if-ast.cpp b/clang/test/SemaOpenACC/data-construct-if-ast.cpp new file mode 100644 index 0000000000000..9ceee4e1c0749 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-if-ast.cpp @@ -0,0 +1,143 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER +void NormalFunc(int j, float f) { + // CHECK: FunctionDecl{{.*}}NormalFunc + // CHECK-NEXT: ParmVarDecl + // CHECK-NEXT: ParmVarDecl + // CHECK-NEXT: CompoundStmt +#pragma acc data if( j < f) default(none) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}} 'int' lvalue ParmVar{{.*}} 'j' 'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float' + // CHECK-NEXT: DeclRefExpr{{.*}} 'float' lvalue ParmVar{{.*}} 'f' 'float' + // CHECK-NEXT: default(none) + // CHECK-NEXT: NullStmt + +} + +int Global; + +template +void TemplFunc() { + // CHECK: FunctionTemplateDecl{{.*}}TemplFunc + // CHECK-NEXT: TemplateTypeParmDecl + + // Match the prototype: + // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc + // CHECK-NEXT: CompoundStmt + +#pragma acc data default(none) if(T::SomeFloat < typename T::IntTy{}) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: default(none) + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '' '<' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T' + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'typename T::IntTy' 'typename T::IntTy' + // CHECK-NEXT: InitListExpr{{.*}} 'void' + // CHECK-NEXT: NullStmt + +#pragma acc enter data copyin(Global) if(typename T::IntTy{}) + ; + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: if clause + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'typename T::IntTy' 'typename T::IntTy' + // CHECK-NEXT: InitListExpr{{.*}} 'void' + // CHECK-NEXT: NullStmt + +#pragma acc exit data copyout(Global) if(T::SomeFloat) + ; + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: if clause + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T' + // CHECK-NEXT: NullStmt + +#pragma acc host_data use_device(Global) if(T::BC) + ; + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}}host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: if clause + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'T' + // CHECK-NEXT: NullStmt + + // Match the instantiation: + // CHECK: FunctionDecl{{.*}}TemplFunc{{.*}}implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'InstTy' + // CHECK-NEXT: RecordType{{.*}} 'InstTy' + // CHECK-NEXT: CXXRecord{{.*}} 'InstTy' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: default(none) + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float' + // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float' + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename InstTy::IntTy':'int' functional cast to typename struct InstTy::IntTy + // CHECK-NEXT: InitListExpr {{.*}}'typename InstTy::IntTy':'int' + // CHECK-NEXT: NullStmt + + // CHECK-NEXT: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: if clause + // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename InstTy::IntTy':'int' functional cast to typename struct InstTy::IntTy + // CHECK-NEXT: InitListExpr {{.*}}'typename InstTy::IntTy':'int' + // CHECK-NEXT: NullStmt + + // CHECK-NEXT: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: if clause + // CHECK-NEXT: ImplicitCastExpr{{.*}}'bool' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'float' + // CHECK-NEXT: DeclRefExpr{{.*}} 'const float' lvalue Var{{.*}} 'SomeFloat' 'const float' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy' + // CHECK-NEXT: NullStmt + + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}}host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'Global' 'int' + // CHECK-NEXT: if clause + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'bool' + // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'bool' + // CHECK-NEXT: MemberExpr{{.*}} .operator bool + // CHECK-NEXT: DeclRefExpr{{.*}} 'const BoolConversion' lvalue Var{{.*}} 'BC' 'const BoolConversion' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'InstTy' + // CHECK-NEXT: NullStmt + +} + +struct BoolConversion{ operator bool() const;}; +struct InstTy { + using IntTy = int; + static constexpr float SomeFloat = 5.0; + static constexpr BoolConversion BC; +}; + +void Instantiate() { + TemplFunc(); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-if-clause.c b/clang/test/SemaOpenACC/data-construct-if-clause.c new file mode 100644 index 0000000000000..f22452d2c34a4 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-if-clause.c @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +void Foo() { + int Var; +#pragma acc data default(present) if(1) + ; + // expected-error@+2{{OpenACC 'if' clause cannot appear more than once on a 'data' directive}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(present) if(1) if (2) + ; + +#pragma acc enter data copyin(Var) if(1) + + // expected-error@+2{{OpenACC 'if' clause cannot appear more than once on a 'enter data' directive}} + // expected-note@+1{{previous clause is here}} +#pragma acc enter data copyin(Var) if(1) if (2) + +#pragma acc exit data copyout(Var) if(1) + // expected-error@+2{{OpenACC 'if' clause cannot appear more than once on a 'exit data' directive}} + // expected-note@+1{{previous clause is here}} +#pragma acc exit data copyout(Var) if(1) if (2) + +#pragma acc host_data use_device(Var) if(1) + ; + // expected-error@+2{{OpenACC 'if' clause cannot appear more than once on a 'host_data' directive}} + // expected-note@+1{{previous clause is here}} +#pragma acc host_data use_device(Var) if(1) if (2) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-if_present-ast.cpp b/clang/test/SemaOpenACC/data-construct-if_present-ast.cpp new file mode 100644 index 0000000000000..8dab6bcce58d9 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-if_present-ast.cpp @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s +#ifndef PCH_HELPER +#define PCH_HELPER + +void Uses() { + // CHECK: FunctionDecl{{.*}}Uses + // CHECK-NEXT: CompoundStmt + + int I; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + +#pragma acc host_data use_device(I) if_present + ; + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}}host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'int' + // CHECK-NEXT: if_present clause + // CHECK-NEXT: NullStmt +} + +template +void TemplUses() { + // CHECK: FunctionTemplateDecl{{.*}}TemplUses + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}T + // CHECK-NEXT: FunctionDecl{{.*}}TemplUses + // CHECK-NEXT: CompoundStmt + + T I; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + +#pragma acc host_data use_device(I) if_present + ; + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}}host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'T' + // CHECK-NEXT: if_present clause + // CHECK-NEXT: NullStmt + + // Instantiations + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void ()' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}}host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'int' + // CHECK-NEXT: if_present clause + // CHECK-NEXT: NullStmt +} +void Inst() { + TemplUses(); +} + + +#endif // PCH_HELPER diff --git a/clang/test/SemaOpenACC/data-construct-if_present-clause.c b/clang/test/SemaOpenACC/data-construct-if_present-clause.c new file mode 100644 index 0000000000000..b1290cdccca5f --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-if_present-clause.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +void Test() { + int I; + + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'data' directive}} +#pragma acc data copyin(I) if_present + ; + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'enter data' directive}} +#pragma acc enter data copyin(I) if_present + ; + + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'exit data' directive}} +#pragma acc exit data copyout(I) if_present + ; +#pragma acc host_data use_device(I) if_present + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-no_create-ast.cpp b/clang/test/SemaOpenACC/data-construct-no_create-ast.cpp new file mode 100644 index 0000000000000..9a0465d455942 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-no_create-ast.cpp @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc data no_create(GlobalArray, PointerParam[Global]) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: no_create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: NullStmt +} + +template +void TemplUses(T t, U u) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: NonTypeTemplateParmDecl {{.*}}referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 1 T + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 2 U + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T, U)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced u 'U' + // CHECK-NEXT: CompoundStmt + + +#pragma acc data no_create(t) present(NTTP, u) + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: no_create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: present clause + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: NullStmt + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int, int *)' implicit_instantiation + // CHECK-NEXT: TemplateArgument decl + // CHECK-NEXT: Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: TemplateArgument type 'int *' + // CHECK-NEXT: PointerType{{.*}} 'int *' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} u 'int *' + // CHECK-NEXT: CompoundStmt + +// #pragma acc data no_create(t) present(NTTP, u) + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: no_create clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: present clause + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int *' lvalue ParmVar{{.*}} 'u' 'int *' + // CHECK-NEXT: NullStmt +} + +void Inst() { + static constexpr unsigned CEVar = 1; + int i; + TemplUses(i, &i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-no_create-clause.c b/clang/test/SemaOpenACC/data-construct-no_create-clause.c new file mode 100644 index 0000000000000..0eb459eb0009a --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-no_create-clause.c @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +typedef struct IsComplete { + struct S { int A; } CompositeMember; + int ScalarMember; + float ArrayMember[5]; + void *PointerMember; +} Complete; +void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete CompositeParam) { + int LocalInt; + short *LocalPointer; + float LocalArray[5]; + Complete LocalComposite; + // Check Appertainment: +#pragma acc data no_create(LocalInt) + ; + + // Valid cases: +#pragma acc data no_create(LocalInt, LocalPointer, LocalArray) + ; +#pragma acc data no_create(LocalArray[2:1]) + ; + +#pragma acc data no_create(LocalComposite.ScalarMember, LocalComposite.ScalarMember) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data no_create(1 + IntParam) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data no_create(+IntParam) + ; + + // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}} +#pragma acc data no_create(PointerParam[2:]) + ; + + // expected-error@+1{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} +#pragma acc data no_create(ArrayParam[2:5]) + ; + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data no_create((float*)ArrayParam[2:5]) + ; + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data no_create((float)ArrayParam[2]) + ; + + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{OpenACC 'no_create' clause is not valid on 'exit data' directive}} +#pragma acc exit data no_create(LocalInt) + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{OpenACC 'no_create' clause is not valid on 'enter data' directive}} +#pragma acc enter data no_create(LocalInt) + // expected-error@+2{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+1{{OpenACC 'no_create' clause is not valid on 'host_data' directive}} +#pragma acc host_data no_create(LocalInt) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-present-ast.cpp b/clang/test/SemaOpenACC/data-construct-present-ast.cpp new file mode 100644 index 0000000000000..2a2d81f3f2483 --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-present-ast.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; + +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc data default(none) present(GlobalArray, PointerParam[Global]) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(none) + // CHECK-NEXT: present clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: ArraySubscriptExpr{{.*}}'float' lvalue + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'float *' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue Var{{.*}}'Global' 'int' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt +} + +template +void TemplUses(T t) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: NonTypeTemplateParmDecl {{.*}}referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 1 T + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T' + // CHECK-NEXT: CompoundStmt + +#pragma acc data default(none) present(NTTP, t) + for(int i = 0; i < 5; ++i); + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(none) + // CHECK-NEXT: present clause + // CHECK-NEXT: DeclRefExpr{{.*}}'auto' lvalue NonTypeTemplateParm{{.*}} 'NTTP' 'auto &' + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int)' implicit_instantiation + // CHECK-NEXT: TemplateArgument decl + // CHECK-NEXT: Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int' + // CHECK-NEXT: CompoundStmt + +// #pragma acc parallel seq present(NTTP, t) + // CHECK-NEXT: OpenACCDataConstruct{{.*}} data + // CHECK-NEXT: default(none) + // CHECK-NEXT: present clause + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}}'const unsigned int' lvalue + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'auto &' depth 0 index 0 NTTP + // CHECK-NEXT: DeclRefExpr{{.*}}'const unsigned int' lvalue Var{{.*}} 'CEVar' 'const unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: ForStmt + // CHECK: NullStmt + +} + +void Inst() { + static constexpr unsigned CEVar = 1; + TemplUses(5); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-present-clause.c b/clang/test/SemaOpenACC/data-construct-present-clause.c new file mode 100644 index 0000000000000..b889230d177cd --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-present-clause.c @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +typedef struct IsComplete { + struct S { int A; } CompositeMember; + int ScalarMember; + float ArrayMember[5]; + void *PointerMember; +} Complete; +void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete CompositeParam) { + int LocalInt; + short *LocalPointer; + float LocalArray[5]; + Complete LocalComposite; + // Check Appertainment: +#pragma acc data default(none) present(LocalInt) + ; + + // Valid cases: +#pragma acc data default(none) present(LocalInt, LocalPointer, LocalArray) + ; +#pragma acc data default(none) present(LocalArray[2:1]) + ; + +#pragma acc data default(none) present(LocalComposite.ScalarMember, LocalComposite.ScalarMember) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data default(none) present(1 + IntParam) + ; + + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data default(none) present(+IntParam) + ; + + // expected-error@+1{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}} +#pragma acc data default(none) present(PointerParam[2:]) + ; + + // expected-error@+1{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} +#pragma acc data default(none) present(ArrayParam[2:5]) + ; + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data default(none) present((float*)ArrayParam[2:5]) + ; + // expected-error@+1{{OpenACC variable is not a valid variable name, sub-array, array element, member of a composite variable, or composite variable member}} +#pragma acc data default(none) present((float)ArrayParam[2]) + ; + + // expected-error@+1{{OpenACC 'present' clause is not valid on 'enter data' directive}} +#pragma acc enter data copyin(LocalInt) present(LocalInt) + // expected-error@+1{{OpenACC 'present' clause is not valid on 'exit data' directive}} +#pragma acc exit data copyout(LocalInt) present(LocalInt) + // expected-error@+1{{OpenACC 'present' clause is not valid on 'host_data' directive}} +#pragma acc host_data use_device(LocalInt) present(LocalInt) + ; +} diff --git a/clang/test/SemaOpenACC/data-construct-use_device-ast.cpp b/clang/test/SemaOpenACC/data-construct-use_device-ast.cpp new file mode 100644 index 0000000000000..b8cc30e14671f --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-use_device-ast.cpp @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int Global; +short GlobalArray[5]; +void NormalUses(float *PointerParam) { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK: ParmVarDecl + // CHECK-NEXT: CompoundStmt + +#pragma acc host_data use_device(GlobalArray, PointerParam) + ; + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}} host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'short[5]' lvalue Var{{.*}}'GlobalArray' 'short[5]' + // CHECK-NEXT: DeclRefExpr{{.*}}'float *' lvalue ParmVar{{.*}}'PointerParam' 'float *' + // CHECK-NEXT: NullStmt +} + +template +void TemplUses(T t) { + // CHECK-NEXT: FunctionTemplateDecl + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 0 T + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T' + // CHECK-NEXT: CompoundStmt + +#pragma acc host_data use_device(t) + ; + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}} host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: NullStmt + + // Check the instantiated versions of the above. + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (int)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'int' + // CHECK-NEXT: BuiltinType{{.*}} 'int' + // CHECK-NEXT: ParmVarDecl{{.*}} used t 'int' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCHostDataConstruct{{.*}} host_data + // CHECK-NEXT: use_device clause + // CHECK-NEXT: DeclRefExpr{{.*}}'int' lvalue ParmVar{{.*}} 't' 'int' + // CHECK-NEXT: NullStmt +} + +void Inst() { + int i; + TemplUses(i); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-use_device-clause.c b/clang/test/SemaOpenACC/data-construct-use_device-clause.c new file mode 100644 index 0000000000000..c2e7fd17f8c8d --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-use_device-clause.c @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +typedef struct IsComplete { + struct S { int A; } CompositeMember; + int ScalarMember; + float ArrayMember[5]; + void *PointerMember; +} Complete; +void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete CompositeParam) { + int LocalInt; + short *LocalPointer; + float LocalArray[5]; + Complete LocalComposite; + // Check Appertainment: +#pragma acc host_data use_device(LocalInt) + + // Valid cases: +#pragma acc host_data use_device(LocalInt, LocalPointer, LocalArray) + ; + ; + // expected-error@+2{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(LocalComposite.ScalarMember, LocalComposite.ScalarMember) + ; + + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(LocalArray[2:1]) + + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(1 + IntParam) + ; + + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(+IntParam) + ; + + // expected-error@+2{{OpenACC sub-array length is unspecified and cannot be inferred because the subscripted value is not an array}} + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(PointerParam[2:]) + ; + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(ArrayParam[2:5]) + ; + + // expected-error@+2{{OpenACC sub-array specified range [2:5] would be out of the range of the subscripted array size of 5}} + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device((float*)ArrayParam[2:5]) + ; + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device((float)ArrayParam[2]) + ; + + // expected-error@+2{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'data' directive}} +#pragma acc data use_device(LocalInt) + ; + // expected-error@+2{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'enter data' directive}} +#pragma acc enter data use_device(LocalInt) + // expected-error@+2{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'exit data' directive}} +#pragma acc exit data use_device(LocalInt) +} diff --git a/clang/test/SemaOpenACC/data-construct-wait-ast.cpp b/clang/test/SemaOpenACC/data-construct-wait-ast.cpp new file mode 100644 index 0000000000000..7fb82313669df --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-wait-ast.cpp @@ -0,0 +1,266 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int some_int(); +long some_long(); + +void NormalUses() { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK-NEXT: CompoundStmt + + int I; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + +#pragma acc data copyin(I) wait + ; + // CHECK-NEXT: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'int' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt +#pragma acc enter data copyin(I) wait() + // CHECK: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'int' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> +#pragma acc exit data copyout(I) wait(some_int(), some_long()) + // CHECK: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}} 'I' 'int' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' +#pragma acc data copyin(I) wait(queues:some_int(), some_long()) + ; + // CHECK: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'int' + // CHECK-NEXT: wait clause has queues tag + // CHECK-NEXT: <<>> + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' + // CHECK-NEXT: NullStmt +#pragma acc enter data copyin(I) wait(devnum: some_int() :some_int(), some_long()) + // CHECK: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'int' + // CHECK-NEXT: wait clause has devnum + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' +#pragma acc exit data copyout(I) wait(devnum: some_int() : queues :some_int(), some_long()) wait(devnum: some_int() : queues :some_int(), some_long()) + // CHECK: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}} 'I' 'int' + // CHECK-NEXT: wait clause has devnum has queues tag + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' + // CHECK-NEXT: wait clause has devnum has queues tag + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()' +} + +template +void TemplUses(U u) { + // CHECK: FunctionTemplateDecl + // CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 0 U + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (U)' + // CHECK-NEXT: ParmVarDecl{{.*}} referenced u 'U' + // CHECK-NEXT: CompoundStmt + + U I; + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + +#pragma acc data copyin(I) wait + ; + // CHECK: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'U' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt + +#pragma acc enter data copyin(I) wait() + // CHECK: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'U' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> + +#pragma acc exit data copyout(I) wait(U::value, u) + // CHECK: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}} 'I' 'U' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'U' + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + +#pragma acc data copyin(I) wait(queues: U::value, u) + ; + // CHECK: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'U' + // CHECK-NEXT: wait clause has queues tag + // CHECK-NEXT: <<>> + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'U' + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: NullStmt + +#pragma acc enter data copyin(I) wait(devnum:u:queues: U::value, u) + // CHECK: OpenACCEnterDataConstruct{{.*}}data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'U' + // CHECK-NEXT: wait clause has devnum has queues tag + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'U' + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + +#pragma acc exit data copyout(I) wait(devnum:u: U::value, u) + // CHECK: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}} 'I' 'U' + // CHECK-NEXT: wait clause has devnum + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' lvalue + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'U' + // CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U' + + // Check the instantiated versions of the above. + // CHECK: FunctionDecl{{.*}} used TemplUses 'void (HasInt)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'HasInt' + // CHECK-NEXT: RecordType{{.*}} 'HasInt' + // CHECK-NEXT: CXXRecord{{.*}} 'HasInt' + // CHECK-NEXT: ParmVarDecl{{.*}} used u 'HasInt' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: DeclStmt + // CHECK-NEXT: VarDecl + + // CHECK: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'HasInt' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt + + // CHECK: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'HasInt' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> + + // CHECK: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}} 'I' 'HasInt' + // CHECK-NEXT: wait clause + // CHECK-NEXT: <<>> + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + + // CHECK: OpenACCDataConstruct{{.*}}data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'HasInt' + // CHECK-NEXT: wait clause has queues tag + // CHECK-NEXT: <<>> + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: NullStmt + + // CHECK: OpenACCEnterDataConstruct{{.*}}enter data + // CHECK-NEXT: copyin clause + // CHECK-NEXT: DeclRefExpr{{.*}}'I' 'HasInt' + // CHECK-NEXT: wait clause has devnum has queues tag + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + + // CHECK: OpenACCExitDataConstruct{{.*}}exit data + // CHECK-NEXT: copyout clause + // CHECK-NEXT: DeclRefExpr{{.*}} 'I' 'HasInt' + // CHECK-NEXT: wait clause has devnum + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}} '' .operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar +} + +struct HasInt { + using IntTy = int; + using ShortTy = short; + static constexpr int value = 1; + + operator char(); +}; + +void Inst() { + TemplUses({}); +} +#endif diff --git a/clang/test/SemaOpenACC/data-construct-wait-clause.c b/clang/test/SemaOpenACC/data-construct-wait-clause.c new file mode 100644 index 0000000000000..cef2dbdca29ed --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct-wait-clause.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct NotConvertible{} NC; +short getS(); +int getI(); + +void uses() { + int arr[5]; + +#pragma acc data copyin(arr[0]) wait + ; + +#pragma acc enter data copyin(arr[0]) wait() + +#pragma acc exit data copyout(arr[0]) wait(getS(), getI()) + + // expected-error@+1{{OpenACC 'wait' clause is not valid on 'host_data' directive}} +#pragma acc host_data use_device(arr) wait(getS(), getI()) + ; + +#pragma acc data copyin(arr[0]) wait(devnum:getS(): getI()) + ; + +#pragma acc enter data copyin(arr[0]) wait(devnum:getS(): queues: getI()) wait(devnum:getI(): queues: getS(), getI(), 5) + + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc exit data copyout(arr[0]) wait(devnum:NC : 5) + + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc data copyin(arr[0]) wait(devnum:5 : NC) + ; + + // expected-error@+3{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}} + // expected-error@+2{{OpenACC clause 'wait' requires expression of integer type ('int[5]' invalid)}} + // expected-error@+1{{OpenACC clause 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc enter data copyin(arr[0]) wait(devnum:arr : queues: arr, NC, 5) + + // expected-error@+1{{OpenACC 'wait' clause is not valid on 'loop' directive}} +#pragma acc loop wait + for(int i = 5; i < 10;++i); +} diff --git a/clang/test/SemaOpenACC/data-construct.cpp b/clang/test/SemaOpenACC/data-construct.cpp new file mode 100644 index 0000000000000..4c868b68e332e --- /dev/null +++ b/clang/test/SemaOpenACC/data-construct.cpp @@ -0,0 +1,201 @@ +// RUN: %clang_cc1 %s -fopenacc -verify -Wno-empty-body -Wno-unused-value + +void HasStmt() { + { + // expected-error@+2{{expected statement}} +#pragma acc data default(none) + } + + int I; + { + // expected-error@+2{{expected statement}} +#pragma acc host_data use_device(I) + } + // Don't have statements, so this is fine. + { +#pragma acc enter data copyin(I) + } + { +#pragma acc exit data copyout(I) + } +} + +void AtLeastOneOf() { + int Var; + int *VarPtr = &Var; +// Data +#pragma acc data copy(Var) + ; +#pragma acc data copyin(Var) + ; +#pragma acc data copyout(Var) + ; +#pragma acc data create(Var) + ; +#pragma acc data no_create(Var) + ; +#pragma acc data present(Var) + ; +#pragma acc data deviceptr(VarPtr) + ; +#pragma acc data attach(VarPtr) + ; +#pragma acc data default(none) + ; + + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} +#pragma acc data if(Var) + ; + + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} +#pragma acc data async + ; + + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} +#pragma acc data wait + ; + + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} +#pragma acc data device_type(*) + ; + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} +#pragma acc data + ; + + // Enter Data +#pragma acc enter data copyin(Var) +#pragma acc enter data create(Var) +#pragma acc enter data attach(VarPtr) + + // expected-error@+1{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} +#pragma acc enter data if(Var) + // expected-error@+1{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} +#pragma acc enter data async + // expected-error@+1{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} +#pragma acc enter data wait + // expected-error@+1{{OpenACC 'enter data' construct must have at least one 'copyin', 'create' or 'attach' clause}} +#pragma acc enter data + + // Exit Data +#pragma acc exit data copyout(Var) +#pragma acc exit data delete(Var) +#pragma acc exit data detach(VarPtr) + + // expected-error@+1{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} +#pragma acc exit data if(Var) + // expected-error@+1{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} +#pragma acc exit data async + // expected-error@+1{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} +#pragma acc exit data wait + // expected-error@+1{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} +#pragma acc exit data finalize + // expected-error@+1{{OpenACC 'exit data' construct must have at least one 'copyout', 'delete' or 'detach' clause}} +#pragma acc exit data + + // Host Data +#pragma acc host_data use_device(Var) + ; + + // expected-error@+1{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} +#pragma acc host_data if(Var) + ; + // expected-error@+1{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} +#pragma acc host_data if_present + ; + // expected-error@+1{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} +#pragma acc host_data + ; +} + +void DataRules() { + int Var; + // expected-error@+2{{OpenACC clause 'copy' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) copy(Var) + ; + // expected-error@+2{{OpenACC clause 'copyin' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) copyin(Var) + ; + // expected-error@+2{{OpenACC clause 'copyout' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) copyout(Var) + ; + // expected-error@+2{{OpenACC clause 'create' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) create(Var) + ; + // expected-error@+2{{OpenACC clause 'no_create' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) no_create(Var) + ; + // expected-error@+2{{OpenACC clause 'present' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) present(Var) + ; + // expected-error@+2{{OpenACC clause 'deviceptr' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) deviceptr(Var) + ; + // expected-error@+2{{OpenACC clause 'attach' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) attach(Var) + ; + // expected-error@+2{{OpenACC clause 'default' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) default(none) + ; + // expected-error@+2{{OpenACC clause 'if' may not follow a 'device_type' clause in a 'data' construct}} + // expected-note@+1{{previous clause is here}} +#pragma acc data default(none) device_type(*) if(Var) + ; +#pragma acc data default(none) device_type(*) async + ; +#pragma acc data default(none) device_type(*) wait + ; +} + +struct HasMembers { + int Member; + + void HostDataError() { + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(this) + ; + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(this->Member) + ; + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(Member) + ; + } +}; + +void HostDataRules() { + int Var, Var2; + // expected-error@+3{{OpenACC 'host_data' construct must have at least one 'use_device' clause}} + // expected-error@+2{{OpenACC 'if' clause cannot appear more than once on a 'host_data' directive}} + // expected-note@+1{{previous clause is here}} +#pragma acc host_data if(Var) if (Var2) + ; + +#pragma acc host_data use_device(Var) + ; + + int Array[5]; +#pragma acc host_data use_device(Array) + ; + + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(Array[1:1]) + ; + + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(Array[1]) + ; + HasMembers HM; + // expected-error@+1{{OpenACC variable in 'use_device' clause is not a valid variable name or array name}} +#pragma acc host_data use_device(HM.Member) + ; + +} diff --git a/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c b/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c index ecf2835776673..d196633c8b6d9 100644 --- a/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c +++ b/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c @@ -37,10 +37,10 @@ void uses() { int *VarPtr; // 'auto' can combine with any other clause. - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'loop' directive}} #pragma acc loop auto finalize for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'loop' directive}} #pragma acc loop auto if_present for(unsigned i = 0; i < 5; ++i); #pragma acc loop auto worker @@ -68,16 +68,16 @@ void uses() { // expected-error@+1{{OpenACC 'present_or_copy' clause is not valid on 'loop' directive}} #pragma acc loop auto present_or_copy(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'loop' directive}} #pragma acc loop auto use_device(Var) for(unsigned i = 0; i < 5; ++i); // expected-error@+1{{OpenACC 'attach' clause is not valid on 'loop' directive}} #pragma acc loop auto attach(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'loop' directive}} #pragma acc loop auto delete(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'loop' directive}} #pragma acc loop auto detach(Var) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -171,10 +171,10 @@ void uses() { #pragma acc loop auto wait for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'loop' directive}} #pragma acc loop finalize auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'loop' directive}} #pragma acc loop if_present auto for(unsigned i = 0; i < 5; ++i); #pragma acc loop worker auto @@ -202,16 +202,16 @@ void uses() { // expected-error@+1{{OpenACC 'present_or_copy' clause is not valid on 'loop' directive}} #pragma acc loop present_or_copy(Var) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'loop' directive}} #pragma acc loop use_device(Var) auto for(unsigned i = 0; i < 5; ++i); // expected-error@+1{{OpenACC 'attach' clause is not valid on 'loop' directive}} #pragma acc loop attach(Var) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'loop' directive}} #pragma acc loop delete(Var) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'loop' directive}} #pragma acc loop detach(Var) auto for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -306,10 +306,10 @@ void uses() { for(unsigned i = 0; i < 5; ++i); // 'independent' can also be combined with any clauses - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'loop' directive}} #pragma acc loop independent finalize for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'loop' directive}} #pragma acc loop independent if_present for(unsigned i = 0; i < 5; ++i); #pragma acc loop independent worker @@ -337,16 +337,16 @@ void uses() { // expected-error@+1{{OpenACC 'present_or_copy' clause is not valid on 'loop' directive}} #pragma acc loop independent present_or_copy(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'loop' directive}} #pragma acc loop independent use_device(Var) for(unsigned i = 0; i < 5; ++i); // expected-error@+1{{OpenACC 'attach' clause is not valid on 'loop' directive}} #pragma acc loop independent attach(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'loop' directive}} #pragma acc loop independent delete(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'loop' directive}} #pragma acc loop independent detach(Var) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -440,10 +440,10 @@ void uses() { #pragma acc loop independent wait for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'loop' directive}} #pragma acc loop finalize independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'loop' directive}} #pragma acc loop if_present independent for(unsigned i = 0; i < 5; ++i); #pragma acc loop worker independent @@ -471,16 +471,16 @@ void uses() { // expected-error@+1{{OpenACC 'present_or_copy' clause is not valid on 'loop' directive}} #pragma acc loop present_or_copy(Var) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'loop' directive}} #pragma acc loop use_device(Var) independent for(unsigned i = 0; i < 5; ++i); // expected-error@+1{{OpenACC 'attach' clause is not valid on 'loop' directive}} #pragma acc loop attach(Var) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'loop' directive}} #pragma acc loop delete(Var) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'loop' directive}} #pragma acc loop detach(Var) independent for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -587,10 +587,10 @@ void uses() { // expected-note@+1{{previous clause is here}} #pragma acc loop seq vector for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'loop' directive}} #pragma acc loop seq finalize for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'loop' directive}} #pragma acc loop seq if_present for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'nohost' not yet implemented}} @@ -614,16 +614,16 @@ void uses() { // expected-error@+1{{OpenACC 'present_or_copy' clause is not valid on 'loop' directive}} #pragma acc loop seq present_or_copy(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'loop' directive}} #pragma acc loop seq use_device(Var) for(unsigned i = 0; i < 5; ++i); // expected-error@+1{{OpenACC 'attach' clause is not valid on 'loop' directive}} #pragma acc loop seq attach(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'loop' directive}} #pragma acc loop seq delete(Var) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'loop' directive}} #pragma acc loop seq detach(Var) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} @@ -727,10 +727,10 @@ void uses() { // expected-note@+1{{previous clause is here}} #pragma acc loop vector seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'finalize' not yet implemented}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'loop' directive}} #pragma acc loop finalize seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'if_present' not yet implemented}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'loop' directive}} #pragma acc loop if_present seq for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'nohost' not yet implemented}} @@ -754,16 +754,16 @@ void uses() { // expected-error@+1{{OpenACC 'present_or_copy' clause is not valid on 'loop' directive}} #pragma acc loop present_or_copy(Var) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'use_device' not yet implemented}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'loop' directive}} #pragma acc loop use_device(Var) seq for(unsigned i = 0; i < 5; ++i); // expected-error@+1{{OpenACC 'attach' clause is not valid on 'loop' directive}} #pragma acc loop attach(Var) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'delete' not yet implemented}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'loop' directive}} #pragma acc loop delete(Var) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'detach' not yet implemented}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'loop' directive}} #pragma acc loop detach(Var) seq for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'device' not yet implemented}} diff --git a/clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp b/clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp index dc954e36d765d..4d45d1107d03b 100644 --- a/clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp +++ b/clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp @@ -323,14 +323,17 @@ void no_other_directives() { #pragma acc loop collapse(2) for(unsigned i = 0; i < 5; ++i) { for(unsigned j = 0; j < 5; ++j) { -#pragma acc data // expected-warning{{OpenACC construct 'data' not yet implemented}} + // expected-error@+1{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} +#pragma acc data + ; } } // expected-note@+1{{active 'collapse' clause defined here}} #pragma acc loop collapse(2) for(unsigned i = 0; i < 5; ++i) { + // expected-error@+2{{OpenACC 'data' construct must have at least one 'copy', 'copyin', 'copyout', 'create', 'no_create', 'present', 'deviceptr', 'attach' or 'default' clause}} // expected-error@+1{{OpenACC 'data' construct cannot appear in intervening code of a 'loop' with a 'collapse' clause}} -#pragma acc data // expected-warning{{OpenACC construct 'data' not yet implemented}} +#pragma acc data for(unsigned j = 0; j < 5; ++j) { } } diff --git a/clang/test/SemaOpenACC/loop-construct-device_type-clause.c b/clang/test/SemaOpenACC/loop-construct-device_type-clause.c index 94406de079cdc..3e4d0da60b6b2 100644 --- a/clang/test/SemaOpenACC/loop-construct-device_type-clause.c +++ b/clang/test/SemaOpenACC/loop-construct-device_type-clause.c @@ -41,12 +41,10 @@ void uses() { #pragma acc loop device_type(*) vector for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'finalize' may not follow a 'device_type' clause in a 'loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'finalize' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) finalize for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'if_present' may not follow a 'device_type' clause in a 'loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'if_present' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) if_present for(int i = 0; i < 5; ++i); #pragma acc loop device_type(*) seq @@ -82,19 +80,16 @@ void uses() { // expected-error@+1{{OpenACC 'present_or_copy' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) present_or_copy(Var) for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'use_device' may not follow a 'device_type' clause in a 'loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'use_device' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) use_device(Var) for(int i = 0; i < 5; ++i); // expected-error@+1{{OpenACC 'attach' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) attach(Var) for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'delete' may not follow a 'device_type' clause in a 'loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'delete' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) delete(Var) for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'detach' may not follow a 'device_type' clause in a 'loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'detach' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) detach(Var) for(int i = 0; i < 5; ++i); // expected-error@+2{{OpenACC clause 'device' may not follow a 'device_type' clause in a 'loop' construct}} diff --git a/clang/test/SemaOpenACC/unimplemented-construct.c b/clang/test/SemaOpenACC/unimplemented-construct.c index 3f4bc375cff80..42737eb08d93f 100644 --- a/clang/test/SemaOpenACC/unimplemented-construct.c +++ b/clang/test/SemaOpenACC/unimplemented-construct.c @@ -4,8 +4,8 @@ #pragma acc routine struct S { -// expected-warning@+1{{OpenACC construct 'wait' not yet implemented, pragma ignored}} -#pragma acc wait +// expected-warning@+1{{OpenACC construct 'set' not yet implemented, pragma ignored}} +#pragma acc set int foo; }; diff --git a/clang/test/SemaOpenACC/wait-construct-ast.cpp b/clang/test/SemaOpenACC/wait-construct-ast.cpp new file mode 100644 index 0000000000000..58214f1f7c886 --- /dev/null +++ b/clang/test/SemaOpenACC/wait-construct-ast.cpp @@ -0,0 +1,225 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s + +#ifndef PCH_HELPER +#define PCH_HELPER + +int some_int(); +long some_long(); + +void NormalFunc() { + // CHECK-LABEL: NormalFunc + // CHECK-NEXT: CompoundStmt + +#pragma acc wait async(some_int()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: async clause + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' +#pragma acc wait() async + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: async clause +#pragma acc wait(some_int(), some_long()) if (some_int() < some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +#pragma acc wait(queues:some_int(), some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +#pragma acc wait(devnum:some_int() : queues:some_int(), some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +#pragma acc wait(devnum:some_int() : some_int(), some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +} + +template +void TemplFunc(T t) { + // CHECK-LABEL: FunctionTemplateDecl {{.*}}TemplFunc + // CHECK-NEXT: TemplateTypeParmDecl + // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc + // CHECK-NEXT: ParmVarDecl{{.*}} t 'T' + // CHECK-NEXT: CompoundStmt + +#pragma acc wait async(T::value) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: async clause + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' +#pragma acc wait() async + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: async clause +#pragma acc wait(t, T::value) if (T::value > t) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: DeclRefExpr{{.*}} 'T' lvalue ParmVar{{.*}} 't' 'T' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '' '>' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: DeclRefExpr{{.*}} 'T' lvalue ParmVar{{.*}} 't' 'T' +#pragma acc wait(queues:typename T::IntTy{}, T::value) if (typename T::IntTy{} < typename T::ShortTy{}) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::IntTy' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '' '<' + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::IntTy' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list + // CHECK-NEXT: InitListExpr +#pragma acc wait(devnum:typename T::ShortTy{} : queues:some_int(), T::value) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' +#pragma acc wait(devnum:typename T::ShortTy{} : T::value, some_long()) + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'typename T::ShortTy' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' + + // Instantiation: + // CHECK-NEXT: FunctionDecl{{.*}} TemplFunc 'void (HasInt)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'HasInt' + // CHECK-NEXT: RecordType{{.*}} 'HasInt' + // CHECK-NEXT: CXXRecord{{.*}} 'HasInt' + // CHECK-NEXT: ParmVarDecl{{.*}} t 'HasInt' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: async clause + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: async clause + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: ImplicitCastExpr{{.*}}'char' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}}.operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar{{.*}} 't' 'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'char' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'char' + // CHECK-NEXT: MemberExpr{{.*}}.operator char + // CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar{{.*}} 't' 'HasInt' + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: <<> + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::IntTy':'int' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::IntTy':'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::IntTy':'int' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::IntTy':'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short' + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: CallExpr{{.*}}'int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // + // CHECK-NEXT: OpenACCWaitConstruct{{.*}}wait + // CHECK-NEXT: CXXFunctionalCastExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const int' + // CHECK-NEXT: NestedNameSpecifier {{.*}}'HasInt' + // CHECK-NEXT: CallExpr{{.*}}'long' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' +} + +struct HasInt { + using IntTy = int; + using ShortTy = short; + static constexpr int value = 1; + + operator char(); +}; +void use() { + TemplFunc(HasInt{}); +} +#endif diff --git a/clang/test/SemaOpenACC/wait-construct.cpp b/clang/test/SemaOpenACC/wait-construct.cpp new file mode 100644 index 0000000000000..a68fc54b6e8f2 --- /dev/null +++ b/clang/test/SemaOpenACC/wait-construct.cpp @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + +struct NotConvertible{} NC; +short getS(); +int getI(); + +struct AmbiguousConvert{ + operator int(); // #AMBIG_INT + operator short(); // #AMBIG_SHORT + operator float(); +} Ambiguous; + +struct ExplicitConvertOnly { + explicit operator int() const; // #EXPL_CONV +} Explicit; + +void uses() { + int arr[5]; +#pragma acc wait(getS(), getI()) +#pragma acc wait(devnum:getS(): getI()) +#pragma acc wait(devnum:getS(): queues: getI(), getS()) +#pragma acc wait(devnum:getS(): getI(), getS()) + + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc wait(devnum:NC : 5) + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc wait(devnum:5 : NC) + // expected-error@+3{{OpenACC directive 'wait' requires expression of integer type ('int[5]' invalid)}} + // expected-error@+2{{OpenACC directive 'wait' requires expression of integer type ('int[5]' invalid)}} + // expected-error@+1{{OpenACC directive 'wait' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc wait(devnum:arr : queues: arr, NC, 5) + + // expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc wait(Ambiguous) + + // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} +#pragma acc wait(4, Explicit, 5) + + // expected-error@+1{{use of undeclared identifier 'queues'}} +#pragma acc wait(devnum: queues: 5) + +#pragma acc wait async +#pragma acc wait async(getI()) + // expected-error@+1{{OpenACC clause 'async' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc wait async(NC) + +#pragma acc wait if(getI() < getS()) + // expected-error@+1{{value of type 'struct NotConvertible' is not contextually convertible to 'bool'}} +#pragma acc wait if(NC) + +} + +template +void TestInst() { + // expected-error@+4{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}} + // expected-note@#INST{{in instantiation of function template specialization}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc wait(devnum:T::value :queues:T::ACValue) + + // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} + // expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc wait(devnum:T::EXValue :queues:T::ACValue) + + // expected-error@+1{{no member named 'Invalid' in 'HasInt'}} +#pragma acc wait(queues: T::Invalid, T::Invalid2) + + // expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}} + // expected-note@#AMBIG_INT{{conversion to integral type 'int'}} + // expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}} +#pragma acc wait async(T::ACValue) + +#pragma acc wait if(T::value < T{}) + // expected-error@+1{{value of type 'const ExplicitConvertOnly' is not contextually convertible to 'bool'}} +#pragma acc wait if(T::EXValue) +} + +struct HasInt { + using IntTy = int; + using ShortTy = short; + static constexpr int value = 1; + static constexpr AmbiguousConvert ACValue; + static constexpr ExplicitConvertOnly EXValue; + + operator char(); +}; +void Inst() { + TestInst(); // #INST +} diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp index 3fa79636de5d7..8a2c3463189fa 100644 --- a/clang/tools/clang-installapi/Options.cpp +++ b/clang/tools/clang-installapi/Options.cpp @@ -31,41 +31,21 @@ namespace drv = clang::driver::options; namespace clang { namespace installapi { -/// Create prefix string literals used in InstallAPIOpts.td. -#define PREFIX(NAME, VALUE) \ - static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \ - static constexpr llvm::ArrayRef NAME( \ - NAME##_init, std::size(NAME##_init) - 1); +#define OPTTABLE_STR_TABLE_CODE #include "InstallAPIOpts.inc" -#undef PREFIX +#undef OPTTABLE_STR_TABLE_CODE -static constexpr const llvm::StringLiteral PrefixTable_init[] = -#define PREFIX_UNION(VALUES) VALUES +#define OPTTABLE_PREFIXES_TABLE_CODE #include "InstallAPIOpts.inc" -#undef PREFIX_UNION - ; -static constexpr const ArrayRef - PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1); +#undef OPTTABLE_PREFIXES_TABLE_CODE + +#define OPTTABLE_PREFIXES_UNION_CODE +#include "InstallAPIOpts.inc" +#undef OPTTABLE_PREFIXES_UNION_CODE /// Create table mapping all options defined in InstallAPIOpts.td. static constexpr OptTable::Info InfoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ - VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \ - VALUES) \ - {PREFIX, \ - NAME, \ - HELPTEXT, \ - HELPTEXTSFORVARIANTS, \ - METAVAR, \ - OPT_##ID, \ - Option::KIND##Class, \ - PARAM, \ - FLAGS, \ - VISIBILITY, \ - OPT_##GROUP, \ - OPT_##ALIAS, \ - ALIASARGS, \ - VALUES}, +#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "InstallAPIOpts.inc" #undef OPTION }; @@ -75,7 +55,9 @@ namespace { /// \brief Create OptTable class for parsing actual command line arguments. class DriverOptTable : public opt::PrecomputedOptTable { public: - DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {} + DriverOptTable() + : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable, + OptionPrefixesUnion) {} }; } // end anonymous namespace. diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index ebafd7eb7774e..4201f043944ed 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -174,12 +174,13 @@ enum ID { #undef OPTION }; -#define PREFIX(NAME, VALUE) \ - static constexpr StringLiteral NAME##_init[] = VALUE; \ - static constexpr ArrayRef NAME(NAME##_init, \ - std::size(NAME##_init) - 1); +#define OPTTABLE_STR_TABLE_CODE #include "LinkerWrapperOpts.inc" -#undef PREFIX +#undef OPTTABLE_STR_TABLE_CODE + +#define OPTTABLE_PREFIXES_TABLE_CODE +#include "LinkerWrapperOpts.inc" +#undef OPTTABLE_PREFIXES_TABLE_CODE static constexpr OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), @@ -189,7 +190,8 @@ static constexpr OptTable::Info InfoTable[] = { class WrapperOptTable : public opt::GenericOptTable { public: - WrapperOptTable() : opt::GenericOptTable(InfoTable) {} + WrapperOptTable() + : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {} }; const OptTable &getOptTable() { @@ -594,6 +596,7 @@ Expected linkDevice(ArrayRef InputFiles, case Triple::ppc64: case Triple::ppc64le: case Triple::systemz: + case Triple::loongarch64: return generic::clang(InputFiles, Args); default: return createStringError(Triple.getArchName() + diff --git a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp index bc191afdca739..faf73a7c2f193 100644 --- a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp +++ b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp @@ -109,12 +109,13 @@ enum ID { #undef OPTION }; -#define PREFIX(NAME, VALUE) \ - static constexpr StringLiteral NAME##_init[] = VALUE; \ - static constexpr ArrayRef NAME(NAME##_init, \ - std::size(NAME##_init) - 1); +#define OPTTABLE_STR_TABLE_CODE #include "NVLinkOpts.inc" -#undef PREFIX +#undef OPTTABLE_STR_TABLE_CODE + +#define OPTTABLE_PREFIXES_TABLE_CODE +#include "NVLinkOpts.inc" +#undef OPTTABLE_PREFIXES_TABLE_CODE static constexpr OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), @@ -124,7 +125,8 @@ static constexpr OptTable::Info InfoTable[] = { class WrapperOptTable : public opt::GenericOptTable { public: - WrapperOptTable() : opt::GenericOptTable(InfoTable) {} + WrapperOptTable() + : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {} }; const OptTable &getOptTable() { diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index 58b56dcfd3bec..bd36181fca3f3 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -50,12 +50,13 @@ enum ID { #undef OPTION }; -#define PREFIX(NAME, VALUE) \ - constexpr llvm::StringLiteral NAME##_init[] = VALUE; \ - constexpr llvm::ArrayRef NAME( \ - NAME##_init, std::size(NAME##_init) - 1); +#define OPTTABLE_STR_TABLE_CODE #include "Opts.inc" -#undef PREFIX +#undef OPTTABLE_STR_TABLE_CODE + +#define OPTTABLE_PREFIXES_TABLE_CODE +#include "Opts.inc" +#undef OPTTABLE_PREFIXES_TABLE_CODE const llvm::opt::OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), @@ -65,7 +66,8 @@ const llvm::opt::OptTable::Info InfoTable[] = { class ScanDepsOptTable : public llvm::opt::GenericOptTable { public: - ScanDepsOptTable() : GenericOptTable(InfoTable) { + ScanDepsOptTable() + : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) { setGroupedShortOptions(true); } }; diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp index 076458a275d98..2bcb3757d49d0 100644 --- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp +++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp @@ -88,12 +88,13 @@ enum ID { #undef OPTION }; -#define PREFIX(NAME, VALUE) \ - static constexpr StringLiteral NAME##_init[] = VALUE; \ - static constexpr ArrayRef NAME(NAME##_init, \ - std::size(NAME##_init) - 1); +#define OPTTABLE_STR_TABLE_CODE #include "SYCLLinkOpts.inc" -#undef PREFIX +#undef OPTTABLE_STR_TABLE_CODE + +#define OPTTABLE_PREFIXES_TABLE_CODE +#include "SYCLLinkOpts.inc" +#undef OPTTABLE_PREFIXES_TABLE_CODE static constexpr OptTable::Info InfoTable[] = { #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), @@ -103,7 +104,8 @@ static constexpr OptTable::Info InfoTable[] = { class LinkerOptTable : public opt::GenericOptTable { public: - LinkerOptTable() : opt::GenericOptTable(InfoTable) {} + LinkerOptTable() + : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {} }; const OptTable &getOptTable() { diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index def4524449355..9bdc4c9f8ce23 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2185,6 +2185,11 @@ class EnqueueVisitor : public ConstStmtVisitor, void VisitOpenACCComputeConstruct(const OpenACCComputeConstruct *D); void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *D); void VisitOpenACCCombinedConstruct(const OpenACCCombinedConstruct *D); + void VisitOpenACCDataConstruct(const OpenACCDataConstruct *D); + void VisitOpenACCEnterDataConstruct(const OpenACCEnterDataConstruct *D); + void VisitOpenACCExitDataConstruct(const OpenACCExitDataConstruct *D); + void VisitOpenACCHostDataConstruct(const OpenACCHostDataConstruct *D); + void VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *D); void VisitOMPExecutableDirective(const OMPExecutableDirective *D); void VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *D); void VisitOMPLoopDirective(const OMPLoopDirective *D); @@ -2882,6 +2887,19 @@ void OpenACCClauseEnqueue::VisitCreateClause(const OpenACCCreateClause &C) { void OpenACCClauseEnqueue::VisitAttachClause(const OpenACCAttachClause &C) { VisitVarList(C); } + +void OpenACCClauseEnqueue::VisitDetachClause(const OpenACCDetachClause &C) { + VisitVarList(C); +} +void OpenACCClauseEnqueue::VisitDeleteClause(const OpenACCDeleteClause &C) { + VisitVarList(C); +} + +void OpenACCClauseEnqueue::VisitUseDeviceClause( + const OpenACCUseDeviceClause &C) { + VisitVarList(C); +} + void OpenACCClauseEnqueue::VisitDevicePtrClause( const OpenACCDevicePtrClause &C) { VisitVarList(C); @@ -2917,6 +2935,10 @@ void OpenACCClauseEnqueue::VisitAutoClause(const OpenACCAutoClause &C) {} void OpenACCClauseEnqueue::VisitIndependentClause( const OpenACCIndependentClause &C) {} void OpenACCClauseEnqueue::VisitSeqClause(const OpenACCSeqClause &C) {} +void OpenACCClauseEnqueue::VisitFinalizeClause(const OpenACCFinalizeClause &C) { +} +void OpenACCClauseEnqueue::VisitIfPresentClause( + const OpenACCIfPresentClause &C) {} void OpenACCClauseEnqueue::VisitCollapseClause(const OpenACCCollapseClause &C) { Visitor.AddStmt(C.getLoopCount()); } @@ -3587,6 +3609,35 @@ void EnqueueVisitor::VisitOpenACCCombinedConstruct( for (auto *Clause : C->clauses()) EnqueueChildren(Clause); } +void EnqueueVisitor::VisitOpenACCDataConstruct(const OpenACCDataConstruct *C) { + EnqueueChildren(C); + for (auto *Clause : C->clauses()) + EnqueueChildren(Clause); +} +void EnqueueVisitor::VisitOpenACCEnterDataConstruct( + const OpenACCEnterDataConstruct *C) { + EnqueueChildren(C); + for (auto *Clause : C->clauses()) + EnqueueChildren(Clause); +} +void EnqueueVisitor::VisitOpenACCExitDataConstruct( + const OpenACCExitDataConstruct *C) { + EnqueueChildren(C); + for (auto *Clause : C->clauses()) + EnqueueChildren(Clause); +} +void EnqueueVisitor::VisitOpenACCHostDataConstruct( + const OpenACCHostDataConstruct *C) { + EnqueueChildren(C); + for (auto *Clause : C->clauses()) + EnqueueChildren(Clause); +} + +void EnqueueVisitor::VisitOpenACCWaitConstruct(const OpenACCWaitConstruct *C) { + EnqueueChildren(C); + for (auto *Clause : C->clauses()) + EnqueueChildren(Clause); +} void EnqueueVisitor::VisitAnnotateAttr(const AnnotateAttr *A) { EnqueueChildren(A); @@ -5270,7 +5321,7 @@ CXString clang_getCursorSpelling(CXCursor C) { if (const OverloadExpr *E = Storage.dyn_cast()) return cxstring::createDup(E->getName().getAsString()); OverloadedTemplateStorage *Ovl = - Storage.get(); + cast(Storage); if (Ovl->size() == 0) return cxstring::createEmpty(); return cxstring::createDup((*Ovl->begin())->getNameAsString()); @@ -6342,6 +6393,16 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("OpenACCLoopConstruct"); case CXCursor_OpenACCCombinedConstruct: return cxstring::createRef("OpenACCCombinedConstruct"); + case CXCursor_OpenACCDataConstruct: + return cxstring::createRef("OpenACCDataConstruct"); + case CXCursor_OpenACCEnterDataConstruct: + return cxstring::createRef("OpenACCEnterDataConstruct"); + case CXCursor_OpenACCExitDataConstruct: + return cxstring::createRef("OpenACCExitDataConstruct"); + case CXCursor_OpenACCHostDataConstruct: + return cxstring::createRef("OpenACCHostDataConstruct"); + case CXCursor_OpenACCWaitConstruct: + return cxstring::createRef("OpenACCWaitConstruct"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -7309,7 +7370,7 @@ unsigned clang_getNumOverloadedDecls(CXCursor C) { Storage.dyn_cast()) return S->size(); - const Decl *D = Storage.get(); + const Decl *D = cast(Storage); if (const UsingDecl *Using = dyn_cast(D)) return Using->shadow_size(); @@ -7332,7 +7393,7 @@ CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) { Storage.dyn_cast()) return MakeCXCursor(S->begin()[index], TU); - const Decl *D = Storage.get(); + const Decl *D = cast(Storage); if (const UsingDecl *Using = dyn_cast(D)) { // FIXME: This is, unfortunately, linear time. UsingDecl::shadow_iterator Pos = Using->shadow_begin(); diff --git a/clang/tools/libclang/CIndexCXX.cpp b/clang/tools/libclang/CIndexCXX.cpp index ea6f97d39644e..a1be70dde9f67 100644 --- a/clang/tools/libclang/CIndexCXX.cpp +++ b/clang/tools/libclang/CIndexCXX.cpp @@ -101,11 +101,11 @@ CXCursor clang_getSpecializedCursorTemplate(CXCursor C) { llvm::PointerUnion Result = ClassSpec->getSpecializedTemplateOrPartial(); - if (Result.is()) - Template = Result.get(); + if (isa(Result)) + Template = cast(Result); else - Template = Result.get(); - + Template = cast(Result); + } else Template = CXXRecord->getInstantiatedFromMemberClass(); } else if (const FunctionDecl *Function = dyn_cast(D)) { diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index c8cf51d806132..b9fd3b4c7f364 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -888,6 +888,21 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::OpenACCCombinedConstructClass: K = CXCursor_OpenACCCombinedConstruct; break; + case Stmt::OpenACCDataConstructClass: + K = CXCursor_OpenACCDataConstruct; + break; + case Stmt::OpenACCEnterDataConstructClass: + K = CXCursor_OpenACCEnterDataConstruct; + break; + case Stmt::OpenACCExitDataConstructClass: + K = CXCursor_OpenACCExitDataConstruct; + break; + case Stmt::OpenACCHostDataConstructClass: + K = CXCursor_OpenACCHostDataConstruct; + break; + case Stmt::OpenACCWaitConstructClass: + K = CXCursor_OpenACCWaitConstruct; + break; case Stmt::OMPTargetParallelGenericLoopDirectiveClass: K = CXCursor_OMPTargetParallelGenericLoopDirective; break; diff --git a/clang/unittests/AST/ASTContextParentMapTest.cpp b/clang/unittests/AST/ASTContextParentMapTest.cpp index 515dfb99e1126..9af0a46817a25 100644 --- a/clang/unittests/AST/ASTContextParentMapTest.cpp +++ b/clang/unittests/AST/ASTContextParentMapTest.cpp @@ -148,5 +148,54 @@ TEST(GetParents, FriendTypeLoc) { ElementsAre(DynTypedNode::create(FrA))); } +TEST(GetParents, UserDefinedTupleLikeTypes) { + MatchVerifier Verifier; + EXPECT_TRUE(Verifier.match( + R"( +namespace std { + +using size_t = __typeof(sizeof(int)); + +template +struct tuple_size; + +template +struct tuple_size : tuple_size{}; + +template +requires requires { tuple_size::value; } +struct tuple_size : tuple_size{}; + + +template +struct tuple_element; + + +} // namespace std + +struct Decomposable {}; + +template<> struct std::tuple_size { + static constexpr size_t value = 2; +}; + +template struct std::tuple_element { + using type = int; +}; + +template struct std::tuple_element { + using type = const int; +}; + +template +const int& get(const Decomposable& d); + +void F(const Decomposable& d) { + const auto& [x, y] = d; +} +)", + varDecl(hasName("x"), hasAncestor(decompositionDecl())), Lang_CXX20)); +} + } // end namespace ast_matchers } // end namespace clang diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index abf07d094e62c..f3f314b723dfc 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -9657,7 +9657,7 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportConflictTypeAliasTemplate) { AST_MATCHER(ClassTemplateSpecializationDecl, hasInstantiatedFromMember) { if (auto Instantiate = Node.getInstantiatedFrom()) { if (auto *FromPartialSpecialization = - Instantiate.get()) { + cast(Instantiate)) { return nullptr != FromPartialSpecialization->getInstantiatedFromMember(); } } diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 39e7001393e5e..0f731f4532535 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -25,6 +25,7 @@ #include "gtest/gtest.h" #include #include +#include #include namespace clang { @@ -143,6 +144,15 @@ const Formula &getFormula(const ValueDecl &D, const Environment &Env) { return cast(Env.getValue(D))->formula(); } +const BindingDecl *findBindingDecl(ASTContext &ASTCtx, std::string_view Name) { + using ast_matchers::bindingDecl; + using ast_matchers::hasName; + auto TargetNodes = + ast_matchers::match(bindingDecl(hasName(Name)).bind("v"), ASTCtx); + assert(TargetNodes.size() == 1 && "Name must be unique"); + return ast_matchers::selectFirst("v", TargetNodes); +} + TEST(TransferTest, CNotSupported) { TestInputs Inputs("void target() {}"); Inputs.Language = TestLanguage::Lang_C89; @@ -5515,10 +5525,10 @@ TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); + const ValueDecl *BoundFooDecl = findBindingDecl(ASTCtx, "BoundFoo"); ASSERT_THAT(BoundFooDecl, NotNull()); - const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); + const ValueDecl *BoundBarDecl = findBindingDecl(ASTCtx, "BoundBar"); ASSERT_THAT(BoundBarDecl, NotNull()); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); @@ -5596,10 +5606,10 @@ TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); - const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); + const ValueDecl *BoundFooDecl = findBindingDecl(ASTCtx, "BoundFoo"); ASSERT_THAT(BoundFooDecl, NotNull()); - const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); + const ValueDecl *BoundBarDecl = findBindingDecl(ASTCtx, "BoundBar"); ASSERT_THAT(BoundBarDecl, NotNull()); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 63d8dc2486e45..e892f10433c55 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -5724,6 +5724,24 @@ TEST_F(FormatTest, HashInMacroDefinition) { getLLVMStyleWithColumns(22)); verifyFormat("#define A void # ## #", getLLVMStyleWithColumns(22)); + +#if 0 + // FIXME: The correct format is: + verifyFormat("{\n" + " {\n" + "#define GEN_ID(_x) char *_x{#_x}\n" + " GEN_ID(one);\n" + " }\n" + "}"); +#endif + verifyFormat("{\n" + " {\n" + "#define GEN_ID(_x) \\\n" + " char *_x { #_x }\n" + " GEN_ID(one);\n" + " }\n" + "}", + getGoogleStyle()); } TEST_F(FormatTest, RespectWhitespaceInMacroDefinitions) { @@ -9441,6 +9459,15 @@ TEST_F(FormatTest, AlignsAfterOpenBracket) { " aaaaaaaaaaaaaaaa\n" ");", Style); + verifyFormat("void foo(\n" + " void (*foobarpntr)(\n" + " aaaaaaaaaaaaaaaaaa *,\n" + " bbbbbbbbbbbbbb *,\n" + " cccccccccccccccccccc *,\n" + " dddddddddddddddddd *\n" + " )\n" + ");", + Style); verifyFormat("aaaaaaa const aaaaaaaaaa{\n" " aaaaaaaaaaaaa(aaaaaaaaaaa, aaaaaaaaaaaaaaaa)\n" "};", @@ -14476,10 +14503,13 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) { FormatStyle DoNotMergeNoColumnLimit = NoColumnLimit; DoNotMergeNoColumnLimit.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; - verifyFormat("A()\n" - " : b(0) {\n" + verifyFormat("A() : b(0) {\n" "}", - "A():b(0){}", DoNotMergeNoColumnLimit); + DoNotMergeNoColumnLimit); + verifyNoChange("A()\n" + " : b(0) {\n" + "}", + DoNotMergeNoColumnLimit); verifyFormat("A()\n" " : b(0) {\n" "}", diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index 4b15e7b7da339..78c9f887a159b 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -1753,6 +1753,10 @@ TEST_F(FormatTestJS, ClassDeclarations) { " x: {y: Z;} = {};\n" " private y: {y: Z;} = {};\n" "}"); + verifyFormat("class Foo {\n" + " private addGrammarCheckOneboxProductInfo(\n" + " productInfo: {[key: string]: string;}) {}\n" + "}"); // ':' is not a type declaration here. verifyFormat("class X {\n" @@ -2157,6 +2161,13 @@ TEST_F(FormatTestJS, TemplateStringMultiLineExpression) { " aaaa: aaaaa,\n" " bbbb: bbbbb,\n" " })}`;"); + + verifyFormat("`${\n" + " (\n" + " FOOFOOFOOFOO____FOO_FOO_FO_FOO_FOOO -\n" + " (barbarbarbar____bar_bar_bar_bar_bar_bar +\n" + " bar_bar_bar_barbarbar___bar_bar_bar + 1),\n" + " )}`;"); } TEST_F(FormatTestJS, TemplateStringASI) { diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 9db3187ac44e7..b2fb5227993c3 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -2277,6 +2277,13 @@ TEST_F(TokenAnnotatorTest, UnderstandsTrailingReturnArrow) { ASSERT_EQ(Tokens.size(), 21u) << Tokens; EXPECT_TOKEN(Tokens[13], tok::arrow, TT_Unknown); + Tokens = annotate("Class{foo}->func(arg);"); + ASSERT_EQ(Tokens.size(), 14u) << Tokens; + EXPECT_TOKEN(Tokens[4], tok::l_brace, TT_Unknown); // Not FunctionLBrace + EXPECT_BRACE_KIND(Tokens[4], BK_BracedInit); + EXPECT_BRACE_KIND(Tokens[6], BK_BracedInit); + EXPECT_TOKEN(Tokens[7], tok::arrow, TT_Unknown); + auto Style = getLLVMStyle(); Style.StatementAttributeLikeMacros.push_back("emit"); Tokens = annotate("emit foo()->bar;", Style); @@ -3346,6 +3353,25 @@ TEST_F(TokenAnnotatorTest, BraceKind) { EXPECT_BRACE_KIND(Tokens[11], BK_BracedInit); EXPECT_BRACE_KIND(Tokens[13], BK_Block); + Tokens = annotate("{\n" + " {\n" + "#define GEN_ID(_x) char *_x{#_x}\n" + " GEN_ID(one);\n" + " }\n" + "}"); + ASSERT_EQ(Tokens.size(), 23u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_brace, TT_BlockLBrace); + EXPECT_BRACE_KIND(Tokens[0], BK_Block); + EXPECT_TOKEN(Tokens[1], tok::l_brace, TT_BlockLBrace); + EXPECT_BRACE_KIND(Tokens[1], BK_Block); +#if 0 + // FIXME: + EXPECT_BRACE_KIND(Tokens[11], BK_BracedInit); + EXPECT_BRACE_KIND(Tokens[14], BK_BracedInit); +#endif + EXPECT_BRACE_KIND(Tokens[20], BK_Block); + EXPECT_BRACE_KIND(Tokens[21], BK_Block); + Tokens = annotate("a = class extends goog.a {};", getGoogleStyle(FormatStyle::LK_JavaScript)); ASSERT_EQ(Tokens.size(), 11u) << Tokens; diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp index 4ff6824f1e21e..94ab9fe8451e0 100644 --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -31,17 +31,19 @@ class CommandLineTest : public ::testing::Test { public: IntrusiveRefCntPtr Diags; SmallVector GeneratedArgs; - SmallVector GeneratedArgsStorage; + BumpPtrAllocator Alloc; + StringSaver StringPool; CompilerInvocation Invocation; const char *operator()(const Twine &Arg) { - return GeneratedArgsStorage.emplace_back(Arg.str()).c_str(); + return StringPool.save(Arg).data(); } CommandLineTest() : Diags(CompilerInstance::createDiagnostics( *llvm::vfs::getRealFileSystem(), new DiagnosticOptions(), - new TextDiagnosticBuffer())) {} + new TextDiagnosticBuffer())), + StringPool(Alloc) {} }; template diff --git a/clang/unittests/Serialization/CMakeLists.txt b/clang/unittests/Serialization/CMakeLists.txt index e7eebd0cb9823..e7005b5d511eb 100644 --- a/clang/unittests/Serialization/CMakeLists.txt +++ b/clang/unittests/Serialization/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_unittest(SerializationTests ModuleCacheTest.cpp NoCommentsTest.cpp PreambleInNamedModulesTest.cpp + LoadSpecLazilyTest.cpp SourceLocationEncodingTest.cpp VarDeclConstantInitTest.cpp ) diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp new file mode 100644 index 0000000000000..7cc074c51fcd0 --- /dev/null +++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp @@ -0,0 +1,264 @@ +//== unittests/Serialization/LoadSpecLazily.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 +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Parse/ParseAST.h" +#include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; +using namespace clang::tooling; + +namespace { + +class LoadSpecLazilyTest : public ::testing::Test { + void SetUp() override { + ASSERT_FALSE( + sys::fs::createUniqueDirectory("load-spec-lazily-test", TestDir)); + } + + void TearDown() override { sys::fs::remove_directories(TestDir); } + +public: + SmallString<256> TestDir; + + void addFile(StringRef Path, StringRef Contents) { + ASSERT_FALSE(sys::path::is_absolute(Path)); + + SmallString<256> AbsPath(TestDir); + sys::path::append(AbsPath, Path); + + ASSERT_FALSE( + sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath))); + + std::error_code EC; + llvm::raw_fd_ostream OS(AbsPath, EC); + ASSERT_FALSE(EC); + OS << Contents; + } + + std::string GenerateModuleInterface(StringRef ModuleName, + StringRef Contents) { + std::string FileName = llvm::Twine(ModuleName + ".cppm").str(); + addFile(FileName, Contents); + + IntrusiveRefCntPtr VFS = + llvm::vfs::createPhysicalFileSystem(); + IntrusiveRefCntPtr Diags = + CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions()); + CreateInvocationOptions CIOpts; + CIOpts.Diags = Diags; + CIOpts.VFS = VFS; + + std::string CacheBMIPath = + llvm::Twine(TestDir + "/" + ModuleName + ".pcm").str(); + std::string PrebuiltModulePath = + "-fprebuilt-module-path=" + TestDir.str().str(); + const char *Args[] = {"clang++", + "-std=c++20", + "--precompile", + PrebuiltModulePath.c_str(), + "-working-directory", + TestDir.c_str(), + "-I", + TestDir.c_str(), + FileName.c_str(), + "-o", + CacheBMIPath.c_str()}; + std::shared_ptr Invocation = + createInvocation(Args, CIOpts); + EXPECT_TRUE(Invocation); + + CompilerInstance Instance; + Instance.setDiagnostics(Diags.get()); + Instance.setInvocation(Invocation); + Instance.getFrontendOpts().OutputFile = CacheBMIPath; + // Avoid memory leaks. + Instance.getFrontendOpts().DisableFree = false; + GenerateModuleInterfaceAction Action; + EXPECT_TRUE(Instance.ExecuteAction(Action)); + EXPECT_FALSE(Diags->hasErrorOccurred()); + + return CacheBMIPath; + } +}; + +enum class CheckingMode { Forbidden, Required }; + +class DeclsReaderListener : public ASTDeserializationListener { + StringRef SpeficiedName; + CheckingMode Mode; + + bool ReadedSpecifiedName = false; + +public: + void DeclRead(GlobalDeclID ID, const Decl *D) override { + auto *ND = dyn_cast(D); + if (!ND) + return; + + ReadedSpecifiedName |= ND->getName().contains(SpeficiedName); + if (Mode == CheckingMode::Forbidden) { + EXPECT_FALSE(ReadedSpecifiedName); + } + } + + DeclsReaderListener(StringRef SpeficiedName, CheckingMode Mode) + : SpeficiedName(SpeficiedName), Mode(Mode) {} + + ~DeclsReaderListener() { + if (Mode == CheckingMode::Required) { + EXPECT_TRUE(ReadedSpecifiedName); + } + } +}; + +class LoadSpecLazilyConsumer : public ASTConsumer { + DeclsReaderListener Listener; + +public: + LoadSpecLazilyConsumer(StringRef SpecifiedName, CheckingMode Mode) + : Listener(SpecifiedName, Mode) {} + + ASTDeserializationListener *GetASTDeserializationListener() override { + return &Listener; + } +}; + +class CheckLoadSpecLazilyAction : public ASTFrontendAction { + StringRef SpecifiedName; + CheckingMode Mode; + +public: + std::unique_ptr + CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override { + return std::make_unique(SpecifiedName, Mode); + } + + CheckLoadSpecLazilyAction(StringRef SpecifiedName, CheckingMode Mode) + : SpecifiedName(SpecifiedName), Mode(Mode) {} +}; + +TEST_F(LoadSpecLazilyTest, BasicTest) { + GenerateModuleInterface("M", R"cpp( +export module M; +export template +class A {}; +export class ShouldNotBeLoaded {}; +export class Temp { + A AS; +}; + )cpp"); + + const char *test_file_contents = R"cpp( +import M; +A a; + )cpp"; + std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str(); + EXPECT_TRUE( + runToolOnCodeWithArgs(std::make_unique( + "ShouldNotBeLoaded", CheckingMode::Forbidden), + test_file_contents, + { + "-std=c++20", + DepArg.c_str(), + "-I", + TestDir.c_str(), + }, + "test.cpp")); +} + +TEST_F(LoadSpecLazilyTest, ChainedTest) { + GenerateModuleInterface("M", R"cpp( +export module M; +export template +class A {}; + )cpp"); + + GenerateModuleInterface("N", R"cpp( +export module N; +export import M; +export class ShouldNotBeLoaded {}; +export class Temp { + A AS; +}; + )cpp"); + + const char *test_file_contents = R"cpp( +import N; +A a; + )cpp"; + std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str(); + EXPECT_TRUE( + runToolOnCodeWithArgs(std::make_unique( + "ShouldNotBeLoaded", CheckingMode::Forbidden), + test_file_contents, + { + "-std=c++20", + DepArg.c_str(), + "-I", + TestDir.c_str(), + }, + "test.cpp")); +} + +/// Test that we won't crash due to we may invalidate the lazy specialization +/// lookup table during the loading process. +TEST_F(LoadSpecLazilyTest, ChainedTest2) { + GenerateModuleInterface("M", R"cpp( +export module M; +export template +class A {}; + +export class B {}; + +export class C { + A D; +}; + )cpp"); + + GenerateModuleInterface("N", R"cpp( +export module N; +export import M; +export class MayBeLoaded {}; + +export class Temp { + A AS; +}; + +export class ExportedClass {}; + +export template<> class A { + A AS; + A AB; +}; + )cpp"); + + const char *test_file_contents = R"cpp( +import N; +Temp T; +A a; + )cpp"; + std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str(); + EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique( + "MayBeLoaded", CheckingMode::Required), + test_file_contents, + { + "-std=c++20", + DepArg.c_str(), + "-I", + TestDir.c_str(), + }, + "test.cpp")); +} + +} // namespace diff --git a/clang/unittests/StaticAnalyzer/Z3CrosscheckOracleTest.cpp b/clang/unittests/StaticAnalyzer/Z3CrosscheckOracleTest.cpp index ef07e47ee911b..626f5c163d17d 100644 --- a/clang/unittests/StaticAnalyzer/Z3CrosscheckOracleTest.cpp +++ b/clang/unittests/StaticAnalyzer/Z3CrosscheckOracleTest.cpp @@ -38,8 +38,8 @@ static const AnalyzerOptions DefaultOpts = [] { // Remember to update the tests in this file when these values change. // Also update the doc comment of `interpretQueryResult`. - assert(Config.Z3CrosscheckRLimitThreshold == 400'000); - assert(Config.Z3CrosscheckTimeoutThreshold == 300_ms); + assert(Config.Z3CrosscheckRLimitThreshold == 0); + assert(Config.Z3CrosscheckTimeoutThreshold == 15'000_ms); // Usually, when the timeout/rlimit threshold is reached, Z3 only slightly // overshoots until it realizes that it overshoot and needs to back off. // Consequently, the measured timeout should be fairly close to the threshold. @@ -47,8 +47,17 @@ static const AnalyzerOptions DefaultOpts = [] { return Config; }(); +static const AnalyzerOptions LimitedOpts = [] { + AnalyzerOptions Config = DefaultOpts; + Config.Z3CrosscheckEQClassTimeoutThreshold = 700_ms; + Config.Z3CrosscheckTimeoutThreshold = 300_step; + Config.Z3CrosscheckRLimitThreshold = 400'000_step; + return Config; +}(); + namespace { +template class Z3CrosscheckOracleTest : public testing::Test { public: Z3Decision interpretQueryResult(const Z3Result &Result) { @@ -56,58 +65,100 @@ class Z3CrosscheckOracleTest : public testing::Test { } private: - Z3CrosscheckOracle Oracle = Z3CrosscheckOracle(DefaultOpts); + Z3CrosscheckOracle Oracle = Z3CrosscheckOracle(Opts); }; -TEST_F(Z3CrosscheckOracleTest, AcceptsFirstSAT) { +using DefaultZ3CrosscheckOracleTest = Z3CrosscheckOracleTest; +using LimitedZ3CrosscheckOracleTest = Z3CrosscheckOracleTest; + +TEST_F(DefaultZ3CrosscheckOracleTest, AcceptsFirstSAT) { + ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 25_ms, 1000_step})); +} +TEST_F(LimitedZ3CrosscheckOracleTest, AcceptsFirstSAT) { ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 25_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, AcceptsSAT) { +TEST_F(DefaultZ3CrosscheckOracleTest, AcceptsSAT) { + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); + ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 25_ms, 1000_step})); +} +TEST_F(LimitedZ3CrosscheckOracleTest, AcceptsSAT) { ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 25_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, SATWhenItGoesOverTime) { +TEST_F(DefaultZ3CrosscheckOracleTest, SATWhenItGoesOverTime) { + // Even if it times out, if it is SAT, we should accept it. + ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 15'010_ms, 1000_step})); +} +TEST_F(LimitedZ3CrosscheckOracleTest, SATWhenItGoesOverTime) { // Even if it times out, if it is SAT, we should accept it. ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 310_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, UNSATWhenItGoesOverTime) { +TEST_F(DefaultZ3CrosscheckOracleTest, UNSATWhenItGoesOverTime) { + ASSERT_EQ(RejectEQClass, interpretQueryResult({UNSAT, 15'010_ms, 1000_step})); +} +TEST_F(LimitedZ3CrosscheckOracleTest, UNSATWhenItGoesOverTime) { ASSERT_EQ(RejectEQClass, interpretQueryResult({UNSAT, 310_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, RejectsTimeout) { +TEST_F(DefaultZ3CrosscheckOracleTest, RejectsTimeout) { + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); + ASSERT_EQ(RejectEQClass, interpretQueryResult({UNDEF, 15'010_ms, 1000_step})); +} +TEST_F(LimitedZ3CrosscheckOracleTest, RejectsTimeout) { ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(RejectEQClass, interpretQueryResult({UNDEF, 310_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, RejectsUNSATs) { +TEST_F(DefaultZ3CrosscheckOracleTest, RejectsUNSATs) { + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); +} +TEST_F(LimitedZ3CrosscheckOracleTest, RejectsUNSATs) { ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); } -// Testing cut heuristics: -// ======================= +// Testing cut heuristics of the two configurations: +// ================================================= -TEST_F(Z3CrosscheckOracleTest, RejectEQClassIfSpendsTooMuchTotalTime) { +TEST_F(DefaultZ3CrosscheckOracleTest, RejectEQClassIfSpendsTooMuchTotalTime) { + // Simulate long queries, that barely doesn't trigger the timeout. + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 14'990_ms, 1000_step})); + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 14'990_ms, 1000_step})); + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 14'990_ms, 1000_step})); +} +TEST_F(LimitedZ3CrosscheckOracleTest, RejectEQClassIfSpendsTooMuchTotalTime) { // Simulate long queries, that barely doesn't trigger the timeout. ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 290_ms, 1000_step})); ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 290_ms, 1000_step})); ASSERT_EQ(RejectEQClass, interpretQueryResult({UNSAT, 290_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, SATWhenItSpendsTooMuchTotalTime) { +TEST_F(DefaultZ3CrosscheckOracleTest, SATWhenItSpendsTooMuchTotalTime) { + // Simulate long queries, that barely doesn't trigger the timeout. + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 14'990_ms, 1000_step})); + ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 14'990_ms, 1000_step})); + ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 14'990_ms, 1000_step})); +} +TEST_F(LimitedZ3CrosscheckOracleTest, SATWhenItSpendsTooMuchTotalTime) { // Simulate long queries, that barely doesn't trigger the timeout. ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 290_ms, 1000_step})); ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 290_ms, 1000_step})); ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 290_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, RejectEQClassIfAttemptsManySmallQueries) { +// Z3CrosscheckEQClassTimeoutThreshold is disabled in default configuration, so +// it doesn't make sense to test that. +TEST_F(LimitedZ3CrosscheckOracleTest, RejectEQClassIfAttemptsManySmallQueries) { // Simulate quick, but many queries: 35 quick UNSAT queries. // 35*20ms = 700ms, which is equal to the 700ms threshold. for (int i = 0; i < 35; ++i) { @@ -117,7 +168,9 @@ TEST_F(Z3CrosscheckOracleTest, RejectEQClassIfAttemptsManySmallQueries) { ASSERT_EQ(RejectEQClass, interpretQueryResult({UNSAT, 1_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, SATWhenIfAttemptsManySmallQueries) { +// Z3CrosscheckEQClassTimeoutThreshold is disabled in default configuration, so +// it doesn't make sense to test that. +TEST_F(LimitedZ3CrosscheckOracleTest, SATWhenItAttemptsManySmallQueries) { // Simulate quick, but many queries: 35 quick UNSAT queries. // 35*20ms = 700ms, which is equal to the 700ms threshold. for (int i = 0; i < 35; ++i) { @@ -128,16 +181,34 @@ TEST_F(Z3CrosscheckOracleTest, SATWhenIfAttemptsManySmallQueries) { ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 200_ms, 1000_step})); } -TEST_F(Z3CrosscheckOracleTest, RejectEQClassIfExhaustsRLimit) { +// Z3CrosscheckRLimitThreshold is disabled in default configuration, so it +// doesn't make sense to test that. +TEST_F(LimitedZ3CrosscheckOracleTest, RejectEQClassIfExhaustsRLimit) { ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(RejectEQClass, interpretQueryResult({UNDEF, 25_ms, 405'000_step})); } -TEST_F(Z3CrosscheckOracleTest, SATWhenItExhaustsRLimit) { +// Z3CrosscheckRLimitThreshold is disabled in default configuration, so it +// doesn't make sense to test that. +TEST_F(LimitedZ3CrosscheckOracleTest, SATWhenItExhaustsRLimit) { ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(RejectReport, interpretQueryResult({UNSAT, 25_ms, 1000_step})); ASSERT_EQ(AcceptReport, interpretQueryResult({SAT, 25_ms, 405'000_step})); } +// Demonstrate the weaknesses of the default configuration: +// ======================================================== + +TEST_F(DefaultZ3CrosscheckOracleTest, ManySlowQueriesHangTheAnalyzer) { + // Simulate many slow queries: 250 slow UNSAT queries. + // 250*14000ms = 3500s, ~1 hour. Since we disabled the total time limitation, + // this eqclass would take roughly 1 hour to process. + // It doesn't matter what rlimit the queries consume. + for (int i = 0; i < 250; ++i) { + ASSERT_EQ(RejectReport, + interpretQueryResult({UNSAT, 14'000_ms, 1'000'000_step})); + } +} + } // namespace diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 630beaef983bc..cc6a8eaebd44e 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3183,7 +3183,6 @@ void clang::EmitClangAttrClass(const RecordKeeper &Records, raw_ostream &OS) { OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n"; OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n"; - OS << "#include \"clang/Support/Compiler.h\"\n\n"; emitAttributes(Records, OS, true); diff --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp index 6a4a64a081306..72b3468dac486 100644 --- a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -362,7 +362,7 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic, if (auto *V = DiagsInPedantic.dyn_cast()) V->push_back(R); else - DiagsInPedantic.get()->insert(R); + cast(DiagsInPedantic)->insert(R); } if (!GroupsInPedantic) @@ -389,7 +389,7 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic, if (auto *V = GroupsInPedantic.dyn_cast()) V->push_back(Group); else - GroupsInPedantic.get()->insert(Group); + cast(GroupsInPedantic)->insert(Group); } } @@ -1907,8 +1907,7 @@ void clang::EmitClangDiagDocs(const RecordKeeper &Records, raw_ostream &OS) { // Write out the diagnostic groups. for (const Record *G : DiagGroups) { bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup); - auto &GroupInfo = - DiagsInGroup[std::string(G->getValueAsString("GroupName"))]; + auto &GroupInfo = DiagsInGroup[G->getValueAsString("GroupName")]; bool IsSynonym = GroupInfo.DiagsInGroup.empty() && GroupInfo.SubGroups.size() == 1; diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index 2d9f5c3381018..14e5637f62517 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -253,7 +253,7 @@ class Intrinsic { /// Return true if the intrinsic takes a splat operand. bool hasSplat() const { // These prototype modifiers are described in arm_sve.td. - return Proto.find_first_of("ajfrKLR@") != std::string::npos; + return Proto.find_first_of("ajfrKLR@!") != std::string::npos; } /// Return the parameter index of the splat operand. @@ -262,7 +262,7 @@ class Intrinsic { for (; I < Proto.size(); ++I, ++Param) { if (Proto[I] == 'a' || Proto[I] == 'j' || Proto[I] == 'f' || Proto[I] == 'r' || Proto[I] == 'K' || Proto[I] == 'L' || - Proto[I] == 'R' || Proto[I] == '@') + Proto[I] == 'R' || Proto[I] == '@' || Proto[I] == '!') break; // Multivector modifier can be skipped @@ -910,6 +910,11 @@ void SVEType::applyModifier(char Mod) { Kind = MFloat8; ElementBitwidth = 8; break; + case '!': + Kind = MFloat8; + Bitwidth = ElementBitwidth = 8; + NumVectors = 0; + break; case '.': llvm_unreachable(". is never a type in itself"); break; diff --git a/clang/utils/perf-training/bolt.lit.cfg b/clang/utils/perf-training/bolt.lit.cfg index 1d0cf9a8a17a8..dbb2dd3fd8587 100644 --- a/clang/utils/perf-training/bolt.lit.cfg +++ b/clang/utils/perf-training/bolt.lit.cfg @@ -4,6 +4,7 @@ from lit import Test import lit.formats import lit.util import os +import re import subprocess clang_bolt_mode = config.clang_bolt_mode.lower() @@ -20,9 +21,13 @@ elif clang_bolt_mode == "perf": else: assert 0, "Unsupported CLANG_BOLT_MODE variable" -config.clang = perf_wrapper + os.path.realpath( +clang_nowrapper = os.path.realpath( lit.util.which(clang_binary, config.clang_tools_dir) ).replace("\\", "/") +config.clang = perf_wrapper + clang_nowrapper +config.cmake_compiler_args = "-DCMAKE_C_COMPILER='{0}' -DCMAKE_CXX_COMPILER='{0};--driver-mode=g++'".format( + re.sub(r"\s+", ";", clang_nowrapper) +) config.name = "Clang Perf Training" config.suffixes = [ @@ -49,6 +54,8 @@ config.substitutions.append(("%clang_cpp", f" {config.clang} --driver-mode=g++ " config.substitutions.append(("%clang_skip_driver", config.clang)) config.substitutions.append(("%clang", config.clang)) config.substitutions.append(("%test_root", config.test_exec_root)) +config.substitutions.append(("%cmake_compiler_args", config.cmake_compiler_args)) config.substitutions.append(('%cmake_generator', config.cmake_generator)) config.substitutions.append(('%cmake', config.cmake_exe)) config.substitutions.append(('%llvm_src_dir', config.llvm_src_dir)) +config.substitutions.append(('%perf_wrapper', perf_wrapper)) diff --git a/clang/utils/perf-training/lit.cfg b/clang/utils/perf-training/lit.cfg index 654961e215da6..adefc7893ac44 100644 --- a/clang/utils/perf-training/lit.cfg +++ b/clang/utils/perf-training/lit.cfg @@ -31,14 +31,19 @@ cc1_wrapper = '%s %s/perf-helper.py cc1' % (config.python_exe, config.perf_helpe use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") config.test_format = lit.formats.ShTest(use_lit_shell == "0") +config.cmake_compiler_args = '-DCMAKE_C_COMPILER="{0}" -DCMAKE_CXX_COMPILER="{0};--driver-mode=g++"'.format( + config.clang.replace(' ', ';') +) config.substitutions.append( ('%clang_cpp_skip_driver', ' %s %s %s ' % (cc1_wrapper, config.clang, sysroot_flags))) config.substitutions.append( ('%clang_cpp', ' %s --driver-mode=g++ %s ' % (config.clang, sysroot_flags))) config.substitutions.append( ('%clang_skip_driver', ' %s %s %s ' % (cc1_wrapper, config.clang, sysroot_flags))) config.substitutions.append( ('%clang', '%s %s ' % (config.clang, sysroot_flags) ) ) config.substitutions.append( ('%test_root', config.test_exec_root ) ) +config.substitutions.append( ('%cmake_compiler_args', config.cmake_compiler_args)) config.substitutions.append( ('%cmake_generator', config.cmake_generator ) ) config.substitutions.append( ('%cmake', config.cmake_exe ) ) config.substitutions.append( ('%llvm_src_dir', config.llvm_src_dir ) ) +config.substitutions.append( ('%perf_wrapper', '' ) ) config.environment['LLVM_PROFILE_FILE'] = 'perf-training-%4m.profraw' diff --git a/clang/utils/perf-training/llvm-support/build.test b/clang/utils/perf-training/llvm-support/build.test index f29a594c84686..32ce9a870b91d 100644 --- a/clang/utils/perf-training/llvm-support/build.test +++ b/clang/utils/perf-training/llvm-support/build.test @@ -1,2 +1,2 @@ -RUN: %cmake -G %cmake_generator -B %t -S %llvm_src_dir -DCMAKE_C_COMPILER=%clang -DCMAKE_CXX_COMPILER=%clang -DCMAKE_CXX_FLAGS="--driver-mode=g++" -DCMAKE_BUILD_TYPE=Release -RUN: %cmake --build %t -v --target LLVMSupport +RUN: %cmake -G %cmake_generator -B %t -S %llvm_src_dir %cmake_compiler_args -DCMAKE_BUILD_TYPE=Release +RUN: %perf_wrapper %cmake --build %t -v --target LLVMSupport diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index cdedbcbaa4072..386c57250b7db 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -16726,7 +16726,7 @@

C++ defect report implementation status

2813 DRWP Class member access with prvalues - Unknown + Clang 20 2814 diff --git a/compiler-rt/Maintainers.md b/compiler-rt/Maintainers.md new file mode 100644 index 0000000000000..5faf6741c4679 --- /dev/null +++ b/compiler-rt/Maintainers.md @@ -0,0 +1,110 @@ +# Compiler-rt maintainers + +This file is a list of the +[maintainers](https://llvm.org/docs/DeveloperPolicy.html#maintainers) for +LLVM compiler-rt. + +## Current Maintainers + +The following people are the active maintainers for the project. Please reach +out to them for code reviews, questions about their area of expertise, or other +assistance. + +### Builtins Library + +Saleem Abdulrasool \ +compnerd@compnerd.org (email), [compnerd](https://github.com/compnerd) (GitHub) + +### CFI + +Peter Collingbourne \ +peter@pcc.me.uk (email), [pcc](https://github.com/pcc) (GitHub) + +### CMake build + +Petr Hosek \ +phosek@google.com (email), [petrhosek](https://github.com/petrhosek) (GitHub) + +### CRT + +Petr Hosek \ +phosek@google.com (email), [petrhosek](https://github.com/petrhosek) (GitHub) + +### GWP ASAN + +Christopher Ferris \ +cferris@google.com (email), [cferris1000](https://github.com/cferris1000) (GitHub) + +### MemProfiling + +Teresa Johnson \ +tejohnson@google.com (email), [teresajohnson](https://github.com/teresajohnson) (GitHub) + +### SafeStack + +Peter Collingbourne \ +peter@pcc.me.uk (email), [pcc](https://github.com/pcc) (GitHub) + +### Sanitizers + +#### Sanitizers not covered by someone else + +Vitaly Buka \ +vitalybuka@google.com (email), [vitalybuka](https://github.com/vitalybuka) (GitHub) \ +Alexander Potapenko \ +glider@google.com (email), [ramosian-glider](https://github.com/ramosian-glider) (GitHub) + +#### Data Flow Sanitizer + +Andrew Browne \ +browneee@google.com (email), [browneee](https://github.com/browneee) (GitHub) + +#### Numerical Sanitizer (NSAN) + +Alexander Shaposhnikov \ +alexander.v.shaposhnikov@gmail.com (email), [alexander-shaposhnikov](https://github.com/alexander-shaposhnikov) (GitHub) + +#### Realtime Sanitizer (RTSan) + +Christopher Apple \ +cja-private@pm.me (email), [cjappl](https://github.com/cjappl) (GitHub) \ +David Trevelyan \ +david.trevelyan@gmail.com (email), [davidtrevelyan](https://github.com/davidtrevelyan) (GitHub) + +#### Thread Sanitizer + +Dmitry Vyukov \ +dvyukov@google.com (email), [dvyukov](https://github.com/dvyukov) (GitHub) + +#### Undefined Behavior Sanitizer + +Richard Smith \ +richard-llvm@metafoo.co.uk (email), [zygoloid](https://github.com/zygoloid) (GitHub) + +### ORC + +Lang Hames \ +lhames@gmail.com (email), [lhames](https://github.com/lhames) (GitHub) + +### Profile runtime library + +Bill Wendling \ +isanbard@gmail.com (email), [isanbard](https://github.com/isanbard) (GitHub) + +### SCUDO + +Christopher Ferris \ +cferris@google.com (email), [cferris1000](https://github.com/cferris1000) (GitHub) + +## Inactive Maintainers + +The following people have graciously spent time performing maintainer +responsibilities but are no longer active in that role. Thank you for all your +help with the success of the project! + +### Inactive or former component maintainers + +Kostya Serebryany ([kcc](https://github.com/kcc)) -- Sanitizers \ +Evgeniy Stepanov ([eugenis](https://github.com/eugenis)) -- Sanitizers \ +Kostya Kortchinsky ([cryptoad](https://github.com/cryptoad)) -- SCUDO \ +Mitch Phillips ([hctim](https://github.com/hctim)) -- GWP ASAN diff --git a/compiler-rt/Maintainers.txt b/compiler-rt/Maintainers.txt deleted file mode 100644 index bd51a1073cc38..0000000000000 --- a/compiler-rt/Maintainers.txt +++ /dev/null @@ -1,77 +0,0 @@ -This file is a list of the people responsible for ensuring that patches for a -particular part of compiler-rt are reviewed, either by themself or by -someone else. They are also the gatekeepers for their part of compiler-rt, with -the final word on what goes in or not. - -The list is sorted by surname and formatted to allow easy grepping and -beautification by scripts. The fields are: name (N), email (E), web-address -(W), PGP key ID and fingerprint (P), description (D), and snail-mail address -(S). - -N: Saleem Abdulrasool -E: compnerd@compnerd.org -D: builtins library - -N: Andrew Browne -E: browneee@google.com -D: DataFlowSanitizer - -N: Vitaly Buka -E: vitalybuka@google.com -D: Sanitizers - -N: Peter Collingbourne -E: peter@pcc.me.uk -D: CFI, SafeStack - -N: Lang Hames -E: lhames@gmail.com -D: ORC - -N: Petr Hosek -E: phosek@google.com -D: CRT, CMake build - -N: Teresa Johnson -E: tejohnson@google.com -D: MemProf - -N: Kostya Kortchinsky -E: kostya.kortchinsky@gmail.com -D: SCUDO - -N: Mitch Phillips -E: mitchp@google.com -D: GWP ASAN - -N: Alexander Potapenko -E: glider@google.com -D: Sanitizers - -N: Kostya Serebryany -E: kcc@google.com -D: AddressSanitizer, sanitizer_common, LeakSanitizer, LibFuzzer - -N: Richard Smith -E: richard-llvm@metafoo.co.uk -D: UndefinedBehaviorSanitizer - -N: Evgeniy Stepanov -E: eugenis@google.com -D: MemorySanitizer, Android port of sanitizers - -N: Dmitry Vyukov -E: dvyukov@google.com -D: ThreadSanitizer - -N: Bill Wendling -E: isanbard@gmail.com -D: Profile runtime library - -N: Christopher Apple, David Trevelyan -E: cja-private@pm.me, realtime.sanitizer@gmail.com -D: Realtime Sanitizer (RTSan) - -N: Alexander Shaposhnikov -E: alexander.v.shaposhnikov@gmail.com -D: Numerical Sanitizer (NSAN) diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index b29ae179c2b4f..ab5d55a9a35c0 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -85,6 +85,7 @@ else() set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X} ${LOONGARCH64} ${RISCV64}) endif() +set(ALL_TYSAN_SUPPORTED_ARCH ${X86_64} ${ARM64}) set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64} ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON} ${LOONGARCH64}) @@ -102,7 +103,7 @@ if(APPLE) set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM64}) else() set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} - powerpc64le ${HEXAGON} ${LOONGARCH64}) + powerpc64le ${HEXAGON} ${LOONGARCH64} ${RISCV32} ${RISCV64}) endif() set(ALL_XRAY_DSO_SUPPORTED_ARCH ${X86_64} ${ARM64}) set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64}) diff --git a/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake index d8a491dbbd732..53aa750d934d7 100644 --- a/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake +++ b/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake @@ -1,4 +1,3 @@ -include(CMakeParseArguments) include(CompilerRTUtils) function(get_aix_libatomic_default_link_flags link_flags export_list) diff --git a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake index 74a5d4edcd859..fa8c6be6c5d46 100644 --- a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -1,4 +1,3 @@ -include(CMakeParseArguments) include(CompilerRTUtils) include(BuiltinTests) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index 6d52eecc9a91f..cf729c3adb1f5 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -458,6 +458,7 @@ if(APPLE) set(SANITIZER_COMMON_SUPPORTED_OS osx) set(PROFILE_SUPPORTED_OS osx) set(TSAN_SUPPORTED_OS osx) + set(TYSAN_SUPPORTED_OS osx) set(XRAY_SUPPORTED_OS osx) set(FUZZER_SUPPORTED_OS osx) set(ORC_SUPPORTED_OS) @@ -593,6 +594,7 @@ if(APPLE) list(APPEND FUZZER_SUPPORTED_OS ${platform}) list(APPEND ORC_SUPPORTED_OS ${platform}) list(APPEND UBSAN_SUPPORTED_OS ${platform}) + list(APPEND TYSAN_SUPPORTED_OS ${platform}) list(APPEND LSAN_SUPPORTED_OS ${platform}) list(APPEND STATS_SUPPORTED_OS ${platform}) endif() @@ -651,6 +653,9 @@ if(APPLE) list_intersect(CTX_PROFILE_SUPPORTED_ARCH ALL_CTX_PROFILE_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) + list_intersect(TYSAN_SUPPORTED_ARCH + ALL_TYSAN_SUPPORTED_ARCH + SANITIZER_COMMON_SUPPORTED_ARCH) list_intersect(TSAN_SUPPORTED_ARCH ALL_TSAN_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) @@ -703,6 +708,7 @@ else() filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH}) filter_available_targets(CTX_PROFILE_SUPPORTED_ARCH ${ALL_CTX_PROFILE_SUPPORTED_ARCH}) filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH}) + filter_available_targets(TYSAN_SUPPORTED_ARCH ${ALL_TYSAN_SUPPORTED_ARCH}) filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH}) filter_available_targets(SAFESTACK_SUPPORTED_ARCH ${ALL_SAFESTACK_SUPPORTED_ARCH}) @@ -748,7 +754,7 @@ if(COMPILER_RT_SUPPORTED_ARCH) endif() message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}") -set(ALL_SANITIZERS asan;rtsan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi) +set(ALL_SANITIZERS asan;rtsan;dfsan;msan;hwasan;tsan;tysan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi) set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})") list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") @@ -843,6 +849,13 @@ else() set(COMPILER_RT_HAS_CTX_PROFILE FALSE) endif() +if (COMPILER_RT_HAS_SANITIZER_COMMON AND TYSAN_SUPPORTED_ARCH AND + OS_NAME MATCHES "Linux|Darwin") + set(COMPILER_RT_HAS_TYSAN TRUE) +else() + set(COMPILER_RT_HAS_TYSAN FALSE) +endif() + if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH) if (OS_NAME MATCHES "Linux|Darwin|FreeBSD|NetBSD") set(COMPILER_RT_HAS_TSAN TRUE) diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp index 56deb1b0d082b..9cfb70bd00c78 100644 --- a/compiler-rt/lib/asan/asan_flags.cpp +++ b/compiler-rt/lib/asan/asan_flags.cpp @@ -240,6 +240,13 @@ void InitializeFlags() { DisplayHelpMessages(&asan_parser); ProcessFlags(); + + // TODO: Update other globals and data structures that may need to change + // after initialization due to new flags potentially being set changing after + // `__asan_default_options` is registered. + // See GH issue 'https://github.com/llvm/llvm-project/issues/117925' for + // details. + SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); }); # if CAN_SANITIZE_UB diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 70dc7d860d8f6..3a868c11e7288 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -572,9 +572,11 @@ set(aarch64_SOURCES aarch64/fp_mode.c ) +set(COMPILER_RT_AARCH64_FMV_USES_GLOBAL_CONSTRUCTOR NOT(FUCHSIA OR APPLE)) + if (COMPILER_RT_HAS_AARCH64_SME) - if (NOT COMPILER_RT_DISABLE_AARCH64_FMV AND COMPILER_RT_HAS_FNO_BUILTIN_FLAG AND (COMPILER_RT_HAS_AUXV OR COMPILER_RT_BAREMETAL_BUILD)) - list(APPEND aarch64_SOURCES aarch64/sme-abi.S aarch64/sme-libc-mem-routines.S aarch64/sme-abi-init.c aarch64/sme-libc-routines.c) + if (NOT COMPILER_RT_DISABLE_AARCH64_FMV AND COMPILER_RT_HAS_FNO_BUILTIN_FLAG AND COMPILER_RT_AARCH64_FMV_USES_GLOBAL_CONSTRUCTOR) + list(APPEND aarch64_SOURCES aarch64/sme-abi.S aarch64/sme-libc-mem-routines.S aarch64/sme-abi-assert.c aarch64/sme-libc-routines.c) message(STATUS "AArch64 SME ABI routines enabled") set_source_files_properties(aarch64/sme-libc-routines.c PROPERTIES COMPILE_FLAGS "-fno-builtin") else() @@ -842,6 +844,8 @@ else () if(COMPILER_RT_DISABLE_AARCH64_FMV) list(APPEND BUILTIN_DEFS DISABLE_AARCH64_FMV) + elseif(COMPILER_RT_BAREMETAL_BUILD) + list(APPEND BUILTIN_DEFS ENABLE_BAREMETAL_AARCH64_FMV) endif() append_list_if(COMPILER_RT_HAS_ASM_LSE HAS_ASM_LSE BUILTIN_DEFS) diff --git a/compiler-rt/lib/builtins/aarch64/sme-abi-assert.c b/compiler-rt/lib/builtins/aarch64/sme-abi-assert.c new file mode 100644 index 0000000000000..4333353f8d2d1 --- /dev/null +++ b/compiler-rt/lib/builtins/aarch64/sme-abi-assert.c @@ -0,0 +1,10 @@ +// 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 + +// We rely on the FMV __aarch64_cpu_features mechanism to determine +// which features are set at runtime. + +#include "../cpu_model/AArch64CPUFeatures.inc" +_Static_assert(FEAT_SVE == 30, "sme-abi.S assumes FEAT_SVE = 30"); +_Static_assert(FEAT_SME == 42, "sme-abi.S assumes FEAT_SME = 42"); diff --git a/compiler-rt/lib/builtins/aarch64/sme-abi-init.c b/compiler-rt/lib/builtins/aarch64/sme-abi-init.c deleted file mode 100644 index d3cd8278a5d21..0000000000000 --- a/compiler-rt/lib/builtins/aarch64/sme-abi-init.c +++ /dev/null @@ -1,50 +0,0 @@ -// 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 - -__attribute__((visibility("hidden"), nocommon)) -_Bool __aarch64_has_sme_and_tpidr2_el0; - -// We have multiple ways to check that the function has SME, depending on our -// target. -// * For Linux/Glibc we can use getauxval(). -// * For Android we can use getauxval(). -// * For newlib we can use __aarch64_sme_accessible(). - -#if defined(__linux__) - -#if defined(__ANDROID__) -#include -#elif __has_include() -#include -#else -#define getauxval(x) 0 -#endif -#include "../cpu_model/aarch64/hwcap.inc" - -static _Bool has_sme(void) { return getauxval(AT_HWCAP2) & HWCAP2_SME; } - -#else // defined(__linux__) - -#if defined(COMPILER_RT_SHARED_LIB) -__attribute__((weak)) -#endif -extern _Bool __aarch64_sme_accessible(void); - -static _Bool has_sme(void) { -#if defined(COMPILER_RT_SHARED_LIB) - if (!__aarch64_sme_accessible) - return 0; -#endif - return __aarch64_sme_accessible(); -} - -#endif // defined(__linux__) - -#if __GNUC__ >= 9 -#pragma GCC diagnostic ignored "-Wprio-ctor-dtor" -#endif -__attribute__((constructor(90))) -static void init_aarch64_has_sme(void) { - __aarch64_has_sme_and_tpidr2_el0 = has_sme(); -} diff --git a/compiler-rt/lib/builtins/aarch64/sme-abi.S b/compiler-rt/lib/builtins/aarch64/sme-abi.S index 3e9bd2c23b2fc..45bd221655fd6 100644 --- a/compiler-rt/lib/builtins/aarch64/sme-abi.S +++ b/compiler-rt/lib/builtins/aarch64/sme-abi.S @@ -8,17 +8,16 @@ #include "../assembly.h" +.set FEAT_SVE_BIT, 30 +.set FEAT_SME_BIT, 42 +.set SVCR_PSTATE_SM_BIT, 0 #if !defined(__APPLE__) -#define TPIDR2_SYMBOL SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0) -#define TPIDR2_SYMBOL_OFFSET :lo12:SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0) #define CPU_FEATS_SYMBOL SYMBOL_NAME(__aarch64_cpu_features) #define CPU_FEATS_SYMBOL_OFFSET :lo12:SYMBOL_NAME(__aarch64_cpu_features) #else // MachO requires @page/@pageoff directives because the global is defined // in a different file. Otherwise this file may fail to build. -#define TPIDR2_SYMBOL SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)@page -#define TPIDR2_SYMBOL_OFFSET SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)@pageoff #define CPU_FEATS_SYMBOL SYMBOL_NAME(__aarch64_cpu_features)@page #define CPU_FEATS_SYMBOL_OFFSET SYMBOL_NAME(__aarch64_cpu_features)@pageoff #endif @@ -41,7 +40,7 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(do_abort) .cfi_offset w30, -24 .cfi_offset w29, -32 .cfi_offset 46, -16 - bl __arm_sme_state + bl SYMBOL_NAME(__arm_sme_state) tbz x0, #0, 2f 1: smstop sm @@ -55,15 +54,15 @@ END_COMPILERRT_FUNCTION(do_abort) // __arm_sme_state fills the result registers based on a local // that is set as part of the compiler-rt startup code. // __aarch64_has_sme_and_tpidr2_el0 -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sme_state) +DEFINE_COMPILERRT_FUNCTION(__arm_sme_state) .variant_pcs __arm_sme_state BTI_C mov x0, xzr mov x1, xzr - adrp x16, TPIDR2_SYMBOL - ldrb w16, [x16, TPIDR2_SYMBOL_OFFSET] - cbz w16, 1f + adrp x16, CPU_FEATS_SYMBOL + ldr x16, [x16, CPU_FEATS_SYMBOL_OFFSET] + tbz x16, #FEAT_SME_BIT, 1f 0: orr x0, x0, #0xC000000000000000 mrs x16, SVCR @@ -71,9 +70,9 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sme_state) mrs x1, TPIDR2_EL0 1: ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_sme_state) +END_COMPILERRT_FUNCTION(__arm_sme_state) -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_restore) +DEFINE_COMPILERRT_FUNCTION(__arm_tpidr2_restore) .variant_pcs __arm_tpidr2_restore BTI_C // If TPIDR2_EL0 is nonnull, the subroutine aborts in some platform-specific @@ -107,16 +106,16 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_restore) ret 2: b SYMBOL_NAME(do_abort) -END_COMPILERRT_OUTLINE_FUNCTION(__arm_tpidr2_restore) +END_COMPILERRT_FUNCTION(__arm_tpidr2_restore) -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_save) +DEFINE_COMPILERRT_FUNCTION(__arm_tpidr2_save) .variant_pcs __arm_tpidr2_save BTI_C // If the current thread does not have access to TPIDR2_EL0, the subroutine // does nothing. - adrp x14, TPIDR2_SYMBOL - ldrb w14, [x14, TPIDR2_SYMBOL_OFFSET] - cbz w14, 1f + adrp x14, CPU_FEATS_SYMBOL + ldr x14, [x14, CPU_FEATS_SYMBOL_OFFSET] + tbz x14, #FEAT_SME_BIT, 1f // If TPIDR2_EL0 is null, the subroutine does nothing. mrs x16, TPIDR2_EL0 @@ -148,16 +147,17 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_save) ret 2: b SYMBOL_NAME(do_abort) -END_COMPILERRT_OUTLINE_FUNCTION(__arm_tpidr2_save) +END_COMPILERRT_FUNCTION(__arm_tpidr2_save) -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable) +DEFINE_COMPILERRT_FUNCTION(__arm_za_disable) + .cfi_startproc .variant_pcs __arm_za_disable BTI_C // If the current thread does not have access to SME, the subroutine does // nothing. - adrp x14, TPIDR2_SYMBOL - ldrb w14, [x14, TPIDR2_SYMBOL_OFFSET] - cbz w14, 0f + adrp x14, CPU_FEATS_SYMBOL + ldr x14, [x14, CPU_FEATS_SYMBOL_OFFSET] + tbz x14, #FEAT_SME_BIT, 0f // Otherwise, the subroutine behaves as if it did the following: // * Call __arm_tpidr2_save. @@ -167,7 +167,7 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable) .cfi_def_cfa w29, 16 .cfi_offset w30, -8 .cfi_offset w29, -16 - bl __arm_tpidr2_save + bl SYMBOL_NAME(__arm_tpidr2_save) // * Set TPIDR2_EL0 to null. msr TPIDR2_EL0, xzr @@ -182,47 +182,27 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable) .cfi_restore w29 0: ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_za_disable) + .cfi_endproc +END_COMPILERRT_FUNCTION(__arm_za_disable) -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_get_current_vg) +DEFINE_COMPILERRT_FUNCTION(__arm_get_current_vg) .variant_pcs __arm_get_current_vg BTI_C - stp x29, x30, [sp, #-16]! - .cfi_def_cfa_offset 16 - mov x29, sp - .cfi_def_cfa w29, 16 - .cfi_offset w30, -8 - .cfi_offset w29, -16 adrp x17, CPU_FEATS_SYMBOL - ldr w17, [x17, CPU_FEATS_SYMBOL_OFFSET] - tbnz w17, #30, 0f - adrp x16, TPIDR2_SYMBOL - ldrb w16, [x16, TPIDR2_SYMBOL_OFFSET] - cbz w16, 1f + ldr x17, [x17, CPU_FEATS_SYMBOL_OFFSET] + tbnz w17, #FEAT_SVE_BIT, 1f + tbz x17, #FEAT_SME_BIT, 2f 0: - mov x18, x1 - bl __arm_sme_state - mov x1, x18 - and x17, x17, #0x40000000 - bfxil x17, x0, #0, #1 - cbz x17, 1f + mrs x17, SVCR + tbz x17, #SVCR_PSTATE_SM_BIT, 2f +1: cntd x0 - .cfi_def_cfa wsp, 16 - ldp x29, x30, [sp], #16 - .cfi_def_cfa_offset 0 - .cfi_restore w30 - .cfi_restore w29 ret -1: +2: mov x0, xzr - .cfi_def_cfa wsp, 16 - ldp x29, x30, [sp], #16 - .cfi_def_cfa_offset 0 - .cfi_restore w30 - .cfi_restore w29 ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_get_current_vg) +END_COMPILERRT_FUNCTION(__arm_get_current_vg) NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S b/compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S index 6e13a03691cfd..e736829967c0c 100644 --- a/compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S +++ b/compiler-rt/lib/builtins/aarch64/sme-libc-mem-routines.S @@ -6,8 +6,6 @@ #include "../assembly.h" -#define L(l) .L ## l - // // __arm_sc_memcpy / __arm_sc_memmove // @@ -52,17 +50,17 @@ The loop tail is handled by always copying 64 bytes from the end. */ -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memcpy) +DEFINE_COMPILERRT_FUNCTION(__arm_sc_memcpy) add srcend1, src, count add dstend1, dstin, count cmp count, 128 - b.hi L(copy_long) + b.hi 7f // copy_long cmp count, 32 - b.hi L(copy32_128) + b.hi 4f // copy32_128 /* Small copies: 0..32 bytes. */ cmp count, 16 - b.lo L(copy16) + b.lo 0f // copy16 ldp A_l, A_h, [src] ldp D_l, D_h, [srcend1, -16] stp A_l, A_h, [dstin] @@ -70,8 +68,8 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memcpy) ret /* Copy 8-15 bytes. */ -L(copy16): - tbz count, 3, L(copy8) +0: // copy16 + tbz count, 3, 1f // copy8 ldr A_l, [src] ldr A_h, [srcend1, -8] str A_l, [dstin] @@ -80,8 +78,8 @@ L(copy16): .p2align 3 /* Copy 4-7 bytes. */ -L(copy8): - tbz count, 2, L(copy4) +1: // copy8 + tbz count, 2, 2f // copy4 ldr A_lw, [src] ldr B_lw, [srcend1, -4] str A_lw, [dstin] @@ -89,8 +87,8 @@ L(copy8): ret /* Copy 0..3 bytes using a branchless sequence. */ -L(copy4): - cbz count, L(copy0) +2: // copy4 + cbz count, 3f // copy0 lsr tmp1, count, 1 ldrb A_lw, [src] ldrb C_lw, [srcend1, -1] @@ -98,18 +96,18 @@ L(copy4): strb A_lw, [dstin] strb B_lw, [dstin, tmp1] strb C_lw, [dstend1, -1] -L(copy0): +3: // copy0 ret .p2align 4 /* Medium copies: 33..128 bytes. */ -L(copy32_128): +4: // copy32_128 ldp A_l, A_h, [src] ldp B_l, B_h, [src, 16] ldp C_l, C_h, [srcend1, -32] ldp D_l, D_h, [srcend1, -16] cmp count, 64 - b.hi L(copy128) + b.hi 5f // copy128 stp A_l, A_h, [dstin] stp B_l, B_h, [dstin, 16] stp C_l, C_h, [dstend1, -32] @@ -118,16 +116,16 @@ L(copy32_128): .p2align 4 /* Copy 65..128 bytes. */ -L(copy128): +5: // copy128 ldp E_l, E_h, [src, 32] ldp F_l, F_h, [src, 48] cmp count, 96 - b.ls L(copy96) + b.ls 6f // copy96 ldp G_l, G_h, [srcend1, -64] ldp H_l, H_h, [srcend1, -48] stp G_l, G_h, [dstend1, -64] stp H_l, H_h, [dstend1, -48] -L(copy96): +6: // copy96 stp A_l, A_h, [dstin] stp B_l, B_h, [dstin, 16] stp E_l, E_h, [dstin, 32] @@ -138,12 +136,12 @@ L(copy96): .p2align 4 /* Copy more than 128 bytes. */ -L(copy_long): +7: // copy_long /* Use backwards copy if there is an overlap. */ sub tmp1, dstin, src - cbz tmp1, L(copy0) + cbz tmp1, 3b // copy0 cmp tmp1, count - b.lo L(copy_long_backwards) + b.lo 10f //copy_long_backwards /* Copy 16 bytes and then align dst to 16-byte alignment. */ @@ -158,8 +156,8 @@ L(copy_long): ldp C_l, C_h, [src, 48] ldp D_l, D_h, [src, 64]! subs count, count, 128 + 16 /* Test and readjust count. */ - b.ls L(copy64_from_end) -L(loop64): + b.ls 9f // copy64_from_end +8: // loop64 stp A_l, A_h, [dst, 16] ldp A_l, A_h, [src, 16] stp B_l, B_h, [dst, 32] @@ -169,10 +167,10 @@ L(loop64): stp D_l, D_h, [dst, 64]! ldp D_l, D_h, [src, 64]! subs count, count, 64 - b.hi L(loop64) + b.hi 8b // loop64 /* Write the last iteration and copy 64 bytes from the end. */ -L(copy64_from_end): +9: // copy64_from_end ldp E_l, E_h, [srcend1, -64] stp A_l, A_h, [dst, 16] ldp A_l, A_h, [srcend1, -48] @@ -191,7 +189,7 @@ L(copy64_from_end): /* Large backwards copy for overlapping copies. Copy 16 bytes and then align dst to 16-byte alignment. */ -L(copy_long_backwards): +10: // copy_long_backwards ldp D_l, D_h, [srcend1, -16] and tmp1, dstend1, 15 sub srcend1, srcend1, tmp1 @@ -203,9 +201,9 @@ L(copy_long_backwards): ldp D_l, D_h, [srcend1, -64]! sub dstend1, dstend1, tmp1 subs count, count, 128 - b.ls L(copy64_from_start) + b.ls 12f // copy64_from_start -L(loop64_backwards): +11: // loop64_backwards stp A_l, A_h, [dstend1, -16] ldp A_l, A_h, [srcend1, -16] stp B_l, B_h, [dstend1, -32] @@ -215,10 +213,10 @@ L(loop64_backwards): stp D_l, D_h, [dstend1, -64]! ldp D_l, D_h, [srcend1, -64]! subs count, count, 64 - b.hi L(loop64_backwards) + b.hi 11b // loop64_backwards /* Write the last iteration and copy 64 bytes from the start. */ -L(copy64_from_start): +12: // copy64_from_start ldp G_l, G_h, [src, 48] stp A_l, A_h, [dstend1, -16] ldp A_l, A_h, [src, 32] @@ -232,7 +230,7 @@ L(copy64_from_start): stp B_l, B_h, [dstin, 16] stp C_l, C_h, [dstin] ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_sc_memcpy) +END_COMPILERRT_FUNCTION(__arm_sc_memcpy) DEFINE_COMPILERRT_FUNCTION_ALIAS(__arm_sc_memmove, __arm_sc_memcpy) @@ -250,7 +248,7 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__arm_sc_memmove, __arm_sc_memcpy) #define dstend2 x4 #define zva_val x5 -DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memset) +DEFINE_COMPILERRT_FUNCTION(__arm_sc_memset) #ifdef __ARM_FEATURE_SVE mov z0.b, valw #else @@ -263,9 +261,9 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memset) add dstend2, dstin, count cmp count, 96 - b.hi L(set_long) + b.hi 7f // set_long cmp count, 16 - b.hs L(set_medium) + b.hs 4f // set_medium mov val, v0.D[0] /* Set 0..15 bytes. */ @@ -285,38 +283,38 @@ DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memset) 3: ret /* Set 17..96 bytes. */ -L(set_medium): +4: // set_medium str q0, [dstin] - tbnz count, 6, L(set96) + tbnz count, 6, 6f // set96 str q0, [dstend2, -16] - tbz count, 5, 1f + tbz count, 5, 5f str q0, [dstin, 16] str q0, [dstend2, -32] -1: ret +5: ret .p2align 4 /* Set 64..96 bytes. Write 64 bytes from the start and 32 bytes from the end. */ -L(set96): +6: // set96 str q0, [dstin, 16] stp q0, q0, [dstin, 32] stp q0, q0, [dstend2, -32] ret .p2align 4 -L(set_long): +7: // set_long and valw, valw, 255 bic dst, dstin, 15 str q0, [dstin] cmp count, 160 ccmp valw, 0, 0, hs - b.ne L(no_zva) + b.ne 9f // no_zva #ifndef SKIP_ZVA_CHECK mrs zva_val, dczid_el0 and zva_val, zva_val, 31 cmp zva_val, 4 /* ZVA size is 64 bytes. */ - b.ne L(no_zva) + b.ne 9f // no_zva #endif str q0, [dst, 16] stp q0, q0, [dst, 32] @@ -325,27 +323,27 @@ L(set_long): sub count, count, 128 /* Adjust count and bias for loop. */ .p2align 4 -L(zva_loop): +8: // zva_loop add dst, dst, 64 dc zva, dst subs count, count, 64 - b.hi L(zva_loop) + b.hi 8b // zva_loop stp q0, q0, [dstend2, -64] stp q0, q0, [dstend2, -32] ret -L(no_zva): +9: // no_zva sub count, dstend2, dst /* Count is 16 too large. */ sub dst, dst, 16 /* Dst is biased by -32. */ sub count, count, 64 + 16 /* Adjust count and bias for loop. */ -L(no_zva_loop): +10: // no_zva_loop stp q0, q0, [dst, 32] stp q0, q0, [dst, 64]! subs count, count, 64 - b.hi L(no_zva_loop) + b.hi 10b // no_zva_loop stp q0, q0, [dstend2, -64] stp q0, q0, [dstend2, -32] ret -END_COMPILERRT_OUTLINE_FUNCTION(__arm_sc_memset) +END_COMPILERRT_FUNCTION(__arm_sc_memset) #endif // __aarch64__ diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64.c b/compiler-rt/lib/builtins/cpu_model/aarch64.c index 74e5e01b66c54..4082fd62ea11a 100644 --- a/compiler-rt/lib/builtins/cpu_model/aarch64.c +++ b/compiler-rt/lib/builtins/cpu_model/aarch64.c @@ -80,6 +80,8 @@ struct { #include "aarch64/fmv/getauxval.inc" #elif defined(_WIN32) #include "aarch64/fmv/windows.inc" +#elif defined(ENABLE_BAREMETAL_AARCH64_FMV) +#include "aarch64/fmv/baremetal.inc" #else #include "aarch64/fmv/unimplemented.inc" #endif diff --git a/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc b/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc new file mode 100644 index 0000000000000..f188e84808e01 --- /dev/null +++ b/compiler-rt/lib/builtins/cpu_model/aarch64/fmv/baremetal.inc @@ -0,0 +1,31 @@ +// For baremetal platforms, we don't really initialise '__aarch64_cpu_features', +// with exception of FEAT_SME that we can get from '__aarch64_sme_accessible'. + +#if defined(COMPILER_RT_SHARED_LIB) +__attribute__((weak)) +#endif +extern _Bool +__aarch64_sme_accessible(void); + +static _Bool has_sme(void) { +#if defined(COMPILER_RT_SHARED_LIB) + if (!__aarch64_sme_accessible) + return 0; +#endif + return __aarch64_sme_accessible(); +} + +void __init_cpu_features_resolver(unsigned long hwcap, + const __ifunc_arg_t *arg) {} + +void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) { + // CPU features already initialized. + if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) + return; + + unsigned long long feat = 0; + if (has_sme()) + feat |= 1ULL << FEAT_SME; + + __atomic_store_n(&__aarch64_cpu_features.features, feat, __ATOMIC_RELAXED); +} diff --git a/compiler-rt/lib/builtins/fp_div_impl.inc b/compiler-rt/lib/builtins/fp_div_impl.inc index 29bcd1920edfb..de61e55cd083b 100644 --- a/compiler-rt/lib/builtins/fp_div_impl.inc +++ b/compiler-rt/lib/builtins/fp_div_impl.inc @@ -334,7 +334,6 @@ static __inline fp_t __divXf3__(fp_t a, fp_t b) { // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W x_UQ0 -= RECIPROCAL_PRECISION; // Now 1/b - (2*P) * 2^-W < x < 1/b - // FIXME Is x_UQ0 still >= 0.5? rep_t quotient_UQ1, dummy; wideMultiply(x_UQ0, aSignificand << 1, "ient_UQ1, &dummy); @@ -344,6 +343,12 @@ static __inline fp_t __divXf3__(fp_t a, fp_t b) { // adjust it to be in [1.0, 2.0) as UQ1.SB. rep_t residualLo; if (quotient_UQ1 < (implicitBit << 1)) { + if (quotient_UQ1 < implicitBit) { + // In a rare case where quotient is < 0.5, we can adjust the quotient and + // the written exponent, and then treat them the same way as in [0.5, 1.0) + quotient_UQ1 <<= 1; + writtenExponent -= 1; + } // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB, // effectively doubling its value as well as its error estimation. residualLo = (aSignificand << (significandBits + 1)) - quotient_UQ1 * bSignificand; diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp index b0fb263b62f15..a5897274521e9 100644 --- a/compiler-rt/lib/interception/interception_win.cpp +++ b/compiler-rt/lib/interception/interception_win.cpp @@ -634,6 +634,8 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0xD284: // 84 D2 : test dl,dl return 2; + case 0xE483: // 83 E4 XX : and esp, XX + case 0xEC83: // 83 EC XX : sub esp, XX case 0xC1F6: // F6 C1 XX : test cl, XX return 3; @@ -642,10 +644,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { return 0; } - switch (0x00FFFFFF & *(u32*)address) { - case 0xF8E483: // 83 E4 F8 : and esp, 0xFFFFFFF8 - case 0x64EC83: // 83 EC 64 : sub esp, 64h - return 3; + switch (0x00FFFFFF & *(u32 *)address) { case 0x24A48D: // 8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX] return 7; } @@ -774,7 +773,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0xdb8548: // 48 85 db : test rbx, rbx case 0xdb854d: // 4d 85 db : test r11, r11 case 0xdc8b4c: // 4c 8b dc : mov r11, rsp - case 0xe0e483: // 83 e4 e0 : and esp, 0xFFFFFFE0 case 0xe48548: // 48 85 e4 : test rsp, rsp case 0xe4854d: // 4d 85 e4 : test r12, r12 case 0xe58948: // 48 89 e5 : mov rbp, rsp @@ -873,7 +871,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0x5D8B: // 8B 5D XX : mov ebx, dword ptr [ebp + XX] case 0x7D8B: // 8B 7D XX : mov edi, dword ptr [ebp + XX] case 0x758B: // 8B 75 XX : mov esi, dword ptr [ebp + XX] - case 0xEC83: // 83 EC XX : sub esp, XX case 0x75FF: // FF 75 XX : push dword ptr [ebp + XX] return 3; case 0xC1F7: // F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX diff --git a/compiler-rt/lib/interception/tests/interception_win_test.cpp b/compiler-rt/lib/interception/tests/interception_win_test.cpp index 761c07d4288f7..04d9a6766f65a 100644 --- a/compiler-rt/lib/interception/tests/interception_win_test.cpp +++ b/compiler-rt/lib/interception/tests/interception_win_test.cpp @@ -852,6 +852,8 @@ const struct InstructionSizeData { { 2, {0x8B, 0xC1}, 0, "8B C1 : mov eax, ecx"}, { 2, {0x8B, 0xEC}, 0, "8B EC : mov ebp, esp"}, { 2, {0x8B, 0xFF}, 0, "8B FF : mov edi, edi"}, + { 3, {0x83, 0xE4, 0x72}, 0, "83 E4 XX : and esp, XX"}, + { 3, {0x83, 0xEC, 0x72}, 0, "83 EC XX : sub esp, XX"}, { 3, {0xc2, 0x71, 0x72}, 0, "C2 XX XX : ret XX (needed for registering weak functions)"}, { 5, {0x68, 0x71, 0x72, 0x73, 0x74}, 0, "68 XX XX XX XX : push imm32"}, { 5, {0xb8, 0x71, 0x72, 0x73, 0x74}, 0, "b8 XX XX XX XX : mov eax, XX XX XX XX"}, diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp index 19b2b90106824..c3448c22532bb 100644 --- a/compiler-rt/lib/memprof/memprof_allocator.cpp +++ b/compiler-rt/lib/memprof/memprof_allocator.cpp @@ -301,7 +301,8 @@ struct Allocator { ~Allocator() { atomic_store_relaxed(&destructing, 1); - FinishAndWrite(); + if (flags()->dump_at_exit) + FinishAndWrite(); } static void PrintCallback(const uptr Key, LockedMemInfoBlock *const &Value, diff --git a/compiler-rt/lib/memprof/memprof_flags.inc b/compiler-rt/lib/memprof/memprof_flags.inc index 7c5dc091f7935..1d8e77752caa5 100644 --- a/compiler-rt/lib/memprof/memprof_flags.inc +++ b/compiler-rt/lib/memprof/memprof_flags.inc @@ -38,4 +38,7 @@ MEMPROF_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true, MEMPROF_FLAG(bool, print_text, false, "If set, prints the heap profile in text format. Else use the raw binary serialization format.") MEMPROF_FLAG(bool, print_terse, false, - "If set, prints memory profile in a terse format. Only applicable if print_text = true.") \ No newline at end of file + "If set, prints memory profile in a terse format. Only applicable " + "if print_text = true.") +MEMPROF_FLAG(bool, dump_at_exit, true, + "If set, dump profiles when the program terminates.") diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index f0b1dc905678b..76255cdb742a3 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -1358,79 +1358,6 @@ INTERCEPTOR(int, forkpty, int *aparent, char *name, const void *termp, #define MSAN_MAYBE_INTERCEPT_FORKPTY #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID -INTERCEPTOR(int, __b64_ntop, unsigned char const *src, SIZE_T srclength, - char *target, SIZE_T targsize) { - ENSURE_MSAN_INITED(); - CHECK_UNPOISONED(src, srclength); - InterceptorScope interceptor_scope; - int res = REAL(__b64_ntop)(src, srclength, target, targsize); - if (res >= 0) - __msan_unpoison(target, res + 1); - return res; -} -INTERCEPTOR(int, __b64_pton, char const *src, char *target, SIZE_T targsize) { - ENSURE_MSAN_INITED(); - CHECK_UNPOISONED(src, internal_strlen(src) + 1); - InterceptorScope interceptor_scope; - int res = REAL(__b64_pton)(src, target, targsize); - if (res >= 0) - __msan_unpoison(target, res); - return res; -} -# define MSAN_MAYBE_INTERCEPT___B64_TO \ - MSAN_INTERCEPT_FUNC(__b64_ntop); \ - COMMON_INTERCEPT_FUNCTION(__b64_pton); -#else -# define MSAN_MAYBE_INTERCEPT___B64_TO -#endif - -#if SANITIZER_LINUX && !SANITIZER_ANDROID -# if __GLIBC_PREREQ(2, 34) -// Changed with https://sourceware.org/git/?p=glibc.git;h=640bbdf -# define DN_COMP_INTERCEPTOR_NAME dn_comp -# define DN_EXPAND_INTERCEPTOR_NAME dn_expand -# else -# define DN_COMP_INTERCEPTOR_NAME __dn_comp -# define DN_EXPAND_INTERCEPTOR_NAME __dn_expand -# endif -INTERCEPTOR(int, DN_COMP_INTERCEPTOR_NAME, unsigned char *exp_dn, - unsigned char *comp_dn, int length, unsigned char **dnptrs, - unsigned char **lastdnptr) { - ENSURE_MSAN_INITED(); - InterceptorScope interceptor_scope; - int res = REAL(DN_COMP_INTERCEPTOR_NAME)(exp_dn, comp_dn, length, dnptrs, - lastdnptr); - if (res >= 0) { - __msan_unpoison(comp_dn, res); - if (dnptrs && lastdnptr) { - unsigned char **p = dnptrs; - for (; p != lastdnptr && *p; ++p); - if (p != lastdnptr) - ++p; - __msan_unpoison(dnptrs, (p - dnptrs) * sizeof(*p)); - } - } - return res; -} -INTERCEPTOR(int, DN_EXPAND_INTERCEPTOR_NAME, unsigned char const *base, - unsigned char const *end, unsigned char const *src, char *dest, - int space) { - ENSURE_MSAN_INITED(); - // TODO: add read check if __dn_comp intercept added - InterceptorScope interceptor_scope; - int res = REAL(DN_EXPAND_INTERCEPTOR_NAME)(base, end, src, dest, space); - if (res >= 0) - __msan_unpoison(dest, internal_strlen(dest) + 1); - return res; -} -# define MSAN_MAYBE_INTERCEPT_DN_COMP_EXPAND \ - MSAN_INTERCEPT_FUNC(DN_COMP_INTERCEPTOR_NAME); \ - MSAN_INTERCEPT_FUNC(DN_EXPAND_INTERCEPTOR_NAME); -#else -# define MSAN_MAYBE_INTERCEPT_DN_COMP_EXPAND -#endif - struct MSanInterceptorContext { bool in_interceptor_scope; }; @@ -1989,9 +1916,6 @@ void InitializeInterceptors() { MSAN_MAYBE_INTERCEPT_OPENPTY; MSAN_MAYBE_INTERCEPT_FORKPTY; - MSAN_MAYBE_INTERCEPT___B64_TO; - MSAN_MAYBE_INTERCEPT_DN_COMP_EXPAND; - inited = 1; } } // namespace __msan diff --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt index c95700ab53876..7da230d8296e9 100644 --- a/compiler-rt/lib/orc/CMakeLists.txt +++ b/compiler-rt/lib/orc/CMakeLists.txt @@ -53,6 +53,7 @@ if (APPLE) macho_tlv.x86-64.S macho_tlv.arm64.S sysv_reenter.arm64.S + sysv_reenter.x86-64.S ) set(ORC_IMPL_HEADERS @@ -119,6 +120,7 @@ else() # not Apple elfnix_tls.aarch64.S elfnix_tls.ppc64.S sysv_reenter.arm64.S + sysv_reenter.x86-64.S ) endif() diff --git a/compiler-rt/lib/orc/macho_tlv.x86-64.S b/compiler-rt/lib/orc/macho_tlv.x86-64.S index e3daf23e3029e..04b5bd7eba676 100644 --- a/compiler-rt/lib/orc/macho_tlv.x86-64.S +++ b/compiler-rt/lib/orc/macho_tlv.x86-64.S @@ -1,4 +1,4 @@ -//===-- orc_rt_macho_tlv.x86-64.s -------------------------------*- ASM -*-===// +//===-- macho_tlv.x86-64.s --------------------------------------*- ASM -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/orc/sysv_reenter.arm64.S b/compiler-rt/lib/orc/sysv_reenter.arm64.S index bd74a33bc6344..74941c459d6ac 100644 --- a/compiler-rt/lib/orc/sysv_reenter.arm64.S +++ b/compiler-rt/lib/orc/sysv_reenter.arm64.S @@ -15,7 +15,7 @@ .text - // Saves GPRs, calls __orc_rt_sysv_resolve + // Saves GPRs, calls __orc_rt_resolve .globl __orc_rt_sysv_reenter __orc_rt_sysv_reenter: // Save register state, set up new stack frome. @@ -49,14 +49,14 @@ __orc_rt_sysv_reenter: stp q2, q3, [sp, #-32]! stp q0, q1, [sp, #-32]! - // Look up the return address and subtract 8 from it (on the - // assumption that it's a standard arm64 reentry trampoline) to get - // back the trampoline's address. + // Look up the return address and subtract 8 from it (on the assumption + // that it's a standard arm64 reentry trampoline) to get back the + // trampoline's address. sub x0, x30, #8 - // Call __orc_rt_sysv_resolve to look up the implementation - // corresponding to the calling stub, then store this in x17 (which - // we'll return to below. + // Call __orc_rt_resolve to look up the implementation corresponding to + // the calling stub, then store this in x17 (which we'll return to + // below). #if !defined(__APPLE__) bl __orc_rt_resolve #else diff --git a/compiler-rt/lib/orc/sysv_reenter.x86-64.S b/compiler-rt/lib/orc/sysv_reenter.x86-64.S new file mode 100644 index 0000000000000..0a36280f1d1f8 --- /dev/null +++ b/compiler-rt/lib/orc/sysv_reenter.x86-64.S @@ -0,0 +1,81 @@ +//===-- orc_rt_macho_tlv.x86-64.s -------------------------------*- ASM -*-===// +// +// 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 is a part of the ORC runtime support library. +// +//===----------------------------------------------------------------------===// + +// The content of this file is x86_64-only +#if defined(__x86_64__) + +// Save all GRPS except %rsp. +// This value is also subtracted from %rsp below, despite the fact that %rbp +// has already been pushed, because we need %rsp to stay 16-byte aligned. +#define GPR_SAVE_SPACE_SIZE 15 * 8 +#define FXSAVE64_SAVE_SPACE_SIZE 512 +#define REGISTER_SAVE_SPACE_SIZE \ + GPR_SAVE_SPACE_SIZE + FXSAVE64_SAVE_SPACE_SIZE + + .text + + // returns address of TLV in %rax, all other registers preserved + .globl __orc_rt_sysv_reenter +__orc_rt_sysv_reenter: + pushq %rbp + movq %rsp, %rbp + subq $REGISTER_SAVE_SPACE_SIZE, %rsp + movq %rax, -8(%rbp) + movq %rbx, -16(%rbp) + movq %rcx, -24(%rbp) + movq %rdx, -32(%rbp) + movq %rsi, -40(%rbp) + movq %rdi, -48(%rbp) + movq %r8, -56(%rbp) + movq %r9, -64(%rbp) + movq %r10, -72(%rbp) + movq %r11, -80(%rbp) + movq %r12, -88(%rbp) + movq %r13, -96(%rbp) + movq %r14, -104(%rbp) + movq %r15, -112(%rbp) + fxsave64 (%rsp) + movq 8(%rbp), %rdi + + // Load return address and subtract five from it (on the assumption + // that it's a call instruction). + subq $5, %rdi + + // Call __orc_rt_resolve to look up the implementation corresponding to + // the calling stub, then store this in x17 (which we'll return to + // below). +#if !defined(__APPLE__) + call __orc_rt_resolve +#else + call ___orc_rt_resolve +#endif + movq %rax, 8(%rbp) + fxrstor64 (%rsp) + movq -112(%rbp), %r15 + movq -104(%rbp), %r14 + movq -96(%rbp), %r13 + movq -88(%rbp), %r12 + movq -80(%rbp), %r11 + movq -72(%rbp), %r10 + movq -64(%rbp), %r9 + movq -56(%rbp), %r8 + movq -48(%rbp), %rdi + movq -40(%rbp), %rsi + movq -32(%rbp), %rdx + movq -24(%rbp), %rcx + movq -16(%rbp), %rbx + movq -8(%rbp), %rax + addq $REGISTER_SAVE_SPACE_SIZE, %rsp + popq %rbp + ret + +#endif // defined(__x86_64__) diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp index f076c7eae9a22..f000deb3039a8 100644 --- a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp +++ b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp @@ -46,6 +46,7 @@ void OSSpinLockLock(volatile OSSpinLock *__lock); #include #include #include +#include #include #include #include diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 133eec755bfa5..47436a6cd20f0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -2538,6 +2538,82 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags, #define INIT_GLOB64 #endif // SANITIZER_INTERCEPT_GLOB64 +#if SANITIZER_INTERCEPT___B64_TO +INTERCEPTOR(int, __b64_ntop, unsigned char const *src, SIZE_T srclength, + char *target, SIZE_T targsize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __b64_ntop, src, srclength, target, targsize); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, srclength); + int res = REAL(__b64_ntop)(src, srclength, target, targsize); + if (res >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, target, res + 1); + return res; +} +INTERCEPTOR(int, __b64_pton, char const *src, char *target, SIZE_T targsize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __b64_pton, src, target, targsize); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src) + 1); + int res = REAL(__b64_pton)(src, target, targsize); + if (res >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, target, res); + return res; +} +#define INIT___B64_TO \ + COMMON_INTERCEPT_FUNCTION(__b64_ntop); \ + COMMON_INTERCEPT_FUNCTION(__b64_pton); +#else // SANITIZER_INTERCEPT___B64_TO +#define INIT___B64_TO +#endif // SANITIZER_INTERCEPT___B64_TO + +#if SANITIZER_INTERCEPT_DN_COMP_EXPAND +# if __GLIBC_PREREQ(2, 34) +// Changed with https://sourceware.org/git/?p=glibc.git;h=640bbdf +# define DN_COMP_INTERCEPTOR_NAME dn_comp +# define DN_EXPAND_INTERCEPTOR_NAME dn_expand +# else +# define DN_COMP_INTERCEPTOR_NAME __dn_comp +# define DN_EXPAND_INTERCEPTOR_NAME __dn_expand +# endif +INTERCEPTOR(int, DN_COMP_INTERCEPTOR_NAME, unsigned char *exp_dn, + unsigned char *comp_dn, int length, unsigned char **dnptrs, + unsigned char **lastdnptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, DN_COMP_INTERCEPTOR_NAME, exp_dn, comp_dn, + length, dnptrs, lastdnptr); + int res = REAL(DN_COMP_INTERCEPTOR_NAME)(exp_dn, comp_dn, length, dnptrs, + lastdnptr); + if (res >= 0) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, comp_dn, res); + if (dnptrs && lastdnptr) { + unsigned char **p = dnptrs; + for (; p != lastdnptr && *p; ++p) + ; + if (p != lastdnptr) + ++p; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dnptrs, (p - dnptrs) * sizeof(*p)); + } + } + return res; +} +INTERCEPTOR(int, DN_EXPAND_INTERCEPTOR_NAME, unsigned char const *base, + unsigned char const *end, unsigned char const *src, char *dest, + int space) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, DN_EXPAND_INTERCEPTOR_NAME, base, end, src, + dest, space); + // TODO: add read check if __dn_comp intercept added + int res = REAL(DN_EXPAND_INTERCEPTOR_NAME)(base, end, src, dest, space); + if (res >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, internal_strlen(dest) + 1); + return res; +} +# define INIT_DN_COMP_EXPAND \ + COMMON_INTERCEPT_FUNCTION(DN_COMP_INTERCEPTOR_NAME); \ + COMMON_INTERCEPT_FUNCTION(DN_EXPAND_INTERCEPTOR_NAME); +#else // SANITIZER_INTERCEPT_DN_COMP_EXPAND +# define INIT_DN_COMP_EXPAND +#endif // SANITIZER_INTERCEPT_DN_COMP_EXPAND + #if SANITIZER_INTERCEPT_POSIX_SPAWN template @@ -10270,6 +10346,8 @@ static void InitializeCommonInterceptors() { INIT_TIMESPEC_GET; INIT_GLOB; INIT_GLOB64; + INIT___B64_TO; + INIT_DN_COMP_EXPAND; INIT_POSIX_SPAWN; INIT_WAIT; INIT_WAIT4; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index b4940b66da971..190cad7cf7c3f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -266,6 +266,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #define SANITIZER_INTERCEPT_TIMESPEC_GET SI_LINUX #define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC +#define SANITIZER_INTERCEPT___B64_TO SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_DN_COMP_EXPAND SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_POSIX_SPAWN SI_POSIX #define SANITIZER_INTERCEPT_WAIT SI_POSIX #define SANITIZER_INTERCEPT_INET SI_POSIX diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index cacbb5b9959e0..ea0933ca64af1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -601,7 +601,7 @@ struct __sanitizer_siginfo_pad { #if SANITIZER_LINUX # define SANITIZER_HAS_SIGINFO 1 union __sanitizer_siginfo { - struct { + __extension__ struct { int si_signo; # if SANITIZER_MIPS int si_code; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp index ea513d5f263fe..fd0f989ee392b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -164,7 +164,24 @@ void UnmapOrDie(void *addr, uptr size, bool raw_report) { static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, const char *mmap_type) { error_t last_error = GetLastError(); - if (last_error == ERROR_NOT_ENOUGH_MEMORY) + + // Assumption: VirtualAlloc is the last system call that was invoked before + // this method. + // VirtualAlloc emits one of 3 error codes when running out of memory + // 1. ERROR_NOT_ENOUGH_MEMORY: + // There's not enough memory to execute the command + // 2. ERROR_INVALID_PARAMETER: + // VirtualAlloc will return this if the request would allocate memory at an + // address exceeding or being very close to the maximum application address + // (the `lpMaximumApplicationAddress` field within the `SystemInfo` struct). + // This does not seem to be officially documented, but is corroborated here: + // https://stackoverflow.com/questions/45833674/why-does-virtualalloc-fail-for-lpaddress-greater-than-0x6ffffffffff + // 3. ERROR_COMMITMENT_LIMIT: + // VirtualAlloc will return this if e.g. the pagefile is too small to commit + // the requested amount of memory. + if (last_error == ERROR_NOT_ENOUGH_MEMORY || + last_error == ERROR_INVALID_PARAMETER || + last_error == ERROR_COMMITMENT_LIMIT) return nullptr; ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); } diff --git a/compiler-rt/lib/scudo/standalone/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/CMakeLists.txt index dc700cec9becb..3f9ae866a7553 100644 --- a/compiler-rt/lib/scudo/standalone/CMakeLists.txt +++ b/compiler-rt/lib/scudo/standalone/CMakeLists.txt @@ -98,6 +98,7 @@ set(SCUDO_HEADERS tsd_exclusive.h tsd_shared.h tsd.h + type_traits.h vector.h wrappers_c_checks.h wrappers_c.h diff --git a/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h b/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h index 5477236ac1f39..ea12a5b1447f6 100644 --- a/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h +++ b/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h @@ -12,35 +12,7 @@ #include "condition_variable.h" #include "internal_defs.h" #include "secondary.h" - -namespace { - -template struct removeConst { - using type = T; -}; -template struct removeConst { - using type = T; -}; - -// This is only used for SFINAE when detecting if a type is defined. -template struct voidAdaptor { - using type = void; -}; - -// This is used for detecting the case that defines the flag with wrong type and -// it'll be viewed as undefined optional flag. -template struct assertSameType { - template struct isSame { - static constexpr bool value = false; - }; - template struct isSame { - static constexpr bool value = true; - }; - static_assert(isSame::value, "Flag type mismatches"); - using type = R; -}; - -} // namespace +#include "type_traits.h" namespace scudo { diff --git a/compiler-rt/lib/scudo/standalone/list.h b/compiler-rt/lib/scudo/standalone/list.h index c6bd32a8fa325..e0b82788251b7 100644 --- a/compiler-rt/lib/scudo/standalone/list.h +++ b/compiler-rt/lib/scudo/standalone/list.h @@ -10,17 +10,7 @@ #define SCUDO_LIST_H_ #include "internal_defs.h" - -// TODO: Move the helpers to a header. -namespace { -template struct isPointer { - static constexpr bool value = false; -}; - -template struct isPointer { - static constexpr bool value = true; -}; -} // namespace +#include "type_traits.h" namespace scudo { @@ -58,10 +48,11 @@ class LinkOp { template class LinkOp { public: - using LinkTy = decltype(T::Next); + using LinkTy = typename assertSameType< + typename removeConst::type, + typename removeConst::type>::type; LinkOp() = default; - // TODO: Check if the `BaseSize` can fit in `Size`. LinkOp(T *BaseT, uptr BaseSize) : Base(BaseT), Size(static_cast(BaseSize)) {} void init(T *LinkBase, uptr BaseSize) { @@ -80,11 +71,12 @@ template class LinkOp { } // Set `X->Next` to `Next`. void setNext(T *X, T *Next) const { - // TODO: Check if the offset fits in the size of `LinkTy`. - if (Next == nullptr) + if (Next == nullptr) { X->Next = getEndOfListVal(); - else + } else { + assertElementInRange(Next); X->Next = static_cast(Next - Base); + } } T *getPrev(T *X) const { @@ -96,17 +88,22 @@ template class LinkOp { } // Set `X->Prev` to `Prev`. void setPrev(T *X, T *Prev) const { - DCHECK_LT(reinterpret_cast(Prev), - reinterpret_cast(Base + Size)); - if (Prev == nullptr) + if (Prev == nullptr) { X->Prev = getEndOfListVal(); - else + } else { + assertElementInRange(Prev); X->Prev = static_cast(Prev - Base); + } } - // TODO: `LinkTy` should be the same as decltype(T::EndOfListVal). LinkTy getEndOfListVal() const { return T::EndOfListVal; } +private: + void assertElementInRange(T *X) const { + DCHECK_GE(reinterpret_cast(X), reinterpret_cast(Base)); + DCHECK_LE(static_cast(X - Base), Size); + } + protected: T *Base = nullptr; LinkTy Size = 0; diff --git a/compiler-rt/lib/scudo/standalone/type_traits.h b/compiler-rt/lib/scudo/standalone/type_traits.h new file mode 100644 index 0000000000000..16ed5a048f82b --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/type_traits.h @@ -0,0 +1,47 @@ +//===-- type_traits.h -------------------------------------------*- 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 SCUDO_TYPE_TRAITS_H_ +#define SCUDO_TYPE_TRAITS_H_ + +namespace scudo { + +template struct removeConst { + using type = T; +}; +template struct removeConst { + using type = T; +}; + +// This is only used for SFINAE when detecting if a type is defined. +template struct voidAdaptor { + using type = void; +}; + +template struct assertSameType { + template struct isSame { + static constexpr bool value = false; + }; + template struct isSame { + static constexpr bool value = true; + }; + static_assert(isSame::value, "Type mismatches"); + using type = R; +}; + +template struct isPointer { + static constexpr bool value = false; +}; + +template struct isPointer { + static constexpr bool value = true; +}; + +} // namespace scudo + +#endif // SCUDO_TYPE_TRAITS_H_ diff --git a/compiler-rt/lib/tysan/CMakeLists.txt b/compiler-rt/lib/tysan/CMakeLists.txt new file mode 100644 index 0000000000000..859b67928f004 --- /dev/null +++ b/compiler-rt/lib/tysan/CMakeLists.txt @@ -0,0 +1,64 @@ +include_directories(..) + +# Runtime library sources and build flags. +set(TYSAN_SOURCES + tysan.cpp + tysan_interceptors.cpp) +set(TYSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF TYSAN_COMMON_CFLAGS) +# Prevent clang from generating libc calls. +append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding TYSAN_COMMON_CFLAGS) + +add_compiler_rt_object_libraries(RTTysan_dynamic + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${TYSAN_SUPPORTED_ARCH} + SOURCES ${TYSAN_SOURCES} + ADDITIONAL_HEADERS ${TYSAN_HEADERS} + CFLAGS ${TYSAN_DYNAMIC_CFLAGS} + DEFS ${TYSAN_DYNAMIC_DEFINITIONS}) + + +# Static runtime library. +add_compiler_rt_component(tysan) + + +if(APPLE) + add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS) + + add_compiler_rt_runtime(clang_rt.tysan + SHARED + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${TYSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTTysan_dynamic + RTInterception + RTSanitizerCommon + RTSanitizerCommonLibc + RTSanitizerCommonSymbolizer + CFLAGS ${TYSAN_DYNAMIC_CFLAGS} + LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS} + DEFS ${TYSAN_DYNAMIC_DEFINITIONS} + PARENT_TARGET tysan) + + add_compiler_rt_runtime(clang_rt.tysan_static + STATIC + ARCHS ${TYSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTTysan_static + CFLAGS ${TYSAN_CFLAGS} + DEFS ${TYSAN_COMMON_DEFINITIONS} + PARENT_TARGET tysan) +else() + foreach(arch ${TYSAN_SUPPORTED_ARCH}) + set(TYSAN_CFLAGS ${TYSAN_COMMON_CFLAGS}) + append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TYSAN_CFLAGS) + add_compiler_rt_runtime(clang_rt.tysan + STATIC + ARCHS ${arch} + SOURCES ${TYSAN_SOURCES} + $ + $ + $ + $ + CFLAGS ${TYSAN_CFLAGS} + PARENT_TARGET tysan) + endforeach() +endif() diff --git a/compiler-rt/lib/tysan/lit.cfg b/compiler-rt/lib/tysan/lit.cfg new file mode 100644 index 0000000000000..e3ef6c9c97147 --- /dev/null +++ b/compiler-rt/lib/tysan/lit.cfg @@ -0,0 +1,35 @@ +# -*- Python -*- + +import os + +# Setup config name. +config.name = 'TypeSanitizer' + getattr(config, 'name_suffix', 'default') + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Setup default compiler flags used with -fsanitize=type option. +clang_tysan_cflags = (["-fsanitize=type", + "-mno-omit-leaf-frame-pointer", + "-fno-omit-frame-pointer", + "-fno-optimize-sibling-calls"] + + config.target_cflags + + config.debug_info_flags) +clang_tysan_cxxflags = config.cxx_mode_flags + clang_tysan_cflags + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + +config.substitutions.append( ("%clang_tysan ", build_invocation(clang_tysan_cflags)) ) +config.substitutions.append( ("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags)) ) + +# Default test suffixes. +config.suffixes = ['.c', '.cc', '.cpp'] + +# TypeSanitizer tests are currently supported on Linux only. +if config.host_os not in ['Linux']: + config.unsupported = True + +if config.target_arch != 'aarch64': + config.available_features.add('stable-runtime') + diff --git a/compiler-rt/lib/tysan/lit.site.cfg.in b/compiler-rt/lib/tysan/lit.site.cfg.in new file mode 100644 index 0000000000000..673d04e514379 --- /dev/null +++ b/compiler-rt/lib/tysan/lit.site.cfg.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@TYSAN_TEST_CONFIG_SUFFIX@" +config.target_cflags = "@TYSAN_TEST_TARGET_CFLAGS@" +config.target_arch = "@TYSAN_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@TYSAN_LIT_SOURCE_DIR@/lit.cfg") diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp new file mode 100644 index 0000000000000..39d78e7c95e0c --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -0,0 +1,346 @@ +//===-- tysan.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 file is a part of TypeSanitizer. +// +// TypeSanitizer runtime. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_symbolizer.h" + +#include "tysan/tysan.h" + +#include + +using namespace __sanitizer; +using namespace __tysan; + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +tysan_set_type_unknown(const void *addr, uptr size) { + if (tysan_inited) + internal_memset(shadow_for(addr), 0, size * sizeof(uptr)); +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +tysan_copy_types(const void *daddr, const void *saddr, uptr size) { + if (tysan_inited) + internal_memmove(shadow_for(daddr), shadow_for(saddr), size * sizeof(uptr)); +} + +static const char *getDisplayName(const char *Name) { + if (Name[0] == '\0') + return ""; + + // Clang generates tags for C++ types that demangle as typeinfo. Remove the + // prefix from the generated string. + const char *TIPrefix = "typeinfo name for "; + size_t TIPrefixLen = strlen(TIPrefix); + + const char *DName = Symbolizer::GetOrInit()->Demangle(Name); + if (!internal_strncmp(DName, TIPrefix, TIPrefixLen)) + DName += TIPrefixLen; + + return DName; +} + +static void printTDName(tysan_type_descriptor *td) { + if (((sptr)td) <= 0) { + Printf(""); + return; + } + + switch (td->Tag) { + default: + CHECK(false && "invalid enum value"); + break; + case TYSAN_MEMBER_TD: + printTDName(td->Member.Access); + if (td->Member.Access != td->Member.Base) { + Printf(" (in "); + printTDName(td->Member.Base); + Printf(" at offset %zu)", td->Member.Offset); + } + break; + case TYSAN_STRUCT_TD: + Printf("%s", getDisplayName( + (char *)(td->Struct.Members + td->Struct.MemberCount))); + break; + } +} + +static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) { + tysan_type_descriptor *RootTD = TD; + + do { + RootTD = TD; + + if (TD->Tag == TYSAN_STRUCT_TD) { + if (TD->Struct.MemberCount > 0) + TD = TD->Struct.Members[0].Type; + else + TD = nullptr; + } else if (TD->Tag == TYSAN_MEMBER_TD) { + TD = TD->Member.Access; + } else { + CHECK(false && "invalid enum value"); + break; + } + } while (TD); + + return RootTD; +} + +static bool isAliasingLegalUp(tysan_type_descriptor *TDA, + tysan_type_descriptor *TDB, int TDAOffset) { + // Walk up the tree starting with TDA to see if we reach TDB. + uptr OffsetA = 0, OffsetB = 0; + if (TDB->Tag == TYSAN_MEMBER_TD) { + OffsetB = TDB->Member.Offset; + TDB = TDB->Member.Base; + } + + if (TDA->Tag == TYSAN_MEMBER_TD) { + OffsetA = TDA->Member.Offset - TDAOffset; + TDA = TDA->Member.Base; + } + + do { + if (TDA == TDB) + return OffsetA == OffsetB; + + if (TDA->Tag == TYSAN_STRUCT_TD) { + // Reached root type descriptor. + if (!TDA->Struct.MemberCount) + break; + + uptr Idx = 0; + for (; Idx < TDA->Struct.MemberCount - 1; ++Idx) { + if (TDA->Struct.Members[Idx].Offset >= OffsetA) + break; + } + + OffsetA -= TDA->Struct.Members[Idx].Offset; + TDA = TDA->Struct.Members[Idx].Type; + } else { + CHECK(false && "invalid enum value"); + break; + } + } while (TDA); + + return false; +} + +static bool isAliasingLegal(tysan_type_descriptor *TDA, + tysan_type_descriptor *TDB, int TDAOffset = 0) { + if (TDA == TDB || !TDB || !TDA) + return true; + + // Aliasing is legal is the two types have different root nodes. + if (getRootTD(TDA) != getRootTD(TDB)) + return true; + + // TDB may have been adjusted by offset TDAOffset in the caller to point to + // the outer type. Check for aliasing with and without adjusting for this + // offset. + return isAliasingLegalUp(TDA, TDB, 0) || isAliasingLegalUp(TDB, TDA, 0) || + isAliasingLegalUp(TDA, TDB, TDAOffset); +} + +namespace __tysan { +class Decorator : public __sanitizer::SanitizerCommonDecorator { +public: + Decorator() : SanitizerCommonDecorator() {} + const char *Warning() { return Red(); } + const char *Name() { return Green(); } + const char *End() { return Default(); } +}; +} // namespace __tysan + +ALWAYS_INLINE +static void reportError(void *Addr, int Size, tysan_type_descriptor *TD, + tysan_type_descriptor *OldTD, const char *AccessStr, + const char *DescStr, int Offset, uptr pc, uptr bp, + uptr sp) { + Decorator d; + Printf("%s", d.Warning()); + Report("ERROR: TypeSanitizer: type-aliasing-violation on address %p" + " (pc %p bp %p sp %p tid %llu)\n", + Addr, (void *)pc, (void *)bp, (void *)sp, GetTid()); + Printf("%s", d.End()); + Printf("%s of size %d at %p with type ", AccessStr, Size, Addr); + + Printf("%s", d.Name()); + printTDName(TD); + Printf("%s", d.End()); + + Printf(" %s of type ", DescStr); + + Printf("%s", d.Name()); + printTDName(OldTD); + Printf("%s", d.End()); + + if (Offset != 0) + Printf(" that starts at offset %d\n", Offset); + else + Printf("\n"); + + if (pc) { + + bool request_fast = StackTrace::WillUseFastUnwind(true); + BufferedStackTrace ST; + ST.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, request_fast); + ST.Print(); + } else { + Printf("\n"); + } +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { + GET_CALLER_PC_BP_SP; + + bool IsRead = flags & 1; + bool IsWrite = flags & 2; + const char *AccessStr; + if (IsRead && !IsWrite) + AccessStr = "READ"; + else if (!IsRead && IsWrite) + AccessStr = "WRITE"; + else + AccessStr = "ATOMIC UPDATE"; + + tysan_type_descriptor **OldTDPtr = shadow_for(addr); + tysan_type_descriptor *OldTD = *OldTDPtr; + if (((sptr)OldTD) < 0) { + int i = -((sptr)OldTD); + OldTDPtr -= i; + OldTD = *OldTDPtr; + + if (!isAliasingLegal(td, OldTD, i)) + reportError(addr, size, td, OldTD, AccessStr, + "accesses part of an existing object", -i, pc, bp, sp); + + return; + } + + if (!isAliasingLegal(td, OldTD)) { + reportError(addr, size, td, OldTD, AccessStr, "accesses an existing object", + 0, pc, bp, sp); + return; + } + + // These types are allowed to alias (or the stored type is unknown), report + // an error if we find an interior type. + + for (int i = 0; i < size; ++i) { + OldTDPtr = shadow_for((void *)(((uptr)addr) + i)); + OldTD = *OldTDPtr; + if (((sptr)OldTD) >= 0 && !isAliasingLegal(td, OldTD)) + reportError(addr, size, td, OldTD, AccessStr, + "partially accesses an object", i, pc, bp, sp); + } +} + +Flags __tysan::flags_data; + +SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_shadow_memory_address; +SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_app_memory_mask; + +#ifdef TYSAN_RUNTIME_VMA +// Runtime detected VMA size. +int __tysan::vmaSize; +#endif + +void Flags::SetDefaults() { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "tysan_flags.inc" +#undef TYSAN_FLAG +} + +static void RegisterTySanFlags(FlagParser *parser, Flags *f) { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &f->Name); +#include "tysan_flags.inc" +#undef TYSAN_FLAG +} + +static void InitializeFlags() { + SetCommonFlagsDefaults(); + { + CommonFlags cf; + cf.CopyFrom(*common_flags()); + cf.external_symbolizer_path = GetEnv("TYSAN_SYMBOLIZER_PATH"); + OverrideCommonFlags(cf); + } + + flags().SetDefaults(); + + FlagParser parser; + RegisterCommonFlags(&parser); + RegisterTySanFlags(&parser, &flags()); + parser.ParseString(GetEnv("TYSAN_OPTIONS")); + InitializeCommonFlags(); + if (Verbosity()) + ReportUnrecognizedFlags(); + if (common_flags()->help) + parser.PrintFlagDescriptions(); +} + +static void TySanInitializePlatformEarly() { + AvoidCVE_2016_2143(); +#ifdef TYSAN_RUNTIME_VMA + vmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); +#if defined(__aarch64__) && !SANITIZER_APPLE + if (vmaSize != 39 && vmaSize != 42 && vmaSize != 48) { + Printf("FATAL: TypeSanitizer: unsupported VMA range\n"); + Printf("FATAL: Found %d - Supported 39, 42 and 48\n", vmaSize); + Die(); + } +#endif +#endif + + __sanitizer::InitializePlatformEarly(); + + __tysan_shadow_memory_address = ShadowAddr(); + __tysan_app_memory_mask = AppMask(); +} + +namespace __tysan { +bool tysan_inited = false; +bool tysan_init_is_running; +} // namespace __tysan + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tysan_init() { + CHECK(!tysan_init_is_running); + if (tysan_inited) + return; + tysan_init_is_running = true; + + InitializeFlags(); + TySanInitializePlatformEarly(); + + InitializeInterceptors(); + + if (!MmapFixedNoReserve(ShadowAddr(), AppAddr() - ShadowAddr())) + Die(); + + tysan_init_is_running = false; + tysan_inited = true; +} + +#if SANITIZER_CAN_USE_PREINIT_ARRAY +__attribute__((section(".preinit_array"), + used)) static void (*tysan_init_ptr)() = __tysan_init; +#endif diff --git a/compiler-rt/lib/tysan/tysan.h b/compiler-rt/lib/tysan/tysan.h new file mode 100644 index 0000000000000..97df28037b0d2 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.h @@ -0,0 +1,78 @@ +//===-- tysan.h -------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file is a part of TypeSanitizer. +// +// Private TySan header. +//===----------------------------------------------------------------------===// + +#ifndef TYSAN_H +#define TYSAN_H + +#include "sanitizer_common/sanitizer_internal_defs.h" + +using __sanitizer::sptr; +using __sanitizer::u16; +using __sanitizer::uptr; + +#include "tysan_platform.h" + +extern "C" { +void tysan_set_type_unknown(const void *addr, uptr size); +void tysan_copy_types(const void *daddr, const void *saddr, uptr size); +} + +namespace __tysan { +extern bool tysan_inited; +extern bool tysan_init_is_running; + +void InitializeInterceptors(); + +enum { TYSAN_MEMBER_TD = 1, TYSAN_STRUCT_TD = 2 }; + +struct tysan_member_type_descriptor { + struct tysan_type_descriptor *Base; + struct tysan_type_descriptor *Access; + uptr Offset; +}; + +struct tysan_struct_type_descriptor { + uptr MemberCount; + struct { + struct tysan_type_descriptor *Type; + uptr Offset; + } Members[1]; // Tail allocated. +}; + +struct tysan_type_descriptor { + uptr Tag; + union { + tysan_member_type_descriptor Member; + tysan_struct_type_descriptor Struct; + }; +}; + +inline tysan_type_descriptor **shadow_for(const void *ptr) { + return (tysan_type_descriptor **)((((uptr)ptr) & AppMask()) * sizeof(ptr) + + ShadowAddr()); +} + +struct Flags { +#define TYSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "tysan_flags.inc" +#undef TYSAN_FLAG + + void SetDefaults(); +}; + +extern Flags flags_data; +inline Flags &flags() { return flags_data; } + +} // namespace __tysan + +#endif // TYSAN_H diff --git a/compiler-rt/lib/tysan/tysan.syms.extra b/compiler-rt/lib/tysan/tysan.syms.extra new file mode 100644 index 0000000000000..04e7854316199 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan.syms.extra @@ -0,0 +1,2 @@ +tysan_* +__tysan_* diff --git a/compiler-rt/lib/tysan/tysan_flags.inc b/compiler-rt/lib/tysan/tysan_flags.inc new file mode 100644 index 0000000000000..98b6591f844ef --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_flags.inc @@ -0,0 +1,17 @@ +//===-- tysan_flags.inc ---------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// TySan runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef TYSAN_FLAG +#error "Define TYSAN_FLAG prior to including this file!" +#endif + +// TYSAN_FLAG(Type, Name, DefaultValue, Description) +// See COMMON_FLAG in sanitizer_flags.inc for more details. diff --git a/compiler-rt/lib/tysan/tysan_interceptors.cpp b/compiler-rt/lib/tysan/tysan_interceptors.cpp new file mode 100644 index 0000000000000..5fc6f24412272 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_interceptors.cpp @@ -0,0 +1,250 @@ +//===-- tysan_interceptors.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 file is a part of TypeSanitizer. +// +// Interceptors for standard library functions. +//===----------------------------------------------------------------------===// + +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_common.h" +#include "tysan/tysan.h" + +#if SANITIZER_LINUX && !SANITIZER_ANDROID +#define TYSAN_INTERCEPT___STRDUP 1 +#else +#define TYSAN_INTERCEPT___STRDUP 0 +#endif + +#if SANITIZER_LINUX +extern "C" int mallopt(int param, int value); +#endif + +using namespace __sanitizer; +using namespace __tysan; + +static const uptr early_alloc_buf_size = 16384; +static uptr allocated_bytes; +static char early_alloc_buf[early_alloc_buf_size]; + +static bool isInEarlyAllocBuf(const void *ptr) { + return ((uptr)ptr >= (uptr)early_alloc_buf && + ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf)); +} + +// Handle allocation requests early (before all interceptors are setup). dlsym, +// for example, calls calloc. +static void *handleEarlyAlloc(uptr size) { + void *mem = (void *)&early_alloc_buf[allocated_bytes]; + allocated_bytes += size; + CHECK_LT(allocated_bytes, early_alloc_buf_size); + return mem; +} + +INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { + if (!tysan_inited && REAL(memset) == nullptr) + return internal_memset(dst, v, size); + + void *res = REAL(memset)(dst, v, size); + tysan_set_type_unknown(dst, size); + return res; +} + +INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { + if (!tysan_inited && REAL(memmove) == nullptr) + return internal_memmove(dst, src, size); + + void *res = REAL(memmove)(dst, src, size); + tysan_copy_types(dst, src, size); + return res; +} + +INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { + if (!tysan_inited && REAL(memcpy) == nullptr) { + // memmove is used here because on some platforms this will also + // intercept the memmove implementation. + return internal_memmove(dst, src, size); + } + + void *res = REAL(memcpy)(dst, src, size); + tysan_copy_types(dst, src, size); + return res; +} + +INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, + int fd, OFF_T offset) { + void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) + tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize())); + return res; +} + +#if !SANITIZER_APPLE +INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, + int fd, OFF64_T offset) { + void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) + tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize())); + return res; +} +#endif + +INTERCEPTOR(char *, strdup, const char *s) { + char *res = REAL(strdup)(s); + if (res) + tysan_copy_types(res, const_cast(s), internal_strlen(s)); + return res; +} + +#if TYSAN_INTERCEPT___STRDUP +INTERCEPTOR(char *, __strdup, const char *s) { + char *res = REAL(__strdup)(s); + if (res) + tysan_copy_types(res, const_cast(s), internal_strlen(s)); + return res; +} +#endif // TYSAN_INTERCEPT___STRDUP + +INTERCEPTOR(void *, malloc, uptr size) { + if (tysan_init_is_running && REAL(malloc) == nullptr) + return handleEarlyAlloc(size); + + void *res = REAL(malloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +INTERCEPTOR(void *, realloc, void *ptr, uptr size) { + void *res = REAL(realloc)(ptr, size); + // We might want to copy the types from the original allocation (although + // that would require that we knew its size). + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) { + if (tysan_init_is_running && REAL(calloc) == nullptr) + return handleEarlyAlloc(nmemb * size); + + void *res = REAL(calloc)(nmemb, size); + if (res) + tysan_set_type_unknown(res, nmemb * size); + return res; +} + +INTERCEPTOR(void, free, void *p) { + // There are only a few early allocation requests, + // so we simply skip the free. + if (isInEarlyAllocBuf(p)) + return; + REAL(free)(p); +} + +INTERCEPTOR(void *, valloc, uptr size) { + void *res = REAL(valloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} + +#if SANITIZER_INTERCEPT_MEMALIGN +INTERCEPTOR(void *, memalign, uptr alignment, uptr size) { + void *res = REAL(memalign)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) +#else +#define TYSAN_MAYBE_INTERCEPT_MEMALIGN +#endif // SANITIZER_INTERCEPT_MEMALIGN + +#if SANITIZER_INTERCEPT___LIBC_MEMALIGN +INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { + void *res = REAL(__libc_memalign)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN \ + INTERCEPT_FUNCTION(__libc_memalign) +#else +#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN +#endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN + +#if SANITIZER_INTERCEPT_PVALLOC +INTERCEPTOR(void *, pvalloc, uptr size) { + void *res = REAL(pvalloc)(size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) +#else +#define TYSAN_MAYBE_INTERCEPT_PVALLOC +#endif // SANITIZER_INTERCEPT_PVALLOC + +#if SANITIZER_INTERCEPT_ALIGNED_ALLOC +INTERCEPTOR(void *, aligned_alloc, uptr alignment, uptr size) { + void *res = REAL(aligned_alloc)(alignment, size); + if (res) + tysan_set_type_unknown(res, size); + return res; +} +#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) +#else +#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC +#endif + +INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { + int res = REAL(posix_memalign)(memptr, alignment, size); + if (res == 0 && *memptr) + tysan_set_type_unknown(*memptr, size); + return res; +} + +namespace __tysan { +void InitializeInterceptors() { + static int inited = 0; + CHECK_EQ(inited, 0); + + // Instruct libc malloc to consume less memory. +#if SANITIZER_LINUX + mallopt(1, 0); // M_MXFAST + mallopt(-3, 32 * 1024); // M_MMAP_THRESHOLD +#endif + + INTERCEPT_FUNCTION(mmap); + + INTERCEPT_FUNCTION(mmap64); + + INTERCEPT_FUNCTION(strdup); +#if TYSAN_INTERCEPT___STRDUP + INTERCEPT_FUNCTION(__strdup); +#endif + + INTERCEPT_FUNCTION(malloc); + INTERCEPT_FUNCTION(calloc); + INTERCEPT_FUNCTION(free); + INTERCEPT_FUNCTION(realloc); + INTERCEPT_FUNCTION(valloc); + TYSAN_MAYBE_INTERCEPT_MEMALIGN; + TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; + TYSAN_MAYBE_INTERCEPT_PVALLOC; + TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC + INTERCEPT_FUNCTION(posix_memalign); + + INTERCEPT_FUNCTION(memset); + INTERCEPT_FUNCTION(memmove); + INTERCEPT_FUNCTION(memcpy); + + inited = 1; +} +} // namespace __tysan diff --git a/compiler-rt/lib/tysan/tysan_platform.h b/compiler-rt/lib/tysan/tysan_platform.h new file mode 100644 index 0000000000000..f01392885d939 --- /dev/null +++ b/compiler-rt/lib/tysan/tysan_platform.h @@ -0,0 +1,93 @@ +//===------------------------ tysan_platform.h ----------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file is a part of TypeSanitizer. +// +// Platform specific information for TySan. +//===----------------------------------------------------------------------===// + +#ifndef TYSAN_PLATFORM_H +#define TYSAN_PLATFORM_H + +namespace __tysan { + +#if defined(__x86_64__) || SANITIZER_APPLE +struct Mapping { + static const uptr kShadowAddr = 0x010000000000ull; + static const uptr kAppAddr = 0x550000000000ull; + static const uptr kAppMemMsk = ~0x780000000000ull; +}; +#elif defined(__aarch64__) +struct Mapping39 { + static const uptr kShadowAddr = 0x0800000000ull; + static const uptr kAppAddr = 0x5500000000ull; + static const uptr kAppMemMsk = ~0x7800000000ull; +}; + +struct Mapping42 { + static const uptr kShadowAddr = 0x10000000000ull; + static const uptr kAppAddr = 0x2aa00000000ull; + static const uptr kAppMemMsk = ~0x3c000000000ull; +}; + +struct Mapping48 { + static const uptr kShadowAddr = 0x0002000000000ull; + static const uptr kAppAddr = 0x0aaaa00000000ull; + static const uptr kAppMemMsk = ~0x0fff800000000ull; +}; +#define TYSAN_RUNTIME_VMA 1 +#else +#error "TySan not supported for this platform!" +#endif + +#if TYSAN_RUNTIME_VMA +extern int vmaSize; +#endif + +enum MappingType { MAPPING_SHADOW_ADDR, MAPPING_APP_ADDR, MAPPING_APP_MASK }; + +template uptr MappingImpl(void) { + switch (Type) { + case MAPPING_SHADOW_ADDR: + return Mapping::kShadowAddr; + case MAPPING_APP_ADDR: + return Mapping::kAppAddr; + case MAPPING_APP_MASK: + return Mapping::kAppMemMsk; + } +} + +template uptr MappingArchImpl(void) { +#if defined(__aarch64__) && !SANITIZER_APPLE + switch (vmaSize) { + case 39: + return MappingImpl(); + case 42: + return MappingImpl(); + case 48: + return MappingImpl(); + } + DCHECK(0); + return 0; +#else + return MappingImpl(); +#endif +} + +ALWAYS_INLINE +uptr ShadowAddr() { return MappingArchImpl(); } + +ALWAYS_INLINE +uptr AppAddr() { return MappingArchImpl(); } + +ALWAYS_INLINE +uptr AppMask() { return MappingArchImpl(); } + +} // namespace __tysan + +#endif diff --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp index 53a3273e4e698..98662c5881c9f 100644 --- a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp +++ b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp @@ -20,12 +20,42 @@ static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs]; // that "too many errors" has already been reported. static __sanitizer::atomic_uint32_t caller_pcs_sz; -__attribute__((noinline)) static bool report_this_error(uintptr_t caller) { +static char *append_str(const char *s, char *buf, const char *end) { + for (const char *p = s; (buf < end) && (*p != '\0'); ++p, ++buf) + *buf = *p; + return buf; +} + +static char *append_hex(uintptr_t d, char *buf, const char *end) { + // Print the address by nibbles. + for (unsigned shift = sizeof(uintptr_t) * 8; shift && buf < end;) { + shift -= 4; + unsigned nibble = (d >> shift) & 0xf; + *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a'; + } + return buf; +} + +static void format_msg(const char *kind, uintptr_t caller, char *buf, + const char *end) { + buf = append_str("ubsan: ", buf, end); + buf = append_str(kind, buf, end); + buf = append_str(" by 0x", buf, end); + buf = append_hex(caller, buf, end); + buf = append_str("\n", buf, end); + if (buf == end) + --buf; // Make sure we don't cause a buffer overflow. + *buf = '\0'; +} + +SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind, + uintptr_t caller) { if (caller == 0) - return false; + return; while (true) { unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz); - if (sz > kMaxCallerPcs) return false; // early exit + if (sz > kMaxCallerPcs) + return; // early exit // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg // succeeds in order to not print it multiple times. if (sz > 0 && sz < kMaxCallerPcs) { @@ -33,7 +63,8 @@ __attribute__((noinline)) static bool report_this_error(uintptr_t caller) { for (unsigned i = 0; i < sz; ++i) { p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]); if (p == 0) break; // Concurrent update. - if (p == caller) return false; + if (p == caller) + return; } if (p == 0) continue; // FIXME: yield? } @@ -44,34 +75,27 @@ __attribute__((noinline)) static bool report_this_error(uintptr_t caller) { if (sz == kMaxCallerPcs) { message("ubsan: too many errors\n"); - return false; + return; } __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller); - return true; - } -} -__attribute__((noinline)) static void decorate_msg(char *buf, - uintptr_t caller) { - // print the address by nibbles - for (unsigned shift = sizeof(uintptr_t) * 8; shift;) { - shift -= 4; - unsigned nibble = (caller >> shift) & 0xf; - *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a'; + char msg_buf[128]; + format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf)); + message(msg_buf); } - // finish the message - buf[0] = '\n'; - buf[1] = '\0'; } #if defined(__ANDROID__) extern "C" __attribute__((weak)) void android_set_abort_message(const char *); -static void abort_with_message(const char *msg) { - if (&android_set_abort_message) android_set_abort_message(msg); +static void abort_with_message(const char *kind, uintptr_t caller) { + char msg_buf[128]; + format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf)); + if (&android_set_abort_message) + android_set_abort_message(msg_buf); abort(); } #else -static void abort_with_message(const char *) { abort(); } +static void abort_with_message(const char *kind, uintptr_t caller) { abort(); } #endif #if SANITIZER_DEBUG @@ -89,33 +113,21 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { #define INTERFACE extern "C" __attribute__((visibility("default"))) -// How many chars we need to reserve to print an address. -constexpr unsigned kAddrBuf = SANITIZER_WORDSIZE / 4; -#define MSG_TMPL(msg) "ubsan: " msg " by 0x" -#define MSG_TMPL_END(buf, msg) (buf + sizeof(MSG_TMPL(msg)) - 1) -// Reserve an additional byte for '\n'. -#define MSG_BUF_LEN(msg) (sizeof(MSG_TMPL(msg)) + kAddrBuf + 1) - -#define HANDLER_RECOVER(name, msg) \ - INTERFACE void __ubsan_handle_##name##_minimal() { \ - uintptr_t caller = GET_CALLER_PC(); \ - if (!report_this_error(caller)) return; \ - char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg); \ - decorate_msg(MSG_TMPL_END(msg_buf, msg), caller); \ - message(msg_buf); \ +#define HANDLER_RECOVER(name, kind) \ + INTERFACE void __ubsan_handle_##name##_minimal() { \ + __ubsan_report_error(kind, GET_CALLER_PC()); \ } -#define HANDLER_NORECOVER(name, msg) \ - INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ - char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg); \ - decorate_msg(MSG_TMPL_END(msg_buf, msg), GET_CALLER_PC()); \ - message(msg_buf); \ - abort_with_message(msg_buf); \ +#define HANDLER_NORECOVER(name, kind) \ + INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ + uintptr_t caller = GET_CALLER_PC(); \ + __ubsan_report_error(kind, caller); \ + abort_with_message(kind, caller); \ } -#define HANDLER(name, msg) \ - HANDLER_RECOVER(name, msg) \ - HANDLER_NORECOVER(name, msg) +#define HANDLER(name, kind) \ + HANDLER_RECOVER(name, kind) \ + HANDLER_NORECOVER(name, kind) HANDLER(type_mismatch, "type-mismatch") HANDLER(alignment_assumption, "alignment-assumption") diff --git a/compiler-rt/lib/xray/CMakeLists.txt b/compiler-rt/lib/xray/CMakeLists.txt index 7e3f1a0aa616e..e7f01a2f4f164 100644 --- a/compiler-rt/lib/xray/CMakeLists.txt +++ b/compiler-rt/lib/xray/CMakeLists.txt @@ -96,6 +96,16 @@ set(hexagon_SOURCES xray_trampoline_hexagon.S ) +set(riscv32_SOURCES + xray_riscv.cpp + xray_trampoline_riscv32.S + ) + +set(riscv64_SOURCES + xray_riscv.cpp + xray_trampoline_riscv64.S + ) + set(XRAY_SOURCE_ARCHS arm armhf @@ -156,6 +166,8 @@ set(XRAY_ALL_SOURCE_FILES ${mips64_SOURCES} ${mips64el_SOURCES} ${powerpc64le_SOURCES} + ${riscv32_SOURCES} + ${riscv64_SOURCES} ${XRAY_IMPL_HEADERS} ) list(REMOVE_DUPLICATES XRAY_ALL_SOURCE_FILES) diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp index b6f0e6762f168..4ec492c266d80 100644 --- a/compiler-rt/lib/xray/xray_interface.cpp +++ b/compiler-rt/lib/xray/xray_interface.cpp @@ -57,6 +57,10 @@ static const int16_t cSledLength = 64; static const int16_t cSledLength = 8; #elif defined(__hexagon__) static const int16_t cSledLength = 20; +#elif defined(__riscv) && (__riscv_xlen == 64) +static const int16_t cSledLength = 68; +#elif defined(__riscv) && (__riscv_xlen == 32) +static const int16_t cSledLength = 52; #else #error "Unsupported CPU Architecture" #endif /* CPU architecture */ diff --git a/compiler-rt/lib/xray/xray_riscv.cpp b/compiler-rt/lib/xray/xray_riscv.cpp new file mode 100644 index 0000000000000..e3a7cdb18b640 --- /dev/null +++ b/compiler-rt/lib/xray/xray_riscv.cpp @@ -0,0 +1,266 @@ +//===-- xray_riscv.cpp ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// Implementation of RISC-V specific routines (32- and 64-bit). +// +//===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_common.h" +#include "xray_defs.h" +#include "xray_interface_internal.h" +#include + +namespace __xray { + +// The machine codes for some instructions used in runtime patching. +enum PatchOpcodes : uint32_t { + PO_ADDI = 0x00000013, // addi rd, rs1, imm + PO_ADD = 0x00000033, // add rd, rs1, rs2 + PO_SW = 0x00002023, // sw rs2, imm(rs1) + PO_SD = 0x00003023, // sd rs2, imm(rs1) + PO_LUI = 0x00000037, // lui rd, imm + PO_OR = 0x00006033, // or rd, rs1, rs2 + PO_SLLI = 0x00001013, // slli rd, rs1, shamt + PO_JALR = 0x00000067, // jalr rd, rs1 + PO_LW = 0x00002003, // lw rd, imm(rs1) + PO_LD = 0x00003003, // ld rd, imm(rs1) + PO_J = 0x0000006f, // jal imm + PO_NOP = PO_ADDI, // addi x0, x0, 0 +}; + +enum RegNum : uint32_t { + RN_X0 = 0, + RN_RA = 1, + RN_SP = 2, + RN_T1 = 6, + RN_A0 = 10, +}; + +static inline uint32_t encodeRTypeInstruction(uint32_t Opcode, uint32_t Rs1, + uint32_t Rs2, uint32_t Rd) { + return Rs2 << 20 | Rs1 << 15 | Rd << 7 | Opcode; +} + +static inline uint32_t encodeITypeInstruction(uint32_t Opcode, uint32_t Rs1, + uint32_t Rd, uint32_t Imm) { + return Imm << 20 | Rs1 << 15 | Rd << 7 | Opcode; +} + +static inline uint32_t encodeSTypeInstruction(uint32_t Opcode, uint32_t Rs1, + uint32_t Rs2, uint32_t Imm) { + uint32_t ImmMSB = (Imm & 0xfe0) << 20; + uint32_t ImmLSB = (Imm & 0x01f) << 7; + return ImmMSB | Rs2 << 20 | Rs1 << 15 | ImmLSB | Opcode; +} + +static inline uint32_t encodeUTypeInstruction(uint32_t Opcode, uint32_t Rd, + uint32_t Imm) { + return Imm << 12 | Rd << 7 | Opcode; +} + +static inline uint32_t encodeJTypeInstruction(uint32_t Opcode, uint32_t Rd, + uint32_t Imm) { + uint32_t ImmMSB = (Imm & 0x100000) << 11; + uint32_t ImmLSB = (Imm & 0x7fe) << 20; + uint32_t Imm11 = (Imm & 0x800) << 9; + uint32_t Imm1912 = (Imm & 0xff000); + return ImmMSB | ImmLSB | Imm11 | Imm1912 | Rd << 7 | Opcode; +} + +static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; } +static uint32_t lo12(uint32_t val) { return val & 0xfff; } + +static inline bool patchSled(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled, + void (*TracingHook)()) XRAY_NEVER_INSTRUMENT { + // When |Enable| == true, + // We replace the following compile-time stub (sled): + // + // xray_sled_n: + // J .tmpN + // 21 or 33 C.NOPs (42 or 66 bytes) + // .tmpN + // + // With one of the following runtime patches: + // + // xray_sled_n (32-bit): + // addi sp, sp, -16 ;create stack frame + // sw ra, 12(sp) ;save return address + // sw a0, 8(sp) ;save register a0 + // lui ra, %hi(__xray_FunctionEntry/Exit) + // addi ra, ra, %lo(__xray_FunctionEntry/Exit) + // lui a0, %hi(function_id) + // addi a0, a0, %lo(function_id) ;pass function id + // jalr ra ;call Tracing hook + // lw a0, 8(sp) ;restore register a0 + // lw ra, 12(sp) ;restore return address + // addi sp, sp, 16 ;delete stack frame + // + // xray_sled_n (64-bit): + // addi sp, sp, -32 ;create stack frame + // sd ra, 24(sp) ;save return address + // sd a0, 16(sp) ;save register a0 + // sd t1, 8(sp) ;save register t1 + // lui t1, %highest(__xray_FunctionEntry/Exit) + // addi t1, t1, %higher(__xray_FunctionEntry/Exit) + // slli t1, t1, 32 + // lui ra, ra, %hi(__xray_FunctionEntry/Exit) + // addi ra, ra, %lo(__xray_FunctionEntry/Exit) + // add ra, t1, ra + // lui a0, %hi(function_id) + // addi a0, a0, %lo(function_id) ;pass function id + // jalr ra ;call Tracing hook + // ld t1, 8(sp) ;restore register t1 + // ld a0, 16(sp) ;restore register a0 + // ld ra, 24(sp) ;restore return address + // addi sp, sp, 32 ;delete stack frame + // + // Replacement of the first 4-byte instruction should be the last and atomic + // operation, so that the user code which reaches the sled concurrently + // either jumps over the whole sled, or executes the whole sled when the + // latter is ready. + // + // When |Enable|==false, we set back the first instruction in the sled to be + // J 44 bytes (rv32) + // J 68 bytes (rv64) + + uint32_t *Address = reinterpret_cast(Sled.address()); + if (Enable) { +#if __riscv_xlen == 64 + // If the ISA is RV64, the Tracing Hook needs to be typecast to a 64 bit + // value. + uint32_t LoTracingHookAddr = lo12(reinterpret_cast(TracingHook)); + uint32_t HiTracingHookAddr = hi20(reinterpret_cast(TracingHook)); + uint32_t HigherTracingHookAddr = + lo12((reinterpret_cast(TracingHook) + 0x80000000) >> 32); + uint32_t HighestTracingHookAddr = + hi20((reinterpret_cast(TracingHook) + 0x80000000) >> 32); +#elif __riscv_xlen == 32 + // We typecast the Tracing Hook to a 32 bit value for RV32 + uint32_t LoTracingHookAddr = lo12(reinterpret_cast(TracingHook)); + uint32_t HiTracingHookAddr = hi20((reinterpret_cast(TracingHook)); +#endif + uint32_t LoFunctionID = lo12(FuncId); + uint32_t HiFunctionID = hi20(FuncId); + + // The sled that is patched in for RISCV64 defined below. We need the entire + // sleds corresponding to both ISAs to be protected by defines because the + // first few instructions are all different, because we store doubles in + // case of RV64 and store words for RV32. Subsequently, we have LUI - and in + // case of RV64, we need extra instructions from this point on, so we see + // differences in addresses to which instructions are stored. + size_t Idx = 1U; + const uint32_t XLenBytes = __riscv_xlen / 8; +#if __riscv_xlen == 64 + const uint32_t LoadOp = PatchOpcodes::PO_LD; + const uint32_t StoreOp = PatchOpcodes::PO_SD; +#elif __riscv_xlen == 32 + const uint32_t LoadOp = PatchOpcodes::PO_LW; + const uint32_t StoreOp = PatchOpcodes::PO_SW; +#endif + + Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP, + RegNum::RN_RA, 3 * XLenBytes); + Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP, + RegNum::RN_A0, 2 * XLenBytes); + +#if __riscv_xlen == 64 + Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP, + RegNum::RN_T1, XLenBytes); + Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_T1, + HighestTracingHookAddr); + Address[Idx++] = + encodeITypeInstruction(PatchOpcodes::PO_ADDI, RegNum::RN_T1, + RegNum::RN_T1, HigherTracingHookAddr); + Address[Idx++] = encodeITypeInstruction(PatchOpcodes::PO_SLLI, + RegNum::RN_T1, RegNum::RN_T1, 32); +#endif + Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_RA, + HiTracingHookAddr); + Address[Idx++] = encodeITypeInstruction( + PatchOpcodes::PO_ADDI, RegNum::RN_RA, RegNum::RN_RA, LoTracingHookAddr); +#if __riscv_xlen == 64 + Address[Idx++] = encodeRTypeInstruction(PatchOpcodes::PO_ADD, RegNum::RN_RA, + RegNum::RN_T1, RegNum::RN_RA); +#endif + Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_A0, + HiFunctionID); + Address[Idx++] = encodeITypeInstruction( + PatchOpcodes::PO_ADDI, RegNum::RN_A0, RegNum::RN_A0, LoFunctionID); + Address[Idx++] = encodeITypeInstruction(PatchOpcodes::PO_JALR, + RegNum::RN_RA, RegNum::RN_RA, 0); + +#if __riscv_xlen == 64 + Address[Idx++] = + encodeITypeInstruction(LoadOp, RegNum::RN_SP, RegNum::RN_T1, XLenBytes); +#endif + Address[Idx++] = encodeITypeInstruction(LoadOp, RegNum::RN_SP, + RegNum::RN_A0, 2 * XLenBytes); + Address[Idx++] = encodeITypeInstruction(LoadOp, RegNum::RN_SP, + RegNum::RN_RA, 3 * XLenBytes); + Address[Idx++] = encodeITypeInstruction( + PatchOpcodes::PO_ADDI, RegNum::RN_SP, RegNum::RN_SP, 4 * XLenBytes); + + uint32_t CreateStackSpace = encodeITypeInstruction( + PatchOpcodes::PO_ADDI, RegNum::RN_SP, RegNum::RN_SP, -4 * XLenBytes); + + std::atomic_store_explicit( + reinterpret_cast *>(Address), CreateStackSpace, + std::memory_order_release); + } else { + uint32_t CreateBranch = encodeJTypeInstruction( + // Jump distance is different in both ISAs due to difference in size of + // sleds +#if __riscv_xlen == 64 + PatchOpcodes::PO_J, RegNum::RN_X0, + 68); // jump encodes an offset of 68 +#elif __riscv_xlen == 32 + PatchOpcodes::PO_J, RegNum::RN_X0, + 44); // jump encodes an offset of 44 +#endif + std::atomic_store_explicit( + reinterpret_cast *>(Address), CreateBranch, + std::memory_order_release); + } + return true; +} + +bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + // We don't support logging argument at this moment, so we always + // use EntryTrampoline. + return patchSled(Enable, FuncId, Sled, Trampolines.EntryTrampoline); +} + +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); +} + +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.TailExitTrampoline); +} + +bool patchCustomEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + return false; +} + +bool patchTypedEvent(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + return false; +} +} // namespace __xray + +extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {} diff --git a/compiler-rt/lib/xray/xray_trampoline_riscv32.S b/compiler-rt/lib/xray/xray_trampoline_riscv32.S new file mode 100644 index 0000000000000..05e3d61e5ef71 --- /dev/null +++ b/compiler-rt/lib/xray/xray_trampoline_riscv32.S @@ -0,0 +1,89 @@ +//===-- xray_trampoline_riscv32.s ----------------------------------*- ASM -*-===// +// +// 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 is a part of XRay, a dynamic runtime instrumentation system. +// +// This implements the riscv32-specific assembler for the trampolines. +// +//===----------------------------------------------------------------------===// + +#include "../sanitizer_common/sanitizer_asm.h" + +.macro SAVE_ARG_REGISTERS + // Push argument registers to stack + addi sp, sp, -112 + CFI_DEF_CFA_OFFSET(112) + sw ra, 108(sp) + sw a7, 104(sp) + sw a6, 100(sp) + sw a5, 96(sp) + sw a4, 92(sp) + sw a3, 88(sp) + sw a2, 84(sp) + sw a1, 80(sp) + sw a0, 76(sp) + fsd fa7, 64(sp) + fsd fa6, 56(sp) + fsd fa5, 48(sp) + fsd fa4, 40(sp) + fsd fa3, 32(sp) + fsd fa2, 24(sp) + fsd fa1, 16(sp) + fsd fa0, 8(sp) +.endm + +.macro RESTORE_ARG_REGISTERS + // Restore argument registers + fld fa0, 8(sp) + fld fa1, 16(sp) + fld fa2, 24(sp) + fld fa3, 32(sp) + fld fa4, 40(sp) + fld fa5, 48(sp) + fld fa6, 56(sp) + fld fa7, 64(sp) + lw a0, 76(sp) + lw a1, 80(sp) + lw a2, 84(sp) + lw a3, 88(sp) + lw a4, 92(sp) + lw a5, 96(sp) + lw a6, 100(sp) + lw a7, 104(sp) + lw ra, 108(sp) + addi sp, sp, 112 + CFI_DEF_CFA_OFFSET(0) +.endm + +.macro SAVE_RET_REGISTERS + // Push return registers to stack + addi sp, sp, -32 + CFI_DEF_CFA_OFFSET(32) + sw ra, 28(sp) + sw a1, 24(sp) + sw a0, 20(sp) + fsd fa1, 8(sp) + fsd fa0, 0(sp) +.endm + +.macro RESTORE_RET_REGISTERS + // Restore return registers + fld fa0, 0(sp) + fld fa1, 8(sp) + lw a0, 20(sp) + lw a1, 24(sp) + lw ra, 28(sp) + addi sp, sp, 32 + CFI_DEF_CFA_OFFSET(0) +.endm + +.macro LOAD_XLEN, rd, src + lw \rd, \src +.endm + +#include "xray_trampoline_riscv_common.S" diff --git a/compiler-rt/lib/xray/xray_trampoline_riscv64.S b/compiler-rt/lib/xray/xray_trampoline_riscv64.S new file mode 100644 index 0000000000000..692350eaaa38e --- /dev/null +++ b/compiler-rt/lib/xray/xray_trampoline_riscv64.S @@ -0,0 +1,89 @@ +//===-- xray_trampoline_riscv64.s ----------------------------------*- ASM -*-===// +// +// 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 is a part of XRay, a dynamic runtime instrumentation system. +// +// This implements the riscv64-specific assembler for the trampolines. +// +//===----------------------------------------------------------------------===// + +#include "../sanitizer_common/sanitizer_asm.h" + +.macro SAVE_ARG_REGISTERS + // Push return registers to stack + addi sp, sp, -144 + CFI_DEF_CFA_OFFSET(144) + sd ra, 136(sp) + sd a7, 128(sp) + sd a6, 120(sp) + sd a5, 112(sp) + sd a4, 104(sp) + sd a3, 96(sp) + sd a2, 88(sp) + sd a1, 80(sp) + sd a0, 72(sp) + fsd fa7, 64(sp) + fsd fa6, 56(sp) + fsd fa5, 48(sp) + fsd fa4, 40(sp) + fsd fa3, 32(sp) + fsd fa2, 24(sp) + fsd fa1, 16(sp) + fsd fa0, 8(sp) +.endm + +.macro SAVE_RET_REGISTERS + // Push return registers to stack + addi sp, sp, -48 + CFI_DEF_CFA_OFFSET(48) + sd ra, 40(sp) + sd a1, 32(sp) + sd a0, 24(sp) + fsd fa1, 16(sp) + fsd fa0, 8(sp) +.endm + +.macro RESTORE_RET_REGISTERS + // Restore return registers + fld fa0, 8(sp) + fld fa1, 16(sp) + ld a0, 24(sp) + ld a1, 32(sp) + ld ra, 40(sp) + addi sp, sp, 48 + CFI_DEF_CFA_OFFSET(0) +.endm + +.macro RESTORE_ARG_REGISTERS + // Restore argument registers + fld fa0, 8(sp) + fld fa1, 16(sp) + fld fa2, 24(sp) + fld fa3, 32(sp) + fld fa4, 40(sp) + fld fa5, 48(sp) + fld fa6, 56(sp) + fld fa7, 64(sp) + ld a0, 72(sp) + ld a1, 80(sp) + ld a2, 88(sp) + ld a3, 96(sp) + ld a4, 104(sp) + ld a5, 112(sp) + ld a6, 120(sp) + ld a7, 128(sp) + ld ra, 136(sp) + addi sp, sp, 144 + CFI_DEF_CFA_OFFSET(0) +.endm + +.macro LOAD_XLEN, rd, src + ld \rd, \src +.endm + +#include "xray_trampoline_riscv_common.S" diff --git a/compiler-rt/lib/xray/xray_trampoline_riscv_common.S b/compiler-rt/lib/xray/xray_trampoline_riscv_common.S new file mode 100644 index 0000000000000..746d612e98204 --- /dev/null +++ b/compiler-rt/lib/xray/xray_trampoline_riscv_common.S @@ -0,0 +1,96 @@ +//===-- xray_trampoline_riscv_common.s --------------------------*- ASM -*-===// +// +// 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 is a part of XRay, a dynamic runtime instrumentation system. +// +// This implements the trampolines code shared between riscv32 and riscv64. +// +//===----------------------------------------------------------------------===// + +#include "../builtins/assembly.h" + + .text + .p2align 2 + .global ASM_SYMBOL(__xray_FunctionEntry) + ASM_TYPE_FUNCTION(__xray_FunctionEntry) +ASM_SYMBOL(__xray_FunctionEntry): + CFI_STARTPROC + SAVE_ARG_REGISTERS + + // Load the handler function pointer into a2 + la a2, ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE) + LOAD_XLEN a2, 0(a2) + + // Handler address will be null if it is not set + beq a2, x0, 1f + + // If we reach here, we are tracing an event + // a0 already contains function id + // a1 = 0 means we are tracing an entry event + li a1, 0 + jalr a2 + +1: + RESTORE_ARG_REGISTERS + jr ra + ASM_SIZE(__xray_FunctionEntry) + CFI_ENDPROC + + .text + .p2align 2 + .global ASM_SYMBOL(__xray_FunctionExit) + ASM_TYPE_FUNCTION(__xray_FunctionExit) +ASM_SYMBOL(__xray_FunctionExit): + CFI_STARTPROC + SAVE_RET_REGISTERS + + // Load the handler function pointer into a2 + la a2, ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE) + LOAD_XLEN a2, 0(a2) + + // Handler address will be null if it is not set + beq a2, x0, 1f + + // If we reach here, we are tracing an event + // a0 already contains function id + // a1 = 1 means we are tracing an exit event + li a1, 1 + jalr a2 + +1: + RESTORE_RET_REGISTERS + jr ra + ASM_SIZE(__xray_FunctionExit) + CFI_ENDPROC + + .text + .p2align 2 + .global ASM_SYMBOL(__xray_FunctionTailExit) + ASM_TYPE_FUNCTION(__xray_FunctionTailExit) +ASM_SYMBOL(__xray_FunctionTailExit): + CFI_STARTPROC + SAVE_ARG_REGISTERS + + // Load the handler function pointer into a2 + la a2, ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE) + LOAD_XLEN a2, 0(a2) + + // Handler address will be null if it is not set + beq a2, x0, 1f + + // If we reach here, we are tracing an event + // a0 already contains function id + // a1 = 2 means we are tracing a tail exit event + li a1, 2 + jalr a2 + +1: + RESTORE_ARG_REGISTERS + jr ra + ASM_SIZE(__xray_FunctionTailExit) + CFI_ENDPROC diff --git a/compiler-rt/lib/xray/xray_tsc.h b/compiler-rt/lib/xray/xray_tsc.h index e1cafe1bf11d2..b62a686d6ce0f 100644 --- a/compiler-rt/lib/xray/xray_tsc.h +++ b/compiler-rt/lib/xray/xray_tsc.h @@ -43,7 +43,7 @@ inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { #elif defined(__powerpc64__) #include "xray_powerpc64.inc" #elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ - defined(__hexagon__) || defined(__loongarch_lp64) + defined(__hexagon__) || defined(__loongarch_lp64) || defined(__riscv) // Emulated TSC. // There is no instruction like RDTSCP in user mode on ARM. ARM's CP15 does // not have a constant frequency like TSC on x86(_64), it may go faster diff --git a/compiler-rt/test/asan/TestCases/Windows/allocator_may_return_null_limits.cpp b/compiler-rt/test/asan/TestCases/Windows/allocator_may_return_null_limits.cpp new file mode 100644 index 0000000000000..90db0d45af2d7 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Windows/allocator_may_return_null_limits.cpp @@ -0,0 +1,34 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ABORT +// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RETURN-NULL + +// RUN: %clangxx_asan -O0 %s -o %t -DUSER_FUNCTION +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RETURN-NULL + +#if USER_FUNCTION +// On Windows, flags configured through the user-defined function `__asan_default_options` +// are suspected to not always be honored according to GitHub bug: +// https://github.com/llvm/llvm-project/issues/117925 +// This test ensures we do not regress on `allocator_may_return_null` specifically. +extern "C" __declspec(dllexport) extern const char *__asan_default_options() { + return "allocator_may_return_null=1"; +} +#endif + +#include +#include +#include +#include + +int main() { + // Attempt to allocate an excessive amount of memory, which should + // terminate the program unless `allocator_may_return_null` is set. + size_t max = std::numeric_limits::max(); + + // CHECK-ABORT: exceeds maximum supported size + // CHECK-ABORT: ABORT + free(malloc(max)); + + printf("Success"); // CHECK-RETURN-NULL: Success + return 0; +} diff --git a/compiler-rt/test/builtins/Unit/divdf3_test.c b/compiler-rt/test/builtins/Unit/divdf3_test.c index 1b8f2b398a91f..f1f3f3b4f7e09 100644 --- a/compiler-rt/test/builtins/Unit/divdf3_test.c +++ b/compiler-rt/test/builtins/Unit/divdf3_test.c @@ -113,5 +113,9 @@ int main() if (test__divdf3(0x1.0p-1022, 0x1.0028p+52, UINT64_C(0x1))) return 1; + // test 1 / (1 - eps(0.5)) = 1 + eps(1) + if (test__divdf3(1.0, 0x1.fffffffffffffp-1, UINT64_C(0x3ff0000000000001))) + return 1; + return 0; } diff --git a/compiler-rt/test/builtins/Unit/divsf3_test.c b/compiler-rt/test/builtins/Unit/divsf3_test.c index 7a783cdfb863c..f8cb6169ac283 100644 --- a/compiler-rt/test/builtins/Unit/divsf3_test.c +++ b/compiler-rt/test/builtins/Unit/divsf3_test.c @@ -107,5 +107,9 @@ int main() if (test__divsf3(0x1.fffffep-126F, 2.F, UINT32_C(0x00800000))) return 1; + // test 1 / (1 - eps(0.5)) = 1 + eps(1) + if (test__divsf3(1.0F, 0x1.fffffep-1F, UINT32_C(0x3f800001))) + return 1; + return 0; } diff --git a/compiler-rt/test/builtins/Unit/divtf3_test.c b/compiler-rt/test/builtins/Unit/divtf3_test.c index d46fcc0477693..3c70e43741afb 100644 --- a/compiler-rt/test/builtins/Unit/divtf3_test.c +++ b/compiler-rt/test/builtins/Unit/divtf3_test.c @@ -156,6 +156,11 @@ int main() { UINT64_C(0x0001000000000000), UINT64_C(0))) return 1; + // test 1 / (1 - eps(0.5)) = 1 + eps(1). + if (test__divtf3(1.0L, TF_C(0x1.ffffffffffffffffffffffffffffp-1), + UINT64_C(0x3FFF000000000000), UINT64_C(1))) + return 1; + #else printf("skipped\n"); diff --git a/compiler-rt/test/memprof/TestCases/dump_at_exit.cpp b/compiler-rt/test/memprof/TestCases/dump_at_exit.cpp new file mode 100644 index 0000000000000..426849d1cea01 --- /dev/null +++ b/compiler-rt/test/memprof/TestCases/dump_at_exit.cpp @@ -0,0 +1,16 @@ +// RUN: %clangxx_memprof %s -o %t + +// RUN: %env_memprof_opts=print_text=true:log_path=stdout:dump_at_exit=false %run %t | count 0 +// RUN: %env_memprof_opts=print_text=true:log_path=stdout:dump_at_exit=true %run %t | FileCheck %s + +#include +#include + +int main() { + char *x = (char *)malloc(10); + memset(x, 0, 10); + free(x); + return 0; +} + +// CHECK: Recorded MIBs diff --git a/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll index e722b813c3fe0..5a8dbfc532b0f 100644 --- a/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll +++ b/compiler-rt/test/orc/TestCases/Generic/lazy-link.ll @@ -11,7 +11,7 @@ ; RUN: -lazy %t/x.o | FileCheck %s ; ; UNSUPPORTED: system-windows -; REQUIRES: target={{(arm|aarch)64.*}} +; REQUIRES: target={{(arm|aarch|x86_)64.*}} ; ; CHECK: Linking {{.*}}main.o ; CHECK-DAG: Linking diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/b64.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/b64.cpp new file mode 100644 index 0000000000000..96fd0138648b3 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/b64.cpp @@ -0,0 +1,42 @@ +// RUN: %clangxx %s -o %t && %run %t %p + +#include +#include +#include +#include +#include + +int main(int iArgc, char *szArgv[]) { + // Check NTOP writing + const char *src = "base64 test data"; + size_t src_len = strlen(src); + size_t dst_len = ((src_len + 2) / 3) * 4 + 1; + char dst[dst_len]; + int res = b64_ntop(reinterpret_cast(src), src_len, dst, + dst_len); + assert(res >= 0); + assert(strcmp(dst, "YmFzZTY0IHRlc3QgZGF0YQ==") == 0); + + // Check PTON writing + unsigned char target[dst_len]; + res = b64_pton(dst, target, dst_len); + assert(res >= 0); + assert(strncmp(reinterpret_cast(target), src, res) == 0); + + // Check NTOP writing for zero length src + src = ""; + src_len = strlen(src); + assert(((src_len + 2) / 3) * 4 + 1 < dst_len); + res = b64_ntop(reinterpret_cast(src), src_len, dst, + dst_len); + assert(res >= 0); + assert(strcmp(dst, "") == 0); + + // Check PTON writing for zero length src + dst[0] = '\0'; + res = b64_pton(dst, target, dst_len); + assert(res >= 0); + assert(strncmp(reinterpret_cast(target), src, res) == 0); + + return 0; +} diff --git a/compiler-rt/test/msan/Linux/dn_expand.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dn_expand.cpp similarity index 79% rename from compiler-rt/test/msan/Linux/dn_expand.cpp rename to compiler-rt/test/sanitizer_common/TestCases/Linux/dn_expand.cpp index a37da83df0022..8fdfa7a6cc1a4 100644 --- a/compiler-rt/test/msan/Linux/dn_expand.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dn_expand.cpp @@ -1,10 +1,10 @@ -// RUN: %clangxx_msan %s -o %t && %run %t %p +// RUN: %clangxx %s -o %t && %run %t %p #include #include #include -#include +#include "sanitizer_common/sanitizer_specific.h" void testWrite() { char unsigned input[] = {0xff, 0xc5, 0xf7, 0xff, 0x00, 0x00, 0xff, 0x0a, 0x00, @@ -18,7 +18,7 @@ void testWrite() { assert(res == 12); assert(strcmp(output, "google\\.com") == 0); - __msan_check_mem_is_initialized(output, strlen(output) + 1); + check_mem_is_good(output, strlen(output) + 1); } void testWriteZeroLength() { @@ -33,7 +33,7 @@ void testWriteZeroLength() { assert(res == 1); assert(strcmp(output, "") == 0); - __msan_check_mem_is_initialized(output, strlen(output) + 1); + check_mem_is_good(output, strlen(output) + 1); } void testComp() { @@ -49,17 +49,17 @@ void testComp() { char unsigned *n1 = mb; int res = dn_comp("llvm.org", mb, me - mb, pb, pe); assert(res == 10); - __msan_check_mem_is_initialized(mb, res); + check_mem_is_good(mb, res); // pb is [msg, llvm.org, nullptr] - __msan_check_mem_is_initialized(pb, sizeof(*pb) * 3); + check_mem_is_good(pb, sizeof(*pb) * 3); mb += res; char unsigned *n2 = mb; res = dn_comp("lab.llvm.org", mb, me - mb, pb, pe); assert(res == 6); - __msan_check_mem_is_initialized(mb, res); + check_mem_is_good(mb, res); // pb is [msg, llvm.org, lab.llvm.org, nullptr] - __msan_check_mem_is_initialized(pb, sizeof(*pb) * 4); + check_mem_is_good(pb, sizeof(*pb) * 4); mb += res; { @@ -69,7 +69,7 @@ void testComp() { fprintf(stderr, "%d\n", res); assert(res == 10); assert(strcmp(output, "llvm.org") == 0); - __msan_check_mem_is_initialized(output, strlen(output) + 1); + check_mem_is_good(output, strlen(output) + 1); } { @@ -78,7 +78,7 @@ void testComp() { assert(res == 6); assert(strcmp(output, "lab.llvm.org") == 0); - __msan_check_mem_is_initialized(output, strlen(output) + 1); + check_mem_is_good(output, strlen(output) + 1); } } diff --git a/compiler-rt/test/tysan/CMakeLists.txt b/compiler-rt/test/tysan/CMakeLists.txt new file mode 100644 index 0000000000000..76f57501e854e --- /dev/null +++ b/compiler-rt/test/tysan/CMakeLists.txt @@ -0,0 +1,32 @@ +set(TYSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +set(TYSAN_TESTSUITES) + +set(TYSAN_TEST_ARCH ${TYSAN_SUPPORTED_ARCH}) +if(APPLE) + darwin_filter_host_archs(TYSAN_SUPPORTED_ARCH TYSAN_TEST_ARCH) +endif() + +foreach(arch ${TYSAN_TEST_ARCH}) + set(TYSAN_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}" TYSAN_TEST_CONFIG_SUFFIX) + get_test_cc_for_arch(${arch} TYSAN_TEST_TARGET_CC TYSAN_TEST_TARGET_CFLAGS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}Config) + + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py) + list(APPEND TYSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endforeach() + +set(TYSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND TYSAN_TEST_DEPS tysan) +endif() + +add_lit_testsuite(check-tysan "Running the TypeSanitizer tests" + ${TYSAN_TESTSUITES} + DEPENDS ${TYSAN_TEST_DEPS} + ) +set_target_properties(check-tysan PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/compiler-rt/test/tysan/anon-ns.cpp b/compiler-rt/test/tysan/anon-ns.cpp new file mode 100644 index 0000000000000..681304411df31 --- /dev/null +++ b/compiler-rt/test/tysan/anon-ns.cpp @@ -0,0 +1,41 @@ +// RUN: %clangxx_tysan -O0 %s -c -o %t.o +// RUN: %clangxx_tysan -O0 %s -DPMAIN -c -o %tm.o +// RUN: %clangxx_tysan -O0 %t.o %tm.o -o %t +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +// This test demonstrates that the types from anonymous namespaces are +// different in different translation units (while the char* type is the same). + +namespace { +struct X { + X(int i, int j) : a(i), b(j) {} + int a; + int b; +}; +} // namespace + +#ifdef PMAIN +void foo(void *context, int i); +char fbyte(void *context); + +int main() { + X x(5, 6); + foo((void *)&x, 8); + std::cout << "fbyte: " << fbyte((void *)&x) << "\n"; +} +#else +void foo(void *context, int i) { + X *x = (X *)context; + x->b = i; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in (anonymous namespace)::X at offset 4) accesses an existing object of type int (in (anonymous namespace)::X at offset 4) + // CHECK: {{#0 0x.* in foo\(void\*, int\) .*anon-ns.cpp:}}[[@LINE-3]] +} + +char fbyte(void *context) { return *(char *)context; } +#endif + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/anon-same-struct.c b/compiler-rt/test/tysan/anon-same-struct.c new file mode 100644 index 0000000000000..b9044f2a0a73c --- /dev/null +++ b/compiler-rt/test/tysan/anon-same-struct.c @@ -0,0 +1,26 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +// The two anonymous structs are structurally identical. As a result, we don't +// report an aliasing violation here. +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +typedef struct { + int i1; +} s1; +typedef struct { + int i2; +} s2; + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1}; + f(&s, (s2 *)&s); +} diff --git a/compiler-rt/test/tysan/anon-struct.c b/compiler-rt/test/tysan/anon-struct.c new file mode 100644 index 0000000000000..25f6633545928 --- /dev/null +++ b/compiler-rt/test/tysan/anon-struct.c @@ -0,0 +1,27 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +typedef struct { + int i1, i1b; +} s1; +typedef struct { + int i2, i2b, i2c; +} s2; + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in at offset 0) accesses an existing object of type int (in at offset 0) + // CHECK: {{#0 0x.* in f .*anon-struct.c:}}[[@LINE-3]] + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1, .i1b = 5}; + f(&s, (s2 *)&s); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/basic.c b/compiler-rt/test/tysan/basic.c new file mode 100644 index 0000000000000..8e66e1a721383 --- /dev/null +++ b/compiler-rt/test/tysan/basic.c @@ -0,0 +1,65 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t 10 >%t.out.0 2>&1 +// RUN: FileCheck %s < %t.out.0 +// RUN: %clang_tysan -O2 %s -o %t && %run %t 10 >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include +#include + +void __attribute__((noinline)) add_flt(float *a) { + *a += 2.0f; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses an existing object of type int + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-3]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type int + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-6]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses an existing object of type long + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-9]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type long + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-12]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-15]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-18]] + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type float partially accesses an object of type short that starts at offset 2 + // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-21]] +} + +int main(int argc, char *argv[]) { + int x = atoi(argv[1]); + add_flt((float *)&x); + printf("x = %d\n", x); + + long y = x; + add_flt((float *)&y); + printf("y = %ld\n", y); + + add_flt(((float *)&y) + 1); + printf("y = %ld\n", y); + + char *mem = (char *)malloc(4 * sizeof(short)); + memset(mem, 0, 4 * sizeof(short)); + *(short *)(mem + 2) = x; + add_flt((float *)mem); + short s1 = *(short *)mem; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 2 at {{.*}} with type short accesses an existing object of type float + // CHECK: {{#0 0x.* in main .*basic.c:}}[[@LINE-3]] + short s2 = *(short *)(mem + 2); + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 2 at {{.*}} with type short accesses part of an existing object of type float that starts at offset -2 + // CHECK: {{#0 0x.* in main .*basic.c:}}[[@LINE-3]] + printf("m[0] = %d, m[1] = %d\n", s1, s2); + free(mem); + + return 0; +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/char-memcpy.c b/compiler-rt/test/tysan/char-memcpy.c new file mode 100644 index 0000000000000..ebbb6b53d0f37 --- /dev/null +++ b/compiler-rt/test/tysan/char-memcpy.c @@ -0,0 +1,45 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out.0 2>&1 +// RUN: FileCheck %s < %t.out.0 +// RUN: %clang_tysan -O2 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +// There's no type-based-aliasing violation here: the memcpy is implemented +// using only char* or unsigned char* (both of which may alias anything). +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +void my_memcpy_uchar(void *dest, void *src, int n) { + unsigned char *p = dest, *q = src, *end = p + n; + while (p < end) + *p++ = *q++; +} + +void my_memcpy_char(void *dest, void *src, int n) { + char *p = dest, *q = src, *end = p + n; + while (p < end) + *p++ = *q++; +} + +void test_uchar() { + struct S { + short x; + short *r; + } s = {10, &s.x}, s2; + my_memcpy_uchar(&s2, &s, sizeof(struct S)); + printf("%d\n", *(s2.r)); +} + +void test_char() { + struct S { + short x; + short *r; + } s = {10, &s.x}, s2; + my_memcpy_char(&s2, &s, sizeof(struct S)); + printf("%d\n", *(s2.r)); +} + +int main() { + test_uchar(); + test_char(); +} diff --git a/compiler-rt/test/tysan/constexpr-subobject.cpp b/compiler-rt/test/tysan/constexpr-subobject.cpp new file mode 100644 index 0000000000000..c473ffe5e445b --- /dev/null +++ b/compiler-rt/test/tysan/constexpr-subobject.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck --allow-empty %s < %t.out + +// CHECK-NOT: TypeSanitizer + +int foo() { return 0; } + +struct Bar { + struct S2 { + int (*fnA)(); + int (*fnB)(); + }; + + static int x() { return 0; } + + static const S2 &get() { + static constexpr S2 Info = {&foo, &Bar::x}; + return Info; + } +}; + +int main() { + auto Info = Bar::get(); + return Info.fnB(); +} diff --git a/compiler-rt/test/tysan/global.c b/compiler-rt/test/tysan/global.c new file mode 100644 index 0000000000000..247ee768a8162 --- /dev/null +++ b/compiler-rt/test/tysan/global.c @@ -0,0 +1,31 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out +#include +#include + +float P; +long L; + +int main() { + *(int *)&P = 5; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type float + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + + void *mem = malloc(sizeof(long)); + *(int *)mem = 6; + memcpy(mem, &L, sizeof(L)); + *(int *)mem = 8; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type long + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + int r = *(((int *)mem) + 1); + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: READ of size 4 at {{.*}} with type int accesses part of an existing object of type long that starts at offset -4 + // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] + free(mem); + + return r; +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/int-long.c b/compiler-rt/test/tysan/int-long.c new file mode 100644 index 0000000000000..b7956c07376e8 --- /dev/null +++ b/compiler-rt/test/tysan/int-long.c @@ -0,0 +1,21 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +long foo(int *x, long *y) { + *x = 0; + *y = 1; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 8 at {{.*}} with type long accesses an existing object of type int + // CHECK: {{#0 0x.* in foo .*int-long.c:}}[[@LINE-3]] + + return *x; +} + +int main(void) { + long l; + printf("%ld\n", foo((int *)&l, &l)); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/lit.cfg.py b/compiler-rt/test/tysan/lit.cfg.py new file mode 100644 index 0000000000000..817a3f0921e8d --- /dev/null +++ b/compiler-rt/test/tysan/lit.cfg.py @@ -0,0 +1,147 @@ +# -*- Python -*- + +import os +import platform +import re +import shlex + +import lit.formats + + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if attr_value is not None: + return attr_value + + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg.py " % attr_name + ) + + +def push_dynamic_library_lookup_path(config, new_path): + if platform.system() == "Windows": + dynamic_library_lookup_var = "PATH" + elif platform.system() == "Darwin": + dynamic_library_lookup_var = "DYLD_LIBRARY_PATH" + else: + dynamic_library_lookup_var = "LD_LIBRARY_PATH" + + new_ld_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path + + if platform.system() == "FreeBSD": + dynamic_library_lookup_var = "LD_32_LIBRARY_PATH" + new_ld_32_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_32_library_path + + if platform.system() == "SunOS": + dynamic_library_lookup_var = "LD_LIBRARY_PATH_32" + new_ld_library_path_32 = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path_32 + + dynamic_library_lookup_var = "LD_LIBRARY_PATH_64" + new_ld_library_path_64 = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, "")) + ) + config.environment[dynamic_library_lookup_var] = new_ld_library_path_64 + + +# Setup config name. +config.name = "TypeSanitizer" + config.name_suffix + +# Platform-specific default TYSAN_OPTIONS for lit tests. +default_tysan_opts = list(config.default_sanitizer_opts) + +default_tysan_opts_str = ":".join(default_tysan_opts) +if default_tysan_opts_str: + config.environment["TYSAN_OPTIONS"] = default_tysan_opts_str + default_tysan_opts_str += ":" +config.substitutions.append( + ("%env_tysan_opts=", "env TYSAN_OPTIONS=" + default_tysan_opts_str) +) + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +if config.host_os not in ["FreeBSD", "NetBSD"]: + libdl_flag = "-ldl" +else: + libdl_flag = "" + +# GCC-ASan doesn't link in all the necessary libraries automatically, so +# we have to do it ourselves. +if config.compiler_id == "GNU": + extra_link_flags = ["-pthread", "-lstdc++", libdl_flag] +else: + extra_link_flags = [] + +# Setup default compiler flags used with -fsanitize=address option. +# FIXME: Review the set of required flags and check if it can be reduced. +target_cflags = [get_required_attr(config, "target_cflags")] + extra_link_flags +target_cxxflags = config.cxx_mode_flags + target_cflags +clang_tysan_static_cflags = ( + [ + "-fsanitize=type", + "-mno-omit-leaf-frame-pointer", + "-fno-omit-frame-pointer", + "-fno-optimize-sibling-calls", + ] + + config.debug_info_flags + + target_cflags +) +if config.target_arch == "s390x": + clang_tysan_static_cflags.append("-mbackchain") +clang_tysan_static_cxxflags = config.cxx_mode_flags + clang_tysan_static_cflags + +clang_tysan_cflags = clang_tysan_static_cflags +clang_tysan_cxxflags = clang_tysan_static_cxxflags + + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + + +config.substitutions.append(("%clang ", build_invocation(target_cflags))) +config.substitutions.append(("%clangxx ", build_invocation(target_cxxflags))) +config.substitutions.append(("%clang_tysan ", build_invocation(clang_tysan_cflags))) +config.substitutions.append(("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags))) + + +# FIXME: De-hardcode this path. +tysan_source_dir = os.path.join( + get_required_attr(config, "compiler_rt_src_root"), "lib", "tysan" +) +python_exec = shlex.quote(get_required_attr(config, "python_executable")) + +# Set LD_LIBRARY_PATH to pick dynamic runtime up properly. +push_dynamic_library_lookup_path(config, config.compiler_rt_libdir) + +# Default test suffixes. +config.suffixes = [".c", ".cpp"] + +if config.host_os == "Darwin": + config.suffixes.append(".mm") + +if config.host_os == "Windows": + config.substitutions.append(("%fPIC", "")) + config.substitutions.append(("%fPIE", "")) + config.substitutions.append(("%pie", "")) +else: + config.substitutions.append(("%fPIC", "-fPIC")) + config.substitutions.append(("%fPIE", "-fPIE")) + config.substitutions.append(("%pie", "-pie")) + +# Only run the tests on supported OSs. +if config.host_os not in [ + "Linux", + "Darwin", +]: + config.unsupported = Tr diff --git a/compiler-rt/test/tysan/lit.site.cfg.py.in b/compiler-rt/test/tysan/lit.site.cfg.py.in new file mode 100644 index 0000000000000..b56dce4fed7a2 --- /dev/null +++ b/compiler-rt/test/tysan/lit.site.cfg.py.in @@ -0,0 +1,17 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@TYSAN_TEST_CONFIG_SUFFIX@" +config.target_cflags = "@TYSAN_TEST_TARGET_CFLAGS@" +config.clang = "@TYSAN_TEST_TARGET_CC@" +config.bits = "@TYSAN_TEST_BITS@" +config.arm_thumb = "@COMPILER_RT_ARM_THUMB@" +config.apple_platform = "@TYSAN_TEST_APPLE_PLATFORM@" +config.apple_platform_min_deployment_target_flag = "@TYSAN_TEST_MIN_DEPLOYMENT_TARGET_FLAG@" +config.target_arch = "@TYSAN_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@TYSAN_LIT_SOURCE_DIR@/lit.cfg.py") diff --git a/compiler-rt/test/tysan/ptr-float.c b/compiler-rt/test/tysan/ptr-float.c new file mode 100644 index 0000000000000..aaa9895986988 --- /dev/null +++ b/compiler-rt/test/tysan/ptr-float.c @@ -0,0 +1,19 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +float *P; +void zero_array() { + int i; + for (i = 0; i < 1; ++i) + P[i] = 0.0f; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type p1 float + // CHECK: {{#0 0x.* in zero_array .*ptr-float.c:}}[[@LINE-3]] +} + +int main() { + P = (float *)&P; + zero_array(); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp b/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp new file mode 100644 index 0000000000000..f7baa14d15aff --- /dev/null +++ b/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp @@ -0,0 +1,51 @@ +// RUN: %clangxx_tysan -O0 %s -c -o %t.o +// RUN: %clangxx_tysan -O0 %s -DPMAIN -c -o %tm.o +// RUN: %clangxx_tysan -O0 %s -DPINIT -c -o %tinit.o +// RUN: %clangxx_tysan -O0 %t.o %tm.o %tinit.o -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include +#include + +extern "C" { +typedef struct X { + int *start; + int *end; + int i; +} X; +}; + +#ifdef PMAIN +int foo(struct X *); +void bar(struct X *); +void init(struct X *); + +int main() { + struct X x; + init(&x); + printf("%d\n", foo(&x)); + free(x.start); + return 0; +} + +#elif PINIT + +void init(struct X *x) { + x->start = (int *)calloc(100, sizeof(int)); + x->end = x->start + 99; + x->i = 0; +} + +#else + +__attribute__((noinline)) int foo(struct X *x) { + if (x->start < x->end) + return 30; + return 10; +} + +void bar(struct X *x) { x->end = NULL; } + +#endif + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct-offset.c b/compiler-rt/test/tysan/struct-offset.c new file mode 100644 index 0000000000000..7295e0ae121ed --- /dev/null +++ b/compiler-rt/test/tysan/struct-offset.c @@ -0,0 +1,26 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include + +struct X { + int i; + int j; +}; + +int foo(struct X *p, struct X *q) { + q->j = 1; + p->i = 0; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in X at offset 0) accesses an existing object of type int (in X at offset 4) + // CHECK: {{#0 0x.* in foo .*struct-offset.c:}}[[@LINE-3]] + return q->j; +} + +int main() { + unsigned char *p = malloc(3 * sizeof(int)); + printf("%i\n", foo((struct X *)(p + sizeof(int)), (struct X *)p)); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/struct.c b/compiler-rt/test/tysan/struct.c new file mode 100644 index 0000000000000..f7ecef5967624 --- /dev/null +++ b/compiler-rt/test/tysan/struct.c @@ -0,0 +1,39 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +typedef struct S1 { + int i1; +} s1; +typedef struct S2 { + int i2; +} s2; + +void g(int *i) { + *i = 5; + printf("%i\n", *i); +} + +void h(char *c) { + *c = 5; + printf("%i\n", (int)*c); +} + +void f(s1 *s1p, s2 *s2p) { + s1p->i1 = 2; + s2p->i2 = 3; + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation + // CHECK: WRITE of size 4 at {{.*}} with type int (in S2 at offset 0) accesses an existing object of type int (in S1 at offset 0) + // CHECK: {{#0 0x.* in f .*struct.c:}}[[@LINE-3]] + printf("%i\n", s1p->i1); +} + +int main() { + s1 s = {.i1 = 1}; + f(&s, (s2 *)&s); + g(&s.i1); + h((char *)&s.i1); +} + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/union-wr-wr.c b/compiler-rt/test/tysan/union-wr-wr.c new file mode 100644 index 0000000000000..6414bbfcf9d95 --- /dev/null +++ b/compiler-rt/test/tysan/union-wr-wr.c @@ -0,0 +1,18 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation + +int main() { + union { + int i; + short s; + } u; + + u.i = 42; + u.s = 1; + + printf("%d\n", u.i); +} diff --git a/compiler-rt/test/tysan/violation-pr45282.c b/compiler-rt/test/tysan/violation-pr45282.c new file mode 100644 index 0000000000000..b3d8b0a6465fd --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr45282.c @@ -0,0 +1,32 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/45282 + +#include + +int main(void) { + + double a[29], b[20]; + int i, j; + + for (i = 0; i < 20; ++i) { + b[i] = 2.01f + 1.f; + ((float *)a)[i] = 2.01f * 2.0145f; + ((float *)a + 38)[i] = 2.01f * 1.0123f; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 8 at {{.+}} with type double accesses an existing object of type float + // CHECK-NEXT: in main {{.*/?}}violation-pr45282.c:25 + + // loop of problems + for (j = 2; j <= 4; ++j) { + a[j - 1] = ((float *)a)[j] * ((float *)a + 38)[j - 1]; + ((float *)a + 38)[j - 1] = ((float *)a)[j - 1] + b[j - 1]; + } + + printf("((float *)a + 38)[2] = %f\n", ((float *)a + 38)[2]); + + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr47137.c b/compiler-rt/test/tysan/violation-pr47137.c new file mode 100644 index 0000000000000..fb895ff729de4 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr47137.c @@ -0,0 +1,41 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/47137 +#include +#include +#include + +void f(int m) { + int n = (4 * m + 2) / 3; + uint64_t *a = malloc(n * sizeof(uint64_t)); + uint64_t *b = malloc(n * sizeof(uint64_t)); + uint64_t aa[] = {0xffff3e0000000001, 0x22eaf0b680a88c16, 0x5a65d25ac40e20f3, + 0x34e7ac346236953e, 0x9dea3e0a26c6ba89, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000}; + uint64_t bb[] = {0x0000000024c0ffff, 0x000000004634d940, 0x00000000219d18ef, + 0x0000000000154519, 0x000000000000035f, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000}; + char l[20]; + l[0] = 0; + for (int i = 0; i < n; i++) { + a[i] = aa[i] + l[0] - '0'; + b[i] = bb[i] + l[0] - '0'; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type long + // CHECK-NEXT: in f {{.*/?}}violation-pr47137.c:31 + for (int i = 0, j = 0; j < 4 * m; i += 4, j += 3) { + for (int k = 0; k < 3; k++) { + ((uint16_t *)a)[j + k] = ((uint16_t *)a)[i + k]; + ((uint16_t *)b)[j + k] = ((uint16_t *)b)[i + k]; + } + } + + printf("a: %016llx\n", a[0]); + free(a); + free(b); +} + +int main() { f(6); } diff --git a/compiler-rt/test/tysan/violation-pr51837.c b/compiler-rt/test/tysan/violation-pr51837.c new file mode 100644 index 0000000000000..d49a813933d65 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr51837.c @@ -0,0 +1,34 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include + +// CHECK-NOT: TypeSanitizer + +union a { + int16_t b; + uint64_t c; +} d; + +uint64_t *e = &d.c; +static uint16_t f(int16_t a, int32_t b, uint64_t c); +static int64_t g(int32_t aa, uint8_t h, union a bb) { + int16_t *i = &d.b; + f(0, h, 0); + *i = h; + return 0; +} +uint16_t f(int16_t a, int32_t b, uint64_t c) { + for (d.c = 0; 0;) + ; + *e = 0; + return 0; +} + +int main() { + uint32_t j = 8; + g(1, j, d); + printf("%d\n", d.b); + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr62544.c b/compiler-rt/test/tysan/violation-pr62544.c new file mode 100644 index 0000000000000..65dd333272116 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr62544.c @@ -0,0 +1,24 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/62544 + +int printf(const char *, ...); +int a, b, c; +long d; +int main() { + short *e = &a; + int *f = &a; + *f = 0; + for (; b <= 9; b++) { + int **g = &f; + *f = d; + *g = &c; + } + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 2 at {{.+}} with type short accesses an existing object of type int + // CHECK-NEXT: in main {{.*/?}}violation-pr62544.c:22 + *e = 3; + printf("%d\n", a); +} diff --git a/compiler-rt/test/tysan/violation-pr62828.cpp b/compiler-rt/test/tysan/violation-pr62828.cpp new file mode 100644 index 0000000000000..709132c4aba64 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr62828.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/62828 +#include + +typedef int int_v8[8]; +typedef short short_v8[8]; +short *test1(int_v8 *cast_c_array, short_v8 *shuf_c_array1, int *ptr) { + int *input1 = reinterpret_cast(((int_v8 *)(cast_c_array))); + short *input2 = reinterpret_cast(reinterpret_cast(input1)); + + short *output1 = reinterpret_cast(((short_v8 *)(shuf_c_array1))); + short *output2 = + reinterpret_cast(reinterpret_cast(output1)); + + for (int r = 0; r < 8; ++r) { + int tmp = (int)((r * 4) + ptr[r]); + if ((ptr[r] / 4) == 0) { + int *input = reinterpret_cast(((int_v8 *)(cast_c_array))); + input[r] = tmp; + } + } + + // CHECK: ERROR: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type int + // CHECK-NEXT: in test1(int (*) [8], short (*) [8], int*) {{.*/?}}violation-pr62828.cpp:29 + for (int i3 = 0; i3 < 4; ++i3) { + output2[i3] = input2[(i3 * 2)]; + } + return output2; +} + +int main() { + int_v8 in[4] = {{4, 4, 4, 4}}; + short_v8 out[4] = {{0}}; + int ptr[8] = {2}; + test1(in, out, ptr); + short *p = reinterpret_cast(out); + for (int i = 0; i < 32; i++) { + printf("%d ", p[i]); + } + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr68655.cpp b/compiler-rt/test/tysan/violation-pr68655.cpp new file mode 100644 index 0000000000000..7be05c7a7d4f8 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr68655.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// https://github.com/llvm/llvm-project/issues/68655 +struct S1 { + long long a; + long long b; +}; + +// CHECK: TypeSanitizer: type-aliasing-violation on address +// CHECK-NEXT: READ of size 4 at {{.+}} with type int accesses an existing object of type long long (in {{.*}}S1 at offset 0) +// CHECK-NEXT: in copyMem(S1*, S1*) {{.*/?}}violation-pr68655.cpp:19 + +void inline copyMem(S1 *dst, S1 *src) { + unsigned *d = reinterpret_cast(dst); + unsigned *s = reinterpret_cast(src); + + for (int i = 0; i < sizeof(S1) / sizeof(unsigned); i++) { + *d = *s; + d++; + s++; + } +} + +void math(S1 *dst, int *srcA, int idx_t) { + S1 zero[4]; + for (int i = 0; i < 2; i++) { + zero[i].a = i + idx_t; + zero[i].b = i * idx_t; + } + + copyMem(&dst[idx_t], &zero[srcA[idx_t]]); +} + +int main() { + S1 dst = {0}; + int Src[2] = {0, 0}; + math(&dst, &Src[0], 0); + return 0; +} diff --git a/compiler-rt/test/tysan/violation-pr86685.c b/compiler-rt/test/tysan/violation-pr86685.c new file mode 100644 index 0000000000000..43b8d478e6851 --- /dev/null +++ b/compiler-rt/test/tysan/violation-pr86685.c @@ -0,0 +1,29 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include + +// Violation reported in https://github.com/llvm/llvm-project/issues/86685. +void foo(int *s, float *f, long n) { + for (long i = 0; i < n; ++i) { + *f = 2; + if (i == 1) + break; + + // CHECK: TypeSanitizer: type-aliasing-violation on address + // CHECK-NEXT: WRITE of size 4 at {{.+}} with type int accesses an existing object of type float + // CHECK-NEXT: #0 {{.+}} in foo {{.*/?}}violation-pr86685.c:17 + *s = 4; + } +} + +int main(void) { + union { + int s; + float f; + } u = {0}; + foo(&u.s, &u.f, 2); + printf("%.f\n", u.f); + return 0; +} diff --git a/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp b/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp new file mode 100644 index 0000000000000..edfe439c92790 --- /dev/null +++ b/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp @@ -0,0 +1,28 @@ +// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && %run %t 1 +// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && not --crash %run %t 3 + +// FIXME: it's always trap for now. + +#include + +struct S { + int k; + int l; +}; + +__attribute__((noinline)) void init(S *s) { + __asm__ __volatile__("" : : "r"(s) : "memory"); +} + +__attribute__((noinline, no_sanitize("memory"))) int test(char i) { + S a; + init(&a); + S b; + init(&b); + return ((int *)(&a))[i]; +} + +int main(int argc, char **argv) { + test(argv[1][0] - '0'); + return 0; +} diff --git a/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp b/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp new file mode 100644 index 0000000000000..edfe439c92790 --- /dev/null +++ b/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp @@ -0,0 +1,28 @@ +// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && %run %t 1 +// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && not --crash %run %t 3 + +// FIXME: it's always trap for now. + +#include + +struct S { + int k; + int l; +}; + +__attribute__((noinline)) void init(S *s) { + __asm__ __volatile__("" : : "r"(s) : "memory"); +} + +__attribute__((noinline, no_sanitize("memory"))) int test(char i) { + S a; + init(&a); + S b; + init(&b); + return ((int *)(&a))[i]; +} + +int main(int argc, char **argv) { + test(argv[1][0] - '0'); + return 0; +} diff --git a/compiler-rt/test/ubsan_minimal/TestCases/override-callback.c b/compiler-rt/test/ubsan_minimal/TestCases/override-callback.c new file mode 100644 index 0000000000000..e11a3712f1be3 --- /dev/null +++ b/compiler-rt/test/ubsan_minimal/TestCases/override-callback.c @@ -0,0 +1,15 @@ +// RUN: %clang -fsanitize=implicit-integer-sign-change %s -o %t && %run %t 0 2>&1 | FileCheck %s +#include +#include +#include + +static int Result; + +void __ubsan_report_error(const char *kind, uintptr_t caller) { + fprintf(stderr, "CUSTOM_CALLBACK: %s\n", kind); +} + +int main(int argc, const char **argv) { + int32_t t0 = (~((uint32_t)0)); + // CHECK: CUSTOM_CALLBACK: implicit-conversion +} diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt index 971e5d5c93f23..68947eaa9c9bd 100644 --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -66,6 +66,13 @@ if (MSVC AND CMAKE_CXX_COMPILER_ID MATCHES Clang) if (IS_DIRECTORY "${LIBDIR}") link_libraries(${CLANG_RT_BUILTINS_LIBRARY}) endif() + + if (MSVC_VERSION EQUAL 1942) + message(FATAL_ERROR "Flang cannot be built with clang and the MSVC 17.12 " + "toolchain version. Please upgrade to 17.13 or later, or switch " + "to the 17.10 LTSC release. " + "See https://github.com/microsoft/STL/issues/4959 for more details.") + endif() endif() if(CMAKE_SIZEOF_VOID_P EQUAL 4) @@ -117,7 +124,6 @@ if (FLANG_STANDALONE_BUILD) set(USE_NO_MAYBE_UNINITIALIZED 1) endif() - include(CMakeParseArguments) include(AddLLVM) include(HandleLLVMOptions) include(VersionFromVCS) @@ -445,7 +451,6 @@ if (APPLE) endif() endif() -include(CMakeParseArguments) include(AddFlang) if (FLANG_INCLUDE_TESTS) diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index 4b4b516d0fb69..626bf4399d632 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -420,6 +420,7 @@ end [-fimplicit-none-type-never] * Old-style `PARAMETER pi=3.14` statement without parentheses [-falternative-parameter-statement] +* `UNSIGNED` type (-funsigned) ### Extensions and legacy features deliberately not supported diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md index 94bca7a3972b6..d0b7999fbd067 100644 --- a/flang/docs/Intrinsics.md +++ b/flang/docs/Intrinsics.md @@ -705,6 +705,7 @@ MALLOC, FREE ### Library subroutine ``` +CALL BACKTRACE() CALL FDATE(TIME) CALL GETLOG(USRNAME) CALL GETENV(NAME [, VALUE, LENGTH, STATUS, TRIM_NAME, ERRMSG ]) @@ -769,7 +770,7 @@ This phase currently supports all the intrinsic procedures listed above but the | Intrinsic subroutines |MVBITS (elemental), CPU_TIME, DATE_AND_TIME, EVENT_QUERY, EXECUTE_COMMAND_LINE, GET_COMMAND, GET_COMMAND_ARGUMENT, GET_ENVIRONMENT_VARIABLE, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER, RANDOM_SEED, SIGNAL, SLEEP, SYSTEM, SYSTEM_CLOCK | | Atomic intrinsic subroutines | ATOMIC_ADD | | Collective intrinsic subroutines | CO_REDUCE | -| Library subroutines | FDATE, GETLOG, GETENV | +| Library subroutines | BACKTRACE, FDATE, GETLOG, GETENV | ### Intrinsic Function Folding diff --git a/flang/docs/Unsigned.md b/flang/docs/Unsigned.md new file mode 100644 index 0000000000000..5c90e2aa185bc --- /dev/null +++ b/flang/docs/Unsigned.md @@ -0,0 +1,121 @@ + + +# Fortran Extensions supported by Flang + +```{contents} +--- +local: +--- +``` + +For better compatibility with GNU Fortran and Sun Fortran, +this compiler supports an option (`-funsigned`) that enables +the `UNSIGNED` data type, constants, intrinsic functions, +its use with intrinsic operations and `SELECT CASE`, and C +language interoperability. + +## `UNSIGNED` type + +`UNSIGNED` is a numeric type with the same kinds as `INTEGER`. +It may appear as a type-spec in any context, including +a type declaration statement, a type-decl in an array +constructor or `ALLOCATE` statement, `IMPLICIT`, or a +function statement's prefix. + +`UNSIGNED` constants are nonempty strings of decimal digits +followed by the letter `U` and optionally a kind suffix with +an underscore. + +## `UNSIGNED` operations + +`UNSIGNED` operands are accepted for unary negation (`-`), +the basic four binary arithmetic intrinsic operations `+`, `-`, `*`, and `/`, +components in complex constructors, +and for numeric relational operators. +The power operator `**` does not accept `UNSIGNED` operands. + +Mixed operations with other types are not allowed. +Mixed operations with one `UNSIGNED` operand and one BOZ literal +constant operand are allowed. +When the operands' kinds differ, the smaller operand is zero-extended +to the size of the larger. + +The arithmetic operations `u+v`, `-u`, `u-v`, and `u*v` are implemented +modulo `MAX(HUGE(u),HUGE(v))+1`; +informally speaking, they always truncate their results, or are +guaranteed to "wrap". + +## `UNSIGNED` intrinsic functions + +`UNSIGNED` operands are accepted as operands to, +or may be returned as results from, +several intrinsic procedures. + +Bitwise operations: +* `NOT` +* `IAND`, `IOR`, `IEOR`, `IBCLR`, `IBSET`, `IBITS`, `MERGE_BITS` +* `BTEST` +* `ISHFT`, `ISHFTC` +* `SHIFTA`, `SHIFTL`, `SHIFTR` +* `TRANSFER` +* `MVBITS` + +The existing unsigned comparisons `BLT`, `BLE`, `BGE`, and `BGT`. + +The inquiries `BIT_SIZE`, `DIGITS`, `HUGE`, and `RANGE`. + +Homogeneous `MAX` and `MIN`. + +`RANDOM_NUMBER`. + +The intrinsic array functions: +* `MAXVAL`, `MINVAL` +* `SUM`, `PRODUCT` +* `IALL`, `IANY`, `IPARITY` +* `DOT_PRODUCT`, `MATMUL` + +All of the restructuring array transformational intrinsics: `CSHIFT`, `EOSHIFT`, + `PACK`, `RESHAPE`, `SPREAD`, `TRANSPOSE`, and `UNPACK`. + +The location transformationals `FINDLOC`, `MAXLOC`, and `MINLOC`. + +There is a new `SELECTED_UNSIGNED_KIND` intrinsic function; it happens +to work identically to the existing `SELECTED_INT_KIND`. + +Two new intrinsic functions `UMASKL` and `UMASKR` work just like +`MASKL` and `MASKR`, returning unsigned results instead of integers. + +Conversions to `UNSIGNED`, or between `UNSIGNED` kinds, can be done +via the new `UINT` intrinsic. The `UNSIGNED` intrinsic name is also +supported as an alias. + +Support for `UNSIGNED` in the `OUT_OF_RANGE` predicate remains to be implemented. + +## Other usage + +`UNSIGNED` is allowed in `SELECT CASE`, but not in `DO` loop indices or +limits, or an arithmetic `IF` expression. + +`UNSIGNED` array indices are not allowed. + +`UNSIGNED` data may be used as data items in I/O statements, including +list-directed and `NAMELIST` I/O. +Format-directed I/O may edit `UNSIGNED` data with `I`, `G`, `B`, `O`, and `Z` +edit descriptors. + +## C interoperability + +`UNSIGNED` data map to type codes for C's `unsigned` types in the +`type` member of a `cdesc_t` descriptor in the `ISO_Fortran_binding.h` +header file. + +## Standard modules + +New definitions (`C_UNSIGNED`, `C_UINT8_T`, &c.) were added to ISO_C_BINDING +and new constants (`UINT8`, `UINT16`, &c.) to ISO_FORTRAN_ENV. diff --git a/flang/docs/index.md b/flang/docs/index.md index 70478fa0936d0..c35f634746e68 100644 --- a/flang/docs/index.md +++ b/flang/docs/index.md @@ -87,6 +87,7 @@ on how to get in touch with us and to learn more about the current status. f2018-grammar.md fstack-arrays Real16MathSupport + Unsigned ``` # Indices and tables diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index 41a6255207976..3a689c335c81c 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -495,8 +495,7 @@ struct NodeVisitor { READ_FEATURE(OmpIfClause::Modifier) READ_FEATURE(OmpDirectiveNameModifier) READ_FEATURE(OmpLinearClause) - READ_FEATURE(OmpLinearClause::WithModifier) - READ_FEATURE(OmpLinearClause::WithoutModifier) + READ_FEATURE(OmpLinearClause::Modifier) READ_FEATURE(OmpLinearModifier) READ_FEATURE(OmpLinearModifier::Value) READ_FEATURE(OmpLoopDirective) diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp index 2dc480f0c901b..665b92be00898 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp @@ -143,6 +143,10 @@ std::string OpenMPCounterVisitor::getName(const OpenMPConstruct &c) { }, c.u); }, + [&](const OpenMPErrorConstruct &c) -> std::string { + const CharBlock &source{std::get<0>(c.t).source}; + return normalize_construct_name(source.ToString()); + }, [&](const OpenMPSectionConstruct &c) -> std::string { return "section"; }, diff --git a/flang/include/flang/Common/Fortran-consts.h b/flang/include/flang/Common/Fortran-consts.h index eedcdae335c40..3ce5b6ac7b686 100644 --- a/flang/include/flang/Common/Fortran-consts.h +++ b/flang/include/flang/Common/Fortran-consts.h @@ -9,13 +9,15 @@ #ifndef FORTRAN_COMMON_FORTRAN_CONSTS_H_ #define FORTRAN_COMMON_FORTRAN_CONSTS_H_ -#include "flang/Common/enum-class.h" +#include "enum-set.h" #include namespace Fortran::common { -// Fortran has five kinds of intrinsic data types, plus the derived types. -ENUM_CLASS(TypeCategory, Integer, Real, Complex, Character, Logical, Derived) +// Fortran has five kinds of standard intrinsic data types, the Unsigned +// extension, and derived types. +ENUM_CLASS( + TypeCategory, Integer, Unsigned, Real, Complex, Character, Logical, Derived) ENUM_CLASS(VectorElementCategory, Integer, Unsigned, Real) ENUM_CLASS(IoStmtKind, None, Backspace, Close, Endfile, Flush, Inquire, Open, diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h index b04f6117ae965..44f88009f8f2c 100644 --- a/flang/include/flang/Common/Fortran-features.h +++ b/flang/include/flang/Common/Fortran-features.h @@ -54,7 +54,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines, PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy, UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr, SavedLocalInSpecExpr, PrintNamelist, AssumedRankPassedToNonAssumedRank, - IgnoreIrrelevantAttributes) + IgnoreIrrelevantAttributes, Unsigned) // Portability and suspicious usage warnings ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable, @@ -73,7 +73,7 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable, PreviousScalarUse, RedeclaredInaccessibleComponent, ImplicitShared, IndexVarRedefinition, IncompatibleImplicitInterfaces, BadTypeForTarget, VectorSubscriptFinalization, UndefinedFunctionResult, UselessIomsg, - MismatchingDummyProcedure, SubscriptedEmptyArray) + MismatchingDummyProcedure, SubscriptedEmptyArray, UnsignedLiteralTruncation) using LanguageFeatures = EnumSet; using UsageWarnings = EnumSet; diff --git a/flang/include/flang/Common/Fortran.h b/flang/include/flang/Common/Fortran.h index 72e4348a42a3f..e1922f7654bb1 100644 --- a/flang/include/flang/Common/Fortran.h +++ b/flang/include/flang/Common/Fortran.h @@ -23,7 +23,8 @@ namespace Fortran::common { class LanguageFeatureControl; constexpr bool IsNumericTypeCategory(TypeCategory category) { - return category == TypeCategory::Integer || category == TypeCategory::Real || + return category == TypeCategory::Integer || + category == TypeCategory::Unsigned || category == TypeCategory::Real || category == TypeCategory::Complex; } diff --git a/flang/include/flang/Evaluate/complex.h b/flang/include/flang/Evaluate/complex.h index 06eef84241094..2dcd28b59968c 100644 --- a/flang/include/flang/Evaluate/complex.h +++ b/flang/include/flang/Evaluate/complex.h @@ -61,10 +61,11 @@ template class Complex { template static ValueWithRealFlags FromInteger(const INT &n, + bool isUnsigned = false, Rounding rounding = TargetCharacteristics::defaultRounding) { ValueWithRealFlags result; - result.value.re_ = - Part::FromInteger(n, rounding).AccumulateFlags(result.flags); + result.value.re_ = Part::FromInteger(n, isUnsigned, rounding) + .AccumulateFlags(result.flags); return result; } diff --git a/flang/include/flang/Evaluate/expression.h b/flang/include/flang/Evaluate/expression.h index 2a40193e32306..9ea037a2f7c42 100644 --- a/flang/include/flang/Evaluate/expression.h +++ b/flang/include/flang/Evaluate/expression.h @@ -209,10 +209,12 @@ template struct Convert : public Operation, TO, SomeKind> { // Fortran doesn't have conversions between kinds of CHARACTER apart from // assignments, and in those the data must be convertible to/from 7-bit ASCII. - static_assert(((TO::category == TypeCategory::Integer || - TO::category == TypeCategory::Real) && - (FROMCAT == TypeCategory::Integer || - FROMCAT == TypeCategory::Real)) || + static_assert( + ((TO::category == TypeCategory::Integer || + TO::category == TypeCategory::Real || + TO::category == TypeCategory::Unsigned) && + (FROMCAT == TypeCategory::Integer || FROMCAT == TypeCategory::Real || + FROMCAT == TypeCategory::Unsigned)) || TO::category == FROMCAT); using Result = TO; using Operand = SomeKind; @@ -526,7 +528,8 @@ class Expr> private: using Conversions = std::tuple, - Convert>; + Convert, + Convert>; using Operations = std::tuple, Negate, Add, Subtract, Multiply, Divide, Power, Extremum>; @@ -547,6 +550,29 @@ class Expr> u; }; +template +class Expr> + : public ExpressionBase> { +public: + using Result = Type; + + EVALUATE_UNION_CLASS_BOILERPLATE(Expr) + +private: + using Conversions = std::tuple, + Convert, + Convert>; + using Operations = + std::tuple, Negate, Add, + Subtract, Multiply, Divide, Extremum>; + using Others = std::tuple, ArrayConstructor, + Designator, FunctionRef>; + +public: + common::TupleToVariant> + u; +}; + template class Expr> : public ExpressionBase> { @@ -560,7 +586,8 @@ class Expr> // N.B. Real->Complex and Complex->Real conversions are done with CMPLX // and part access operations (resp.). using Conversions = std::variant, - Convert>; + Convert, + Convert>; using Operations = std::variant, Parentheses, Negate, Add, Subtract, Multiply, Divide, Power, RealToIntPower, Extremum>; @@ -590,6 +617,7 @@ class Expr> }; FOR_EACH_INTEGER_KIND(extern template class Expr, ) +FOR_EACH_UNSIGNED_KIND(extern template class Expr, ) FOR_EACH_REAL_KIND(extern template class Expr, ) FOR_EACH_COMPLEX_KIND(extern template class Expr, ) @@ -629,7 +657,8 @@ class Relational : public Operation, LogicalResult, T, T> { static_assert(Operand::category == TypeCategory::Integer || Operand::category == TypeCategory::Real || Operand::category == TypeCategory::Complex || - Operand::category == TypeCategory::Character); + Operand::category == TypeCategory::Character || + Operand::category == TypeCategory::Unsigned); CLASS_BOILERPLATE(Relational) Relational( RelationalOperator r, const Expr &a, const Expr &b) @@ -642,7 +671,7 @@ class Relational : public Operation, LogicalResult, T, T> { template <> class Relational { using DirectlyComparableTypes = common::CombineTuples; + ComplexTypes, CharacterTypes, UnsignedTypes>; public: using Result = LogicalResult; @@ -656,6 +685,7 @@ template <> class Relational { }; FOR_EACH_INTEGER_KIND(extern template class Relational, ) +FOR_EACH_UNSIGNED_KIND(extern template class Relational, ) FOR_EACH_REAL_KIND(extern template class Relational, ) FOR_EACH_CHARACTER_KIND(extern template class Relational, ) extern template class Relational; @@ -886,6 +916,7 @@ FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructor, ) FOR_EACH_INTRINSIC_KIND(template class Expr, ) \ FOR_EACH_CATEGORY_TYPE(template class Expr, ) \ FOR_EACH_INTEGER_KIND(template class Relational, ) \ + FOR_EACH_UNSIGNED_KIND(template class Relational, ) \ FOR_EACH_REAL_KIND(template class Relational, ) \ FOR_EACH_CHARACTER_KIND(template class Relational, ) \ template class Relational; \ diff --git a/flang/include/flang/Evaluate/fold.h b/flang/include/flang/Evaluate/fold.h index d2a153fb7919e..b21c0f311fd35 100644 --- a/flang/include/flang/Evaluate/fold.h +++ b/flang/include/flang/Evaluate/fold.h @@ -89,8 +89,19 @@ constexpr std::optional ToInt64( return std::nullopt; } } +template +constexpr std::optional ToInt64( + const Expr> &expr) { + if (auto scalar{ + GetScalarConstantValue>(expr)}) { + return scalar->ToInt64(); + } else { + return std::nullopt; + } +} std::optional ToInt64(const Expr &); +std::optional ToInt64(const Expr &); std::optional ToInt64(const Expr &); std::optional ToInt64(const ActualArgument &); diff --git a/flang/include/flang/Evaluate/integer.h b/flang/include/flang/Evaluate/integer.h index e420eb75e3dff..fccc2ad774a8f 100644 --- a/flang/include/flang/Evaluate/integer.h +++ b/flang/include/flang/Evaluate/integer.h @@ -33,6 +33,12 @@ namespace Fortran::evaluate::value { +// Computes decimal range in the sense of SELECTED_INT_KIND +static constexpr int DecimalRange(int bits) { + // This magic value is LOG10(2.)*1E12. + return static_cast((bits * 301029995664) / 1000000000000); +} + // Implements an integer as an assembly of smaller host integer parts // that constitute the digits of a large-radix fixed-point number. // For best performance, the type of these parts should be half of the @@ -367,9 +373,8 @@ class Integer { static constexpr int DIGITS{bits - 1}; // don't count the sign bit static constexpr Integer HUGE() { return MASKR(bits - 1); } static constexpr Integer Least() { return MASKL(1); } - static constexpr int RANGE{// in the sense of SELECTED_INT_KIND - // This magic value is LOG10(2.)*1E12. - static_cast(((bits - 1) * 301029995664) / 1000000000000)}; + static constexpr int RANGE{DecimalRange(bits - 1)}; + static constexpr int UnsignedRANGE{DecimalRange(bits)}; constexpr bool IsZero() const { for (int j{0}; j < parts; ++j) { diff --git a/flang/include/flang/Evaluate/real.h b/flang/include/flang/Evaluate/real.h index 11cc8f776b0e9..03294881850a1 100644 --- a/flang/include/flang/Evaluate/real.h +++ b/flang/include/flang/Evaluate/real.h @@ -288,8 +288,9 @@ template class Real { template static ValueWithRealFlags FromInteger(const INT &n, + bool isUnsigned = false, Rounding rounding = TargetCharacteristics::defaultRounding) { - bool isNegative{n.IsNegative()}; + bool isNegative{!isUnsigned && n.IsNegative()}; INT absN{n}; if (isNegative) { absN = n.Negate().value; // overflow is safe to ignore diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h index dafacdf1ba0c5..f586c59d46e54 100644 --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -582,7 +582,8 @@ Expr ConvertToType(Expr> &&x) { template Expr ConvertToType(BOZLiteralConstant &&x) { static_assert(IsSpecificIntrinsicType); - if constexpr (TO::category == TypeCategory::Integer) { + if constexpr (TO::category == TypeCategory::Integer || + TO::category == TypeCategory::Unsigned) { return Expr{ Constant{Scalar::ConvertUnsigned(std::move(x)).value}}; } else { @@ -754,11 +755,11 @@ Expr> PromoteAndCombine( // one of the operands to the type of the other. Handles special cases with // typeless literal operands and with REAL/COMPLEX exponentiation to INTEGER // powers. -template