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/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 f037a91f6e5d0..50729e0173506 100644 --- a/.github/workflows/build-ci-container.yml +++ b/.github/workflows/build-ci-container.yml @@ -60,7 +60,7 @@ jobs: - 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: @@ -80,8 +80,8 @@ jobs: - name: Push Container run: | - podman load -i ${{ needs.build-ci-container.outptus.container-filename }} - podman tag ${{ steps.vars.outputs.container-name-tag }} ${{ steps.vars.outputs.container-name }}:latest + 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 ${{ 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 index 32a809ee268ea..58355d261c43c 100644 --- a/.github/workflows/containers/github-action-ci/Dockerfile +++ b/.github/workflows/containers/github-action-ci/Dockerfile @@ -2,7 +2,7 @@ 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 +ENV LLVM_VERSION=19.1.5 RUN apt-get update && \ apt-get install -y \ @@ -41,13 +41,13 @@ RUN ninja -C ./build stage2-clang-bolt stage2-install-distribution && ninja -C . 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 && \ - apt-get install -y \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ binutils \ cmake \ curl \ @@ -56,7 +56,22 @@ RUN apt-get update && \ ninja-build \ nodejs \ perl-modules \ - python3-psutil + 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/docs.yml b/.github/workflows/docs.yml index 3b9fca21d63cf..2845affc66100 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/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml index cba8afbb54f0f..a28bf4d5daf6d 100644 --- a/.github/workflows/libcxx-build-and-test.yaml +++ b/.github/workflows/libcxx-build-and-test.yaml @@ -37,12 +37,13 @@ jobs: stage1: if: github.repository_owner == 'llvm' runs-on: libcxx-self-hosted-linux - container: ghcr.io/llvm/libcxx-linux-builder:0fd6f684b9c84c32d6cbfd9742402e788b2879f1 + container: ghcr.io/llvm/libcxx-linux-builder:d8a0709b1090350a7fe3604d8ab78c7d62f10698 continue-on-error: false strategy: fail-fast: false matrix: config: [ + 'frozen-cxx03-headers', 'generic-cxx03', 'generic-cxx26', 'generic-modules' @@ -74,7 +75,7 @@ jobs: stage2: if: github.repository_owner == 'llvm' runs-on: libcxx-self-hosted-linux - container: ghcr.io/llvm/libcxx-linux-builder:0fd6f684b9c84c32d6cbfd9742402e788b2879f1 + container: ghcr.io/llvm/libcxx-linux-builder:d8a0709b1090350a7fe3604d8ab78c7d62f10698 needs: [ stage1 ] continue-on-error: false strategy: @@ -162,7 +163,7 @@ jobs: - config: 'generic-msan' machine: libcxx-self-hosted-linux runs-on: ${{ matrix.machine }} - container: ghcr.io/llvm/libcxx-linux-builder:0fd6f684b9c84c32d6cbfd9742402e788b2879f1 + container: ghcr.io/llvm/libcxx-linux-builder:d8a0709b1090350a7fe3604d8ab78c7d62f10698 steps: - uses: actions/checkout@v4 - name: ${{ matrix.config }} 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/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index ac96b836ed579..f88e34b8e8962 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -1961,7 +1961,15 @@ void BinaryContext::printInstruction(raw_ostream &OS, const MCInst &Instruction, OS << "\tjit\t" << MIB->getTargetSymbol(Instruction)->getName() << " # ID: " << DynamicID; } else { - InstPrinter->printInst(&Instruction, 0, "", *STI, OS); + // If there are annotations on the instruction, the MCInstPrinter will fail + // to print the preferred alias as it only does so when the number of + // operands is as expected. See + // https://github.com/llvm/llvm-project/blob/782f1a0d895646c364a53f9dcdd6d4ec1f3e5ea0/llvm/lib/MC/MCInstPrinter.cpp#L142 + // Therefore, create a temporary copy of the Inst from which the annotations + // are removed, and print that Inst. + MCInst InstNoAnnot = Instruction; + MIB->stripAnnotations(InstNoAnnot); + InstPrinter->printInst(&InstNoAnnot, 0, "", *STI, OS); } if (MIB->isCall(Instruction)) { if (MIB->isTailCall(Instruction)) 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/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp index 4e888a5b147ac..e9a9741bc3716 100644 --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -75,6 +75,8 @@ static bool isSupportedAArch64(uint64_t Type) { case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: @@ -183,6 +185,8 @@ static size_t getSizeForTypeAArch64(uint64_t Type) { case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: @@ -651,6 +655,8 @@ static bool isTLSAArch64(uint64_t Type) { case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_TLSDESC_CALL: @@ -716,6 +722,8 @@ static bool isPCRelativeAArch64(uint64_t Type) { case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: 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/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp index 03b414b71caca..0532468c237e0 100644 --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -123,6 +123,30 @@ inline raw_ostream &operator<<(raw_ostream &OS, const ORCState &E) { namespace { +/// Extension to DataExtractor that supports reading addresses stored in +/// PC-relative format. +class AddressExtractor : public DataExtractor { + uint64_t DataAddress; + +public: + AddressExtractor(StringRef Data, uint64_t DataAddress, bool IsLittleEndian, + uint8_t AddressSize) + : DataExtractor(Data, IsLittleEndian, AddressSize), + DataAddress(DataAddress) {} + + /// Extract 32-bit PC-relative address/pointer. + uint64_t getPCRelAddress32(Cursor &C) { + const uint64_t Base = DataAddress + C.tell(); + return Base + (int32_t)getU32(C); + } + + /// Extract 64-bit PC-relative address/pointer. + uint64_t getPCRelAddress64(Cursor &C) { + const uint64_t Base = DataAddress + C.tell(); + return Base + (int64_t)getU64(C); + } +}; + class LinuxKernelRewriter final : public MetadataRewriter { /// Information required for updating metadata referencing an instruction. struct InstructionFixup { @@ -423,13 +447,13 @@ Error LinuxKernelRewriter::processSMPLocks() { return createStringError(errc::executable_format_error, "bad size of .smp_locks section"); - DataExtractor DE = DataExtractor(SMPLocksSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); - DataExtractor::Cursor Cursor(0); + AddressExtractor AE(SMPLocksSection->getContents(), SectionAddress, + BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor Cursor(0); while (Cursor && Cursor.tell() < SectionSize) { const uint64_t Offset = Cursor.tell(); - const uint64_t IP = SectionAddress + Offset + (int32_t)DE.getU32(Cursor); + const uint64_t IP = AE.getPCRelAddress32(Cursor); // Consume the status of the cursor. if (!Cursor) @@ -499,20 +523,17 @@ Error LinuxKernelRewriter::readORCTables() { return createStringError(errc::executable_format_error, "ORC entries number mismatch detected"); - const uint64_t IPSectionAddress = ORCUnwindIPSection->getAddress(); - DataExtractor OrcDE = DataExtractor(ORCUnwindSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); - DataExtractor IPDE = DataExtractor(ORCUnwindIPSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); + DataExtractor OrcDE(ORCUnwindSection->getContents(), + BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); + AddressExtractor IPAE( + ORCUnwindIPSection->getContents(), ORCUnwindIPSection->getAddress(), + BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); DataExtractor::Cursor ORCCursor(0); DataExtractor::Cursor IPCursor(0); uint64_t PrevIP = 0; for (uint32_t Index = 0; Index < NumORCEntries; ++Index) { - const uint64_t IP = - IPSectionAddress + IPCursor.tell() + (int32_t)IPDE.getU32(IPCursor); - + const uint64_t IP = IPAE.getPCRelAddress32(IPCursor); // Consume the status of the cursor. if (!IPCursor) return createStringError(errc::executable_format_error, @@ -856,15 +877,13 @@ Error LinuxKernelRewriter::validateORCTables() { if (!ORCUnwindIPSection) return Error::success(); - const uint64_t IPSectionAddress = ORCUnwindIPSection->getAddress(); - DataExtractor IPDE = DataExtractor(ORCUnwindIPSection->getOutputContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); - DataExtractor::Cursor IPCursor(0); + AddressExtractor IPAE( + ORCUnwindIPSection->getOutputContents(), ORCUnwindIPSection->getAddress(), + BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor IPCursor(0); uint64_t PrevIP = 0; for (uint32_t Index = 0; Index < NumORCEntries; ++Index) { - const uint64_t IP = - IPSectionAddress + IPCursor.tell() + (int32_t)IPDE.getU32(IPCursor); + const uint64_t IP = IPAE.getPCRelAddress32(IPCursor); if (!IPCursor) return createStringError(errc::executable_format_error, "out of bounds while reading ORC IP table: %s", @@ -916,16 +935,14 @@ Error LinuxKernelRewriter::readStaticCalls() { "static call table size error"); const uint64_t SectionAddress = StaticCallSection->getAddress(); - DataExtractor DE(StaticCallSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); - DataExtractor::Cursor Cursor(StaticCallTableAddress - SectionAddress); + AddressExtractor AE(StaticCallSection->getContents(), SectionAddress, + BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor Cursor(StaticCallTableAddress - SectionAddress); uint32_t EntryID = 0; while (Cursor && Cursor.tell() < Stop->getAddress() - SectionAddress) { - const uint64_t CallAddress = - SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t KeyAddress = - SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor); + const uint64_t CallAddress = AE.getPCRelAddress32(Cursor); + const uint64_t KeyAddress = AE.getPCRelAddress32(Cursor); // Consume the status of the cursor. if (!Cursor) @@ -1027,18 +1044,15 @@ Error LinuxKernelRewriter::readExceptionTable() { return createStringError(errc::executable_format_error, "exception table size error"); - const uint64_t SectionAddress = ExceptionsSection->getAddress(); - DataExtractor DE(ExceptionsSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); - DataExtractor::Cursor Cursor(0); + AddressExtractor AE( + ExceptionsSection->getContents(), ExceptionsSection->getAddress(), + BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor Cursor(0); uint32_t EntryID = 0; while (Cursor && Cursor.tell() < ExceptionsSection->getSize()) { - const uint64_t InstAddress = - SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t FixupAddress = - SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t Data = DE.getU32(Cursor); + const uint64_t InstAddress = AE.getPCRelAddress32(Cursor); + const uint64_t FixupAddress = AE.getPCRelAddress32(Cursor); + const uint64_t Data = AE.getU32(Cursor); // Consume the status of the cursor. if (!Cursor) @@ -1134,9 +1148,9 @@ Error LinuxKernelRewriter::readParaInstructions() { if (!ParavirtualPatchSection) return Error::success(); - DataExtractor DE = DataExtractor(ParavirtualPatchSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); + DataExtractor DE(ParavirtualPatchSection->getContents(), + BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); uint32_t EntryID = 0; DataExtractor::Cursor Cursor(0); while (Cursor && !DE.eof(Cursor)) { @@ -1235,15 +1249,14 @@ Error LinuxKernelRewriter::readBugTable() { return createStringError(errc::executable_format_error, "bug table size error"); - const uint64_t SectionAddress = BugTableSection->getAddress(); - DataExtractor DE(BugTableSection->getContents(), BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); - DataExtractor::Cursor Cursor(0); + AddressExtractor AE( + BugTableSection->getContents(), BugTableSection->getAddress(), + BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor Cursor(0); uint32_t EntryID = 0; while (Cursor && Cursor.tell() < BugTableSection->getSize()) { const uint64_t Pos = Cursor.tell(); - const uint64_t InstAddress = - SectionAddress + Pos + (int32_t)DE.getU32(Cursor); + const uint64_t InstAddress = AE.getPCRelAddress32(Cursor); Cursor.seek(Pos + BUG_TABLE_ENTRY_SIZE); if (!Cursor) @@ -1402,23 +1415,20 @@ Error LinuxKernelRewriter::readAltInstructions() { Error LinuxKernelRewriter::tryReadAltInstructions(uint32_t AltInstFeatureSize, bool AltInstHasPadLen, bool ParseOnly) { - const uint64_t Address = AltInstrSection->getAddress(); - DataExtractor DE = DataExtractor(AltInstrSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); + AddressExtractor AE( + AltInstrSection->getContents(), AltInstrSection->getAddress(), + BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor Cursor(0); uint64_t EntryID = 0; - DataExtractor::Cursor Cursor(0); - while (Cursor && !DE.eof(Cursor)) { - const uint64_t OrgInstAddress = - Address + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t AltInstAddress = - Address + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t Feature = DE.getUnsigned(Cursor, AltInstFeatureSize); - const uint8_t OrgSize = DE.getU8(Cursor); - const uint8_t AltSize = DE.getU8(Cursor); + while (Cursor && !AE.eof(Cursor)) { + const uint64_t OrgInstAddress = AE.getPCRelAddress32(Cursor); + const uint64_t AltInstAddress = AE.getPCRelAddress32(Cursor); + const uint64_t Feature = AE.getUnsigned(Cursor, AltInstFeatureSize); + const uint8_t OrgSize = AE.getU8(Cursor); + const uint8_t AltSize = AE.getU8(Cursor); // Older kernels may have the padlen field. - const uint8_t PadLen = AltInstHasPadLen ? DE.getU8(Cursor) : 0; + const uint8_t PadLen = AltInstHasPadLen ? AE.getU8(Cursor) : 0; if (!Cursor) return createStringError( @@ -1537,19 +1547,17 @@ Error LinuxKernelRewriter::readPCIFixupTable() { return createStringError(errc::executable_format_error, "PCI fixup table size error"); - const uint64_t Address = PCIFixupSection->getAddress(); - DataExtractor DE = DataExtractor(PCIFixupSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); + AddressExtractor AE( + PCIFixupSection->getContents(), PCIFixupSection->getAddress(), + BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor Cursor(0); uint64_t EntryID = 0; - DataExtractor::Cursor Cursor(0); - while (Cursor && !DE.eof(Cursor)) { - const uint16_t Vendor = DE.getU16(Cursor); - const uint16_t Device = DE.getU16(Cursor); - const uint32_t Class = DE.getU32(Cursor); - const uint32_t ClassShift = DE.getU32(Cursor); - const uint64_t HookAddress = - Address + Cursor.tell() + (int32_t)DE.getU32(Cursor); + while (Cursor && !AE.eof(Cursor)) { + const uint16_t Vendor = AE.getU16(Cursor); + const uint16_t Device = AE.getU16(Cursor); + const uint32_t Class = AE.getU32(Cursor); + const uint32_t ClassShift = AE.getU32(Cursor); + const uint64_t HookAddress = AE.getPCRelAddress32(Cursor); if (!Cursor) return createStringError(errc::executable_format_error, @@ -1654,18 +1662,15 @@ Error LinuxKernelRewriter::readStaticKeysJumpTable() { "static keys jump table size error"); const uint64_t SectionAddress = StaticKeysJumpSection->getAddress(); - DataExtractor DE(StaticKeysJumpSection->getContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); - DataExtractor::Cursor Cursor(StaticKeysJumpTableAddress - SectionAddress); + AddressExtractor AE(StaticKeysJumpSection->getContents(), SectionAddress, + BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor Cursor(StaticKeysJumpTableAddress - SectionAddress); uint32_t EntryID = 0; while (Cursor && Cursor.tell() < Stop->getAddress() - SectionAddress) { - const uint64_t JumpAddress = - SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t TargetAddress = - SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t KeyAddress = - SectionAddress + Cursor.tell() + (int64_t)DE.getU64(Cursor); + const uint64_t JumpAddress = AE.getPCRelAddress32(Cursor); + const uint64_t TargetAddress = AE.getPCRelAddress32(Cursor); + const uint64_t KeyAddress = AE.getPCRelAddress64(Cursor); // Consume the status of the cursor. if (!Cursor) @@ -1859,21 +1864,18 @@ Error LinuxKernelRewriter::updateStaticKeysJumpTablePostEmit() { return Error::success(); const uint64_t SectionAddress = StaticKeysJumpSection->getAddress(); - DataExtractor DE(StaticKeysJumpSection->getOutputContents(), - BC.AsmInfo->isLittleEndian(), - BC.AsmInfo->getCodePointerSize()); - DataExtractor::Cursor Cursor(StaticKeysJumpTableAddress - SectionAddress); + AddressExtractor AE(StaticKeysJumpSection->getOutputContents(), + SectionAddress, BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); + AddressExtractor::Cursor Cursor(StaticKeysJumpTableAddress - SectionAddress); const BinaryData *Stop = BC.getBinaryDataByName("__stop___jump_table"); uint32_t EntryID = 0; uint64_t NumShort = 0; uint64_t NumLong = 0; while (Cursor && Cursor.tell() < Stop->getAddress() - SectionAddress) { - const uint64_t JumpAddress = - SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t TargetAddress = - SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor); - const uint64_t KeyAddress = - SectionAddress + Cursor.tell() + (int64_t)DE.getU64(Cursor); + const uint64_t JumpAddress = AE.getPCRelAddress32(Cursor); + const uint64_t TargetAddress = AE.getPCRelAddress32(Cursor); + const uint64_t KeyAddress = AE.getPCRelAddress64(Cursor); // Consume the status of the cursor. if (!Cursor) 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/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp index 7e08e5c81d26f..679c9774c767f 100644 --- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp +++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp @@ -1449,6 +1449,8 @@ class AArch64MCPlusBuilder : public MCPlusBuilder { case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0: + case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: case ELF::R_AARCH64_MOVW_UABS_G0: case ELF::R_AARCH64_MOVW_UABS_G0_NC: case ELF::R_AARCH64_MOVW_UABS_G1: 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/RISCV/call-annotations.s b/bolt/test/RISCV/call-annotations.s index ff99e0f1dfd84..f876544e214ca 100644 --- a/bolt/test/RISCV/call-annotations.s +++ b/bolt/test/RISCV/call-annotations.s @@ -16,13 +16,13 @@ f: // CHECK-LABEL: Binary Function "_start" after building cfg { // CHECK: auipc ra, f -// CHECK-NEXT: jalr ra, -0x4(ra) # Offset: 4 -// CHECK-NEXT: jal ra, f # Offset: 8 -// CHECK-NEXT: jal zero, f # TAILCALL # Offset: 12 +// CHECK-NEXT: jalr -0x4(ra) # Offset: 4 +// CHECK-NEXT: jal f # Offset: 8 +// CHECK-NEXT: j f # TAILCALL # Offset: 12 // CHECK-LABEL: Binary Function "long_tail" after building cfg { // CHECK: auipc t1, f -// CHECK-NEXT: jalr zero, -0x18(t1) # TAILCALL # Offset: 8 +// CHECK-NEXT: jr -0x18(t1) # TAILCALL # Offset: 8 // CHECK-LABEL: Binary Function "compressed_tail" after building cfg { // CHECK: jr a0 # TAILCALL # Offset: 0 diff --git a/bolt/test/RISCV/relax.s b/bolt/test/RISCV/relax.s index ec390ea76b5c7..74f049b8f8dd9 100644 --- a/bolt/test/RISCV/relax.s +++ b/bolt/test/RISCV/relax.s @@ -5,9 +5,9 @@ // RUN: llvm-objdump -d %t.bolt | FileCheck --check-prefix=OBJDUMP %s // CHECK: Binary Function "_start" after building cfg { -// CHECK: jal ra, near_f +// CHECK: jal near_f // CHECK-NEXT: auipc ra, far_f -// CHECK-NEXT: jalr ra, 0xc(ra) +// CHECK-NEXT: jalr 0xc(ra) // CHECK-NEXT: j near_f // CHECK: Binary Function "_start" after fix-riscv-calls { diff --git a/bolt/test/RISCV/reloc-branch.s b/bolt/test/RISCV/reloc-branch.s index 6a8b5a28e19d9..780d978f36f44 100644 --- a/bolt/test/RISCV/reloc-branch.s +++ b/bolt/test/RISCV/reloc-branch.s @@ -7,7 +7,7 @@ .p2align 1 // CHECK: Binary Function "_start" after building cfg { _start: -// CHECK: beq zero, zero, .Ltmp0 +// CHECK: beqz zero, .Ltmp0 beq zero, zero, 1f nop // CHECK: .Ltmp0 diff --git a/bolt/test/RISCV/reloc-jal.s b/bolt/test/RISCV/reloc-jal.s index ce54265fac05e..62a2f1dbea03a 100644 --- a/bolt/test/RISCV/reloc-jal.s +++ b/bolt/test/RISCV/reloc-jal.s @@ -14,7 +14,7 @@ f: .globl _start .p2align 1 _start: -// CHECK: jal ra, f +// CHECK: jal f jal ra, f ret .size _start, .-_start 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..f737fc75135a1 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); @@ -693,13 +696,11 @@ emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, // What this is a specialization of. auto SpecOf = CTSD->getSpecializedTemplateOrPartial(); - if (SpecOf.is()) { - Specialization.SpecializationOf = - getUSRForDecl(SpecOf.get()); - } else if (SpecOf.is()) { - Specialization.SpecializationOf = - getUSRForDecl(SpecOf.get()); - } + if (auto *CTD = dyn_cast(SpecOf)) + Specialization.SpecializationOf = getUSRForDecl(CTD); + else if (auto *CTPSD = + dyn_cast(SpecOf)) + Specialization.SpecializationOf = getUSRForDecl(CTPSD); // Parameters to the specilization. For partial specializations, get the // parameters "as written" from the ClassTemplatePartialSpecializationDecl @@ -783,7 +784,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 +811,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/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 9c8c93c5d16c7..959b11777e88d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -646,9 +646,9 @@ void exportReplacements(const llvm::StringRef MainFilePath, YAML << TUD; } -NamesAndOptions +ChecksAndOptions getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers) { - NamesAndOptions Result; + ChecksAndOptions Result; ClangTidyOptions Opts; Opts.Checks = "*"; clang::tidy::ClangTidyContext Context( @@ -661,7 +661,7 @@ getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers) { } for (const auto &Factory : Factories) - Result.Names.insert(Factory.getKey()); + Result.Checks.insert(Factory.getKey()); #if CLANG_TIDY_ENABLE_STATIC_ANALYZER SmallString<64> Buffer(AnalyzerCheckNamePrefix); @@ -670,7 +670,7 @@ getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers) { AllowEnablingAnalyzerAlphaCheckers)) { Buffer.truncate(DefSize); Buffer.append(AnalyzerCheck); - Result.Names.insert(Buffer); + Result.Checks.insert(Buffer); } for (std::string OptionName : { #define GET_CHECKER_OPTIONS diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h b/clang-tools-extra/clang-tidy/ClangTidy.h index 51d9e226c7946..4ffd49f6ebf50 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.h +++ b/clang-tools-extra/clang-tidy/ClangTidy.h @@ -58,12 +58,12 @@ class ClangTidyASTConsumerFactory { std::vector getCheckNames(const ClangTidyOptions &Options, bool AllowEnablingAnalyzerAlphaCheckers); -struct NamesAndOptions { - llvm::StringSet<> Names; +struct ChecksAndOptions { + llvm::StringSet<> Checks; llvm::StringSet<> Options; }; -NamesAndOptions +ChecksAndOptions getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers = true); /// Returns the effective check-specific options. diff --git a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp index f2ff27d85fb00..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( @@ -67,12 +90,9 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) { callExpr(argumentCountIs(1), callee(functionDecl(hasName("::std::move"))), hasArgument(0, ignoringImpCasts(OptionalDereferenceMatcher))); Finder->addMatcher( - cxxConstructExpr( - argumentCountIs(1U), hasType(BindOptionalType), - 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/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp index 24eefdb082eb3..30fcba367db67 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -7,9 +7,14 @@ //===----------------------------------------------------------------------===// #include "UseUsingCheck.h" -#include "clang/AST/ASTContext.h" +#include "../utils/LexerUtils.h" #include "clang/AST/DeclGroup.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Lex/Lexer.h" +#include using namespace clang::ast_matchers; namespace { @@ -83,6 +88,9 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { if (!ParentDecl) return; + const SourceManager &SM = *Result.SourceManager; + const LangOptions &LO = getLangOpts(); + // Match CXXRecordDecl only to store the range of the last non-implicit full // declaration, to later check whether it's within the typdef itself. const auto *MatchedTagDecl = Result.Nodes.getNodeAs(TagDeclName); @@ -119,14 +127,51 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { return; } - PrintingPolicy PrintPolicy(getLangOpts()); - PrintPolicy.SuppressScope = true; - PrintPolicy.ConstantArraySizeAsWritten = true; - PrintPolicy.UseVoidForZeroParams = false; - PrintPolicy.PrintInjectedClassNameWithArguments = false; + const TypeLoc TL = MatchedDecl->getTypeSourceInfo()->getTypeLoc(); + + auto [Type, QualifierStr] = [MatchedDecl, this, &TL, &SM, + &LO]() -> std::pair { + SourceRange TypeRange = TL.getSourceRange(); + + // Function pointer case, get the left and right side of the identifier + // without the identifier. + if (TypeRange.fullyContains(MatchedDecl->getLocation())) { + const auto RangeLeftOfIdentifier = CharSourceRange::getCharRange( + TypeRange.getBegin(), MatchedDecl->getLocation()); + const auto RangeRightOfIdentifier = CharSourceRange::getCharRange( + Lexer::getLocForEndOfToken(MatchedDecl->getLocation(), 0, SM, LO), + Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO)); + const std::string VerbatimType = + (Lexer::getSourceText(RangeLeftOfIdentifier, SM, LO) + + Lexer::getSourceText(RangeRightOfIdentifier, SM, LO)) + .str(); + return {VerbatimType, ""}; + } + + StringRef ExtraReference = ""; + if (MainTypeEndLoc.isValid() && TypeRange.fullyContains(MainTypeEndLoc)) { + // Each type introduced in a typedef can specify being a reference or + // pointer type seperately, so we need to sigure out if the new using-decl + // needs to be to a reference or pointer as well. + const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind( + MatchedDecl->getLocation(), SM, LO, tok::TokenKind::star, + tok::TokenKind::amp, tok::TokenKind::comma, + tok::TokenKind::kw_typedef); + + ExtraReference = Lexer::getSourceText( + CharSourceRange::getCharRange(Tok, Tok.getLocWithOffset(1)), SM, LO); - std::string Type = MatchedDecl->getUnderlyingType().getAsString(PrintPolicy); - std::string Name = MatchedDecl->getNameAsString(); + if (ExtraReference != "*" && ExtraReference != "&") + ExtraReference = ""; + + TypeRange.setEnd(MainTypeEndLoc); + } + return { + Lexer::getSourceText(CharSourceRange::getTokenRange(TypeRange), SM, LO) + .str(), + ExtraReference.str()}; + }(); + StringRef Name = MatchedDecl->getName(); SourceRange ReplaceRange = MatchedDecl->getSourceRange(); // typedefs with multiple comma-separated definitions produce multiple @@ -143,7 +188,8 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { // This is the first (and possibly the only) TypedefDecl in a typedef. Save // Type and Name in case we find subsequent TypedefDecl's in this typedef. FirstTypedefType = Type; - FirstTypedefName = Name; + FirstTypedefName = Name.str(); + MainTypeEndLoc = TL.getEndLoc(); } else { // This is additional TypedefDecl in a comma-separated typedef declaration. // Start replacement *after* prior replacement and separate with semicolon. @@ -153,10 +199,10 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { // If this additional TypedefDecl's Type starts with the first TypedefDecl's // type, make this using statement refer back to the first type, e.g. make // "typedef int Foo, *Foo_p;" -> "using Foo = int;\nusing Foo_p = Foo*;" - if (Type.size() > FirstTypedefType.size() && - Type.substr(0, FirstTypedefType.size()) == FirstTypedefType) - Type = FirstTypedefName + Type.substr(FirstTypedefType.size() + 1); + if (Type == FirstTypedefType && !QualifierStr.empty()) + Type = FirstTypedefName; } + if (!ReplaceRange.getEnd().isMacroID()) { const SourceLocation::IntTy Offset = MatchedDecl->getFunctionType() ? 0 : Name.size(); @@ -171,13 +217,12 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { LastTagDeclRange->second.isValid() && ReplaceRange.fullyContains(LastTagDeclRange->second)) { Type = std::string(Lexer::getSourceText( - CharSourceRange::getTokenRange(LastTagDeclRange->second), - *Result.SourceManager, getLangOpts())); + CharSourceRange::getTokenRange(LastTagDeclRange->second), SM, LO)); if (Type.empty()) return; } - std::string Replacement = Using + Name + " = " + Type; + std::string Replacement = (Using + Name + " = " + Type + QualifierStr).str(); Diag << FixItHint::CreateReplacement(ReplaceRange, Replacement); } } // namespace clang::tidy::modernize diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h index 7054778d84a0c..1e54bbf23c984 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h @@ -26,6 +26,7 @@ class UseUsingCheck : public ClangTidyCheck { std::string FirstTypedefType; std::string FirstTypedefName; + SourceLocation MainTypeEndLoc; public: UseUsingCheck(StringRef Name, ClangTidyContext *Context); 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/ContainerSizeEmptyCheck.h b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h index acd8a6bfc50f5..3aa4bdc496194 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h +++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h @@ -18,10 +18,11 @@ namespace clang::tidy::readability { /// a call to `empty()`. /// /// The emptiness of a container should be checked using the `empty()` method -/// instead of the `size()` method. It shows clearer intent to use `empty()`. -/// Furthermore some containers may implement the `empty()` method but not -/// implement the `size()` method. Using `empty()` whenever possible makes it -/// easier to switch to another container in the future. +/// instead of the `size()`/`length()` method. It shows clearer intent to use +/// `empty()`. Furthermore some containers may implement the `empty()` method +/// but not implement the `size()` or `length()` method. Using `empty()` +/// whenever possible makes it easier to switch to another container in the +/// future. class ContainerSizeEmptyCheck : public ClangTidyCheck { public: ContainerSizeEmptyCheck(StringRef Name, ClangTidyContext *Context); 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/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index d42dafa8ffc36..b8d843cba7133 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -526,6 +526,24 @@ static bool verifyFileExtensions( return AnyInvalid; } +static bool verifyOptions(const llvm::StringSet<> &ValidOptions, + const ClangTidyOptions::OptionMap &OptionMap, + StringRef Source) { + bool AnyInvalid = false; + for (auto Key : OptionMap.keys()) { + if (ValidOptions.contains(Key)) + continue; + AnyInvalid = true; + auto &Output = llvm::WithColor::warning(llvm::errs(), Source) + << "unknown check option '" << Key << '\''; + llvm::StringRef Closest = closest(Key, ValidOptions); + if (!Closest.empty()) + Output << "; did you mean '" << Closest << '\''; + Output << VerifyConfigWarningEnd; + } + return AnyInvalid; +} + static SmallString<256> makeAbsolute(llvm::StringRef Input) { if (Input.empty()) return {}; @@ -629,29 +647,17 @@ int clangTidyMain(int argc, const char **argv) { if (VerifyConfig) { std::vector RawOptions = OptionsProvider->getRawOptions(FileName); - NamesAndOptions Valid = + ChecksAndOptions Valid = getAllChecksAndOptions(AllowEnablingAnalyzerAlphaCheckers); bool AnyInvalid = false; for (const auto &[Opts, Source] : RawOptions) { if (Opts.Checks) - AnyInvalid |= verifyChecks(Valid.Names, *Opts.Checks, Source); - + AnyInvalid |= verifyChecks(Valid.Checks, *Opts.Checks, Source); if (Opts.HeaderFileExtensions && Opts.ImplementationFileExtensions) AnyInvalid |= verifyFileExtensions(*Opts.HeaderFileExtensions, *Opts.ImplementationFileExtensions, Source); - - for (auto Key : Opts.CheckOptions.keys()) { - if (Valid.Options.contains(Key)) - continue; - AnyInvalid = true; - auto &Output = llvm::WithColor::warning(llvm::errs(), Source) - << "unknown check option '" << Key << '\''; - llvm::StringRef Closest = closest(Key, Valid.Options); - if (!Closest.empty()) - Output << "; did you mean '" << Closest << '\''; - Output << VerifyConfigWarningEnd; - } + AnyInvalid |= verifyOptions(Valid.Options, Opts.CheckOptions, Source); } if (AnyInvalid) return 1; 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..fa3a8e577a33a 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. @@ -289,6 +317,9 @@ Changes in existing checks member function calls too and to only expand macros starting with ``PRI`` and ``__PRI`` from ```` in the format string. +- Improved :doc:`modernize-use-using + ` check by not expanding macros. + - Improved :doc:`performance-avoid-endl ` check to use ``std::endl`` as placeholder when lexer cannot get source text. 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/cppcoreguidelines/narrowing-conversions.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/narrowing-conversions.rst index 04260e75aa558..7cc0b2809b458 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/narrowing-conversions.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/narrowing-conversions.rst @@ -27,6 +27,40 @@ This check will flag: - All applications of binary operators with a narrowing conversions. For example: ``int i; i+= 0.1;``. +Arithmetic with smaller integer types than ``int`` trigger implicit conversions, +as explained under `"Integral Promotion" on cppreference.com +`_. +This check diagnoses more instances of narrowing than the compiler warning +`-Wconversion` does. The example below demonstrates this behavior. + +.. code-block:: c++ + + // The following function definition demonstrates usage of arithmetic with + // integer types smaller than `int` and how the narrowing conversion happens + // implicitly. + void computation(short argument1, short argument2) { + // Arithmetic written by humans: + short result = argument1 + argument2; + // Arithmetic actually performed by C++: + short result = static_cast(static_cast(argument1) + static_cast(argument2)); + } + + void recommended_resolution(short argument1, short argument2) { + short result = argument1 + argument2; + // ^ warning: narrowing conversion from 'int' to signed type 'short' is implementation-defined + + // The cppcoreguidelines recommend to resolve this issue by using the GSL + // in one of two ways. Either by a cast that throws if a loss of precision + // would occur. + short result = gsl::narrow(argument1 + argument2); + // Or it can be resolved without checking the result risking invalid results. + short result = gsl::narrow_cast(argument1 + argument2); + + // A classical `static_cast` will silence the warning as well if the GSL + // is not available. + short result = static_cast(argument1 + argument2); + } + Options ------- 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/checks/modernize/use-ranges.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst index 1ce866ca1f66a..912b42b33f919 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst @@ -104,6 +104,9 @@ Calls to the following std library algorithms are checked: ``std::unique``, ``std::upper_bound``. +Note: some range algorithms for ``vector`` require C++23 because it uses +proxy iterators. + Reverse Iteration ----------------- 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/cppcoreguidelines/pro-type-vararg.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-vararg.cpp index 6792c7920dd11..3f73d1de333f4 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-vararg.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-vararg.cpp @@ -51,8 +51,8 @@ void my_printf(const char* format, ...) { int my_vprintf(const char* format, va_list arg ); // OK to declare function taking va_list -void ignoredBuiltinsTest() { - (void)__builtin_assume_aligned(0, 8); +void ignoredBuiltinsTest(void *ptr) { + (void)__builtin_assume_aligned(ptr, 8); (void)__builtin_constant_p(0); (void)__builtin_fpclassify(0, 0, 0, 0, 0, 0.f); (void)__builtin_isinf_sign(0.f); 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/test/clang-tidy/checkers/modernize/use-using.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp index 925e5f9c1ca54..214a66f3dcc88 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp @@ -80,7 +80,7 @@ typedef Test another; typedef int* PInt; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using PInt = int *; +// CHECK-FIXES: using PInt = int*; typedef int bla1, bla2, bla3; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' @@ -112,7 +112,7 @@ TYPEDEF Foo Bak; typedef FOO Bam; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' // CHECK-FIXES: #define FOO Foo -// CHECK-FIXES: using Bam = Foo; +// CHECK-FIXES: using Bam = FOO; typedef struct Foo Bap; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' @@ -247,7 +247,7 @@ typedef Q Q3_t; typedef TwoArgTemplate >, S<(0 < 0), Q > > Nested_t; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Nested_t = TwoArgTemplate>, S<(0 < 0), Q>>; +// CHECK-FIXES: using Nested_t = TwoArgTemplate >, S<(0 < 0), Q > >; template class TemplateKeyword { @@ -265,12 +265,12 @@ class Variadic {}; typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Variadic_t = Variadic>, S<(0 < 0), Variadic>>> +// CHECK-FIXES: using Variadic_t = Variadic >, S<(0 < 0), Variadic > > > typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t, *Variadic_p; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' // CHECK-MESSAGES: :[[@LINE-2]]:103: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Variadic_t = Variadic>, S<(0 < 0), Variadic>>>; +// CHECK-FIXES: using Variadic_t = Variadic >, S<(0 < 0), Variadic > > >; // CHECK-FIXES-NEXT: using Variadic_p = Variadic_t*; typedef struct { int a; } R_t, *R_p; @@ -383,3 +383,57 @@ namespace ISSUE_72179 // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use 'using' instead of 'typedef' [modernize-use-using] // CHECK-FIXES: const auto foo4 = [](int a){using d = int;}; } + + +typedef int* int_ptr, *int_ptr_ptr; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-MESSAGES: :[[@LINE-2]]:21: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-FIXES: using int_ptr = int*; +// CHECK-FIXES-NEXT: using int_ptr_ptr = int_ptr*; + +#ifndef SpecialMode +#define SomeMacro(x) x +#else +#define SomeMacro(x) SpecialType +#endif + +class SomeMacro(GH33760) { }; + +typedef void(SomeMacro(GH33760)::* FunctionType)(float, int); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-FIXES: using FunctionType = void(SomeMacro(GH33760)::* )(float, int); + +#define CDECL __attribute((cdecl)) + +// GH37846 & GH41685 +typedef void (CDECL *GH37846)(int); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-FIXES: using GH37846 = void (CDECL *)(int); + +typedef void (__attribute((cdecl)) *GH41685)(int); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-FIXES: using GH41685 = void (__attribute((cdecl)) *)(int); + +namespace GH83568 { + typedef int(*name)(int arg1, int arg2); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-FIXES: using name = int(*)(int arg1, int arg2); +} + +#ifdef FOO +#define GH95716 float +#else +#define GH95716 double +#endif + +typedef GH95716 foo; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-FIXES: using foo = GH95716; + +namespace GH97009 { + typedef double PointType[3]; +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using] + typedef bool (*Function)(PointType, PointType); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-FIXES: using Function = bool (*)(PointType, PointType); +} 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 a545698edcd31..755c071419ce6 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -364,7 +364,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 13242fa42684e..f9732aade7186 100644 --- a/clang/Maintainers.rst +++ b/clang/Maintainers.rst @@ -321,7 +321,7 @@ OpenMP conformance OpenCL conformance ~~~~~~~~~~~~~~~~~~ | Sven van Haastregt -| sven.vanhaastregt@arm.com (email), svenvh (GitHub) +| sven.vanhaastregt\@arm.com (email), svenvh (GitHub) OpenACC diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index 8e161f868d4af..e799900094df3 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -333,7 +333,7 @@ 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} -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() @@ -394,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 475a6372ca696..107c18ff32419 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -736,9 +736,10 @@ at the end to the next power of 2. These reductions support both fixed-sized and scalable vector types. -The integer reduction intrinsics, including ``__builtin_reduce_add``, -``__builtin_reduce_mul``, ``__builtin_reduce_and``, ``__builtin_reduce_or``, -and ``__builtin_reduce_xor``, can be called in a ``constexpr`` context. +The integer reduction intrinsics, including ``__builtin_reduce_max``, +``__builtin_reduce_min``, ``__builtin_reduce_add``, ``__builtin_reduce_mul``, +``__builtin_reduce_and``, ``__builtin_reduce_or``, and ``__builtin_reduce_xor``, +can be called in a ``constexpr`` context. Example: @@ -4547,9 +4548,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``, @@ -5572,7 +5577,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 a541d399d1e74..8b984ecaefeca 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 ------------------ @@ -412,7 +421,14 @@ Non-comprehensive list of changes in this release ``__builtin_reduce_mul``, ``__builtin_reduce_and``, ``__builtin_reduce_or``, ``__builtin_reduce_xor``, ``__builtin_elementwise_popcount``, ``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``, - ``__builtin_elementwise_sub_sat``. + ``__builtin_elementwise_sub_sat``, ``__builtin_reduce_min`` (For integral element type), + ``__builtin_reduce_max`` (For integral element type). + +- 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 ------------------ @@ -430,6 +446,9 @@ New Compiler Flags - The ``-Warray-compare-cxx26`` warning has been added to warn about array comparison starting from C++26, this warning is enabled as an error by default. +- clang-cl and clang-dxc now support ``-fdiagnostics-color=[auto|never|always]`` + in addition to ``-f[no-]color-diagnostics``. + Deprecated Compiler Flags ------------------------- @@ -612,6 +631,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). @@ -664,6 +685,55 @@ 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 + } + +- Fix -Wdangling false positives on conditional operators (#120206). + +- Fixed a bug where Clang hung on an unsupported optional scope specifier ``::`` when parsing + Objective-C. Clang now emits a diagnostic message instead of hanging. + +- The :doc:`ThreadSafetyAnalysis` now supports passing scoped capabilities into functions: + an attribute on the scoped capability parameter indicates both the expected associated capabilities and, + like in the case of attributes on the function declaration itself, their state before and after the call. + + .. code-block:: c++ + + #include "mutex.h" + + Mutex mu1, mu2; + int a GUARDED_BY(mu1); + + void require(MutexLocker& scope REQUIRES(mu1)) { + scope.Unlock(); + a = 0; // Warning! Requires mu1. + scope.Lock(); + } + + void testParameter() { + MutexLocker scope(&mu1), scope2(&mu2); + require(scope2); // Warning! Mutex managed by 'scope2' is 'mu2' instead of 'mu1' + require(scope); // OK. + scope.Unlock(); + require(scope); // Warning! Requires mu1. + } + Improvements to Clang's time-trace ---------------------------------- @@ -803,6 +873,8 @@ 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) @@ -810,6 +882,9 @@ Bug Fixes to C++ Support - 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) +- Fixed a pack expansion issue in checking unexpanded parameter sizes. (#GH17042) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1155,6 +1230,17 @@ 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. + +- Implemented ``-f[no-]sanitize-trap=local-bounds``, and ``-f[no-]sanitize-recover=local-bounds``. + +- ``-fsanitize-merge`` (default) and ``-fno-sanitize-merge`` have been added for + fine-grained, unified control of which UBSan checks can potentially be merged + by the compiler (for example, + ``-fno-sanitize-merge=bool,enum,array-bounds,local-bounds``). + Python Binding Changes ---------------------- - Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``. diff --git a/clang/docs/ThreadSafetyAnalysis.rst b/clang/docs/ThreadSafetyAnalysis.rst index f6517afc3bfc2..9c1c32e46989b 100644 --- a/clang/docs/ThreadSafetyAnalysis.rst +++ b/clang/docs/ThreadSafetyAnalysis.rst @@ -187,10 +187,13 @@ REQUIRES(...), REQUIRES_SHARED(...) *Previously*: ``EXCLUSIVE_LOCKS_REQUIRED``, ``SHARED_LOCKS_REQUIRED`` -``REQUIRES`` is an attribute on functions or methods, which +``REQUIRES`` is an attribute on functions, methods or function parameters of +reference to :ref:`scoped_capability`-annotated type, which declares that the calling thread must have exclusive access to the given capabilities. More than one capability may be specified. The capabilities must be held on entry to the function, *and must still be held on exit*. +Additionally, if the attribute is on a function parameter, it declares that +the scoped capability manages the specified capabilities in the given order. ``REQUIRES_SHARED`` is similar, but requires only shared access. @@ -211,6 +214,20 @@ must be held on entry to the function, *and must still be held on exit*. mu1.Unlock(); } + void require(MutexLocker& scope REQUIRES(mu1)) { + scope.Unlock(); + a = 0; // Warning! Requires mu1. + scope.Lock(); + } + + void testParameter() { + MutexLocker scope(&mu1), scope2(&mu2); + require(scope2); // Warning! Mutex managed by 'scope2' is 'mu2' instead of 'mu1' + require(scope); // OK. + scope.Unlock(); + require(scope); // Warning! Requires mu1. + } + ACQUIRE(...), ACQUIRE_SHARED(...), RELEASE(...), RELEASE_SHARED(...), RELEASE_GENERIC(...) ------------------------------------------------------------------------------------------ @@ -218,10 +235,13 @@ ACQUIRE(...), ACQUIRE_SHARED(...), RELEASE(...), RELEASE_SHARED(...), RELEASE_GE *Previously*: ``EXCLUSIVE_LOCK_FUNCTION``, ``SHARED_LOCK_FUNCTION``, ``UNLOCK_FUNCTION`` -``ACQUIRE`` and ``ACQUIRE_SHARED`` are attributes on functions or methods -declaring that the function acquires a capability, but does not release it. +``ACQUIRE`` and ``ACQUIRE_SHARED`` are attributes on functions, methods +or function parameters of reference to :ref:`scoped_capability`-annotated type, +which declare that the function acquires a capability, but does not release it. The given capability must not be held on entry, and will be held on exit (exclusively for ``ACQUIRE``, shared for ``ACQUIRE_SHARED``). +Additionally, if the attribute is on a function parameter, it declares that +the scoped capability manages the specified capabilities in the given order. ``RELEASE``, ``RELEASE_SHARED``, and ``RELEASE_GENERIC`` declare that the function releases the given capability. The capability must be held on entry @@ -249,6 +269,14 @@ shared for ``RELEASE_GENERIC``), and will no longer be held on exit. myObject.doSomething(); // Warning, mu is not locked. } + void release(MutexLocker& scope RELEASE(mu)) { + } // Warning! Need to unlock mu. + + void testParameter() { + MutexLocker scope(&mu); + release(scope); + } + If no argument is passed to ``ACQUIRE`` or ``RELEASE``, then the argument is assumed to be ``this``, and the analysis will not check the body of the function. This pattern is intended for use by classes which hide locking @@ -283,10 +311,13 @@ EXCLUDES(...) *Previously*: ``LOCKS_EXCLUDED`` -``EXCLUDES`` is an attribute on functions or methods, which declares that +``EXCLUDES`` is an attribute on functions, methods or function parameters +of reference to :ref:`scoped_capability`-annotated type, which declares that the caller must *not* hold the given capabilities. This annotation is used to prevent deadlock. Many mutex implementations are not re-entrant, so deadlock can occur if the function acquires the mutex a second time. +Additionally, if the attribute is on a function parameter, it declares that +the scoped capability manages the specified capabilities in the given order. .. code-block:: c++ @@ -305,6 +336,16 @@ deadlock can occur if the function acquires the mutex a second time. mu.Unlock(); } + void exclude(MutexLocker& scope LOCKS_EXCLUDED(mu)) { + scope.Unlock(); // Warning! mu is not locked. + scope.Lock(); + } // Warning! mu still held at the end of function. + + void testParameter() { + MutexLocker scope(&mu); + exclude(scope); // Warning, mu is held. + } + Unlike ``REQUIRES``, ``EXCLUDES`` is optional. The analysis will not issue a warning if the attribute is missing, which can lead to false negatives in some cases. This issue is discussed further in :ref:`negative`. @@ -393,6 +434,7 @@ class can be used as a capability. The string argument specifies the kind of capability in error messages, e.g. ``"mutex"``. See the ``Container`` example given above, or the ``Mutex`` class in :ref:`mutexheader`. +.. _scoped_capability: SCOPED_CAPABILITY ----------------- diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index 671db7f9f3671..b9ee4484fb9ae 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -276,8 +276,8 @@ Stack traces and report symbolization If you want UBSan to print symbolized stack trace for each error report, you will need to: -#. Compile with ``-g`` and ``-fno-omit-frame-pointer`` to get proper debug - information in your binary. +#. Compile with ``-g``, ``-fno-sanitize-merge`` and ``-fno-omit-frame-pointer`` + to get proper debug information in your binary. #. Run your program with environment variable ``UBSAN_OPTIONS=print_stacktrace=1``. #. Make sure ``llvm-symbolizer`` binary is in ``PATH``. 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 41b1e6aea8843..cf063a213a25e 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2166,9 +2166,39 @@ 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, + + /** OpenACC init Construct. + */ + CXCursor_OpenACCInitConstruct = 328, + + /** OpenACC shutdown Construct. + */ + CXCursor_OpenACCShutdownConstruct = 329, + + CXCursor_LastStmt = CXCursor_OpenACCShutdownConstruct, /** * Cursor that represents the translation unit itself. 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/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 dc0f074711791..0ed46b877ba71 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -28,6 +28,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringSwitch.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 007edd44659f6..d5e4cae864960 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -748,9 +748,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, @@ -763,9 +763,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) { @@ -3459,18 +3458,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(); } @@ -3588,10 +3586,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: @@ -3794,7 +3792,7 @@ class TagDecl : public TypeDecl, TypedefNameDecl *getTypedefNameForAnonDecl() const { return hasExtInfo() ? nullptr - : TypedefNameDeclOrQualifier.get(); + : cast(TypedefNameDeclOrQualifier); } void setTypedefNameForAnonDecl(TypedefNameDecl *TDD); @@ -4012,7 +4010,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 dd92d40b80423..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. @@ -1965,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 @@ -1992,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; @@ -2003,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; } @@ -2013,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. @@ -2734,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 @@ -2761,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; @@ -2772,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; } @@ -2782,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. @@ -3309,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 25be5adfbf61b..276a422f3c1b0 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 9f968ba05b446..4d7ff822fceb7 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -462,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) { @@ -487,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..b4747c68a1dfd 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, @@ -570,6 +619,20 @@ class OpenACCAsyncClause : public OpenACCClauseWithSingleIntExpr { SourceLocation EndLoc); }; +class OpenACCDeviceNumClause : public OpenACCClauseWithSingleIntExpr { + OpenACCDeviceNumClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + Expr *IntExpr, SourceLocation EndLoc); + +public: + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::DeviceNum; + } + static OpenACCDeviceNumClause *Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, Expr *IntExpr, + SourceLocation EndLoc); +}; + /// Represents a 'collapse' clause on a 'loop' construct. This clause takes an /// integer constant expression 'N' that represents how deep to collapse the /// construct. It also takes an optional 'force' tag that permits intervening @@ -614,7 +677,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 +700,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 +723,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 +746,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 +767,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 +861,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 +884,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 +914,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 +947,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 +980,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 +1013,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 9d9605aafeb6e..865b03d41f364 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)); }) @@ -4073,6 +4076,25 @@ 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())); +}) +DEF_TRAVERSE_STMT(OpenACCInitConstruct, + { TRY_TO(VisitOpenACCClauseList(S->clauses())); }) +DEF_TRAVERSE_STMT(OpenACCShutdownConstruct, + { 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/Stmt.h b/clang/include/clang/AST/Stmt.h index 83fafbabb1d46..405c6166adb15 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -109,6 +109,8 @@ class alignas(void *) Stmt { //===--- Statement bitfields classes ---===// + #define NumStmtBits 9 + class StmtBitfields { friend class ASTStmtReader; friend class ASTStmtWriter; @@ -116,9 +118,8 @@ class alignas(void *) Stmt { /// The statement class. LLVM_PREFERRED_TYPE(StmtClass) - unsigned sClass : 8; + unsigned sClass : NumStmtBits; }; - enum { NumStmtBits = 8 }; class NullStmtBitfields { friend class ASTStmtReader; diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h index fa8793e740822..e311eded5599b 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,382 @@ 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); + } +}; + +// This class represents an 'init' construct, which has just a clause list. +class OpenACCInitConstruct final + : public OpenACCConstructStmt, + private llvm::TrailingObjects { + friend TrailingObjects; + OpenACCInitConstruct(unsigned NumClauses) + : OpenACCConstructStmt(OpenACCInitConstructClass, + OpenACCDirectiveKind::Init, SourceLocation{}, + SourceLocation{}, SourceLocation{}) { + std::uninitialized_value_construct( + getTrailingObjects(), + getTrailingObjects() + NumClauses); + setClauseList(MutableArrayRef(getTrailingObjects(), + NumClauses)); + } + OpenACCInitConstruct(SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, + ArrayRef Clauses) + : OpenACCConstructStmt(OpenACCInitConstructClass, + OpenACCDirectiveKind::Init, 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() == OpenACCInitConstructClass; + } + static OpenACCInitConstruct *CreateEmpty(const ASTContext &C, + unsigned NumClauses); + static OpenACCInitConstruct *Create(const ASTContext &C, SourceLocation Start, + SourceLocation DirectiveLoc, + SourceLocation End, + ArrayRef Clauses); +}; + +// This class represents a 'shutdown' construct, which has just a clause list. +class OpenACCShutdownConstruct final + : public OpenACCConstructStmt, + private llvm::TrailingObjects { + friend TrailingObjects; + OpenACCShutdownConstruct(unsigned NumClauses) + : OpenACCConstructStmt(OpenACCShutdownConstructClass, + OpenACCDirectiveKind::Shutdown, SourceLocation{}, + SourceLocation{}, SourceLocation{}) { + std::uninitialized_value_construct( + getTrailingObjects(), + getTrailingObjects() + NumClauses); + setClauseList(MutableArrayRef(getTrailingObjects(), + NumClauses)); + } + OpenACCShutdownConstruct(SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, + ArrayRef Clauses) + : OpenACCConstructStmt(OpenACCShutdownConstructClass, + OpenACCDirectiveKind::Shutdown, 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() == OpenACCShutdownConstructClass; + } + static OpenACCShutdownConstruct *CreateEmpty(const ASTContext &C, + unsigned NumClauses); + static OpenACCShutdownConstruct * + Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, ArrayRef Clauses); +}; + } // 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 1f073e53f53ff..0ea9b5880fcbe 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -412,6 +412,13 @@ 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 VisitOpenACCInitConstruct(const OpenACCInitConstruct *S); + void VisitOpenACCShutdownConstruct(const OpenACCShutdownConstruct *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 e306325a698bf..89d0f4d1d0a7c 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 diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafety.h b/clang/include/clang/Analysis/Analyses/ThreadSafety.h index 0866b09bab299..0fcf5bed1285a 100644 --- a/clang/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/clang/include/clang/Analysis/Analyses/ThreadSafety.h @@ -223,6 +223,42 @@ class ThreadSafetyHandler { virtual void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName, SourceLocation Loc) {} + /// Warn when an actual underlying mutex of a scoped lockable does not match + /// the expected. + /// \param Loc -- The location of the call expression. + /// \param DLoc -- The location of the function declaration. + /// \param ScopeName -- The name of the scope passed to the function. + /// \param Kind -- The kind of the expected mutex. + /// \param Expected -- The name of the expected mutex. + /// \param Actual -- The name of the actual mutex. + virtual void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, + SourceLocation DLoc, + Name ScopeName, StringRef Kind, + Name Expected, Name Actual) {} + + /// Warn when we get fewer underlying mutexes than expected. + /// \param Loc -- The location of the call expression. + /// \param DLoc -- The location of the function declaration. + /// \param ScopeName -- The name of the scope passed to the function. + /// \param Kind -- The kind of the expected mutex. + /// \param Expected -- The name of the expected mutex. + virtual void handleExpectMoreUnderlyingMutexes(SourceLocation Loc, + SourceLocation DLoc, + Name ScopeName, StringRef Kind, + Name Expected) {} + + /// Warn when we get more underlying mutexes than expected. + /// \param Loc -- The location of the call expression. + /// \param DLoc -- The location of the function declaration. + /// \param ScopeName -- The name of the scope passed to the function. + /// \param Kind -- The kind of the actual mutex. + /// \param Actual -- The name of the actual mutex. + virtual void handleExpectFewerUnderlyingMutexes(SourceLocation Loc, + SourceLocation DLoc, + Name ScopeName, + StringRef Kind, Name Actual) { + } + /// Warn that L1 cannot be acquired before L2. virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name, SourceLocation Loc) {} diff --git a/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h b/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h new file mode 100644 index 0000000000000..3e4016518eaac --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h @@ -0,0 +1,63 @@ +//===-- SmartPointerAccessorCaching.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 defines utilities to help cache accessors for smart pointer +// like objects. +// +// These should be combined with CachedConstAccessorsLattice. +// Beyond basic const accessors, smart pointers may have the following two +// additional issues: +// +// 1) There may be multiple accessors for the same underlying object, e.g. +// `operator->`, `operator*`, and `get`. Users may use a mixture of these +// accessors, so the cache should unify them. +// +// 2) There may be non-const overloads of accessors. They are still safe to +// cache, as they don't modify the container object. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SMARTPOINTERACCESSORCACHING_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SMARTPOINTERACCESSORCACHING_H + +#include + +#include "clang/AST/Decl.h" +#include "clang/AST/Stmt.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +namespace clang::dataflow { + +/// Matchers: +/// For now, these match on any class with an `operator*` or `operator->` +/// where the return types have a similar shape as std::unique_ptr +/// and std::optional. +/// +/// - `*` returns a reference to a type `T` +/// - `->` returns a pointer to `T` +/// - `get` returns a pointer to `T` +/// - `value` returns a reference `T` +/// +/// (1) The `T` should all match across the accessors (ignoring qualifiers). +/// +/// (2) The specific accessor used in a call isn't required to be const, +/// but the class must have a const overload of each accessor. +/// +/// For now, we don't have customization to ignore certain classes. +/// For example, if writing a ClangTidy check for `std::optional`, these +/// would also match `std::optional`. In order to have special handling +/// for `std::optional`, we assume the (Matcher, TransferFunction) case +/// with custom handling is ordered early so that these generic cases +/// do not trigger. +ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar(); +ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow(); +ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall(); +ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall(); + +} // namespace clang::dataflow + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SMARTPOINTERACCESSORCACHING_H diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 0995d966eaa60..b8663c3811947 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4787,7 +4787,7 @@ def AcquireCapability : InheritableAttr { Clang<"acquire_shared_capability", 0>, GNU<"exclusive_lock_function">, GNU<"shared_lock_function">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, ParmVar]>; let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; @@ -4819,7 +4819,7 @@ def ReleaseCapability : InheritableAttr { Clang<"release_shared_capability", 0>, Clang<"release_generic_capability", 0>, Clang<"unlock_function", 0>]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, ParmVar]>; let LateParsed = LateAttrParseStandard; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; @@ -4843,7 +4843,7 @@ def RequiresCapability : InheritableAttr { let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, ParmVar]>; let Accessors = [Accessor<"isShared", [Clang<"requires_shared_capability", 0>, Clang<"shared_locks_required", 0>]>]; let Documentation = [Undocumented]; @@ -4965,7 +4965,7 @@ def LocksExcluded : InheritableAttr { let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; let InheritEvenIfAlreadyPresent = 1; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, ParmVar]>; let Documentation = [Undocumented]; } diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h index f91b2d551ecf2..4859244c39452 100644 --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -56,7 +56,6 @@ struct HeaderDesc { #undef HEADER } ID; - constexpr HeaderDesc() : ID() {} constexpr HeaderDesc(HeaderID ID) : ID(ID) {} const char *getName() const; @@ -70,140 +69,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. /// @@ -211,11 +84,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; @@ -231,13 +101,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 { @@ -246,40 +113,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 @@ -290,21 +157,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 @@ -312,7 +179,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 @@ -326,33 +193,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 @@ -377,25 +244,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. @@ -407,20 +276,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 b67464f78b4c7..e0cbf75c05e7a 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -1462,13 +1462,13 @@ def ElementwiseSubSat : Builtin { def ReduceMax : Builtin { let Spellings = ["__builtin_reduce_max"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } def ReduceMin : Builtin { let Spellings = ["__builtin_reduce_min"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } @@ -4781,6 +4781,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/BuiltinsHexagon.def b/clang/include/clang/Basic/BuiltinsHexagon.def index 0dc0f4567dd41..adff9f884c049 100644 --- a/clang/include/clang/Basic/BuiltinsHexagon.def +++ b/clang/include/clang/Basic/BuiltinsHexagon.def @@ -17,8 +17,12 @@ # define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) #endif +#pragma push_macro("V79") +#define V79 "v79" +#pragma push_macro("V75") +#define V75 "v75|" V79 #pragma push_macro("V73") -#define V73 "v73" +#define V73 "v73|" V75 #pragma push_macro("V71") #define V71 "v71|" V73 #pragma push_macro("V69") @@ -40,8 +44,12 @@ #pragma push_macro("V5") #define V5 "v5|" V55 +#pragma push_macro("HVXV79") +#define HVXV79 "hvxv79" +#pragma push_macro("HVXV75") +#define HVXV75 "hvxv75|" HVXV79 #pragma push_macro("HVXV73") -#define HVXV73 "hvxv73" +#define HVXV73 "hvxv73|" HVXV75 #pragma push_macro("HVXV71") #define HVXV71 "hvxv71|" HVXV73 #pragma push_macro("HVXV69") @@ -143,6 +151,8 @@ TARGET_BUILTIN(__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B,"V64iV64iV32iLLi","", " #pragma pop_macro("HVXV69") #pragma pop_macro("HVXV71") #pragma pop_macro("HVXV73") +#pragma pop_macro("HVXV75") +#pragma pop_macro("HVXV79") #pragma pop_macro("V5") #pragma pop_macro("V55") @@ -155,6 +165,8 @@ TARGET_BUILTIN(__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B,"V64iV64iV32iLLi","", " #pragma pop_macro("V69") #pragma pop_macro("V71") #pragma pop_macro("V73") +#pragma pop_macro("V75") +#pragma pop_macro("V79") #undef BUILTIN #undef TARGET_BUILTIN 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 fc2b616d7d6c3..b35c8b2c4b826 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -386,6 +386,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 90047b1701598..7f8f9c73ecf21 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3310,8 +3310,8 @@ def warn_attribute_too_few_arguments : Warning< InGroup; 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">; @@ -3500,7 +3500,7 @@ def warn_typecheck_vector_element_sizes_not_equal : Warning< def err_ext_vector_component_exceeds_length : Error< "vector component access exceeds type %0">; def err_ext_vector_component_name_illegal : Error< - "illegal vector component name '%0'">; + "illegal vector component name %0">; def err_attribute_address_space_negative : Error< "address space is negative">; def err_attribute_address_space_too_high : Error< @@ -4085,6 +4085,10 @@ def warn_thread_attribute_decl_not_lockable : Warning< def warn_thread_attribute_decl_not_pointer : Warning< "%0 only applies to pointer types; type here is %1">, InGroup, DefaultIgnore; +def warn_thread_attribute_not_on_scoped_lockable_param : Warning< + "%0 attribute applies to function parameters only if their type is a " + "reference to a 'scoped_lockable'-annotated type">, + InGroup, DefaultIgnore; def err_attribute_argument_out_of_bounds_extra_info : Error< "%0 attribute parameter %1 is out of bounds: " "%plural{0:no parameters to index into|" @@ -4140,6 +4144,17 @@ def warn_acquired_before : Warning< def warn_acquired_before_after_cycle : Warning< "cycle in acquired_before/after dependencies, starting with '%0'">, InGroup, DefaultIgnore; +def warn_unmatched_underlying_mutexes : Warning< + "%0 managed by '%1' is '%3' instead of '%2'">, + InGroup, DefaultIgnore; +def warn_expect_more_underlying_mutexes : Warning< + "%0 '%2' not managed by '%1'">, + InGroup, DefaultIgnore; +def warn_expect_fewer_underlying_mutexes : Warning< + "did not expect %0 '%2' to be managed by '%1'">, + InGroup, DefaultIgnore; +def note_managed_mismatch_here_for_param : Note< + "see attribute on parameter here">; // Thread safety warnings negative capabilities @@ -5951,10 +5966,10 @@ def err_pack_expansion_without_parameter_packs : Error< "pack expansion does not contain any unexpanded parameter packs">; def err_pack_expansion_length_conflict : Error< "pack expansion contains parameter packs %0 and %1 that have different " - "lengths (%2 vs. %3)">; + "lengths (%2 vs. %select{|at least }3%4))">; def err_pack_expansion_length_conflict_multilevel : Error< "pack expansion contains parameter pack %0 that has a different " - "length (%1 vs. %2) from outer parameter packs">; + "length (%1 vs. %select{|at least }2%3) from outer parameter packs">; def err_pack_expansion_length_conflict_partial : Error< "pack expansion contains parameter pack %0 that has a different " "length (at least %1 vs. %2) from outer parameter packs">; @@ -10343,16 +10358,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< @@ -12437,6 +12452,8 @@ def warn_noderef_to_dereferenceable_pointer : Warning< def err_builtin_launder_invalid_arg : Error< "%select{non-pointer|function pointer|void pointer}0 argument to " "'__builtin_launder' is not allowed">; +def err_builtin_assume_aligned_invalid_arg : Error< + "non-pointer argument to '__builtin_assume_aligned' is not allowed">; def err_builtin_is_within_lifetime_invalid_arg : Error< "%select{non-|function }0pointer argument to '__builtin_is_within_lifetime' " @@ -12966,8 +12983,8 @@ def err_acc_int_expr_requires_integer def err_acc_int_expr_incomplete_class_type : Error<"OpenACC integer expression has incomplete class type %0">; def err_acc_int_expr_explicit_conversion - : Error<"OpenACC integer expression type %0 requires explicit conversion " - "to %1">; + : Error<"OpenACC integer expression requires explicit conversion " + "from %0 to %1">; def note_acc_int_expr_conversion : Note<"conversion to %select{integral|enumeration}0 type %1">; def err_acc_int_expr_multiple_conversions @@ -12981,6 +12998,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 @@ -13100,6 +13120,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..1b619bc0dfd4c 100644 --- a/clang/include/clang/Basic/OpenACCClauses.def +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -38,12 +38,17 @@ VISIT_CLAUSE(Create) CLAUSE_ALIAS(PCreate, Create, true) CLAUSE_ALIAS(PresentOrCreate, Create, true) VISIT_CLAUSE(Default) +VISIT_CLAUSE(Delete) +VISIT_CLAUSE(Detach) +VISIT_CLAUSE(DeviceNum) 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 +59,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 ddf591d7db196..5096b83349bfd 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -315,6 +315,13 @@ 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; +def OpenACCInitConstruct : StmtNode; +def OpenACCShutdownConstruct : 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 7b8ecf29a9de6..1c6bdb8cad2d1 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -463,18 +463,19 @@ let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in { // Contiguous truncating store from quadword (single vector). - def SVST1UWQ : MInst<"svst1wq[_{d}]", "vPcd", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1wq">; - def SVST1UWQ_VNUM : MInst<"svst1wq_vnum[_{d}]", "vPcld", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1wq">; + def SVST1UWQ : MInst<"svst1wq[_{d}]", "vPpd", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1wq">; + def SVST1UWQ_VNUM : MInst<"svst1wq_vnum[_{d}]", "vPpld", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1wq">; - def SVST1UDQ : MInst<"svst1dq[_{d}]", "vPcd", "lUld", [IsStore], MemEltTyInt64, "aarch64_sve_st1dq">; - def SVST1UDQ_VNUM : MInst<"svst1dq_vnum[_{d}]", "vPcld", "lUld", [IsStore], MemEltTyInt64, "aarch64_sve_st1dq">; + def SVST1UDQ : MInst<"svst1dq[_{d}]", "vPpd", "lUld", [IsStore], MemEltTyInt64, "aarch64_sve_st1dq">; + def SVST1UDQ_VNUM : MInst<"svst1dq_vnum[_{d}]", "vPpld", "lUld", [IsStore], MemEltTyInt64, "aarch64_sve_st1dq">; // Store one vector (vector base + scalar offset) def SVST1Q_SCATTER_U64BASE_OFFSET : MInst<"svst1q_scatter[_{2}base]_offset[_{d}]", "vPgld", "cUcsUsiUilUlfhdb", [IsScatterStore, IsByteIndexed], MemEltTyDefault, "aarch64_sve_st1q_scatter_scalar_offset">; def SVST1Q_SCATTER_U64BASE : MInst<"svst1q_scatter[_{2}base][_{d}]", "vPgd", "cUcsUsiUilUlfhdb", [IsScatterStore, IsByteIndexed], MemEltTyDefault, "aarch64_sve_st1q_scatter_scalar_offset">; // Store one vector (scalar base + vector offset) - def SVST1Q_SCATTER_U64OFFSET : MInst<"svst1q_scatter_[{3}]offset[_{d}]", "vPpgd", "cUcsUsiUilUlfhdb", [IsScatterStore, IsByteIndexed], MemEltTyDefault, "aarch64_sve_st1q_scatter_vector_offset">; + def SVST1Q_SCATTER_OFFSETS_U : MInst<"svst1q_scatter_[{3}]offset[_{d}]", "vPpgd", "cUcsUsiUilUlfhdb", [IsScatterStore, IsByteIndexed], MemEltTyDefault, "aarch64_sve_st1q_scatter_vector_offset">; + def SVST1Q_SCATTER_OFFSETS_S : MInst<"svst1q_scatter_[{3}]offset[_{d}]", "vPp#d", "cUcsUsiUilUlfhdb", [IsScatterStore, IsByteIndexed], MemEltTyDefault, "aarch64_sve_st1q_scatter_vector_offset">; // Store N vectors into N-element structure (scalar base) defm SVST2Q : StructStore<"svst2q[_{d}]", "vPc2", "aarch64_sve_st2q">; @@ -488,6 +489,7 @@ let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in { // Scatter store quadwords (scalar base + vector index) def SVST1Q_SCATTER_INDICES_U : MInst<"svst1q_scatter_[{3}]index[_{d}]", "vPpgd", "sUsiUilUlbhfd", [IsScatterStore], MemEltTyDefault, "aarch64_sve_st1q_scatter_index">; + def SVST1Q_SCATTER_INDICES_S : MInst<"svst1q_scatter_[{3}]index[_{d}]", "vPp#d", "sUsiUilUlbhfd", [IsScatterStore], MemEltTyDefault, "aarch64_sve_st1q_scatter_index">; // Scatter store quadwords (vector base + scalar index) def SVST1Q_SCATTER_INDEX_S : MInst<"svst1q_scatter[_{2}base]_index[_{d}]", "vPgld", "sUsiUilUlbhfd", [IsScatterStore], MemEltTyDefault, "aarch64_sve_st1q_scatter_scalar_offset">; @@ -2436,6 +2438,12 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in { // Convert from FP8 to deinterleaved half-precision/BFloat16 multi-vector 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 { @@ -2462,4 +2470,61 @@ let SVETargetGuard = "sve2,fp8", SMETargetGuard = "sme2,fp8" in { // 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..13e7cf45471c2 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 // ------------------ @@ -69,6 +70,7 @@ include "arm_immcheck_incl.td" // x: vector of signed integers // u: vector of unsigned integers // d: default +// p: pointer type // c: const pointer type // P: predicate type // s: scalar of element type @@ -88,6 +90,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 @@ -99,6 +102,7 @@ include "arm_immcheck_incl.td" // [: svuint8_t // t: svint32_t // z: svuint32_t +// #: svint64_t // g: svuint64_t // O: svfloat16_t // M: svfloat32_t diff --git a/clang/include/clang/CIR/CMakeLists.txt b/clang/include/clang/CIR/CMakeLists.txt index f8d6f407a03d0..e20c896171c92 100644 --- a/clang/include/clang/CIR/CMakeLists.txt +++ b/clang/include/clang/CIR/CMakeLists.txt @@ -4,3 +4,4 @@ include_directories(${MLIR_INCLUDE_DIR}) include_directories(${MLIR_TABLEGEN_OUTPUT_DIR}) add_subdirectory(Dialect) +add_subdirectory(Interfaces) diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 75ae74e926fbc..0e414921324b7 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -18,6 +18,14 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { public: CIRBaseBuilderTy(mlir::MLIRContext &mlirContext) : mlir::OpBuilder(&mlirContext) {} + + cir::PointerType getPointerTo(mlir::Type ty) { + return cir::PointerType::get(getContext(), ty); + } + + cir::PointerType getVoidPtrTy() { + return getPointerTo(cir::VoidType::get(getContext())); + } }; } // namespace cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h index 2bc7d77b2bc8a..5d1eb17e146d0 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -16,6 +16,13 @@ #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Types.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" +#include "clang/CIR/Interfaces/CIRFPTypeInterface.h" + +namespace cir { + +bool isAnyFloatingPointType(mlir::Type t); + +} // namespace cir //===----------------------------------------------------------------------===// // CIR Dialect Tablegen'd Types diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index ce0b6ba1d68c5..ef00b26c1fd98 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -14,6 +14,7 @@ #define MLIR_CIR_DIALECT_CIR_TYPES include "clang/CIR/Dialect/IR/CIRDialect.td" +include "clang/CIR/Interfaces/CIRFPTypeInterface.td" include "mlir/Interfaces/DataLayoutInterfaces.td" include "mlir/IR/AttrTypeBase.td" @@ -129,4 +130,224 @@ def PrimitiveInt : AnyTypeOf<[UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64], "primitive int", "::cir::IntType">; +//===----------------------------------------------------------------------===// +// FloatType +//===----------------------------------------------------------------------===// + +class CIR_FloatType + : CIR_Type, + DeclareTypeInterfaceMethods, + ]> {} + +def CIR_Single : CIR_FloatType<"Single", "float"> { + let summary = "CIR single-precision 32-bit float type"; + let description = [{ + A 32-bit floating-point type whose format is IEEE-754 `binary32`. It + represents the types `float`, `_Float32`, and `std::float32_t` in C and C++. + }]; +} + +def CIR_Double : CIR_FloatType<"Double", "double"> { + let summary = "CIR double-precision 64-bit float type"; + let description = [{ + A 64-bit floating-point type whose format is IEEE-754 `binary64`. It + represents the types `double', '_Float64`, `std::float64_t`, and `_Float32x` + in C and C++. This is the underlying type for `long double` on some + platforms, including Windows. + }]; +} + +def CIR_FP16 : CIR_FloatType<"FP16", "f16"> { + let summary = "CIR half-precision 16-bit float type"; + let description = [{ + A 16-bit floating-point type whose format is IEEE-754 `binary16`. It + represents the types '_Float16` and `std::float16_t` in C and C++. + }]; +} + +def CIR_BFloat16 : CIR_FloatType<"BF16", "bf16"> { + let summary = "CIR bfloat16 16-bit float type"; + let description = [{ + A 16-bit floating-point type in the bfloat16 format, which is the same as + IEEE `binary32` except that the lower 16 bits of the mantissa are missing. + It represents the type `std::bfloat16_t` in C++, also spelled `__bf16` in + some implementations. + }]; +} + +def CIR_FP80 : CIR_FloatType<"FP80", "f80"> { + let summary = "CIR x87 80-bit float type"; + let description = [{ + An 80-bit floating-point type in the x87 extended precision format. The + size and alignment of the type are both 128 bits, even though only 80 of + those bits are used. This is the underlying type for `long double` on Linux + x86 platforms, and it is available as an extension in some implementations. + }]; +} + +def CIR_FP128 : CIR_FloatType<"FP128", "f128"> { + let summary = "CIR quad-precision 128-bit float type"; + let description = [{ + A 128-bit floating-point type whose format is IEEE-754 `binary128`. It + represents the types `_Float128` and `std::float128_t` in C and C++, and the + extension `__float128` in some implementations. This is the underlying type + for `long double` on some platforms including Linux Arm. + }]; +} + +def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> { + let summary = "CIR float type for `long double`"; + let description = [{ + A floating-point type that represents the `long double` type in C and C++. + + The underlying floating-point format of a `long double` value depends on the + target platform and the implementation. The `underlying` parameter specifies + the CIR floating-point type that corresponds to this format. Underlying + types of IEEE 64-bit, IEEE 128-bit, x87 80-bit, and IBM's double-double + format are all in use. + }]; + + let parameters = (ins "mlir::Type":$underlying); + + let assemblyFormat = [{ + `<` $underlying `>` + }]; + + let genVerifyDecl = 1; +} + +// Constraints + +def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_FP80, CIR_FP128, CIR_LongDouble, + CIR_FP16, CIR_BFloat16]>; +def CIR_AnyIntOrFloat: AnyTypeOf<[CIR_AnyFloat, CIR_IntType]>; + +//===----------------------------------------------------------------------===// +// PointerType +//===----------------------------------------------------------------------===// + +def CIR_PointerType : CIR_Type<"Pointer", "ptr", + [DeclareTypeInterfaceMethods]> { + + let summary = "CIR pointer type"; + let description = [{ + The `cir.ptr` type represents C and C++ pointer types and C++ reference + types, other than pointers-to-members. The `pointee` type is the type + pointed to. + + TODO(CIR): The address space attribute is not yet implemented. + }]; + + let parameters = (ins "mlir::Type":$pointee); + + let builders = [ + TypeBuilderWithInferredContext<(ins "mlir::Type":$pointee), [{ + return $_get(pointee.getContext(), pointee); + }]>, + TypeBuilder<(ins "mlir::Type":$pointee), [{ + return $_get($_ctxt, pointee); + }]> + ]; + + let assemblyFormat = [{ + `<` $pointee `>` + }]; + + let genVerifyDecl = 1; + + let skipDefaultBuilders = 1; + + let extraClassDeclaration = [{ + bool isVoidPtr() const { + return mlir::isa(getPointee()); + } + }]; +} + +//===----------------------------------------------------------------------===// +// FuncType +//===----------------------------------------------------------------------===// + +def CIR_FuncType : CIR_Type<"Func", "func"> { + let summary = "CIR function type"; + let description = [{ + The `!cir.func` is a function type. It consists of a single return type, a + list of parameter types and can optionally be variadic. + + Example: + + ```mlir + !cir.func + !cir.func + !cir.func + ``` + }]; + + let parameters = (ins ArrayRefParameter<"mlir::Type">:$inputs, + "mlir::Type":$returnType, "bool":$varArg); + let assemblyFormat = [{ + `<` $returnType ` ` `(` custom($inputs, $varArg) `>` + }]; + + let builders = [ + TypeBuilderWithInferredContext<(ins + "llvm::ArrayRef":$inputs, "mlir::Type":$returnType, + CArg<"bool", "false">:$isVarArg), [{ + return $_get(returnType.getContext(), inputs, returnType, isVarArg); + }]> + ]; + + let extraClassDeclaration = [{ + /// Returns whether the function is variadic. + bool isVarArg() const { return getVarArg(); } + + /// Returns the `i`th input operand type. Asserts if out of bounds. + mlir::Type getInput(unsigned i) const { return getInputs()[i]; } + + /// Returns the number of arguments to the function. + unsigned getNumInputs() const { return getInputs().size(); } + + /// Returns the result type of the function as an ArrayRef, enabling better + /// integration with generic MLIR utilities. + llvm::ArrayRef getReturnTypes() const; + + /// Returns whether the function is returns void. + bool isVoid() const; + + /// Returns a clone of this function type with the given argument + /// and result types. + FuncType clone(mlir::TypeRange inputs, mlir::TypeRange results) const; + }]; +} + +//===----------------------------------------------------------------------===// +// Void type +//===----------------------------------------------------------------------===// + +def CIR_VoidType : CIR_Type<"Void", "void"> { + let summary = "CIR void type"; + let description = [{ + The `!cir.void` type represents the C and C++ `void` type. + }]; + let extraClassDeclaration = [{ + std::string getAlias() const { return "void"; }; + }]; +} + +// Constraints + +// Pointer to void +def VoidPtr : Type< + And<[ + CPred<"::mlir::isa<::cir::PointerType>($_self)">, + CPred<"::mlir::isa<::cir::VoidType>(" + "::mlir::cast<::cir::PointerType>($_self).getPointee())">, + ]>, "void*">, + BuildableType< + "cir::PointerType::get($_builder.getContext()," + "cir::VoidType::get($_builder.getContext()))"> { +} + #endif // MLIR_CIR_DIALECT_CIR_TYPES diff --git a/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.h b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.h new file mode 100644 index 0000000000000..40b85ef6cfb62 --- /dev/null +++ b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.h @@ -0,0 +1,22 @@ +//===---------------------------------------------------------------------===// +// +// 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 +// +//===---------------------------------------------------------------------===// +// +// Defines the interface to generically handle CIR floating-point types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H +#define LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H + +#include "mlir/IR/Types.h" +#include "llvm/ADT/APFloat.h" + +/// Include the tablegen'd interface declarations. +#include "clang/CIR/Interfaces/CIRFPTypeInterface.h.inc" + +#endif // LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_H diff --git a/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.td b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.td new file mode 100644 index 0000000000000..973851b61444f --- /dev/null +++ b/clang/include/clang/CIR/Interfaces/CIRFPTypeInterface.td @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the interface to generically handle CIR floating-point types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD +#define LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD + +include "mlir/IR/OpBase.td" + +def CIRFPTypeInterface : TypeInterface<"CIRFPTypeInterface"> { + let description = [{ + Contains helper functions to query properties about a floating-point type. + }]; + let cppNamespace = "::cir"; + + let methods = [ + InterfaceMethod<[{ + Returns the bit width of this floating-point type. + }], + /*retTy=*/"unsigned", + /*methodName=*/"getWidth", + /*args=*/(ins), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return llvm::APFloat::semanticsSizeInBits($_type.getFloatSemantics()); + }] + >, + InterfaceMethod<[{ + Return the mantissa width. + }], + /*retTy=*/"unsigned", + /*methodName=*/"getFPMantissaWidth", + /*args=*/(ins), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return llvm::APFloat::semanticsPrecision($_type.getFloatSemantics()); + }] + >, + InterfaceMethod<[{ + Return the float semantics of this floating-point type. + }], + /*retTy=*/"const llvm::fltSemantics &", + /*methodName=*/"getFloatSemantics" + >, + ]; +} + +#endif // LLVM_CLANG_INCLUDE_CLANG_CIR_INTERFACES_CIRFPTYPEINTERFACE_TD diff --git a/clang/include/clang/CIR/Interfaces/CMakeLists.txt b/clang/include/clang/CIR/Interfaces/CMakeLists.txt new file mode 100644 index 0000000000000..1c90b6b5a23cb --- /dev/null +++ b/clang/include/clang/CIR/Interfaces/CMakeLists.txt @@ -0,0 +1,14 @@ +# This replicates part of the add_mlir_interface cmake function from MLIR that +# cannot be used here. This happens because it expects to be run inside MLIR +# directory which is not the case for CIR (and also FIR, both have similar +# workarounds). + +function(add_clang_mlir_type_interface interface) + set(LLVM_TARGET_DEFINITIONS ${interface}.td) + mlir_tablegen(${interface}.h.inc -gen-type-interface-decls) + mlir_tablegen(${interface}.cpp.inc -gen-type-interface-defs) + add_public_tablegen_target(MLIR${interface}IncGen) + add_dependencies(mlir-generic-headers MLIR${interface}IncGen) +endfunction() + +add_clang_mlir_type_interface(CIRFPTypeInterface) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 2f0af3739d63b..6c8c88f5af646 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1109,11 +1109,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, @@ -1229,7 +1229,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">; @@ -2088,10 +2088,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, @@ -2635,6 +2635,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"]>; @@ -3549,6 +3564,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, @@ -4389,6 +4407,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">, @@ -5749,7 +5770,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">; @@ -5771,10 +5792,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++">, Group; def nolibsycl : Flag<["-"], "nolibsycl">, Flags<[NoXarchOption]>, @@ -5890,7 +5911,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]>, @@ -5954,7 +5975,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]>; @@ -5964,7 +5985,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=">, @@ -6306,6 +6327,10 @@ def mv71t : Flag<["-"], "mv71t">, Group, Alias, AliasArgs<["hexagonv71t"]>; def mv73 : Flag<["-"], "mv73">, Group, Alias, AliasArgs<["hexagonv73"]>; +def mv75 : Flag<["-"], "mv75">, Group, + Alias, AliasArgs<["hexagonv75"]>; +def mv79 : Flag<["-"], "mv79">, Group, + Alias, AliasArgs<["hexagonv79"]>; def mhexagon_hvx : Flag<["-"], "mhvx">, Group, HelpText<"Enable Hexagon Vector eXtensions">; def mhexagon_hvx_EQ : Joined<["-"], "mhvx=">, @@ -6878,7 +6903,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; @@ -7292,6 +7316,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 dce274de0a63d..bc1916a9de3d7 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -860,7 +860,7 @@ class Preprocessor { auto *Info = State.dyn_cast(); if (!Info) { Info = new (PP.getPreprocessorAllocator()) - ModuleMacroInfo(State.get()); + ModuleMacroInfo(cast(State)); State = Info; } @@ -893,7 +893,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) { @@ -946,7 +946,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 2afdba8ea093c..389f04b3f218e 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3707,10 +3707,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 { @@ -3718,6 +3722,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/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 2bf9f2b9e43e5..3d6d577f56996 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 9c686bf5eb29d..ebf51e0526d57 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10680,6 +10680,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..5c599a70532f6 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -135,31 +135,20 @@ struct NormalizedConstraint { return *this; } - bool isAtomic() const { return Constraint.is(); } + bool isAtomic() const { return llvm::isa(Constraint); } bool isFoldExpanded() const { - return Constraint.is(); + return llvm::isa(Constraint); } - bool isCompound() const { return Constraint.is(); } + bool isCompound() const { return llvm::isa(Constraint); } - CompoundConstraintKind getCompoundKind() const { - assert(isCompound() && "getCompoundKind on a non-compound constraint.."); - return Constraint.get().getInt(); - } + CompoundConstraintKind getCompoundKind() const; NormalizedConstraint &getLHS() const; NormalizedConstraint &getRHS() const; - AtomicConstraint *getAtomicConstraint() const { - assert(isAtomic() && - "getAtomicConstraint called on non-atomic constraint."); - return Constraint.get(); - } + AtomicConstraint *getAtomicConstraint() const; - FoldExpandedConstraint *getFoldExpandedConstraint() const { - assert(isFoldExpanded() && - "getFoldExpandedConstraint called on non-fold-expanded constraint."); - return Constraint.get(); - } + FoldExpandedConstraint *getFoldExpandedConstraint() const; private: static std::optional @@ -210,17 +199,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/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 170a6f4885c96..addc33bf3c76b 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -296,13 +296,15 @@ class SemaOpenACC : public SemaBase { assert((ClauseKind == OpenACCClauseKind::NumGangs || ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || + ClauseKind == OpenACCClauseKind::DeviceNum || ClauseKind == OpenACCClauseKind::Tile || ClauseKind == OpenACCClauseKind::Worker || ClauseKind == OpenACCClauseKind::Vector || ClauseKind == OpenACCClauseKind::VectorLength) && "Parsed clause kind does not have a int exprs"); - // 'async' and 'wait' have an optional IntExpr, so be tolerant of that. + // 'async', 'worker', 'vector', and 'wait' have an optional IntExpr, so be + // tolerant of that. if ((ClauseKind == OpenACCClauseKind::Async || ClauseKind == OpenACCClauseKind::Worker || ClauseKind == OpenACCClauseKind::Vector || @@ -346,6 +348,7 @@ class SemaOpenACC : public SemaBase { assert((ClauseKind == OpenACCClauseKind::NumGangs || ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || + ClauseKind == OpenACCClauseKind::DeviceNum || ClauseKind == OpenACCClauseKind::Tile || ClauseKind == OpenACCClauseKind::Gang || ClauseKind == OpenACCClauseKind::Worker || @@ -399,6 +402,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) && @@ -479,6 +485,7 @@ class SemaOpenACC : public SemaBase { assert((ClauseKind == OpenACCClauseKind::NumGangs || ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || + ClauseKind == OpenACCClauseKind::DeviceNum || ClauseKind == OpenACCClauseKind::Tile || ClauseKind == OpenACCClauseKind::Worker || ClauseKind == OpenACCClauseKind::Vector || @@ -490,6 +497,7 @@ class SemaOpenACC : public SemaBase { assert((ClauseKind == OpenACCClauseKind::NumGangs || ClauseKind == OpenACCClauseKind::NumWorkers || ClauseKind == OpenACCClauseKind::Async || + ClauseKind == OpenACCClauseKind::DeviceNum || ClauseKind == OpenACCClauseKind::Tile || ClauseKind == OpenACCClauseKind::Worker || ClauseKind == OpenACCClauseKind::Vector || @@ -535,6 +543,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 +582,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 +667,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 +684,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. 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 14b0964402372..20790e2cd38dd 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -724,11 +724,9 @@ 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. @@ -2030,6 +2028,13 @@ 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, + STMT_OPENACC_INIT_CONSTRUCT, + STMT_OPENACC_SHUTDOWN_CONSTRUCT, // HLSL Constructs EXPR_HLSL_OUT_ARG, diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index f91052be5e129..9f978762a6fb6 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -537,17 +537,14 @@ class ASTReader /// namespace as if it is not delayed. DelayedNamespaceOffsetMapTy DelayedNamespaceOffsetMap; - /// Mapping from FunctionDecl IDs to the corresponding lambda 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; + /// Mapping from main decl ID to the related decls IDs. + /// + /// 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; diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index d98d23decbdc0..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. 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/clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h new file mode 100644 index 0000000000000..84a6bf1406ac6 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h @@ -0,0 +1,64 @@ +//== APSIntPtr.h - Wrapper for APSInt objects owned separately -*- 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_STATICANALYZER_CORE_PATHSENSITIVE_APSIntPtr_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSIntPtr_H + +#include "llvm/ADT/APSInt.h" +#include "llvm/Support/Compiler.h" + +namespace clang::ento { + +/// A safe wrapper around APSInt objects allocated and owned by +/// \c BasicValueFactory. This just wraps a common llvm::APSInt. +class APSIntPtr { + using APSInt = llvm::APSInt; + +public: + APSIntPtr() = delete; + APSIntPtr(const APSIntPtr &) = default; + APSIntPtr &operator=(const APSIntPtr &) & = default; + ~APSIntPtr() = default; + + /// You should not use this API. + /// If do, ensure that the \p Ptr not going to dangle. + /// Prefer using \c BasicValueFactory::getValue() to get an APSIntPtr object. + static APSIntPtr unsafeConstructor(const APSInt *Ptr) { + return APSIntPtr(Ptr); + } + + LLVM_ATTRIBUTE_RETURNS_NONNULL + const APSInt *get() const { return Ptr; } + /*implicit*/ operator const APSInt &() const { return *get(); } + + APSInt operator-() const { return -*Ptr; } + APSInt operator~() const { return ~*Ptr; } + +#define DEFINE_OPERATOR(OP) \ + bool operator OP(APSIntPtr Other) const { return (*Ptr)OP(*Other.Ptr); } + DEFINE_OPERATOR(>) + DEFINE_OPERATOR(>=) + DEFINE_OPERATOR(<) + DEFINE_OPERATOR(<=) + DEFINE_OPERATOR(==) + DEFINE_OPERATOR(!=) +#undef DEFINE_OPERATOR + + const APSInt &operator*() const { return *Ptr; } + const APSInt *operator->() const { return Ptr; } + +private: + explicit APSIntPtr(const APSInt *Ptr) : Ptr(Ptr) {} + + /// Owned by \c BasicValueFactory. + const APSInt *Ptr; +}; + +} // namespace clang::ento + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_APSIntPtr_H diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index ec503b41b381a..ef04f9c485e88 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -18,10 +18,11 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableList.h" @@ -129,7 +130,7 @@ class BasicValueFactory { // This is private because external clients should use the factory // method that takes a QualType. - const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); + APSIntPtr getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); public: BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator &Alloc) @@ -140,9 +141,9 @@ class BasicValueFactory { ASTContext &getContext() const { return Ctx; } - const llvm::APSInt& getValue(const llvm::APSInt& X); - const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned); - const llvm::APSInt& getValue(uint64_t X, QualType T); + APSIntPtr getValue(const llvm::APSInt &X); + APSIntPtr getValue(const llvm::APInt &X, bool isUnsigned); + APSIntPtr getValue(uint64_t X, QualType T); /// Returns the type of the APSInt used to store values of the given QualType. APSIntType getAPSIntType(QualType T) const { @@ -165,79 +166,70 @@ class BasicValueFactory { /// Convert - Create a new persistent APSInt with the same value as 'From' /// but with the bitwidth and signedness of 'To'. - const llvm::APSInt &Convert(const llvm::APSInt& To, - const llvm::APSInt& From) { + APSIntPtr Convert(const llvm::APSInt &To, const llvm::APSInt &From) { APSIntType TargetType(To); if (TargetType == APSIntType(From)) - return From; + return getValue(From); return getValue(TargetType.convert(From)); } - const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) { + APSIntPtr Convert(QualType T, const llvm::APSInt &From) { APSIntType TargetType = getAPSIntType(T); return Convert(TargetType, From); } - const llvm::APSInt &Convert(APSIntType TargetType, const llvm::APSInt &From) { + APSIntPtr Convert(APSIntType TargetType, const llvm::APSInt &From) { if (TargetType == APSIntType(From)) - return From; + return getValue(From); return getValue(TargetType.convert(From)); } - const llvm::APSInt &getIntValue(uint64_t X, bool isUnsigned) { + APSIntPtr getIntValue(uint64_t X, bool isUnsigned) { QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; return getValue(X, T); } - const llvm::APSInt &getMaxValue(const llvm::APSInt &v) { + APSIntPtr getMaxValue(const llvm::APSInt &v) { return getValue(APSIntType(v).getMaxValue()); } - const llvm::APSInt &getMinValue(const llvm::APSInt &v) { + APSIntPtr getMinValue(const llvm::APSInt &v) { return getValue(APSIntType(v).getMinValue()); } - const llvm::APSInt &getMaxValue(QualType T) { - return getMaxValue(getAPSIntType(T)); - } + APSIntPtr getMaxValue(QualType T) { return getMaxValue(getAPSIntType(T)); } - const llvm::APSInt &getMinValue(QualType T) { - return getMinValue(getAPSIntType(T)); - } + APSIntPtr getMinValue(QualType T) { return getMinValue(getAPSIntType(T)); } - const llvm::APSInt &getMaxValue(APSIntType T) { - return getValue(T.getMaxValue()); - } + APSIntPtr getMaxValue(APSIntType T) { return getValue(T.getMaxValue()); } - const llvm::APSInt &getMinValue(APSIntType T) { - return getValue(T.getMinValue()); - } + APSIntPtr getMinValue(APSIntType T) { return getValue(T.getMinValue()); } - const llvm::APSInt &Add1(const llvm::APSInt &V) { + APSIntPtr Add1(const llvm::APSInt &V) { llvm::APSInt X = V; ++X; return getValue(X); } - const llvm::APSInt &Sub1(const llvm::APSInt &V) { + APSIntPtr Sub1(const llvm::APSInt &V) { llvm::APSInt X = V; --X; return getValue(X); } - const llvm::APSInt &getZeroWithTypeSize(QualType T) { + APSIntPtr getZeroWithTypeSize(QualType T) { assert(T->isScalarType()); return getValue(0, Ctx.getTypeSize(T), true); } - const llvm::APSInt &getTruthValue(bool b, QualType T) { + APSIntPtr getTruthValue(bool b, QualType T) { return getValue(b ? 1 : 0, Ctx.getIntWidth(T), T->isUnsignedIntegerOrEnumerationType()); } - const llvm::APSInt &getTruthValue(bool b) { + APSIntPtr getTruthValue(bool b) { return getTruthValue(b, Ctx.getLogicalOperationType()); } @@ -273,9 +265,9 @@ class BasicValueFactory { accumCXXBase(llvm::iterator_range PathRange, const nonloc::PointerToMember &PTM, const clang::CastKind &kind); - const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op, - const llvm::APSInt& V1, - const llvm::APSInt& V2); + std::optional evalAPSInt(BinaryOperator::Opcode Op, + const llvm::APSInt &V1, + const llvm::APSInt &V2); const std::pair& getPersistentSValWithData(const SVal& V, uintptr_t Data); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 0d9566285f5d4..f88bf70d72398 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -1206,7 +1206,7 @@ class ElementRegion : public TypedValueRegion { : TypedValueRegion(sReg, ElementRegionKind), ElementType(elementType), Index(Idx) { assert((!isa(Idx) || - Idx.castAs().getValue().isSigned()) && + Idx.castAs().getValue()->isSigned()) && "The index must be signed"); assert(!elementType.isNull() && !elementType->isVoidType() && "Invalid region type!"); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 29f534eba2a26..a20516b003c7d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -70,7 +70,6 @@ template struct ProgramStateTrait { /// values will never change. class ProgramState : public llvm::FoldingSetNode { public: - typedef llvm::ImmutableSet IntSetTy; typedef llvm::ImmutableMap GenericDataMap; private: diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h index 5766af1fc78a4..7cfb24e5e649d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h @@ -16,6 +16,7 @@ #include "clang/Basic/JsonSupport.h" #include "clang/Basic/TargetInfo.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h" #include @@ -154,7 +155,7 @@ class SMTConstraintManager : public clang::ento::SimpleConstraintManager { return nullptr; // This is the only solution, store it - return &BVF.getValue(Value); + return BVF.getValue(Value).get(); } if (const SymbolCast *SC = dyn_cast(Sym)) { @@ -167,16 +168,16 @@ class SMTConstraintManager : public clang::ento::SimpleConstraintManager { const llvm::APSInt *Value; if (!(Value = getSymVal(State, CastSym))) return nullptr; - return &BVF.Convert(SC->getType(), *Value); + return BVF.Convert(SC->getType(), *Value).get(); } if (const BinarySymExpr *BSE = dyn_cast(Sym)) { const llvm::APSInt *LHS, *RHS; if (const SymIntExpr *SIE = dyn_cast(BSE)) { LHS = getSymVal(State, SIE->getLHS()); - RHS = &SIE->getRHS(); + RHS = SIE->getRHS().get(); } else if (const IntSymExpr *ISE = dyn_cast(BSE)) { - LHS = &ISE->getLHS(); + LHS = ISE->getLHS().get(); RHS = getSymVal(State, ISE->getRHS()); } else if (const SymSymExpr *SSM = dyn_cast(BSE)) { // Early termination to avoid expensive call @@ -195,7 +196,9 @@ class SMTConstraintManager : public clang::ento::SimpleConstraintManager { std::tie(ConvertedRHS, RTy) = SMTConv::fixAPSInt(Ctx, *RHS); SMTConv::doIntTypeConversion( Solver, Ctx, ConvertedLHS, LTy, ConvertedRHS, RTy); - return BVF.evalAPSInt(BSE->getOpcode(), ConvertedLHS, ConvertedRHS); + std::optional Res = + BVF.evalAPSInt(BSE->getOpcode(), ConvertedLHS, ConvertedRHS); + return Res ? Res.value().get() : nullptr; } llvm_unreachable("Unsupported expression to get symbol value!"); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index ec2b2b2456948..54430d426a82a 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -329,11 +329,10 @@ class SValBuilder { } nonloc::SymbolVal makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt &rhs, QualType type); + APSIntPtr rhs, QualType type); - nonloc::SymbolVal makeNonLoc(const llvm::APSInt &rhs, - BinaryOperator::Opcode op, const SymExpr *lhs, - QualType type); + nonloc::SymbolVal makeNonLoc(APSIntPtr rhs, BinaryOperator::Opcode op, + const SymExpr *lhs, QualType type); nonloc::SymbolVal makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType type); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index a054a819a15a8..aeb57b28077c6 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -17,6 +17,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" @@ -298,9 +299,12 @@ class SymbolVal : public NonLoc { /// Value representing integer constant. class ConcreteInt : public NonLoc { public: - explicit ConcreteInt(const llvm::APSInt &V) : NonLoc(ConcreteIntKind, &V) {} + explicit ConcreteInt(APSIntPtr V) : NonLoc(ConcreteIntKind, V.get()) {} - const llvm::APSInt &getValue() const { return *castDataAs(); } + APSIntPtr getValue() const { + // This is safe because in the ctor we take a safe APSIntPtr. + return APSIntPtr::unsafeConstructor(castDataAs()); + } static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; } }; @@ -510,9 +514,12 @@ class MemRegionVal : public Loc { class ConcreteInt : public Loc { public: - explicit ConcreteInt(const llvm::APSInt &V) : Loc(ConcreteIntKind, &V) {} + explicit ConcreteInt(APSIntPtr V) : Loc(ConcreteIntKind, V.get()) {} - const llvm::APSInt &getValue() const { return *castDataAs(); } + APSIntPtr getValue() const { + // This is safe because in the ctor we take a safe APSIntPtr. + return APSIntPtr::unsafeConstructor(castDataAs()); + } static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; } }; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index 3b64d38ee2b23..73732d532f630 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -18,6 +18,7 @@ #include "clang/AST/Type.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" @@ -410,9 +411,7 @@ class BinarySymExpr : public SymExpr { return 1; } - static const llvm::APSInt *getPointer(const llvm::APSInt &Value) { - return &Value; - } + static const llvm::APSInt *getPointer(APSIntPtr Value) { return Value.get(); } static const SymExpr *getPointer(const SymExpr *Value) { return Value; } static void dumpToStreamImpl(raw_ostream &os, const SymExpr *Value); @@ -468,11 +467,11 @@ class BinarySymExprImpl : public BinarySymExpr { }; /// Represents a symbolic expression like 'x' + 3. -using SymIntExpr = BinarySymExprImpl; /// Represents a symbolic expression like 3 - 'x'. -using IntSymExpr = BinarySymExprImpl; /// Represents a symbolic expression like 'x' + 'y'. @@ -537,15 +536,14 @@ class SymbolManager { QualType From, QualType To); const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t); + APSIntPtr rhs, QualType t); const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t) { + APSIntPtr rhs, QualType t) { return getSymIntExpr(&lhs, op, rhs, t); } - const IntSymExpr *getIntSymExpr(const llvm::APSInt& lhs, - BinaryOperator::Opcode op, + const IntSymExpr *getIntSymExpr(APSIntPtr lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t); const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, 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/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 fa06dffdd14b0..646eabd2a5ecd 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -2045,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/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..68c75b01e6f6d 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -4974,20 +4974,35 @@ template bool Compiler::visitIfStmt(const IfStmt *IS) { LabelTy LabelEnd = this->getLabel(); if (!this->jumpFalse(LabelElse)) return false; - if (!visitStmt(IS->getThen())) - return false; + { + LocalScope ThenScope(this); + if (!visitStmt(IS->getThen())) + return false; + if (!ThenScope.destroyLocals()) + return false; + } if (!this->jump(LabelEnd)) return false; this->emitLabel(LabelElse); - if (!visitStmt(Else)) - return false; + { + LocalScope ElseScope(this); + if (!visitStmt(Else)) + return false; + if (!ElseScope.destroyLocals()) + return false; + } this->emitLabel(LabelEnd); } else { LabelTy LabelEnd = this->getLabel(); if (!this->jumpFalse(LabelEnd)) return false; - if (!visitStmt(IS->getThen())) - return false; + { + LocalScope ThenScope(this); + if (!visitStmt(IS->getThen())) + return false; + if (!ThenScope.destroyLocals()) + return false; + } this->emitLabel(LabelEnd); } @@ -6483,14 +6498,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 +6530,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 +6547,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.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..2ae91feb2d9e8 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) { @@ -1861,10 +1862,10 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, } QualType ElemType; - if (SrcPtr.getFieldDesc()->isArray()) - ElemType = SrcPtr.getFieldDesc()->getElemQualType(); + if (DestPtr.getFieldDesc()->isArray()) + ElemType = DestPtr.getFieldDesc()->getElemQualType(); else - ElemType = SrcPtr.getType(); + ElemType = DestPtr.getType(); unsigned ElemSize = S.getASTContext().getTypeSizeInChars(ElemType).getQuantity(); @@ -1875,17 +1876,157 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, return false; } + QualType SrcElemType; + if (SrcPtr.getFieldDesc()->isArray()) + SrcElemType = SrcPtr.getFieldDesc()->getElemQualType(); + else + SrcElemType = SrcPtr.getType(); + + if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) { + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun) + << Move << SrcElemType << ElemType; + 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; - - if (!DoBitCastPtr(S, OpPC, SrcPtr, DestPtr, Size.getZExtValue())) + assert(Size.getZExtValue() % ElemSize == 0); + if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits())) return false; S.Stk.push(DestPtr); 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 +2500,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 7ba0faff25253..0fc94e1694822 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; } @@ -254,24 +254,24 @@ static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, 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()) @@ -290,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. @@ -386,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)); @@ -451,3 +448,34 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, return Success; } + +bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC, + const Pointer &SrcPtr, const Pointer &DestPtr, + Bits Size) { + assert(SrcPtr.isBlockPointer()); + assert(DestPtr.isBlockPointer()); + + unsigned SrcStartOffset = SrcPtr.getByteOffset(); + unsigned DestStartOffset = DestPtr.getByteOffset(); + + enumeratePointerFields(SrcPtr, S.getContext(), Size, + [&](const Pointer &P, PrimType T, Bits BitOffset, + Bits FullBitWidth, bool PackedBools) -> bool { + unsigned SrcOffsetDiff = + P.getByteOffset() - SrcStartOffset; + + Pointer DestP = + Pointer(DestPtr.asBlockPointer().Pointee, + DestPtr.asBlockPointer().Base, + DestStartOffset + SrcOffsetDiff); + + TYPE_SWITCH(T, { + DestP.deref() = P.deref(); + DestP.initialize(); + }); + + return true; + }); + + return true; +} diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.h index 92e6ffc79fc4f..a0191bab693c4 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,6 +31,11 @@ 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); + +bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &SrcPtr, + const Pointer &DestPtr, Bits Size); } // 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/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 457fe93b27817..0d467c2abf083 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -107,6 +107,7 @@ class Pointer { : Offset(Offset), StorageKind(Storage::Fn) { PointeeStorage.Fn = FunctionPointer(F); } + Pointer(Block *Pointee, unsigned Base, uint64_t Offset); ~Pointer(); void operator=(const Pointer &P); @@ -706,8 +707,6 @@ class Pointer { friend struct InitMap; friend class DynamicAllocator; - Pointer(Block *Pointee, unsigned Base, uint64_t Offset); - /// Returns the embedded descriptor preceding a field. InlineDescriptor *getInlineDesc() const { assert(isBlockPointer()); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 6c206e1f7a231..76e17a2b1bafe 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3042,6 +3042,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 66c7728e33248..b79f666aa6e2e 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13673,7 +13673,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_reduce_mul: case Builtin::BI__builtin_reduce_and: case Builtin::BI__builtin_reduce_or: - case Builtin::BI__builtin_reduce_xor: { + case Builtin::BI__builtin_reduce_xor: + case Builtin::BI__builtin_reduce_min: + case Builtin::BI__builtin_reduce_max: { APValue Source; if (!EvaluateAsRValue(Info, E->getArg(0), Source)) return false; @@ -13710,6 +13712,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, Reduced ^= Source.getVectorElt(EltNum).getInt(); break; } + case Builtin::BI__builtin_reduce_min: { + Reduced = std::min(Reduced, Source.getVectorElt(EltNum).getInt()); + break; + } + case Builtin::BI__builtin_reduce_max: { + Reduced = std::max(Reduced, Source.getVectorElt(EltNum).getInt()); + break; + } } } diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 1299e4f807ceb..d69fab5cc413c 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); @@ -44,6 +46,7 @@ bool OpenACCClauseWithCondition::classof(const OpenACCClause *C) { bool OpenACCClauseWithSingleIntExpr::classof(const OpenACCClause *C) { return OpenACCNumWorkersClause::classof(C) || OpenACCVectorLengthClause::classof(C) || + OpenACCDeviceNumClause::classof(C) || OpenACCVectorClause::classof(C) || OpenACCWorkerClause::classof(C) || OpenACCCollapseClause::classof(C) || OpenACCAsyncClause::classof(C); } @@ -216,6 +219,26 @@ OpenACCAsyncClause *OpenACCAsyncClause::Create(const ASTContext &C, return new (Mem) OpenACCAsyncClause(BeginLoc, LParenLoc, IntExpr, EndLoc); } +OpenACCDeviceNumClause::OpenACCDeviceNumClause(SourceLocation BeginLoc, + SourceLocation LParenLoc, Expr *IntExpr, + SourceLocation EndLoc) + : OpenACCClauseWithSingleIntExpr(OpenACCClauseKind::DeviceNum, BeginLoc, + LParenLoc, IntExpr, EndLoc) { + assert((IntExpr->isInstantiationDependent() || + IntExpr->getType()->isIntegerType()) && + "device_num expression type not scalar/dependent"); +} + +OpenACCDeviceNumClause *OpenACCDeviceNumClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + Expr *IntExpr, + SourceLocation EndLoc) { + void *Mem = + C.Allocate(sizeof(OpenACCDeviceNumClause), alignof(OpenACCDeviceNumClause)); + return new (Mem) OpenACCDeviceNumClause(BeginLoc, LParenLoc, IntExpr, EndLoc); +} + OpenACCWaitClause *OpenACCWaitClause::Create( const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef QueueIdExprs, @@ -277,6 +300,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 +497,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 //===----------------------------------------------------------------------===// @@ -499,6 +568,13 @@ void OpenACCClausePrinter::VisitVectorLengthClause( OS << ")"; } +void OpenACCClausePrinter::VisitDeviceNumClause( + const OpenACCDeviceNumClause &C) { + OS << "device_num("; + printExpr(C.getIntExpr()); + OS << ")"; +} + void OpenACCClausePrinter::VisitAsyncClause(const OpenACCAsyncClause &C) { OS << "async"; if (C.hasIntExpr()) { @@ -530,6 +606,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 +783,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/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 1e527ed0b2a2e..d6a351a78c7ba 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -47,6 +47,15 @@ using namespace clang; +#define STMT(CLASS, PARENT) +#define STMT_RANGE(BASE, FIRST, LAST) +#define LAST_STMT_RANGE(BASE, FIRST, LAST) \ + static_assert(llvm::isUInt(Stmt::StmtClass::LAST##Class), \ + "The number of 'StmtClass'es is strictly bound " \ + "by a bitfield of width NumStmtBits"); +#define ABSTRACT_STMT(STMT) +#include "clang/AST/StmtNodes.inc" + static struct StmtClassNameTable { const char *Name; unsigned Counter; diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp index 23dd57d235813..e6d76ea30f029 100644 --- a/clang/lib/AST/StmtOpenACC.cpp +++ b/clang/lib/AST/StmtOpenACC.cpp @@ -110,3 +110,158 @@ 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; +} +OpenACCInitConstruct *OpenACCInitConstruct::CreateEmpty(const ASTContext &C, + unsigned NumClauses) { + void *Mem = + C.Allocate(OpenACCInitConstruct::totalSizeToAlloc( + NumClauses)); + auto *Inst = new (Mem) OpenACCInitConstruct(NumClauses); + return Inst; +} + +OpenACCInitConstruct * +OpenACCInitConstruct::Create(const ASTContext &C, SourceLocation Start, + SourceLocation DirectiveLoc, SourceLocation End, + ArrayRef Clauses) { + void *Mem = + C.Allocate(OpenACCInitConstruct::totalSizeToAlloc( + Clauses.size())); + auto *Inst = + new (Mem) OpenACCInitConstruct(Start, DirectiveLoc, End, Clauses); + return Inst; +} +OpenACCShutdownConstruct * +OpenACCShutdownConstruct::CreateEmpty(const ASTContext &C, + unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCShutdownConstruct::totalSizeToAlloc( + NumClauses)); + auto *Inst = new (Mem) OpenACCShutdownConstruct(NumClauses); + return Inst; +} + +OpenACCShutdownConstruct *OpenACCShutdownConstruct::Create( + const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, + SourceLocation End, ArrayRef Clauses) { + void *Mem = C.Allocate( + OpenACCShutdownConstruct::totalSizeToAlloc( + Clauses.size())); + auto *Inst = + new (Mem) OpenACCShutdownConstruct(Start, DirectiveLoc, End, Clauses); + return Inst; +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index b602a50e30108..f65d32ff35ee7 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -127,6 +127,8 @@ namespace { void PrintOMPExecutableDirective(OMPExecutableDirective *S, bool ForceNoStmt = false); void PrintFPPragmas(CompoundStmt *S); + void PrintOpenACCClauseList(OpenACCConstructStmt *S); + void PrintOpenACCConstruct(OpenACCConstructStmt *S); void PrintExpr(Expr *E) { if (E) @@ -1155,42 +1157,76 @@ void StmtPrinter::VisitOMPTargetParallelGenericLoopDirective( //===----------------------------------------------------------------------===// // OpenACC construct printing methods //===----------------------------------------------------------------------===// -void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) { - Indent() << "#pragma acc " << S->getDirectiveKind(); - +void StmtPrinter::PrintOpenACCClauseList(OpenACCConstructStmt *S) { if (!S->clauses().empty()) { OS << ' '; OpenACCClausePrinter Printer(OS, Policy); Printer.VisitClauseList(S->clauses()); } +} +void StmtPrinter::PrintOpenACCConstruct(OpenACCConstructStmt *S) { + Indent() << "#pragma acc " << S->getDirectiveKind(); + PrintOpenACCClauseList(S); OS << '\n'; - +} +void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) { + PrintOpenACCConstruct(S); PrintStmt(S->getStructuredBlock()); } void StmtPrinter::VisitOpenACCLoopConstruct(OpenACCLoopConstruct *S) { - Indent() << "#pragma acc loop"; - - if (!S->clauses().empty()) { - OS << ' '; - OpenACCClausePrinter Printer(OS, Policy); - Printer.VisitClauseList(S->clauses()); - } - OS << '\n'; - + PrintOpenACCConstruct(S); PrintStmt(S->getLoop()); } void StmtPrinter::VisitOpenACCCombinedConstruct(OpenACCCombinedConstruct *S) { - Indent() << "#pragma acc " << S->getDirectiveKind(); - if (!S->clauses().empty()) { - OS << ' '; - OpenACCClausePrinter Printer(OS, Policy); - Printer.VisitClauseList(S->clauses()); + PrintOpenACCConstruct(S); + PrintStmt(S->getLoop()); +} + +void StmtPrinter::VisitOpenACCDataConstruct(OpenACCDataConstruct *S) { + PrintOpenACCConstruct(S); + PrintStmt(S->getStructuredBlock()); +} +void StmtPrinter::VisitOpenACCHostDataConstruct(OpenACCHostDataConstruct *S) { + PrintOpenACCConstruct(S); + PrintStmt(S->getStructuredBlock()); +} +void StmtPrinter::VisitOpenACCEnterDataConstruct(OpenACCEnterDataConstruct *S) { + PrintOpenACCConstruct(S); +} +void StmtPrinter::VisitOpenACCExitDataConstruct(OpenACCExitDataConstruct *S) { + PrintOpenACCConstruct(S); +} +void StmtPrinter::VisitOpenACCInitConstruct(OpenACCInitConstruct *S) { + PrintOpenACCConstruct(S); +} +void StmtPrinter::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) { + PrintOpenACCConstruct(S); +} + +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 << ")"; } - OS << '\n'; - PrintStmt(S->getLoop()); + PrintOpenACCClauseList(S); + OS << '\n'; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 35a9f7c3f91d2..7cdf09d1fa097 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2542,6 +2542,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); @@ -2559,25 +2564,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) { @@ -2585,6 +2586,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()) @@ -2610,38 +2617,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( @@ -2656,6 +2672,11 @@ void OpenACCClauseProfiler::VisitAsyncClause(const OpenACCAsyncClause &Clause) { Profiler.VisitStmt(Clause.getIntExpr()); } +void OpenACCClauseProfiler::VisitDeviceNumClause( + const OpenACCDeviceNumClause &Clause) { + Profiler.VisitStmt(Clause.getIntExpr()); +} + void OpenACCClauseProfiler::VisitWorkerClause( const OpenACCWorkerClause &Clause) { if (Clause.hasIntExpr()) @@ -2693,8 +2714,7 @@ void OpenACCClauseProfiler::VisitGangClause(const OpenACCGangClause &Clause) { void OpenACCClauseProfiler::VisitReductionClause( const OpenACCReductionClause &Clause) { - for (auto *E : Clause.getVarList()) - Profiler.VisitStmt(E); + VisitClauseWithVarList(Clause); } } // namespace @@ -2724,6 +2744,58 @@ 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::VisitOpenACCInitConstruct(const OpenACCInitConstruct *S) { + VisitStmt(S); + OpenACCClauseProfiler P{*this}; + P.VisitOpenACCClauseList(S->clauses()); +} + +void StmtProfiler::VisitOpenACCShutdownConstruct( + const OpenACCShutdownConstruct *S) { + 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 76df65a999f23..d204e645e0598 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -409,8 +409,13 @@ 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::DeviceNum: case OpenACCClauseKind::DevicePtr: + case OpenACCClauseKind::Finalize: case OpenACCClauseKind::FirstPrivate: case OpenACCClauseKind::NoCreate: case OpenACCClauseKind::NumGangs: @@ -421,6 +426,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', @@ -2939,6 +2945,36 @@ 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::VisitOpenACCInitConstruct(const OpenACCInitConstruct *S) { + OS << " " << S->getDirectiveKind(); +} +void TextNodeDumper::VisitOpenACCShutdownConstruct( + const OpenACCShutdownConstruct *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/AST/Type.cpp b/clang/lib/AST/Type.cpp index c2c38495751de..5b4ca402afa58 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5129,7 +5129,7 @@ bool Type::isHLSLIntangibleType() const { CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); assert(RD != nullptr && - "all HLSL struct and classes should be CXXRecordDecl"); + "all HLSL structs and classes should be CXXRecordDecl"); assert(RD->isCompleteDefinition() && "expecting complete type"); return RD->isHLSLIntangible(); } diff --git a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt index 05cdaa7e27823..0c30df8b4b194 100644 --- a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt +++ b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_library(clangAnalysisFlowSensitive Logger.cpp RecordOps.cpp SimplifyConstraints.cpp + SmartPointerAccessorCaching.cpp Transfer.cpp TypeErasedDataflowAnalysis.cpp Value.cpp diff --git a/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp new file mode 100644 index 0000000000000..a0c81aa933da8 --- /dev/null +++ b/clang/lib/Analysis/FlowSensitive/SmartPointerAccessorCaching.cpp @@ -0,0 +1,147 @@ +#include "clang/Analysis/FlowSensitive/SmartPointerAccessorCaching.h" + +#include "clang/AST/CanonicalType.h" +#include "clang/AST/DeclCXX.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchersMacros.h" +#include "clang/Basic/OperatorKinds.h" + +namespace clang::dataflow { + +namespace { + +using ast_matchers::callee; +using ast_matchers::cxxMemberCallExpr; +using ast_matchers::cxxMethodDecl; +using ast_matchers::cxxOperatorCallExpr; +using ast_matchers::hasName; +using ast_matchers::hasOverloadedOperatorName; +using ast_matchers::ofClass; +using ast_matchers::parameterCountIs; +using ast_matchers::pointerType; +using ast_matchers::referenceType; +using ast_matchers::returns; + +bool hasSmartPointerClassShape(const CXXRecordDecl &RD, bool &HasGet, + bool &HasValue) { + // We may want to cache this search, but in current profiles it hasn't shown + // up as a hot spot (possibly because there aren't many hits, relatively). + bool HasArrow = false; + bool HasStar = false; + CanQualType StarReturnType, ArrowReturnType, GetReturnType, ValueReturnType; + for (const auto *MD : RD.methods()) { + // We only consider methods that are const and have zero parameters. + // It may be that there is a non-const overload for the method, but + // there should at least be a const overload as well. + if (!MD->isConst() || MD->getNumParams() != 0) + continue; + switch (MD->getOverloadedOperator()) { + case OO_Star: + if (MD->getReturnType()->isReferenceType()) { + HasStar = true; + StarReturnType = MD->getReturnType() + .getNonReferenceType() + ->getCanonicalTypeUnqualified(); + } + break; + case OO_Arrow: + if (MD->getReturnType()->isPointerType()) { + HasArrow = true; + ArrowReturnType = MD->getReturnType() + ->getPointeeType() + ->getCanonicalTypeUnqualified(); + } + break; + case OO_None: { + IdentifierInfo *II = MD->getIdentifier(); + if (II == nullptr) + continue; + if (II->isStr("get")) { + if (MD->getReturnType()->isPointerType()) { + HasGet = true; + GetReturnType = MD->getReturnType() + ->getPointeeType() + ->getCanonicalTypeUnqualified(); + } + } else if (II->isStr("value")) { + if (MD->getReturnType()->isReferenceType()) { + HasValue = true; + ValueReturnType = MD->getReturnType() + .getNonReferenceType() + ->getCanonicalTypeUnqualified(); + } + } + } break; + default: + break; + } + } + + if (!HasStar || !HasArrow || StarReturnType != ArrowReturnType) + return false; + HasGet = HasGet && (GetReturnType == StarReturnType); + HasValue = HasValue && (ValueReturnType == StarReturnType); + return true; +} + +} // namespace +} // namespace clang::dataflow + +// AST_MATCHER macros create an "internal" namespace, so we put it in +// its own anonymous namespace instead of in clang::dataflow. +namespace { + +AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGet) { + bool HasGet = false; + bool HasValue = false; + bool HasStarAndArrow = + clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); + return HasStarAndArrow && HasGet; +} + +AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithValue) { + bool HasGet = false; + bool HasValue = false; + bool HasStarAndArrow = + clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); + return HasStarAndArrow && HasValue; +} + +AST_MATCHER(clang::CXXRecordDecl, smartPointerClassWithGetOrValue) { + bool HasGet = false; + bool HasValue = false; + bool HasStarAndArrow = + clang::dataflow::hasSmartPointerClassShape(Node, HasGet, HasValue); + return HasStarAndArrow && (HasGet || HasValue); +} + +} // namespace + +namespace clang::dataflow { + +ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar() { + return cxxOperatorCallExpr( + hasOverloadedOperatorName("*"), + callee(cxxMethodDecl(parameterCountIs(0), returns(referenceType()), + ofClass(smartPointerClassWithGetOrValue())))); +} + +ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow() { + return cxxOperatorCallExpr( + hasOverloadedOperatorName("->"), + callee(cxxMethodDecl(parameterCountIs(0), returns(pointerType()), + ofClass(smartPointerClassWithGetOrValue())))); +} +ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall() { + return cxxMemberCallExpr(callee( + cxxMethodDecl(parameterCountIs(0), returns(referenceType()), + hasName("value"), ofClass(smartPointerClassWithValue())))); +} + +ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall() { + return cxxMemberCallExpr(callee( + cxxMethodDecl(parameterCountIs(0), returns(pointerType()), hasName("get"), + ofClass(smartPointerClassWithGet())))); +} + +} // namespace clang::dataflow 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/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index 5577f45aa5217..bfaf1a0e7c7ff 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -103,6 +103,8 @@ class FactSet; /// FIXME: this analysis does not currently support re-entrant locking. class FactEntry : public CapabilityExpr { public: + enum FactEntryKind { Lockable, ScopedLockable }; + /// Where a fact comes from. enum SourceKind { Acquired, ///< The fact has been directly acquired. @@ -112,6 +114,8 @@ class FactEntry : public CapabilityExpr { }; private: + const FactEntryKind Kind : 8; + /// Exclusive or shared. LockKind LKind : 8; @@ -122,13 +126,14 @@ class FactEntry : public CapabilityExpr { SourceLocation AcquireLoc; public: - FactEntry(const CapabilityExpr &CE, LockKind LK, SourceLocation Loc, - SourceKind Src) - : CapabilityExpr(CE), LKind(LK), Source(Src), AcquireLoc(Loc) {} + FactEntry(FactEntryKind FK, const CapabilityExpr &CE, LockKind LK, + SourceLocation Loc, SourceKind Src) + : CapabilityExpr(CE), Kind(FK), LKind(LK), Source(Src), AcquireLoc(Loc) {} virtual ~FactEntry() = default; LockKind kind() const { return LKind; } SourceLocation loc() const { return AcquireLoc; } + FactEntryKind getFactEntryKind() const { return Kind; } bool asserted() const { return Source == Asserted; } bool declared() const { return Source == Declared; } @@ -857,7 +862,7 @@ class LockableFactEntry : public FactEntry { public: LockableFactEntry(const CapabilityExpr &CE, LockKind LK, SourceLocation Loc, SourceKind Src = Acquired) - : FactEntry(CE, LK, Loc, Src) {} + : FactEntry(Lockable, CE, LK, Loc, Src) {} void handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan, @@ -885,6 +890,10 @@ class LockableFactEntry : public FactEntry { !Cp, LK_Exclusive, UnlockLoc)); } } + + static bool classof(const FactEntry *A) { + return A->getFactEntryKind() == Lockable; + } }; class ScopedLockableFactEntry : public FactEntry { @@ -903,8 +912,16 @@ class ScopedLockableFactEntry : public FactEntry { SmallVector UnderlyingMutexes; public: - ScopedLockableFactEntry(const CapabilityExpr &CE, SourceLocation Loc) - : FactEntry(CE, LK_Exclusive, Loc, Acquired) {} + ScopedLockableFactEntry(const CapabilityExpr &CE, SourceLocation Loc, + SourceKind Src) + : FactEntry(ScopedLockable, CE, LK_Exclusive, Loc, Src) {} + + CapExprSet getUnderlyingMutexes() const { + CapExprSet UnderlyingMutexesSet; + for (const UnderlyingCapability &UnderlyingMutex : UnderlyingMutexes) + UnderlyingMutexesSet.push_back(UnderlyingMutex.Cap); + return UnderlyingMutexesSet; + } void addLock(const CapabilityExpr &M) { UnderlyingMutexes.push_back(UnderlyingCapability{M, UCK_Acquired}); @@ -971,6 +988,10 @@ class ScopedLockableFactEntry : public FactEntry { FSet.removeLock(FactMan, Cp); } + static bool classof(const FactEntry *A) { + return A->getFactEntryKind() == ScopedLockable; + } + private: void lock(FactSet &FSet, FactManager &FactMan, const CapabilityExpr &Cp, LockKind kind, SourceLocation loc, @@ -1806,7 +1827,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D, if (Exp) { assert(!Self); const auto *TagT = Exp->getType()->getAs(); - if (TagT && Exp->isPRValue()) { + if (D->hasAttrs() && TagT && Exp->isPRValue()) { std::pair Placeholder = Analyzer->SxBuilder.createThisPlaceholder(Exp); [[maybe_unused]] auto inserted = @@ -1915,6 +1936,101 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D, } } + std::optional Args; + if (Exp) { + if (const auto *CE = dyn_cast(Exp)) + Args = CE->arguments(); + else if (const auto *CE = dyn_cast(Exp)) + Args = CE->arguments(); + else + llvm_unreachable("Unknown call kind"); + } + const auto *CalledFunction = dyn_cast(D); + if (CalledFunction && Args.has_value()) { + for (auto [Param, Arg] : zip(CalledFunction->parameters(), *Args)) { + CapExprSet DeclaredLocks; + for (const Attr *At : Param->attrs()) { + switch (At->getKind()) { + case attr::AcquireCapability: { + const auto *A = cast(At); + Analyzer->getMutexIDs(A->isShared() ? SharedLocksToAdd + : ExclusiveLocksToAdd, + A, Exp, D, Self); + Analyzer->getMutexIDs(DeclaredLocks, A, Exp, D, Self); + break; + } + + case attr::ReleaseCapability: { + const auto *A = cast(At); + if (A->isGeneric()) + Analyzer->getMutexIDs(GenericLocksToRemove, A, Exp, D, Self); + else if (A->isShared()) + Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, Self); + else + Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, Self); + Analyzer->getMutexIDs(DeclaredLocks, A, Exp, D, Self); + break; + } + + case attr::RequiresCapability: { + const auto *A = cast(At); + for (auto *Arg : A->args()) + Analyzer->warnIfMutexNotHeld(FSet, D, Exp, + A->isShared() ? AK_Read : AK_Written, + Arg, POK_FunctionCall, Self, Loc); + Analyzer->getMutexIDs(DeclaredLocks, A, Exp, D, Self); + break; + } + + case attr::LocksExcluded: { + const auto *A = cast(At); + for (auto *Arg : A->args()) + Analyzer->warnIfMutexHeld(FSet, D, Exp, Arg, Self, Loc); + Analyzer->getMutexIDs(DeclaredLocks, A, Exp, D, Self); + break; + } + + default: + break; + } + } + if (DeclaredLocks.empty()) + continue; + CapabilityExpr Cp(Analyzer->SxBuilder.translate(Arg, nullptr), + StringRef("mutex"), false); + if (const auto *CBTE = dyn_cast(Arg->IgnoreCasts()); + Cp.isInvalid() && CBTE) { + if (auto Object = Analyzer->ConstructedObjects.find(CBTE->getSubExpr()); + Object != Analyzer->ConstructedObjects.end()) + Cp = CapabilityExpr(Object->second, StringRef("mutex"), false); + } + const FactEntry *Fact = FSet.findLock(Analyzer->FactMan, Cp); + if (!Fact) { + Analyzer->Handler.handleMutexNotHeld(Cp.getKind(), D, POK_FunctionCall, + Cp.toString(), LK_Exclusive, + Exp->getExprLoc()); + continue; + } + const auto *Scope = cast(Fact); + for (const auto &[a, b] : + zip_longest(DeclaredLocks, Scope->getUnderlyingMutexes())) { + if (!a.has_value()) { + Analyzer->Handler.handleExpectFewerUnderlyingMutexes( + Exp->getExprLoc(), D->getLocation(), Scope->toString(), + b.value().getKind(), b.value().toString()); + } else if (!b.has_value()) { + Analyzer->Handler.handleExpectMoreUnderlyingMutexes( + Exp->getExprLoc(), D->getLocation(), Scope->toString(), + a.value().getKind(), a.value().toString()); + } else if (!a.value().equals(b.value())) { + Analyzer->Handler.handleUnmatchedUnderlyingMutexes( + Exp->getExprLoc(), D->getLocation(), Scope->toString(), + a.value().getKind(), a.value().toString(), b.value().toString()); + break; + } + } + } + } // Remove locks first to allow lock upgrading/downgrading. // FIXME -- should only fully remove if the attribute refers to 'this'. bool Dtor = isa(D); @@ -1937,7 +2053,8 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D, if (!Scp.shouldIgnore()) { // Add the managing object as a dummy mutex, mapped to the underlying mutex. - auto ScopedEntry = std::make_unique(Scp, Loc); + auto ScopedEntry = std::make_unique( + Scp, Loc, FactEntry::Acquired); for (const auto &M : ExclusiveLocksToAdd) ScopedEntry->addLock(M); for (const auto &M : SharedLocksToAdd) @@ -2084,7 +2201,7 @@ void BuildLockset::VisitCallExpr(const CallExpr *Exp) { } auto *D = dyn_cast_or_null(Exp->getCalleeDecl()); - if(!D || !D->hasAttrs()) + if (!D) return; handleCall(Exp, D); } @@ -2324,7 +2441,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { // Add locks from exclusive_locks_required and shared_locks_required // to initial lockset. Also turn off checking for lock and unlock functions. // FIXME: is there a more intelligent way to check lock/unlock functions? - if (!SortedGraph->empty() && D->hasAttrs()) { + if (!SortedGraph->empty()) { assert(*SortedGraph->begin() == &CFGraph->getEntry()); FactSet &InitialLockset = Initial.EntrySet; @@ -2362,6 +2479,44 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { return; } } + ArrayRef Params; + if (CurrentFunction) + Params = CurrentFunction->getCanonicalDecl()->parameters(); + else if (auto CurrentMethod = dyn_cast(D)) + Params = CurrentMethod->getCanonicalDecl()->parameters(); + else + llvm_unreachable("Unknown function kind"); + for (const ParmVarDecl *Param : Params) { + CapExprSet UnderlyingLocks; + for (const auto *Attr : Param->attrs()) { + Loc = Attr->getLocation(); + if (const auto *A = dyn_cast(Attr)) { + getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A, + nullptr, Param); + getMutexIDs(LocksReleased, A, nullptr, Param); + getMutexIDs(UnderlyingLocks, A, nullptr, Param); + } else if (const auto *A = dyn_cast(Attr)) { + getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A, + nullptr, Param); + getMutexIDs(UnderlyingLocks, A, nullptr, Param); + } else if (const auto *A = dyn_cast(Attr)) { + getMutexIDs(A->isShared() ? SharedLocksAcquired + : ExclusiveLocksAcquired, + A, nullptr, Param); + getMutexIDs(UnderlyingLocks, A, nullptr, Param); + } else if (const auto *A = dyn_cast(Attr)) { + getMutexIDs(UnderlyingLocks, A, nullptr, Param); + } + } + if (UnderlyingLocks.empty()) + continue; + CapabilityExpr Cp(SxBuilder.createVariable(Param), StringRef(), false); + auto ScopedEntry = std::make_unique( + Cp, Param->getLocation(), FactEntry::Declared); + for (const CapabilityExpr &M : UnderlyingLocks) + ScopedEntry->addLock(M); + addLock(InitialLockset, std::move(ScopedEntry), true); + } // FIXME -- Loc can be wrong here. for (const auto &Mu : ExclusiveLocksToAdd) { 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 289843742e863..ec303f8b968a3 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)) @@ -165,7 +126,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; } @@ -176,23 +137,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) { @@ -209,7 +167,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; @@ -232,7 +190,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; @@ -259,7 +217,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 e664a259758fd..e21f548a42b60 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -780,6 +780,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); } @@ -788,6 +791,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 10fd855e927f2..a36f11b5c72bc 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..b5e06b679ece7 100644 --- a/clang/lib/Basic/Targets/Hexagon.cpp +++ b/clang/lib/Basic/Targets/Hexagon.cpp @@ -78,6 +78,12 @@ void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, } else if (CPU == "hexagonv73") { Builder.defineMacro("__HEXAGON_V73__"); Builder.defineMacro("__HEXAGON_ARCH__", "73"); + } else if (CPU == "hexagonv75") { + Builder.defineMacro("__HEXAGON_V75__"); + Builder.defineMacro("__HEXAGON_ARCH__", "75"); + } else if (CPU == "hexagonv79") { + Builder.defineMacro("__HEXAGON_V79__"); + Builder.defineMacro("__HEXAGON_ARCH__", "79"); } if (hasFeature("hvx-length64b")) { @@ -198,19 +204,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; @@ -233,13 +235,14 @@ struct CPUSuffix { }; static constexpr CPUSuffix Suffixes[] = { - {{"hexagonv5"}, {"5"}}, {{"hexagonv55"}, {"55"}}, - {{"hexagonv60"}, {"60"}}, {{"hexagonv62"}, {"62"}}, - {{"hexagonv65"}, {"65"}}, {{"hexagonv66"}, {"66"}}, + {{"hexagonv5"}, {"5"}}, {{"hexagonv55"}, {"55"}}, + {{"hexagonv60"}, {"60"}}, {{"hexagonv62"}, {"62"}}, + {{"hexagonv65"}, {"65"}}, {{"hexagonv66"}, {"66"}}, {{"hexagonv67"}, {"67"}}, {{"hexagonv67t"}, {"67t"}}, - {{"hexagonv68"}, {"68"}}, {{"hexagonv69"}, {"69"}}, - {{"hexagonv71"}, {"71"}}, {{"hexagonv71t"}, {"71t"}}, - {{"hexagonv73"}, {"73"}}, + {{"hexagonv68"}, {"68"}}, {{"hexagonv69"}, {"69"}}, + {{"hexagonv71"}, {"71"}}, {{"hexagonv71t"}, {"71t"}}, + {{"hexagonv73"}, {"73"}}, {{"hexagonv75"}, {"75"}}, + {{"hexagonv79"}, {"79"}}, }; std::optional HexagonTargetInfo::getHexagonCPURev(StringRef Name) { @@ -268,7 +271,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 57671c89d50f3..693152e1741c4 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"}; @@ -311,7 +307,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 2307d940d3233..0a427438bea66 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 c0351f26e9bee..53dd23c312963 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; } } }; @@ -787,7 +790,9 @@ template class LLVM_LIBRARY_VISIBILITY UEFITargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - MacroBuilder &Builder) const override {} + MacroBuilder &Builder) const override { + Builder.defineMacro("__UEFI__"); + } public: UEFITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) 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 b58375f6f3793..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; } 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 cc6a3100f2ae0..2b26261bec365 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -165,10 +165,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 ""; } @@ -612,8 +609,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 04e00bac64476..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; 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 14f1ac20747f5..7b0fd0c841ba2 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -20,19 +20,15 @@ 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"}, {"lime1"}}; @@ -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 6ce2bb00e5f2a..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; 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..553c452d4ba3c 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 { @@ -834,11 +832,6 @@ class LLVM_LIBRARY_VISIBILITY UEFIX86_64TargetInfo "i64:64-i128:128-f80:128-n8:16:32:64-S128"); } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { - getOSDefines(Opts, X86TargetInfo::getTriple(), Builder); - } - BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } 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/CMakeLists.txt b/clang/lib/CIR/CMakeLists.txt index 11cca734808df..f3ef8525e15c2 100644 --- a/clang/lib/CIR/CMakeLists.txt +++ b/clang/lib/CIR/CMakeLists.txt @@ -4,3 +4,4 @@ include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include) add_subdirectory(Dialect) add_subdirectory(CodeGen) add_subdirectory(FrontendAction) +add_subdirectory(Interfaces) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 92115778518d4..01d56963883cc 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -21,6 +21,18 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { public: CIRGenBuilderTy(mlir::MLIRContext &mlirContext, const CIRGenTypeCache &tc) : CIRBaseBuilderTy(mlirContext), typeCache(tc) {} + + cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const { + if (&format == &llvm::APFloat::IEEEdouble()) + return cir::LongDoubleType::get(getContext(), typeCache.DoubleTy); + if (&format == &llvm::APFloat::x87DoubleExtended()) + return cir::LongDoubleType::get(getContext(), typeCache.FP80Ty); + if (&format == &llvm::APFloat::IEEEquad()) + return cir::LongDoubleType::get(getContext(), typeCache.FP128Ty); + if (&format == &llvm::APFloat::PPCDoubleDouble()) + llvm_unreachable("NYI: PPC double-double format for long double"); + llvm_unreachable("Unsupported format for long double"); + } }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 0db24c3b41d18..416d532028d09 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -35,6 +35,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, diags(diags), target(astContext.getTargetInfo()), genTypes(*this) { // Initialize cached types + VoidTy = cir::VoidType::get(&getMLIRContext()); SInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/true); SInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/true); SInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/true); @@ -45,6 +46,12 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false); UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false); UInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/false); + FP16Ty = cir::FP16Type::get(&getMLIRContext()); + BFloat16Ty = cir::BF16Type::get(&getMLIRContext()); + FloatTy = cir::SingleType::get(&getMLIRContext()); + DoubleTy = cir::DoubleType::get(&getMLIRContext()); + FP80Ty = cir::FP80Type::get(&getMLIRContext()); + FP128Ty = cir::FP128Type::get(&getMLIRContext()); } mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) { diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h index a357663c33e0f..99c0123c64b28 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h @@ -23,6 +23,9 @@ namespace clang::CIRGen { struct CIRGenTypeCache { CIRGenTypeCache() = default; + // ClangIR void type + cir::VoidType VoidTy; + // ClangIR signed integral types of common sizes cir::IntType SInt8Ty; cir::IntType SInt16Ty; @@ -36,6 +39,14 @@ struct CIRGenTypeCache { cir::IntType UInt32Ty; cir::IntType UInt64Ty; cir::IntType UInt128Ty; + + // ClangIR floating-point types with fixed formats + cir::FP16Type FP16Ty; + cir::BF16Type BFloat16Ty; + cir::SingleType FloatTy; + cir::DoubleType DoubleTy; + cir::FP80Type FP80Ty; + cir::FP128Type FP128Ty; }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index 181af1898baff..8519854556b1c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -4,6 +4,9 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" + +#include using namespace clang; using namespace clang::CIRGen; @@ -18,6 +21,70 @@ mlir::MLIRContext &CIRGenTypes::getMLIRContext() const { return *builder.getContext(); } +/// Return true if the specified type in a function parameter or result position +/// can be converted to a CIR type at this point. This boils down to being +/// whether it is complete, as well as whether we've temporarily deferred +/// expanding the type because we're in a recursive context. +bool CIRGenTypes::isFuncParamTypeConvertible(clang::QualType type) { + // Some ABIs cannot have their member pointers represented in LLVM IR unless + // certain circumstances have been reached. + assert(!type->getAs() && "NYI"); + + // If this isn't a tag type, we can convert it. + const TagType *tagType = type->getAs(); + if (!tagType) + return true; + + // Function types involving incomplete class types are problematic in MLIR. + return !tagType->isIncompleteType(); +} + +/// Code to verify a given function type is complete, i.e. the return type and +/// all of the parameter types are complete. Also check to see if we are in a +/// RS_StructPointer context, and if so whether any struct types have been +/// pended. If so, we don't want to ask the ABI lowering code to handle a type +/// that cannot be converted to a CIR type. +bool CIRGenTypes::isFuncTypeConvertible(const FunctionType *ft) { + if (!isFuncParamTypeConvertible(ft->getReturnType())) + return false; + + if (const auto *fpt = dyn_cast(ft)) + for (unsigned i = 0, e = fpt->getNumParams(); i != e; i++) + if (!isFuncParamTypeConvertible(fpt->getParamType(i))) + return false; + + return true; +} + +mlir::Type CIRGenTypes::ConvertFunctionTypeInternal(QualType qft) { + assert(qft.isCanonical()); + const FunctionType *ft = cast(qft.getTypePtr()); + // First, check whether we can build the full fucntion type. If the function + // type depends on an incomplete type (e.g. a struct or enum), we cannot lower + // the function type. + if (!isFuncTypeConvertible(ft)) { + cgm.errorNYI(SourceLocation(), "function type involving an incomplete type", + qft); + return cir::FuncType::get(SmallVector{}, cgm.VoidTy); + } + + // TODO(CIR): This is a stub of what the final code will be. See the + // implementation of this function and the implementation of class + // CIRGenFunction in the ClangIR incubator project. + + if (const auto *fpt = dyn_cast(ft)) { + SmallVector mlirParamTypes; + for (unsigned i = 0; i < fpt->getNumParams(); ++i) { + mlirParamTypes.push_back(convertType(fpt->getParamType(i))); + } + return cir::FuncType::get( + mlirParamTypes, convertType(fpt->getReturnType().getUnqualifiedType()), + fpt->isVariadic()); + } + cgm.errorNYI(SourceLocation(), "non-prototype function type", qft); + return cir::FuncType::get(SmallVector{}, cgm.VoidTy); +} + mlir::Type CIRGenTypes::convertType(QualType type) { type = astContext.getCanonicalType(type); const Type *ty = type.getTypePtr(); @@ -34,6 +101,12 @@ mlir::Type CIRGenTypes::convertType(QualType type) { switch (ty->getTypeClass()) { case Type::Builtin: { switch (cast(ty)->getKind()) { + + // void + case BuiltinType::Void: + resultType = cgm.VoidTy; + break; + // Signed integral types. case BuiltinType::Char_S: case BuiltinType::Int: @@ -63,6 +136,47 @@ mlir::Type CIRGenTypes::convertType(QualType type) { cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty), /*isSigned=*/false); break; + + // Floating-point types + case BuiltinType::Float16: + resultType = cgm.FP16Ty; + break; + case BuiltinType::Half: + if (astContext.getLangOpts().NativeHalfType || + !astContext.getTargetInfo().useFP16ConversionIntrinsics()) { + resultType = cgm.FP16Ty; + } else { + cgm.errorNYI(SourceLocation(), "processing of built-in type", type); + resultType = cgm.SInt32Ty; + } + break; + case BuiltinType::BFloat16: + resultType = cgm.BFloat16Ty; + break; + case BuiltinType::Float: + assert(&astContext.getFloatTypeSemantics(type) == + &llvm::APFloat::IEEEsingle() && + "ClangIR NYI: 'float' in a format other than IEEE 32-bit"); + resultType = cgm.FloatTy; + break; + case BuiltinType::Double: + assert(&astContext.getFloatTypeSemantics(type) == + &llvm::APFloat::IEEEdouble() && + "ClangIR NYI: 'double' in a format other than IEEE 64-bit"); + resultType = cgm.DoubleTy; + break; + case BuiltinType::LongDouble: + resultType = + builder.getLongDoubleTy(astContext.getFloatTypeSemantics(type)); + break; + case BuiltinType::Float128: + resultType = cgm.FP128Ty; + break; + case BuiltinType::Ibm128: + cgm.errorNYI(SourceLocation(), "processing of built-in type", type); + resultType = cgm.SInt32Ty; + break; + default: cgm.errorNYI(SourceLocation(), "processing of built-in type", type); resultType = cgm.SInt32Ty; @@ -70,6 +184,23 @@ mlir::Type CIRGenTypes::convertType(QualType type) { } break; } + + case Type::Pointer: { + const PointerType *ptrTy = cast(ty); + QualType elemTy = ptrTy->getPointeeType(); + assert(!elemTy->isConstantMatrixType() && "not implemented"); + + mlir::Type pointeeType = convertType(elemTy); + + resultType = builder.getPointerTo(pointeeType); + break; + } + + case Type::FunctionNoProto: + case Type::FunctionProto: + resultType = ConvertFunctionTypeInternal(type); + break; + case Type::BitInt: { const auto *bitIntTy = cast(type); if (bitIntTy->getNumBits() > cir::IntType::maxBitwidth()) { @@ -81,6 +212,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) { } break; } + default: cgm.errorNYI(SourceLocation(), "processing of type", type); resultType = cgm.SInt32Ty; diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index 563d7759831fa..71427e1200027 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -19,6 +19,7 @@ namespace clang { class ASTContext; +class FunctionType; class QualType; class Type; } // namespace clang @@ -39,10 +40,18 @@ class CIRGenTypes { clang::ASTContext &astContext; CIRGenBuilderTy &builder; + /// Heper for ConvertType. + mlir::Type ConvertFunctionTypeInternal(clang::QualType ft); + public: CIRGenTypes(CIRGenModule &cgm); ~CIRGenTypes(); + /// Utility to check whether a function type can be converted to a CIR type + /// (i.e. doesn't depend on an incomplete tag type). + bool isFuncTypeConvertible(const clang::FunctionType *ft); + bool isFuncParamTypeConvertible(clang::QualType type); + /// 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; diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 9ada31c11de95..782b814d75daa 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -21,4 +21,5 @@ add_clang_library(clangCIR clangLex ${dialect_libs} MLIRCIR + MLIRCIRInterfaces ) diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index de38337057d3d..48be11ba4e243 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -16,6 +16,16 @@ #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "llvm/ADT/TypeSwitch.h" +//===----------------------------------------------------------------------===// +// CIR Custom Parser/Printer Signatures +//===----------------------------------------------------------------------===// + +static mlir::ParseResult +parseFuncTypeArgs(mlir::AsmParser &p, llvm::SmallVector ¶ms, + bool &isVarArg); +static void printFuncTypeArgs(mlir::AsmPrinter &p, + mlir::ArrayRef params, bool isVarArg); + //===----------------------------------------------------------------------===// // Get autogenerated stuff //===----------------------------------------------------------------------===// @@ -133,6 +143,276 @@ IntType::verify(llvm::function_ref emitError, return mlir::success(); } +//===----------------------------------------------------------------------===// +// Floating-point type definitions +//===----------------------------------------------------------------------===// + +const llvm::fltSemantics &SingleType::getFloatSemantics() const { + return llvm::APFloat::IEEEsingle(); +} + +llvm::TypeSize +SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t +SingleType::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +SingleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +const llvm::fltSemantics &DoubleType::getFloatSemantics() const { + return llvm::APFloat::IEEEdouble(); +} + +llvm::TypeSize +DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t +DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +DoubleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +const llvm::fltSemantics &FP16Type::getFloatSemantics() const { + return llvm::APFloat::IEEEhalf(); +} + +llvm::TypeSize +FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +FP16Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +const llvm::fltSemantics &BF16Type::getFloatSemantics() const { + return llvm::APFloat::BFloat(); +} + +llvm::TypeSize +BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +BF16Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +const llvm::fltSemantics &FP80Type::getFloatSemantics() const { + return llvm::APFloat::x87DoubleExtended(); +} + +llvm::TypeSize +FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + // Though only 80 bits are used for the value, the type is 128 bits in size. + return llvm::TypeSize::getFixed(128); +} + +uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return 16; +} + +uint64_t +FP80Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return 16; +} + +const llvm::fltSemantics &FP128Type::getFloatSemantics() const { + return llvm::APFloat::IEEEquad(); +} + +llvm::TypeSize +FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return 16; +} + +uint64_t +FP128Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return 16; +} + +const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const { + return mlir::cast(getUnderlying()) + .getFloatSemantics(); +} + +llvm::TypeSize +LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return mlir::cast(getUnderlying()) + .getTypeSizeInBits(dataLayout, params); +} + +uint64_t +LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return mlir::cast(getUnderlying()) + .getABIAlignment(dataLayout, params); +} + +uint64_t LongDoubleType::getPreferredAlignment( + const ::mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return mlir::cast(getUnderlying()) + .getPreferredAlignment(dataLayout, params); +} + +LogicalResult +LongDoubleType::verify(function_ref emitError, + mlir::Type underlying) { + if (!mlir::isa(underlying)) { + emitError() << "invalid underlying type for long double"; + return failure(); + } + + return success(); +} + +//===----------------------------------------------------------------------===// +// Floating-point type helpers +//===----------------------------------------------------------------------===// + +bool cir::isAnyFloatingPointType(mlir::Type t) { + return isa(t); +} + +//===----------------------------------------------------------------------===// +// FuncType Definitions +//===----------------------------------------------------------------------===// + +FuncType FuncType::clone(TypeRange inputs, TypeRange results) const { + assert(results.size() == 1 && "expected exactly one result type"); + return get(llvm::to_vector(inputs), results[0], isVarArg()); +} + +mlir::ParseResult parseFuncTypeArgs(mlir::AsmParser &p, + llvm::SmallVector ¶ms, + bool &isVarArg) { + isVarArg = false; + // `(` `)` + if (succeeded(p.parseOptionalRParen())) + return mlir::success(); + + // `(` `...` `)` + if (succeeded(p.parseOptionalEllipsis())) { + isVarArg = true; + return p.parseRParen(); + } + + // type (`,` type)* (`,` `...`)? + mlir::Type type; + if (p.parseType(type)) + return mlir::failure(); + params.push_back(type); + while (succeeded(p.parseOptionalComma())) { + if (succeeded(p.parseOptionalEllipsis())) { + isVarArg = true; + return p.parseRParen(); + } + if (p.parseType(type)) + return mlir::failure(); + params.push_back(type); + } + + return p.parseRParen(); +} + +void printFuncTypeArgs(mlir::AsmPrinter &p, mlir::ArrayRef params, + bool isVarArg) { + llvm::interleaveComma(params, p, + [&p](mlir::Type type) { p.printType(type); }); + if (isVarArg) { + if (!params.empty()) + p << ", "; + p << "..."; + } + p << ')'; +} + +llvm::ArrayRef FuncType::getReturnTypes() const { + return static_cast(getImpl())->returnType; +} + +bool FuncType::isVoid() const { return mlir::isa(getReturnType()); } + +//===----------------------------------------------------------------------===// +// PointerType Definitions +//===----------------------------------------------------------------------===// + +llvm::TypeSize +PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + // FIXME: improve this in face of address spaces + return llvm::TypeSize::getFixed(64); +} + +uint64_t +PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + // FIXME: improve this in face of address spaces + return 8; +} + +uint64_t PointerType::getPreferredAlignment( + const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + // FIXME: improve this in face of address spaces + return 8; +} + +mlir::LogicalResult +PointerType::verify(llvm::function_ref emitError, + mlir::Type pointee) { + // TODO(CIR): Verification of the address space goes here. + return mlir::success(); +} + //===----------------------------------------------------------------------===// // CIR Dialect //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt index 7ddc4ce501907..df60f69df6fc0 100644 --- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt @@ -11,5 +11,6 @@ add_clang_library(MLIRCIR MLIRDLTIDialect MLIRDataLayoutInterfaces MLIRFuncDialect + MLIRCIRInterfaces clangAST ) diff --git a/clang/lib/CIR/Interfaces/CIRFPTypeInterface.cpp b/clang/lib/CIR/Interfaces/CIRFPTypeInterface.cpp new file mode 100644 index 0000000000000..41817e90b5232 --- /dev/null +++ b/clang/lib/CIR/Interfaces/CIRFPTypeInterface.cpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the interface to generically handle CIR floating-point types. +// +//===----------------------------------------------------------------------===// + +#include "clang/CIR/Interfaces/CIRFPTypeInterface.h" + +using namespace cir; + +/// Include the generated interfaces. +#include "clang/CIR/Interfaces/CIRFPTypeInterface.cpp.inc" diff --git a/clang/lib/CIR/Interfaces/CMakeLists.txt b/clang/lib/CIR/Interfaces/CMakeLists.txt new file mode 100644 index 0000000000000..fcd8b6963d06c --- /dev/null +++ b/clang/lib/CIR/Interfaces/CMakeLists.txt @@ -0,0 +1,14 @@ +add_clang_library(MLIRCIRInterfaces + CIRFPTypeInterface.cpp + + ADDITIONAL_HEADER_DIRS + ${MLIR_MAIN_INCLUDE_DIR}/mlir/Interfaces + + DEPENDS + MLIRCIRFPTypeInterfaceIncGen + + LINK_LIBS + ${dialect_libs} + MLIRIR + MLIRSupport + ) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index dd9bab1a161ce..98423cff814a6 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -94,6 +94,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" @@ -777,9 +778,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); @@ -1095,19 +1104,26 @@ void EmitAssemblyHelper::RunOptimizationPipeline( // of the pipeline. if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) PB.registerScalarOptimizerLateEPCallback( - [](FunctionPassManager &FPM, OptimizationLevel Level) { - FPM.addPass(BoundsCheckingPass()); + [this](FunctionPassManager &FPM, OptimizationLevel Level) { + BoundsCheckingPass::ReportingMode Mode; + bool Merge = CodeGenOpts.SanitizeMergeHandlers.has( + SanitizerKind::LocalBounds); + + if (CodeGenOpts.SanitizeTrap.has(SanitizerKind::LocalBounds)) { + Mode = BoundsCheckingPass::ReportingMode::Trap; + } else if (CodeGenOpts.SanitizeMinimalRuntime) { + Mode = CodeGenOpts.SanitizeRecover.has(SanitizerKind::LocalBounds) + ? BoundsCheckingPass::ReportingMode::MinRuntime + : BoundsCheckingPass::ReportingMode::MinRuntimeAbort; + } else { + Mode = CodeGenOpts.SanitizeRecover.has(SanitizerKind::LocalBounds) + ? BoundsCheckingPass::ReportingMode::FullRuntime + : BoundsCheckingPass::ReportingMode::FullRuntimeAbort; + } + BoundsCheckingPass::BoundsCheckingOptions Options(Mode, Merge); + FPM.addPass(BoundsCheckingPass(Options)); }); - if (LangOpts.Sanitize.has(SanitizerKind::Realtime)) { - PB.registerScalarOptimizerLateEPCallback( - [](FunctionPassManager &FPM, OptimizationLevel Level) { - RealtimeSanitizerOptions Opts; - FPM.addPass(RealtimeSanitizerPass(Opts)); - }); - MPM.addPass(ModuleRealtimeSanitizerPass()); - } - // Don't add sanitizers if we are here from ThinLTO PostLink. That already // done on PreLink stage. if (!IsThinLTOPostLink) { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index b7a0ff0db5491..2f264d7508c5d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -10881,7 +10881,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())); } @@ -19595,6 +19604,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/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 886ec5db1f6d7..61915b44d0711 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2031,28 +2031,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. @@ -3006,20 +2988,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 b8fd0a8d899d8..80fed80ad820e 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -481,6 +481,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 b17eabec060e0..52c40103e768c 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -53,11 +53,6 @@ using namespace clang; using namespace CodeGen; -// Experiment to make sanitizers easier to debug -static llvm::cl::opt ClSanitizeDebugDeoptimization( - "ubsan-unique-traps", llvm::cl::Optional, - llvm::cl::desc("Deoptimize traps for UBSAN so there is 1 trap per check.")); - // TODO: Introduce frontend options to enabled per sanitizers, similar to // `fsanitize-trap`. static llvm::cl::opt ClSanitizeGuardChecks( @@ -3555,7 +3550,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()) { @@ -3590,10 +3585,8 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF, llvm::AttributeList::FunctionIndex, B), /*Local=*/true); llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs); - bool NoMerge = - ClSanitizeDebugDeoptimization || - !CGF.CGM.getCodeGenOpts().OptimizationLevel || - (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr()); + NoMerge = NoMerge || !CGF.CGM.getCodeGenOpts().OptimizationLevel || + (CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr()); if (NoMerge) HandlerCall->addFnAttr(llvm::Attribute::NoMerge); if (!MayReturn) { @@ -3617,6 +3610,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=. @@ -3627,6 +3621,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) { @@ -3641,7 +3638,7 @@ void CodeGenFunction::EmitCheck( } if (TrapCond) - EmitTrapCheck(TrapCond, CheckHandler); + EmitTrapCheck(TrapCond, CheckHandler, NoMerge); if (!FatalCond && !RecoverableCond) return; @@ -3707,7 +3704,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. @@ -3717,10 +3714,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); @@ -3910,7 +3907,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 @@ -3920,9 +3918,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID]; - bool NoMerge = ClSanitizeDebugDeoptimization || - !CGM.getCodeGenOpts().OptimizationLevel || - (CurCodeDecl && CurCodeDecl->hasAttr()); + NoMerge = NoMerge || !CGM.getCodeGenOpts().OptimizationLevel || + (CurCodeDecl && CurCodeDecl->hasAttr()); if (TrapBB && !NoMerge) { auto Call = TrapBB->begin(); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index fb15b1993e74a..c354e58e15f4b 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -512,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 f9efb1bc99641..edb87f9d5efdf 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -92,6 +92,7 @@ class CGHLSLRuntime { 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) @@ -102,8 +103,9 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp) GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp) - GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, handle_fromBinding) - GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, bufferUpdateCounter) + GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, + resource_handlefrombinding) + GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter) GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync, group_memory_barrier_with_group_sync) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index c3264cd1bd8c5..feaa6f8d873d5 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)); @@ -9044,337 +9044,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..3974739d2abb4 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -458,6 +458,27 @@ 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; + case Stmt::OpenACCInitConstructClass: + EmitOpenACCInitConstruct(cast(*S)); + break; + case Stmt::OpenACCShutdownConstructClass: + EmitOpenACCShutdownConstruct(cast(*S)); + break; } } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index f597f484c1a64..ed0fb1fc7ae4d 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1041,6 +1041,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 f7235d52022e4..f472dfc8748dc 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4116,6 +4116,45 @@ 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. + } + + void EmitOpenACCInitConstruct(const OpenACCInitConstruct &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 EmitOpenACCShutdownConstruct(const OpenACCShutdownConstruct &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 //===--------------------------------------------------------------------===// @@ -5200,7 +5239,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 6b2f005ff2d6f..1d39150c75f1a 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -424,8 +424,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())); @@ -1273,6 +1273,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 = @@ -4732,7 +4735,7 @@ void CodeGenModule::emitMultiVersionFunctions() { getContext().forEachMultiversionedFunctionVersion( FD, [&](const FunctionDecl *CurFD) { llvm::SmallVector Feats; - bool IsDefined = CurFD->doesThisDeclarationHaveABody(); + bool IsDefined = CurFD->getDefinition() != nullptr; if (const auto *TA = CurFD->getAttr()) { assert(getTarget().getTriple().isX86() && "Unsupported target"); 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 6921d98ec924d..7868776608f2e 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 611367b2784ce..66a95c31693b5 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -3455,7 +3455,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..61fdf3399ff3c 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); @@ -88,6 +145,9 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, for (auto *Attr : D.specific_attrs()) NoSanitizeMask |= Attr->getMask(); + if (D.hasExternalStorage()) + NoSanitizeMask |= SanitizerKind::Type; + return NoSanitizeMask; }; diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index be33e26f04784..ad7f405cc7255 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -52,6 +52,7 @@ class AArch64ABIInfo : public ABIInfo { bool isIllegalVectorType(QualType Ty) const; + bool passAsAggregateType(QualType Ty) const; bool passAsPureScalableType(QualType Ty, unsigned &NV, unsigned &NP, SmallVectorImpl &CoerceToSeq) const; @@ -337,6 +338,10 @@ ABIArgInfo AArch64ABIInfo::coerceAndExpandPureScalableAggregate( NSRN += NVec; NPRN += NPred; + // Handle SVE vector tuples. + if (Ty->isSVESizelessBuiltinType()) + return ABIArgInfo::getDirect(); + llvm::Type *UnpaddedCoerceToType = UnpaddedCoerceToSeq.size() == 1 ? UnpaddedCoerceToSeq[0] @@ -362,7 +367,7 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn, if (isIllegalVectorType(Ty)) return coerceIllegalVector(Ty, NSRN, NPRN); - if (!isAggregateTypeForABI(Ty)) { + if (!passAsAggregateType(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); @@ -417,7 +422,7 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn, // elsewhere for GNU compatibility. uint64_t Size = getContext().getTypeSize(Ty); bool IsEmpty = isEmptyRecord(getContext(), Ty, true); - if (IsEmpty || Size == 0) { + if (!Ty->isSVESizelessBuiltinType() && (IsEmpty || Size == 0)) { if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS()) return ABIArgInfo::getIgnore(); @@ -504,7 +509,7 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128) return getNaturalAlignIndirect(RetTy); - if (!isAggregateTypeForABI(RetTy)) { + if (!passAsAggregateType(RetTy)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); @@ -519,7 +524,8 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, } uint64_t Size = getContext().getTypeSize(RetTy); - if (isEmptyRecord(getContext(), RetTy, true) || Size == 0) + if (!RetTy->isSVESizelessBuiltinType() && + (isEmptyRecord(getContext(), RetTy, true) || Size == 0)) return ABIArgInfo::getIgnore(); const Type *Base = nullptr; @@ -654,6 +660,15 @@ bool AArch64ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate() return true; } +bool AArch64ABIInfo::passAsAggregateType(QualType Ty) const { + if (Kind == AArch64ABIKind::AAPCS && Ty->isSVESizelessBuiltinType()) { + const auto *BT = Ty->getAs(); + return !BT->isSVECount() && + getContext().getBuiltinVectorTypeInfo(BT).NumVectors > 1; + } + return isAggregateTypeForABI(Ty); +} + // Check if a type needs to be passed in registers as a Pure Scalable Type (as // defined by AAPCS64). Return the number of data vectors and the number of // predicate vectors in the type, into `NVec` and `NPred`, respectively. Upon @@ -719,37 +734,38 @@ bool AArch64ABIInfo::passAsPureScalableType( return true; } - const auto *VT = Ty->getAs(); - if (!VT) - return false; + if (const auto *VT = Ty->getAs()) { + if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) { + ++NPred; + if (CoerceToSeq.size() + 1 > 12) + return false; + CoerceToSeq.push_back(convertFixedToScalableVectorType(VT)); + return true; + } - if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) { - ++NPred; - if (CoerceToSeq.size() + 1 > 12) - return false; - CoerceToSeq.push_back(convertFixedToScalableVectorType(VT)); - return true; - } + if (VT->getVectorKind() == VectorKind::SveFixedLengthData) { + ++NVec; + if (CoerceToSeq.size() + 1 > 12) + return false; + CoerceToSeq.push_back(convertFixedToScalableVectorType(VT)); + return true; + } - if (VT->getVectorKind() == VectorKind::SveFixedLengthData) { - ++NVec; - if (CoerceToSeq.size() + 1 > 12) - return false; - CoerceToSeq.push_back(convertFixedToScalableVectorType(VT)); - return true; + return false; } - if (!VT->isBuiltinType()) + if (!Ty->isBuiltinType()) return false; - switch (cast(VT)->getKind()) { + bool isPredicate; + switch (Ty->getAs()->getKind()) { #define SVE_VECTOR_TYPE(Name, MangledName, Id, SingletonId) \ case BuiltinType::Id: \ - ++NVec; \ + isPredicate = false; \ break; #define SVE_PREDICATE_TYPE(Name, MangledName, Id, SingletonId) \ case BuiltinType::Id: \ - ++NPred; \ + isPredicate = true; \ break; #define SVE_TYPE(Name, Id, SingletonId) #include "clang/Basic/AArch64SVEACLETypes.def" @@ -761,6 +777,10 @@ bool AArch64ABIInfo::passAsPureScalableType( getContext().getBuiltinVectorTypeInfo(cast(Ty)); assert(Info.NumVectors > 0 && Info.NumVectors <= 4 && "Expected 1, 2, 3 or 4 vectors!"); + if (isPredicate) + NPred += Info.NumVectors; + else + NVec += Info.NumVectors; auto VTy = llvm::ScalableVectorType::get(CGT.ConvertType(Info.ElementType), Info.EC.getKnownMinValue()); diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index c32cb7fb2811a..7f330f99e0b9a 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1632,6 +1632,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. @@ -1643,7 +1671,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 @@ -1654,15 +1682,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: @@ -1677,21 +1703,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; @@ -1703,8 +1729,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, 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 31882cfefea91..6194b61535ec1 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -27,9 +27,9 @@ using namespace llvm::opt; static const SanitizerMask NeedsUbsanRt = SanitizerKind::Undefined | SanitizerKind::Integer | - SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | - SanitizerKind::CFI | SanitizerKind::FloatDivideByZero | - SanitizerKind::ObjCCast; + SanitizerKind::LocalBounds | SanitizerKind::ImplicitConversion | + SanitizerKind::Nullability | SanitizerKind::CFI | + SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast; static const SanitizerMask NeedsUbsanCxxRt = SanitizerKind::Vptr | SanitizerKind::CFI; static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr; @@ -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,7 +68,9 @@ static const SanitizerMask TrappingSupported = SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::LocalBounds | SanitizerKind::CFI | SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast; -static const SanitizerMask TrappingDefault = SanitizerKind::CFI; +static const SanitizerMask MergeDefault = SanitizerKind::Undefined; +static const SanitizerMask TrappingDefault = + SanitizerKind::CFI | SanitizerKind::LocalBounds; static const SanitizerMask CFIClasses = SanitizerKind::CFIVCall | SanitizerKind::CFINVCall | SanitizerKind::CFIMFCall | SanitizerKind::CFIDerivedCast | @@ -182,6 +184,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 +250,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 +459,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 +573,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 +687,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. @@ -1080,10 +1107,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, options::OPT_fno_sanitize_link_runtime, LinkRuntimes); // Parse -link-cxx-sanitizer flag. - LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime, - options::OPT_fno_sanitize_link_cxx_runtime, - LinkCXXRuntimes) || - D.CCCIsCXX(); + LinkCXXRuntimes = D.CCCIsCXX(); + LinkCXXRuntimes = + Args.hasFlag(options::OPT_fsanitize_link_cxx_runtime, + options::OPT_fno_sanitize_link_cxx_runtime, LinkCXXRuntimes); NeedsMemProfRt = Args.hasFlag(options::OPT_fmemory_profile, options::OPT_fmemory_profile_EQ, @@ -1095,6 +1122,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) { @@ -1313,6 +1342,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, @@ -1480,13 +1513,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 df98170dc528a..028f66e867b47 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3898,7 +3898,8 @@ 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() && diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 8ee95d60c2c32..a60d0b9f36c99 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -502,6 +502,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( @@ -1416,7 +1449,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"); } @@ -1453,6 +1486,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"); @@ -1525,13 +1560,13 @@ 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"); } else { StaticRuntimes.push_back("ubsan_standalone"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("ubsan_standalone_cxx"); } } if (SanArgs.needsSafeStackRt()) { @@ -1541,11 +1576,13 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt())) { if (SanArgs.needsCfiRt()) StaticRuntimes.push_back("cfi"); - if (SanArgs.needsCfiDiagRt()) { + if (SanArgs.needsCfiDiagRt()) StaticRuntimes.push_back("cfi_diag"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("ubsan_standalone_cxx"); - } + } + if (SanArgs.linkCXXRuntimes() && !SanArgs.requiresMinimalRuntime() && + ((!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) || + SanArgs.needsCfiDiagRt())) { + StaticRuntimes.push_back("ubsan_standalone_cxx"); } if (SanArgs.needsStatsRt()) { NonWholeStaticRuntimes.push_back("stats"); 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 c98fdbd157bac..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)) { diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index 3d744bc087f46..88a27e3192827 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -213,11 +213,19 @@ 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; } - if (Triple.isRISCV64()) { + if (Triple.isLoongArch64() || Triple.isRISCV64()) { CmdArgs.push_back("-X"); if (Args.hasArg(options::OPT_mno_relax)) CmdArgs.push_back("--no-relax"); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index a4bd9c802a744..176b70dbabe91 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -855,6 +855,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 4e71bd7fe1e25..ff835f623d860 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -126,6 +126,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()) { if (Args.hasArg(options::OPT_fsycl) && !Args.hasArg(options::OPT_nolibsycl)) diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index c2eeb8f513066..fd4c2f9bf68cd 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -361,9 +361,10 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (StringRef Jobs = getLTOParallelism(Args, D); !Jobs.empty()) AddLTOFlag(Twine("jobs=") + Jobs); + Args.AddAllArgs(CmdArgs, options::OPT_L); TC.AddFilePathLibArgs(Args, CmdArgs); - Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_s, options::OPT_t}); + Args.addAllArgs(CmdArgs, + {options::OPT_T_Group, options::OPT_s, options::OPT_t}); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); diff --git a/clang/lib/Driver/ToolChains/UEFI.cpp b/clang/lib/Driver/ToolChains/UEFI.cpp index 66cbbec59246c..a9d7e7892c5a6 100644 --- a/clang/lib/Driver/ToolChains/UEFI.cpp +++ b/clang/lib/Driver/ToolChains/UEFI.cpp @@ -35,6 +35,24 @@ UEFI::UEFI(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Tool *UEFI::buildLinker() const { return new tools::uefi::Linker(*this); } +void UEFI::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(getDriver().ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + if (std::optional Path = getStdlibIncludePath()) + addSystemInclude(DriverArgs, CC1Args, *Path); +} + void tools::uefi::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, diff --git a/clang/lib/Driver/ToolChains/UEFI.h b/clang/lib/Driver/ToolChains/UEFI.h index a126ac32db6c6..7e038b5cb8b18 100644 --- a/clang/lib/Driver/ToolChains/UEFI.h +++ b/clang/lib/Driver/ToolChains/UEFI.h @@ -51,6 +51,10 @@ class LLVM_LIBRARY_VISIBILITY UEFI : public ToolChain { return false; } bool isPICDefaultForced() const override { return true; } + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; }; } // namespace toolchains 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/MacroExpander.cpp b/clang/lib/Format/MacroExpander.cpp index fd2a16894d643..ba2992889e674 100644 --- a/clang/lib/Format/MacroExpander.cpp +++ b/clang/lib/Format/MacroExpander.cpp @@ -233,6 +233,10 @@ MacroExpander::expand(FormatToken *ID, if (Result.size() > 1) { ++Result[0]->MacroCtx->StartOfExpansion; ++Result[Result.size() - 2]->MacroCtx->EndOfExpansion; + } else { + // If the macro expansion is empty, mark the start and end. + Result[0]->MacroCtx->StartOfExpansion = 1; + Result[0]->MacroCtx->EndOfExpansion = 1; } return Result; } diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp index 593f8efff25aa..530b2dd538cee 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -348,7 +348,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( } } - if (Next->is(tok::kw_auto)) + if (Next && Next->is(tok::kw_auto)) TypeToken = Next; // Place the Qualifier at the end of the list of qualifiers. diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 05c86db55641f..f2cfa7f49f62f 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 && 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); diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index de7e261b21d30..654148a161bd7 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -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 f1c0fcc767bcf..3580d39f996f9 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)); \ } @@ -1776,6 +1799,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); @@ -2262,6 +2289,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); @@ -4416,6 +4446,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 8ada1f1d98229..bbb572df3aad1 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -780,6 +780,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_2_512convertintrin.h b/clang/lib/Headers/avx10_2_512convertintrin.h index a34e135fa3047..60a5b1ef4548d 100644 --- a/clang/lib/Headers/avx10_2_512convertintrin.h +++ b/clang/lib/Headers/avx10_2_512convertintrin.h @@ -308,13 +308,13 @@ static __inline __m512h __DEFAULT_FN_ATTRS512 _mm512_cvtpbf8_ph(__m256i __A) { } static __inline __m512h __DEFAULT_FN_ATTRS512 -_mm512_mask_cvtpbf8_ph(__m512h __S, __mmask16 __U, __m256i __A) { +_mm512_mask_cvtpbf8_ph(__m512h __S, __mmask32 __U, __m256i __A) { return _mm512_castsi512_ph( _mm512_mask_slli_epi16((__m512i)__S, __U, _mm512_cvtepi8_epi16(__A), 8)); } static __inline __m512h __DEFAULT_FN_ATTRS512 -_mm512_maskz_cvtpbf8_ph(__mmask16 __U, __m256i __A) { +_mm512_maskz_cvtpbf8_ph(__mmask32 __U, __m256i __A) { return _mm512_castsi512_ph( _mm512_slli_epi16(_mm512_maskz_cvtepi8_epi16(__U, __A), 8)); } diff --git a/clang/lib/Headers/avx10_2convertintrin.h b/clang/lib/Headers/avx10_2convertintrin.h index 134adb2850c8d..efe8477cbbf9b 100644 --- a/clang/lib/Headers/avx10_2convertintrin.h +++ b/clang/lib/Headers/avx10_2convertintrin.h @@ -580,13 +580,13 @@ static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_cvtpbf8_ph(__m128i __A) { } static __inline__ __m256h __DEFAULT_FN_ATTRS256 -_mm256_mask_cvtpbf8_ph(__m256h __S, __mmask8 __U, __m128i __A) { +_mm256_mask_cvtpbf8_ph(__m256h __S, __mmask16 __U, __m128i __A) { return _mm256_castsi256_ph( _mm256_mask_slli_epi16((__m256i)__S, __U, _mm256_cvtepi8_epi16(__A), 8)); } static __inline__ __m256h __DEFAULT_FN_ATTRS256 -_mm256_maskz_cvtpbf8_ph(__mmask8 __U, __m128i __A) { +_mm256_maskz_cvtpbf8_ph(__mmask16 __U, __m128i __A) { return _mm256_castsi256_ph( _mm256_slli_epi16(_mm256_maskz_cvtepi8_epi16(__U, __A), 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/Headers/hvx_hexagon_protos.h b/clang/lib/Headers/hvx_hexagon_protos.h index 7e3679a38b2cf..fd120a589f64f 100644 --- a/clang/lib/Headers/hvx_hexagon_protos.h +++ b/clang/lib/Headers/hvx_hexagon_protos.h @@ -5178,6 +5178,433 @@ #define Q6_Vuh_vmpy_VuhVuh_rs16(Vu,Vv) __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmpyuhvs)(Vu,Vv) #endif /* __HEXAGON_ARCH___ >= 69 */ +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vdd32.sf=vadd(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_VectorPair Q6_Wsf_vadd_VbfVbf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Wsf_vadd_VbfVbf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vadd_sf_bf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vd32.h=Vu32.hf + C Intrinsic Prototype: HVX_Vector Q6_Vh_equals_Vhf(HVX_Vector Vu) + Instruction Type: CVI_VS + Execution Slots: SLOT0123 + ========================================================================== */ + +#define Q6_Vh_equals_Vhf(Vu) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vconv_h_hf)(Vu) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vd32.hf=Vu32.h + C Intrinsic Prototype: HVX_Vector Q6_Vhf_equals_Vh(HVX_Vector Vu) + Instruction Type: CVI_VS + Execution Slots: SLOT0123 + ========================================================================== */ + +#define Q6_Vhf_equals_Vh(Vu) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vconv_hf_h)(Vu) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vd32.sf=Vu32.w + C Intrinsic Prototype: HVX_Vector Q6_Vsf_equals_Vw(HVX_Vector Vu) + Instruction Type: CVI_VS + Execution Slots: SLOT0123 + ========================================================================== */ + +#define Q6_Vsf_equals_Vw(Vu) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vconv_sf_w)(Vu) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vd32.w=Vu32.sf + C Intrinsic Prototype: HVX_Vector Q6_Vw_equals_Vsf(HVX_Vector Vu) + Instruction Type: CVI_VS + Execution Slots: SLOT0123 + ========================================================================== */ + +#define Q6_Vw_equals_Vsf(Vu) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vconv_w_sf)(Vu) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vd32.bf=vcvt(Vu32.sf,Vv32.sf) + C Intrinsic Prototype: HVX_Vector Q6_Vbf_vcvt_VsfVsf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Vbf_vcvt_VsfVsf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vcvt_bf_sf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Qd4=vcmp.gt(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_VectorPred Q6_Q_vcmp_gt_VbfVbf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VA Execution Slots: SLOT0123 + ========================================================================== */ + +#define Q6_Q_vcmp_gt_VbfVbf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vandqrt) \ + ((__BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vgtbf)(Vu, Vv)), -1) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Qx4&=vcmp.gt(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_VectorPred Q6_Q_vcmp_gtand_QVbfVbf(HVX_VectorPred + Qx, HVX_Vector Vu, HVX_Vector Vv) Instruction Type: CVI_VA Execution + Slots: SLOT0123 + ========================================================================== */ + +#define Q6_Q_vcmp_gtand_QVbfVbf(Qx, Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vandqrt) \ + ((__BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vgtbf_and)( \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vandvrt)((Qx), -1), Vu, \ + Vv)), \ + -1) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Qx4|=vcmp.gt(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_VectorPred Q6_Q_vcmp_gtor_QVbfVbf(HVX_VectorPred + Qx, HVX_Vector Vu, HVX_Vector Vv) Instruction Type: CVI_VA Execution + Slots: SLOT0123 + ========================================================================== */ + +#define Q6_Q_vcmp_gtor_QVbfVbf(Qx, Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vandqrt) \ + ((__BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vgtbf_or)( \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vandvrt)((Qx), -1), Vu, \ + Vv)), \ + -1) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Qx4^=vcmp.gt(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_VectorPred Q6_Q_vcmp_gtxacc_QVbfVbf(HVX_VectorPred + Qx, HVX_Vector Vu, HVX_Vector Vv) Instruction Type: CVI_VA Execution + Slots: SLOT0123 + ========================================================================== */ + +#define Q6_Q_vcmp_gtxacc_QVbfVbf(Qx, Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vandqrt) \ + ((__BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vgtbf_xor)( \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vandvrt)((Qx), -1), Vu, \ + Vv)), \ + -1) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vd32.bf=vmax(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_Vector Q6_Vbf_vmax_VbfVbf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX_LATE Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Vbf_vmax_VbfVbf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmax_bf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vd32.bf=vmin(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_Vector Q6_Vbf_vmin_VbfVbf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX_LATE Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Vbf_vmin_VbfVbf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmin_bf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vdd32.sf=vmpy(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_VectorPair Q6_Wsf_vmpy_VbfVbf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Wsf_vmpy_VbfVbf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmpy_sf_bf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vxx32.sf+=vmpy(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_VectorPair Q6_Wsf_vmpyacc_WsfVbfVbf(HVX_VectorPair + Vxx, HVX_Vector Vu, HVX_Vector Vv) Instruction Type: CVI_VX_DV Execution + Slots: SLOT23 + ========================================================================== */ + +#define Q6_Wsf_vmpyacc_WsfVbfVbf(Vxx, Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmpy_sf_bf_acc)(Vxx, Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 73 +/* ========================================================================== + Assembly Syntax: Vdd32.sf=vsub(Vu32.bf,Vv32.bf) + C Intrinsic Prototype: HVX_VectorPair Q6_Wsf_vsub_VbfVbf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Wsf_vsub_VbfVbf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vsub_sf_bf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 73 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32=vgetqfext(Vu32.x,Rt32) + C Intrinsic Prototype: HVX_Vector Q6_V_vgetqfext_VR(HVX_Vector Vu, Word32 Rt) + Instruction Type: CVI_VX + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_V_vgetqfext_VR(Vu, Rt) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_get_qfext)(Vu, Rt) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vx32|=vgetqfext(Vu32.x,Rt32) + C Intrinsic Prototype: HVX_Vector Q6_V_vgetqfextor_VVR(HVX_Vector Vx, + HVX_Vector Vu, Word32 Rt) Instruction Type: CVI_VX Execution Slots: + SLOT23 + ========================================================================== */ + +#define Q6_V_vgetqfextor_VVR(Vx, Vu, Rt) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_get_qfext_oracc)(Vx, Vu, Rt) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.x=vsetqfext(Vu32,Rt32) + C Intrinsic Prototype: HVX_Vector Q6_V_vsetqfext_VR(HVX_Vector Vu, Word32 Rt) + Instruction Type: CVI_VX + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_V_vsetqfext_VR(Vu, Rt) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_set_qfext)(Vu, Rt) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.f8=vabs(Vu32.f8) + C Intrinsic Prototype: HVX_Vector Q6_V_vabs_V(HVX_Vector Vu) + Instruction Type: CVI_VX_LATE + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_V_vabs_V(Vu) __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vabs_f8)(Vu) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vdd32.hf=vadd(Vu32.f8,Vv32.f8) + C Intrinsic Prototype: HVX_VectorPair Q6_Whf_vadd_VV(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Whf_vadd_VV(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vadd_hf_f8)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.b=vcvt2(Vu32.hf,Vv32.hf) + C Intrinsic Prototype: HVX_Vector Q6_Vb_vcvt2_VhfVhf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Vb_vcvt2_VhfVhf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vcvt2_b_hf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vdd32.hf=vcvt2(Vu32.b) + C Intrinsic Prototype: HVX_VectorPair Q6_Whf_vcvt2_Vb(HVX_Vector Vu) + Instruction Type: CVI_VX_DV + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Whf_vcvt2_Vb(Vu) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vcvt2_hf_b)(Vu) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vdd32.hf=vcvt2(Vu32.ub) + C Intrinsic Prototype: HVX_VectorPair Q6_Whf_vcvt2_Vub(HVX_Vector Vu) + Instruction Type: CVI_VX_DV + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Whf_vcvt2_Vub(Vu) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vcvt2_hf_ub)(Vu) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.ub=vcvt2(Vu32.hf,Vv32.hf) + C Intrinsic Prototype: HVX_Vector Q6_Vub_vcvt2_VhfVhf(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Vub_vcvt2_VhfVhf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vcvt2_ub_hf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.f8=vcvt(Vu32.hf,Vv32.hf) + C Intrinsic Prototype: HVX_Vector Q6_V_vcvt_VhfVhf(HVX_Vector Vu, HVX_Vector + Vv) Instruction Type: CVI_VX Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_V_vcvt_VhfVhf(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vcvt_f8_hf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vdd32.hf=vcvt(Vu32.f8) + C Intrinsic Prototype: HVX_VectorPair Q6_Whf_vcvt_V(HVX_Vector Vu) + Instruction Type: CVI_VX_DV + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Whf_vcvt_V(Vu) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vcvt_hf_f8)(Vu) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.f8=vfmax(Vu32.f8,Vv32.f8) + C Intrinsic Prototype: HVX_Vector Q6_V_vfmax_VV(HVX_Vector Vu, HVX_Vector Vv) + Instruction Type: CVI_VX_LATE + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_V_vfmax_VV(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vfmax_f8)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.f8=vfmin(Vu32.f8,Vv32.f8) + C Intrinsic Prototype: HVX_Vector Q6_V_vfmin_VV(HVX_Vector Vu, HVX_Vector Vv) + Instruction Type: CVI_VX_LATE + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_V_vfmin_VV(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vfmin_f8)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.f8=vfneg(Vu32.f8) + C Intrinsic Prototype: HVX_Vector Q6_V_vfneg_V(HVX_Vector Vu) + Instruction Type: CVI_VX_LATE + Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_V_vfneg_V(Vu) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vfneg_f8)(Vu) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32=vmerge(Vu32.x,Vv32.w) + C Intrinsic Prototype: HVX_Vector Q6_V_vmerge_VVw(HVX_Vector Vu, HVX_Vector + Vv) Instruction Type: CVI_VS Execution Slots: SLOT0123 + ========================================================================== */ + +#define Q6_V_vmerge_VVw(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmerge_qf)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vdd32.hf=vmpy(Vu32.f8,Vv32.f8) + C Intrinsic Prototype: HVX_VectorPair Q6_Whf_vmpy_VV(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Whf_vmpy_VV(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmpy_hf_f8)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vxx32.hf+=vmpy(Vu32.f8,Vv32.f8) + C Intrinsic Prototype: HVX_VectorPair Q6_Whf_vmpyacc_WhfVV(HVX_VectorPair + Vxx, HVX_Vector Vu, HVX_Vector Vv) Instruction Type: CVI_VX_DV Execution + Slots: SLOT23 + ========================================================================== */ + +#define Q6_Whf_vmpyacc_WhfVV(Vxx, Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmpy_hf_f8_acc)(Vxx, Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.qf16=vmpy(Vu32.hf,Rt32.hf) + C Intrinsic Prototype: HVX_Vector Q6_Vqf16_vmpy_VhfRhf(HVX_Vector Vu, Word32 + Rt) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Vqf16_vmpy_VhfRhf(Vu, Rt) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmpy_rt_hf)(Vu, Rt) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.qf16=vmpy(Vu32.qf16,Rt32.hf) + C Intrinsic Prototype: HVX_Vector Q6_Vqf16_vmpy_Vqf16Rhf(HVX_Vector Vu, + Word32 Rt) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Vqf16_vmpy_Vqf16Rhf(Vu, Rt) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmpy_rt_qf16)(Vu, Rt) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vd32.qf32=vmpy(Vu32.sf,Rt32.sf) + C Intrinsic Prototype: HVX_Vector Q6_Vqf32_vmpy_VsfRsf(HVX_Vector Vu, Word32 + Rt) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Vqf32_vmpy_VsfRsf(Vu, Rt) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vmpy_rt_sf)(Vu, Rt) +#endif /* __HEXAGON_ARCH___ >= 79 */ + +#if __HVX_ARCH__ >= 79 +/* ========================================================================== + Assembly Syntax: Vdd32.hf=vsub(Vu32.f8,Vv32.f8) + C Intrinsic Prototype: HVX_VectorPair Q6_Whf_vsub_VV(HVX_Vector Vu, + HVX_Vector Vv) Instruction Type: CVI_VX_DV Execution Slots: SLOT23 + ========================================================================== */ + +#define Q6_Whf_vsub_VV(Vu, Vv) \ + __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_vsub_hf_f8)(Vu, Vv) +#endif /* __HEXAGON_ARCH___ >= 79 */ + #endif /* __HVX__ */ #endif 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/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 6cd60a9bcf4f3..fa4c1439c9261 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -719,9 +719,7 @@ llvm::Error Interpreter::LoadDynamicLibrary(const char *name) { if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load( name, DL.getGlobalPrefix())) - // FIXME: Eventually we should put each library in its own JITDylib and - // turn off process symbols by default. - EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG)); + EE->getMainJITDylib().addGenerator(std::move(*DLSG)); else return DLSG.takeError(); diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp index ea02f5dfb6264..67c9d92b849ea 100644 --- a/clang/lib/Lex/InitHeaderSearch.cpp +++ b/clang/lib/Lex/InitHeaderSearch.cpp @@ -301,6 +301,7 @@ bool InitHeaderSearch::ShouldAddDefaultIncludePaths( case llvm::Triple::PS5: case llvm::Triple::RTEMS: case llvm::Triple::Solaris: + case llvm::Triple::UEFI: case llvm::Triple::WASI: case llvm::Triple::ZOS: return false; 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/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index b64c72904b19a..ede409096548c 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,11 @@ void SkipUntilEndOfDirective(Parser &P) { bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) { switch (DirKind) { default: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Wait: + case OpenACCDirectiveKind::Init: + case OpenACCDirectiveKind::Shutdown: return false; case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: @@ -575,6 +584,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 +603,14 @@ 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: + case OpenACCDirectiveKind::Init: + case OpenACCDirectiveKind::Shutdown: + return 0; case OpenACCDirectiveKind::Invalid: llvm_unreachable("Shouldn't be creating a scope for an invalid construct"); default: @@ -985,17 +1004,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; @@ -1066,6 +1085,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( // TODO OpenACC: as we implement the 'rest' of the above, this 'if' should // be removed leaving just the 'setIntExprDetails'. if (ClauseKind == OpenACCClauseKind::NumWorkers || + ClauseKind == OpenACCClauseKind::DeviceNum || ClauseKind == OpenACCClauseKind::VectorLength) ParsedClause.setIntExprDetails(IntExpr.get()); @@ -1275,7 +1295,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 +1430,7 @@ Parser::ParseOpenACCDirective() { SourceLocation StartLoc = ConsumeAnnotationToken(); SourceLocation DirLoc = getCurToken().getLocation(); OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); + Parser::OpenACCWaitParseInfo WaitInfo; getActions().OpenACC().ActOnConstruct(DirKind, DirLoc); @@ -1449,7 +1471,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 +1486,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 +1528,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 +1545,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/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 36e56a92c3092..8ba6a5dce8a99 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2222,8 +2222,15 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec( } } - if (SS.isEmpty()) + if (SS.isEmpty()) { + if (getLangOpts().ObjC && !getLangOpts().CPlusPlus && + Tok.is(tok::coloncolon)) { + // ObjectiveC does not allow :: as as a scope token. + Diag(ConsumeToken(), diag::err_expected_type); + return true; + } return false; + } // A C++ scope specifier that isn't followed by a typename. AnnotateScopeToken(SS, IsNewScope); diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 37d966a5a0463..589869d018657 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1843,6 +1843,14 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { : getNotes(); } + OptionalNotes makeManagedMismatchNoteForParam(SourceLocation DeclLoc) { + return DeclLoc.isValid() + ? getNotes(PartialDiagnosticAt( + DeclLoc, + S.PDiag(diag::note_managed_mismatch_here_for_param))) + : getNotes(); + } + public: ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL) : S(S), FunLocation(FL), FunEndLocation(FEL), @@ -1863,6 +1871,38 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { } } + void handleUnmatchedUnderlyingMutexes(SourceLocation Loc, SourceLocation DLoc, + Name scopeName, StringRef Kind, + Name expected, Name actual) override { + PartialDiagnosticAt Warning(Loc, + S.PDiag(diag::warn_unmatched_underlying_mutexes) + << Kind << scopeName << expected << actual); + Warnings.emplace_back(std::move(Warning), + makeManagedMismatchNoteForParam(DLoc)); + } + + void handleExpectMoreUnderlyingMutexes(SourceLocation Loc, + SourceLocation DLoc, Name scopeName, + StringRef Kind, + Name expected) override { + PartialDiagnosticAt Warning( + Loc, S.PDiag(diag::warn_expect_more_underlying_mutexes) + << Kind << scopeName << expected); + Warnings.emplace_back(std::move(Warning), + makeManagedMismatchNoteForParam(DLoc)); + } + + void handleExpectFewerUnderlyingMutexes(SourceLocation Loc, + SourceLocation DLoc, Name scopeName, + StringRef Kind, + Name actual) override { + PartialDiagnosticAt Warning( + Loc, S.PDiag(diag::warn_expect_fewer_underlying_mutexes) + << Kind << scopeName << actual); + Warnings.emplace_back(std::move(Warning), + makeManagedMismatchNoteForParam(DLoc)); + } + void handleInvalidLockExp(SourceLocation Loc) override { PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock) << Loc); diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 868081292bc32..7109de03cadd1 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; } @@ -580,6 +582,15 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call, // Temp().ptr; // Here ptr might not dangle. if (isa(Arg->IgnoreImpCasts())) return; + // Avoid false positives when the object is constructed from a conditional + // operator argument. A common case is: + // // 'ptr' might not be owned by the Owner object. + // std::string_view s = cond() ? Owner().ptr : sv; + if (const auto *Cond = + dyn_cast(Arg->IgnoreImpCasts()); + Cond && isPointerLikeType(Cond->getType())) + return; + auto ReturnType = Callee->getReturnType(); // Once we initialized a value with a non gsl-owner reference, it can no @@ -1089,14 +1100,13 @@ enum PathLifetimeKind { /// supposed to lifetime-extend along. static PathLifetimeKind shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) { - PathLifetimeKind Kind = PathLifetimeKind::Extend; for (auto Elem : Path) { if (Elem.Kind == IndirectLocalPathEntry::DefaultInit) return PathLifetimeKind::Extend; - else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit) + if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit) return PathLifetimeKind::NoExtend; } - return Kind; + return PathLifetimeKind::Extend; } /// Find the range for the first interesting entry in the path at or after I. @@ -1152,6 +1162,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 +1279,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 79fc2751b7381..d34d3ef2996ac 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() && @@ -546,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. @@ -847,6 +864,10 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, .addDefaultHandleConstructor(); } +// This function is responsible for constructing the constraint expression for +// this concept: +// template concept is_typed_resource_element_compatible = +// __is_typed_resource_element_compatible; static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc, TemplateTypeParmDecl *T) { ASTContext &Context = S.getASTContext(); @@ -868,8 +889,58 @@ static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc, return TypedResExpr; } -static ConceptDecl *constructTypedBufferConceptDecl(Sema &S, - NamespaceDecl *NSD) { +// This function is responsible for constructing the constraint expression for +// this concept: +// template concept is_structured_resource_element_compatible = +// !__is_intangible && sizeof(T) >= 1; +static Expr *constructStructuredBufferConstraintExpr(Sema &S, + SourceLocation NameLoc, + TemplateTypeParmDecl *T) { + ASTContext &Context = S.getASTContext(); + + // Obtain the QualType for 'bool' + QualType BoolTy = Context.BoolTy; + + // Create a QualType that points to this TemplateTypeParmDecl + QualType TType = Context.getTypeDeclType(T); + + // Create a TypeSourceInfo for the template type parameter 'T' + TypeSourceInfo *TTypeSourceInfo = + Context.getTrivialTypeSourceInfo(TType, NameLoc); + + TypeTraitExpr *IsIntangibleExpr = + TypeTraitExpr::Create(Context, BoolTy, NameLoc, UTT_IsIntangibleType, + {TTypeSourceInfo}, NameLoc, true); + + // negate IsIntangibleExpr + UnaryOperator *NotIntangibleExpr = UnaryOperator::Create( + Context, IsIntangibleExpr, UO_LNot, BoolTy, VK_LValue, OK_Ordinary, + NameLoc, false, FPOptionsOverride()); + + // element types also may not be of 0 size + UnaryExprOrTypeTraitExpr *SizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr( + UETT_SizeOf, TTypeSourceInfo, BoolTy, NameLoc, NameLoc); + + // Create a BinaryOperator that checks if the size of the type is not equal to + // 1 Empty structs have a size of 1 in HLSL, so we need to check for that + IntegerLiteral *rhs = IntegerLiteral::Create( + Context, llvm::APInt(Context.getTypeSize(Context.getSizeType()), 1, true), + Context.getSizeType(), NameLoc); + + BinaryOperator *SizeGEQOneExpr = + BinaryOperator::Create(Context, SizeOfExpr, rhs, BO_GE, BoolTy, VK_LValue, + OK_Ordinary, NameLoc, FPOptionsOverride()); + + // Combine the two constraints + BinaryOperator *CombinedExpr = BinaryOperator::Create( + Context, NotIntangibleExpr, SizeGEQOneExpr, BO_LAnd, BoolTy, VK_LValue, + OK_Ordinary, NameLoc, FPOptionsOverride()); + + return CombinedExpr; +} + +static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD, + bool isTypedBuffer) { ASTContext &Context = S.getASTContext(); DeclContext *DC = NSD->getDeclContext(); SourceLocation DeclLoc = SourceLocation(); @@ -890,9 +961,18 @@ static ConceptDecl *constructTypedBufferConceptDecl(Sema &S, TemplateParameterList *ConceptParams = TemplateParameterList::Create( Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr); - DeclarationName DeclName = DeclarationName( - &Context.Idents.get("__is_typed_resource_element_compatible")); - Expr *ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T); + DeclarationName DeclName; + Expr *ConstraintExpr = nullptr; + + if (isTypedBuffer) { + DeclName = DeclarationName( + &Context.Idents.get("__is_typed_resource_element_compatible")); + ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T); + } else { + DeclName = DeclarationName( + &Context.Idents.get("__is_structured_resource_element_compatible")); + ConstraintExpr = constructStructuredBufferConstraintExpr(S, DeclLoc, T); + } // Create a ConceptDecl ConceptDecl *CD = @@ -910,8 +990,10 @@ static ConceptDecl *constructTypedBufferConceptDecl(Sema &S, void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { CXXRecordDecl *Decl; - ConceptDecl *TypedBufferConcept = - constructTypedBufferConceptDecl(*SemaPtr, HLSLNamespace); + ConceptDecl *TypedBufferConcept = constructBufferConceptDecl( + *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ true); + ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl( + *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ false); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer") .addSimpleTemplateParams({"element_type"}, TypedBufferConcept) .finalizeForwardDeclaration(); @@ -921,38 +1003,42 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { ResourceKind::TypedBuffer, /*IsROV=*/false, /*RawBuffer=*/false) .addArraySubscriptOperators() + .addLoadMethods() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer") - .addSimpleTemplateParams({"element_type"}) + .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept) .finalizeForwardDeclaration(); onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::TypedBuffer, /*IsROV=*/true, /*RawBuffer=*/false) .addArraySubscriptOperators() + .addLoadMethods() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer") - .addSimpleTemplateParams({"element_type"}) + .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept) .finalizeForwardDeclaration(); onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, ResourceKind::RawBuffer, /*IsROV=*/false, /*RawBuffer=*/true) .addArraySubscriptOperators() + .addLoadMethods() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer") - .addSimpleTemplateParams({"element_type"}) + .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept) .finalizeForwardDeclaration(); onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer, /*IsROV=*/false, /*RawBuffer=*/true) .addArraySubscriptOperators() + .addLoadMethods() .addIncrementCounterMethod() .addDecrementCounterMethod() .completeDefinition(); @@ -960,7 +1046,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer") - .addSimpleTemplateParams({"element_type"}) + .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept) .finalizeForwardDeclaration(); onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer, @@ -971,7 +1057,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer") - .addSimpleTemplateParams({"element_type"}) + .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept) .finalizeForwardDeclaration(); onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer, @@ -982,12 +1068,13 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedStructuredBuffer") - .addSimpleTemplateParams({"element_type"}) + .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept) .finalizeForwardDeclaration(); onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer, /*IsROV=*/true, /*RawBuffer=*/true) .addArraySubscriptOperators() + .addLoadMethods() .addIncrementCounterMethod() .addDecrementCounterMethod() .completeDefinition(); 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/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8253771ffe341..de74db73b29e9 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5735,9 +5735,11 @@ bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) { { ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg); - if (checkBuiltinArgument(*this, TheCall, 0)) + if (!FirstArgResult.get()->getType()->isPointerType()) { + Diag(TheCall->getBeginLoc(), diag::err_builtin_assume_aligned_invalid_arg) + << TheCall->getSourceRange(); return true; - /// In-place updation of FirstArg by checkBuiltinArgument is ignored. + } TheCall->setArg(0, FirstArgResult.get()); } @@ -6997,27 +6999,33 @@ void CheckFormatHandler::HandleNonStandardConversionSpecifier( void CheckFormatHandler::HandlePosition(const char *startPos, unsigned posLen) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_positional_arg), - getLocationOfByte(startPos), - /*IsStringLocation*/true, - getSpecifierRange(startPos, posLen)); + if (!S.getDiagnostics().isIgnored( + diag::warn_format_non_standard_positional_arg, SourceLocation())) + EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_positional_arg), + getLocationOfByte(startPos), + /*IsStringLocation*/ true, + getSpecifierRange(startPos, posLen)); } void CheckFormatHandler::HandleInvalidPosition( const char *startSpecifier, unsigned specifierLen, analyze_format_string::PositionContext p) { - EmitFormatDiagnostic( - S.PDiag(diag::warn_format_invalid_positional_specifier) << (unsigned)p, - getLocationOfByte(startSpecifier), /*IsStringLocation*/ true, - getSpecifierRange(startSpecifier, specifierLen)); + if (!S.getDiagnostics().isIgnored( + diag::warn_format_invalid_positional_specifier, SourceLocation())) + EmitFormatDiagnostic( + S.PDiag(diag::warn_format_invalid_positional_specifier) << (unsigned)p, + getLocationOfByte(startSpecifier), /*IsStringLocation*/ true, + getSpecifierRange(startSpecifier, specifierLen)); } void CheckFormatHandler::HandleZeroPosition(const char *startPos, unsigned posLen) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_zero_positional_specifier), - getLocationOfByte(startPos), - /*IsStringLocation*/true, - getSpecifierRange(startPos, posLen)); + if (!S.getDiagnostics().isIgnored(diag::warn_format_zero_positional_specifier, + SourceLocation())) + EmitFormatDiagnostic(S.PDiag(diag::warn_format_zero_positional_specifier), + getLocationOfByte(startPos), + /*IsStringLocation*/ true, + getSpecifierRange(startPos, posLen)); } void CheckFormatHandler::HandleNullChar(const char *nullCharacter) { @@ -8488,8 +8496,9 @@ static void CheckFormatString( } if (Type == Sema::FST_Printf || Type == Sema::FST_NSString || - Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSLog || - Type == Sema::FST_OSTrace || Type == Sema::FST_Syslog) { + Type == Sema::FST_Kprintf || Type == Sema::FST_FreeBSDKPrintf || + Type == Sema::FST_OSLog || Type == Sema::FST_OSTrace || + Type == Sema::FST_Syslog) { CheckPrintfHandler H( S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs, (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, APK, @@ -8498,7 +8507,7 @@ static void CheckFormatString( if (!analyze_format_string::ParsePrintfString( H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(), - Type == Sema::FST_FreeBSDKPrintf)) + Type == Sema::FST_Kprintf || Type == Sema::FST_FreeBSDKPrintf)) H.DoneProcessing(); } else if (Type == Sema::FST_Scanf) { CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg, diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index ff1df7b71b1a4..539de00bd104f 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -1958,3 +1958,21 @@ concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) : Value(T), Status(T->getType()->isInstantiationDependentType() ? SS_Dependent : SS_Satisfied) {} + +NormalizedConstraint::CompoundConstraintKind +NormalizedConstraint::getCompoundKind() const { + assert(isCompound() && "getCompoundKind on a non-compound constraint.."); + return cast(Constraint).getInt(); +} + +AtomicConstraint *NormalizedConstraint::getAtomicConstraint() const { + assert(isAtomic() && "getAtomicConstraint called on non-atomic constraint."); + return cast(Constraint); +} + +FoldExpandedConstraint * +NormalizedConstraint::getFoldExpandedConstraint() const { + assert(isFoldExpanded() && + "getFoldExpandedConstraint called on non-fold-expanded constraint."); + return cast(Constraint); +} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index efed132da0546..5e25e1fcda4e8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11178,9 +11178,9 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) { static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) { const auto *TA = FD->getAttr(); const auto *TVA = FD->getAttr(); - assert( - (TA || TVA) && - "MultiVersion candidate requires a target or target_version attribute"); + + assert((TA || TVA) && "Expecting target or target_version attribute"); + const TargetInfo &TargetInfo = S.Context.getTargetInfo(); enum ErrType { Feature = 0, Architecture = 1 }; @@ -11477,10 +11477,6 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) { // otherwise it is treated as a normal function. if (TA && !TA->isDefaultVersion()) return false; - // The target_version attribute only causes Multiversioning if this - // declaration is NOT the default version. - if (TVA && TVA->isDefaultVersion()) - return false; if ((TA || TVA) && CheckMultiVersionValue(S, FD)) { FD->setInvalidDecl(); @@ -11527,26 +11523,24 @@ static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, LookupResult &Previous) { assert(!OldFD->isMultiVersion() && "Unexpected MultiVersion"); + const auto *NewTA = NewFD->getAttr(); + const auto *OldTA = OldFD->getAttr(); + const auto *NewTVA = NewFD->getAttr(); + const auto *OldTVA = OldFD->getAttr(); + + assert((NewTA || NewTVA) && "Excpecting target or target_version attribute"); + // The definitions should be allowed in any order. If we have discovered // a new target version and the preceeding was the default, then add the // corresponding attribute to it. patchDefaultTargetVersion(NewFD, OldFD); - const auto *NewTA = NewFD->getAttr(); - const auto *NewTVA = NewFD->getAttr(); - const auto *OldTA = OldFD->getAttr(); - // If the old decl is NOT MultiVersioned yet, and we don't cause that // to change, this is a simple redeclaration. if (NewTA && !NewTA->isDefaultVersion() && (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) return false; - // The target_version attribute only causes Multiversioning if this - // declaration is NOT the default version. - if (NewTVA && NewTVA->isDefaultVersion()) - return false; - // Otherwise, this decl causes MultiVersioning. if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true, NewTVA ? MultiVersionKind::TargetVersion @@ -11561,7 +11555,8 @@ static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, } // If this is 'default', permit the forward declaration. - if (NewTA && NewTA->isDefaultVersion() && !OldTA) { + if ((NewTA && NewTA->isDefaultVersion() && !OldTA) || + (NewTVA && NewTVA->isDefaultVersion() && !OldTVA)) { Redeclaration = true; OldDecl = OldFD; OldFD->setIsMultiVersion(); @@ -11569,7 +11564,7 @@ static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, return false; } - if (CheckMultiVersionValue(S, OldFD)) { + if ((OldTA || OldTVA) && CheckMultiVersionValue(S, OldFD)) { S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); NewFD->setInvalidDecl(); return true; @@ -11866,9 +11861,7 @@ static bool CheckMultiVersionAdditionalDecl( // Else, this is simply a non-redecl case. Checking the 'value' is only // necessary in the Target case, since The CPUSpecific/Dispatch cases are // handled in the attribute adding step. - if ((NewMVKind == MultiVersionKind::TargetVersion || - NewMVKind == MultiVersionKind::Target) && - CheckMultiVersionValue(S, NewFD)) { + if ((NewTA || NewTVA) && CheckMultiVersionValue(S, NewFD)) { NewFD->setInvalidDecl(); return true; } @@ -11904,6 +11897,12 @@ static bool CheckMultiVersionAdditionalDecl( static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) { + const TargetInfo &TI = S.getASTContext().getTargetInfo(); + + // Check if FMV is disabled. + if (TI.getTriple().isAArch64() && !TI.hasFeature("fmv")) + return false; + const auto *NewTA = NewFD->getAttr(); const auto *NewTVA = NewFD->getAttr(); const auto *NewCPUDisp = NewFD->getAttr(); @@ -11926,14 +11925,12 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, return false; } - const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple(); - // Target attribute on AArch64 is not used for multiversioning - if (NewTA && T.isAArch64()) + if (NewTA && TI.getTriple().isAArch64()) return false; // Target attribute on RISCV is not used for multiversioning - if (NewTA && T.isRISCV()) + if (NewTA && TI.getTriple().isRISCV()) return false; if (!OldDecl || !OldDecl->getAsFunction() || diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 216ca3fb0a5f8..a8c0991afc28c 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -317,6 +317,19 @@ static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { return checkRecordDeclForAttr(RT->getDecl()); } +static bool checkRecordTypeForScopedCapability(Sema &S, QualType Ty) { + const RecordType *RT = getRecordType(Ty); + + if (!RT) + return false; + + // Don't check for the capability if the class hasn't been defined yet. + if (RT->isIncompleteType()) + return true; + + return checkRecordDeclForAttr(RT->getDecl()); +} + static bool checkTypedefTypeForCapability(QualType Ty) { const auto *TD = Ty->getAs(); if (!TD) @@ -462,6 +475,19 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, } } +static bool checkFunParamsAreScopedLockable(Sema &S, + const ParmVarDecl *ParamDecl, + const ParsedAttr &AL) { + QualType ParamType = ParamDecl->getType(); + if (const auto *RefType = ParamType->getAs(); + RefType && + checkRecordTypeForScopedCapability(S, RefType->getPointeeType())) + return true; + S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_scoped_lockable_param) + << AL; + return false; +} + //===----------------------------------------------------------------------===// // Attribute Implementations //===----------------------------------------------------------------------===// @@ -689,6 +715,10 @@ static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *ParmDecl = dyn_cast(D); + ParmDecl && !checkFunParamsAreScopedLockable(S, ParmDecl, AL)) + return; + if (!AL.checkAtLeastNumArgs(S, 1)) return; @@ -5969,6 +5999,10 @@ static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleAcquireCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *ParmDecl = dyn_cast(D); + ParmDecl && !checkFunParamsAreScopedLockable(S, ParmDecl, AL)) + return; + SmallVector Args; if (!checkLockFunAttrCommon(S, D, AL, Args)) return; @@ -5989,6 +6023,9 @@ static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, static void handleReleaseCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *ParmDecl = dyn_cast(D); + ParmDecl && !checkFunParamsAreScopedLockable(S, ParmDecl, AL)) + return; // Check that all arguments are lockable objects. SmallVector Args; checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true); @@ -5999,6 +6036,10 @@ static void handleReleaseCapabilityAttr(Sema &S, Decl *D, static void handleRequiresCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *ParmDecl = dyn_cast(D); + ParmDecl && !checkFunParamsAreScopedLockable(S, ParmDecl, AL)) + return; + if (!AL.checkAtLeastNumArgs(S, 1)) return; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a3d59164cc1c9..143d51f221a81 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11962,7 +11962,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 6cc817ab37fa5..dad9006863f8b 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1400,6 +1400,11 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::SYCLBuiltinNumBasesExprClass: case Expr::SYCLBuiltinBaseTypeExprClass: case Expr::HLSLOutArgExprClass: + case Stmt::OpenACCEnterDataConstructClass: + case Stmt::OpenACCExitDataConstructClass: + case Stmt::OpenACCWaitConstructClass: + case Stmt::OpenACCInitConstructClass: + case Stmt::OpenACCShutdownConstructClass: // These expressions can never throw. return CT_Cannot; @@ -1411,6 +1416,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 84102007b2810..468d10cd1bcf9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11863,6 +11863,51 @@ 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(Sema &S, const Expr *LHS, + const Expr *RHS, + BinaryOperatorKind Opc) { + if (!LHS->getType()->isPointerType() || + S.getLangOpts().isSignedOverflowDefined()) + 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, @@ -11972,6 +12017,12 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, S.PDiag(diag::warn_comparison_always) << 1 /*array comparison*/ << Result); + } else if (std::optional Res = + isTautologicalBoundsCheck(S, LHS, RHS, Opc)) { + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_comparison_always) + << 2 /*pointer comparison*/ + << (*Res ? AlwaysTrue : AlwaysFalse)); } } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ac1018cb2c326..e12cb957e834d 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8210,7 +8210,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..d130e8b86bc56 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -434,8 +434,11 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, if (!HalvingSwizzle && *compStr) { // We didn't get to the end of the string. This means the component names // didn't come from the same set *or* we encountered an illegal name. - S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) - << StringRef(compStr, 1) << SourceRange(CompLoc); + size_t Offset = compStr - CompName->getNameStart() + 1; + char Fmt[3] = {'\'', *compStr, '\''}; + S.Diag(OpLoc.getLocWithOffset(Offset), + diag::err_ext_vector_component_name_illegal) + << StringRef(Fmt, 3) << SourceRange(CompLoc); return QualType(); } @@ -1003,15 +1006,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 +1122,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 +1197,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 +1216,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 +1225,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/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 62c3e778ab178..42bbdf1f3f9fa 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,60 @@ 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::DeviceNum: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::Init: + case OpenACCDirectiveKind::Shutdown: + case OpenACCDirectiveKind::Set: + return true; + default: + return false; + } + } + + case OpenACCClauseKind::UseDevice: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::HostData: + return true; + default: + return false; + } + } } default: @@ -431,11 +490,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 +560,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 +578,18 @@ 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 || + DK == OpenACCDirectiveKind::Init || + DK == OpenACCDirectiveKind::Shutdown; +} + class SemaOpenACCClauseVisitor { SemaOpenACC &SemaRef; ASTContext &Ctx; @@ -572,14 +654,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,17 +700,22 @@ 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. - if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause)) + // 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. + // GCC allows this on init/shutdown, presumably for good reason, so we do too. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Init && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Shutdown && + checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause)) return nullptr; // The parser has ensured that we have a proper condition expr, so there @@ -663,8 +742,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 @@ -857,11 +935,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, @@ -878,6 +956,20 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitAsyncClause( Clause.getEndLoc()); } +OpenACCClause *SemaOpenACCClauseVisitor::VisitDeviceNumClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + // Restrictions only properly implemented on certain constructs, so skip/treat + // as unimplemented in those cases. + if (!isDirectiveKindImplemented(Clause.getDirectiveKind())) + return isNotImplemented(); + + assert(Clause.getNumIntExprs() == 1 && + "Invalid number of expressions for device_num"); + return OpenACCDeviceNumClause::Create( + Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getIntExprs()[0], + Clause.getEndLoc()); +} + OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause( SemaOpenACC::OpenACCParsedClause &Clause) { // ActOnVar ensured that everything is a valid variable reference, so there @@ -902,12 +994,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. @@ -919,11 +1005,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 @@ -936,11 +1022,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 @@ -953,11 +1039,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 @@ -970,11 +1056,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 @@ -987,12 +1073,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. @@ -1004,13 +1084,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()}; @@ -1024,13 +1097,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 @@ -1049,11 +1156,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( @@ -1063,13 +1170,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 @@ -1263,8 +1368,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 = @@ -1362,8 +1466,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 = @@ -1475,8 +1578,7 @@ 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 @@ -1597,12 +1699,30 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitGangClause( 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( SemaOpenACC::OpenACCParsedClause &Clause) { // 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: @@ -1760,6 +1880,34 @@ 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: + case OpenACCDirectiveKind::Init: + case OpenACCDirectiveKind::Shutdown: + 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) {} @@ -1774,7 +1922,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 || @@ -1950,24 +2098,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. } } @@ -2175,9 +2322,19 @@ 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: + case OpenACCDirectiveKind::Init: + case OpenACCDirectiveKind::Shutdown: // 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; @@ -2318,6 +2475,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)) { @@ -2338,16 +2504,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 @@ -2362,8 +2532,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(); } @@ -3380,8 +3553,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(); @@ -3408,15 +3608,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(); @@ -3441,6 +3693,37 @@ 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); + } + case OpenACCDirectiveKind::Init: { + return OpenACCInitConstruct::Create(getASTContext(), StartLoc, DirLoc, + EndLoc, Clauses); + } + case OpenACCDirectiveKind::Shutdown: { + return OpenACCShutdownConstruct::Create(getASTContext(), StartLoc, DirLoc, + EndLoc, Clauses); + } } llvm_unreachable("Unhandled case in directive handling?"); } @@ -3451,9 +3734,18 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt( switch (K) { default: llvm_unreachable("Unimplemented associated statement application"); + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::Wait: + case OpenACCDirectiveKind::Init: + case OpenACCDirectiveKind::Shutdown: + 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 94542de216baa..e2a37ef831289 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5951,7 +5951,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() != @@ -6482,11 +6484,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; } @@ -15611,8 +15608,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 b57480299576e..db6968cd4a763 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -227,17 +227,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(); @@ -246,30 +247,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, @@ -280,7 +282,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; @@ -294,8 +296,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; @@ -308,11 +310,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; } } @@ -324,15 +326,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) @@ -340,23 +342,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)) @@ -373,17 +376,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; } } @@ -392,16 +399,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 bd08e76050238..0c7ea52b15f1e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2666,6 +2666,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(); @@ -2678,12 +2695,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) && @@ -5212,6 +5223,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/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 88a21240e1c80..c8452db6bc901 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -780,7 +780,7 @@ bool Sema::CheckParameterPacksForExpansion( } // Determine the size of this argument pack. - unsigned NewPackSize; + unsigned NewPackSize, PendingPackExpansionSize = 0; if (IsVarDeclPack) { // Figure out whether we're instantiating to an argument pack or not. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; @@ -808,7 +808,25 @@ bool Sema::CheckParameterPacksForExpansion( } // Determine the size of the argument pack. - NewPackSize = TemplateArgs(Depth, Index).pack_size(); + ArrayRef Pack = + TemplateArgs(Depth, Index).getPackAsArray(); + NewPackSize = Pack.size(); + PendingPackExpansionSize = + llvm::count_if(Pack, [](const TemplateArgument &TA) { + if (!TA.isPackExpansion()) + return false; + + if (TA.getKind() == TemplateArgument::Type) + return !TA.getAsType() + ->getAs() + ->getNumExpansions(); + + if (TA.getKind() == TemplateArgument::Expression) + return !cast(TA.getAsExpr()) + ->getNumExpansions(); + + return !TA.getNumTemplateExpansions(); + }); } // C++0x [temp.arg.explicit]p9: @@ -831,7 +849,7 @@ bool Sema::CheckParameterPacksForExpansion( } if (!NumExpansions) { - // The is the first pack we've seen for which we have an argument. + // This is the first pack we've seen for which we have an argument. // Record it. NumExpansions = NewPackSize; FirstPack.first = Name; @@ -841,17 +859,44 @@ bool Sema::CheckParameterPacksForExpansion( } if (NewPackSize != *NumExpansions) { + // In some cases, we might be handling packs with unexpanded template + // arguments. For example, this can occur when substituting into a type + // alias declaration that uses its injected template parameters as + // arguments: + // + // template struct S { + // template using Alias = S; + // }; + // + // Consider an instantiation attempt like 'S::Alias', where + // Pack comes from another template parameter. 'S' is first + // instantiated, expanding the outer pack 'Outer' to . The alias + // declaration is accordingly substituted, leaving the template arguments + // as unexpanded + // ''. + // + // Since we have no idea of the size of '' until its expansion, + // we shouldn't assume its pack size for validation. However if we are + // certain that there are extra arguments beyond unexpanded packs, in + // which case the pack size is already larger than the previous expansion, + // we can complain that before instantiation. + unsigned LeastNewPackSize = NewPackSize - PendingPackExpansionSize; + if (PendingPackExpansionSize && LeastNewPackSize <= *NumExpansions) { + ShouldExpand = false; + continue; + } // C++0x [temp.variadic]p5: // All of the parameter packs expanded by a pack expansion shall have // the same number of arguments specified. if (HaveFirstPack) Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) - << FirstPack.first << Name << *NumExpansions << NewPackSize + << FirstPack.first << Name << *NumExpansions + << (LeastNewPackSize != NewPackSize) << LeastNewPackSize << SourceRange(FirstPack.second) << SourceRange(ParmPack.second); else Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) - << Name << *NumExpansions << NewPackSize - << SourceRange(ParmPack.second); + << Name << *NumExpansions << (LeastNewPackSize != NewPackSize) + << LeastNewPackSize << SourceRange(ParmPack.second); return true; } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 309f12d93ffd4..547b8da3e5e57 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2327,6 +2327,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 @@ -2339,15 +2350,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, @@ -2417,15 +2423,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 = @@ -2470,6 +2470,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 968668b7b2595..3a7c8f81c9526 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4115,8 +4115,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, @@ -4125,7 +4126,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, @@ -4134,8 +4136,78 @@ 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 RebuildOpenACCInitConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, + SourceLocation EndLoc, + ArrayRef Clauses) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Init, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); + } + + StmtResult + RebuildOpenACCShutdownConstruct(SourceLocation BeginLoc, + SourceLocation DirLoc, SourceLocation EndLoc, + ArrayRef Clauses) { + return getSema().OpenACC().ActOnEndStmtDirective( + OpenACCDirectiveKind::Shutdown, BeginLoc, DirLoc, SourceLocation{}, + SourceLocation{}, {}, SourceLocation{}, EndLoc, Clauses, {}); + } + + 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) { @@ -11747,6 +11819,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) { @@ -11789,6 +11905,29 @@ void OpenACCClauseTransform::VisitNumWorkersClause( ParsedClause.getEndLoc()); } +template +void OpenACCClauseTransform::VisitDeviceNumClause ( + const OpenACCDeviceNumClause &C) { + Expr *IntExpr = const_cast(C.getIntExpr()); + assert(IntExpr && "device_num clause constructed with invalid int expr"); + + ExprResult Res = Self.TransformExpr(IntExpr); + if (!Res.isUsable()) + return; + + Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid, + C.getClauseKind(), + C.getBeginLoc(), Res.get()); + if (!Res.isUsable()) + return; + + ParsedClause.setIntExprDetails(Res.get()); + NewClause = OpenACCDeviceNumClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.getIntExprs()[0], + ParsedClause.getEndLoc()); +} + template void OpenACCClauseTransform::VisitVectorLengthClause( const OpenACCVectorLengthClause &C) { @@ -11970,6 +12109,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( @@ -12111,8 +12265,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. @@ -12138,8 +12292,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. @@ -12164,8 +12318,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. @@ -12181,6 +12335,166 @@ 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::TransformOpenACCInitConstruct(OpenACCInitConstruct *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().RebuildOpenACCInitConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses); +} + +template +StmtResult TreeTransform::TransformOpenACCShutdownConstruct( + OpenACCShutdownConstruct *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().RebuildOpenACCShutdownConstruct( + C->getBeginLoc(), C->getDirectiveLoc(), C->getEndLoc(), + TransformedClauses); +} + +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/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 4c524c0e72b6a..ff4cb5e53b631 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3963,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; @@ -10285,19 +10285,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)) { @@ -10662,7 +10649,8 @@ void ASTReader::FinishedDeserializing() { // We do this now rather than in finishPendingActions because we want to // be able to walk the complete redeclaration chains of the updated decls. while (!PendingExceptionSpecUpdates.empty() || - !PendingDeducedTypeUpdates.empty()) { + !PendingDeducedTypeUpdates.empty() || + !PendingUndeducedFunctionDecls.empty()) { auto ESUpdates = std::move(PendingExceptionSpecUpdates); PendingExceptionSpecUpdates.clear(); for (auto Update : ESUpdates) { @@ -12425,6 +12413,12 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { return OpenACCNumWorkersClause::Create(getContext(), BeginLoc, LParenLoc, IntExpr, EndLoc); } + case OpenACCClauseKind::DeviceNum: { + SourceLocation LParenLoc = readSourceLocation(); + Expr *IntExpr = readSubExpr(); + return OpenACCDeviceNumClause::Create(getContext(), BeginLoc, LParenLoc, + IntExpr, EndLoc); + } case OpenACCClauseKind::VectorLength: { SourceLocation LParenLoc = readSourceLocation(); Expr *IntExpr = readSubExpr(); @@ -12449,6 +12443,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(); @@ -12541,6 +12553,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: @@ -12586,18 +12602,12 @@ 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: case OpenACCClauseKind::Link: case OpenACCClauseKind::Bind: - case OpenACCClauseKind::DeviceNum: case OpenACCClauseKind::DefaultAsync: case OpenACCClauseKind::Invalid: llvm_unreachable("Clause serialization not yet implemented"); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index be77df81b1ddf..719bc0d06f5b1 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -4329,13 +4329,12 @@ 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); } } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 0a0f8115730cf..9f88956f51e5e 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2881,6 +2881,53 @@ 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::VisitOpenACCInitConstruct(OpenACCInitConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); +} + +void ASTStmtReader::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *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. //===----------------------------------------------------------------------===// @@ -4375,6 +4422,42 @@ 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 STMT_OPENACC_INIT_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCInitConstruct::CreateEmpty(Context, NumClauses); + break; + } + case STMT_OPENACC_SHUTDOWN_CONSTRUCT: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + S = OpenACCShutdownConstruct::CreateEmpty(Context, 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 820da588a75f5..4a6027943072c 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -941,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); @@ -5972,23 +5972,23 @@ 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); } @@ -8326,6 +8326,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { AddStmt(E); return; } + case OpenACCClauseKind::DeviceNum: { + const auto *DNC = cast(C); + writeSourceLocation(DNC->getLParenLoc()); + AddStmt(const_cast(DNC->getIntExpr())); + return; + } case OpenACCClauseKind::NumWorkers: { const auto *NWC = cast(C); writeSourceLocation(NWC->getLParenLoc()); @@ -8356,6 +8362,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()); @@ -8451,6 +8475,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; @@ -8496,18 +8522,12 @@ 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: case OpenACCClauseKind::Link: case OpenACCClauseKind::Bind: - case OpenACCClauseKind::DeviceNum: case OpenACCClauseKind::DefaultAsync: case OpenACCClauseKind::Invalid: llvm_unreachable("Clause serialization not yet implemented"); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 68e2d6b399390..75c1d9a6d438c 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -798,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); @@ -1563,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 { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index e054cfdf1c627..3fd6318ba235a 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -2963,6 +2963,57 @@ 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::VisitOpenACCInitConstruct(OpenACCInitConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); + Code = serialization::STMT_OPENACC_INIT_CONSTRUCT; +} + +void ASTStmtWriter::VisitOpenACCShutdownConstruct(OpenACCShutdownConstruct *S) { + VisitStmt(S); + VisitOpenACCConstructStmt(S); + Code = serialization::STMT_OPENACC_SHUTDOWN_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/MultiOnDiskHashTable.h b/clang/lib/Serialization/MultiOnDiskHashTable.h index a0d75ec3a9e76..6464220f13aef 100644 --- a/clang/lib/Serialization/MultiOnDiskHashTable.h +++ b/clang/lib/Serialization/MultiOnDiskHashTable.h @@ -93,7 +93,7 @@ template class MultiOnDiskHashTable { using result_type = OnDiskTable *; result_type operator()(void *P) const { - return Table::getFromOpaqueValue(P).template get(); + return llvm::cast(Table::getFromOpaqueValue(P)); } }; @@ -130,7 +130,7 @@ template class MultiOnDiskHashTable { Files.insert(PendingOverrides.begin(), PendingOverrides.end()); // Explicitly capture Files to work around an MSVC 2015 rejects-valid bug. auto ShouldRemove = [&Files](void *T) -> bool { - auto *ODT = Table::getFromOpaqueValue(T).template get(); + auto *ODT = llvm::cast(Table::getFromOpaqueValue(T)); bool Remove = Files.count(ODT->File); if (Remove) delete ODT; diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index 3f837564cf47c..6422933c8828a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -22,6 +22,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" @@ -241,26 +242,25 @@ computeOffset(ProgramStateRef State, SValBuilder &SVB, SVal Location) { static std::pair getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent, SValBuilder &svalBuilder) { + const llvm::APSInt &extentVal = extent.getValue(); std::optional SymVal = offset.getAs(); if (SymVal && SymVal->isExpression()) { if (const SymIntExpr *SIE = dyn_cast(SymVal->getSymbol())) { - llvm::APSInt constant = - APSIntType(extent.getValue()).convert(SIE->getRHS()); + llvm::APSInt constant = APSIntType(extentVal).convert(SIE->getRHS()); switch (SIE->getOpcode()) { case BO_Mul: // The constant should never be 0 here, becasue multiplication by zero // is simplified by the engine. - if ((extent.getValue() % constant) != 0) + if ((extentVal % constant) != 0) return std::pair(offset, extent); else return getSimplifiedOffsets( nonloc::SymbolVal(SIE->getLHS()), - svalBuilder.makeIntVal(extent.getValue() / constant), - svalBuilder); + svalBuilder.makeIntVal(extentVal / constant), svalBuilder); case BO_Add: return getSimplifiedOffsets( nonloc::SymbolVal(SIE->getLHS()), - svalBuilder.makeIntVal(extent.getValue() - constant), svalBuilder); + svalBuilder.makeIntVal(extentVal - constant), svalBuilder); default: break; } @@ -363,7 +363,7 @@ static std::string getRegionName(const SubRegion *Region) { static std::optional getConcreteValue(NonLoc SV) { if (auto ConcreteVal = SV.getAs()) { - return ConcreteVal->getValue().tryExtValue(); + return ConcreteVal->getValue()->tryExtValue(); } return std::nullopt; } diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 80f128b917b20..cc089767adfee 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -457,7 +457,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE, if (!V) return; - uint64_t NumberKind = V->getValue().getLimitedValue(); + uint64_t NumberKind = V->getValue()->getLimitedValue(); std::optional OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind); // FIXME: In some cases we can emit an error. diff --git a/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp index 17f1214195b3e..ed26ddea93a26 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp @@ -252,11 +252,11 @@ BugReportPtr BitwiseShiftValidator::checkLeftShiftOverflow() { // We should have already reported a bug if the left operand of the shift was // negative, so it cannot be negative here. - assert(Left->getValue().isNonNegative()); + assert(Left->getValue()->isNonNegative()); const unsigned LeftAvailableBitWidth = LeftBitWidth - static_cast(ShouldPreserveSignBit); - const unsigned UsedBitsInLeftOperand = Left->getValue().getActiveBits(); + const unsigned UsedBitsInLeftOperand = Left->getValue()->getActiveBits(); assert(LeftBitWidth >= UsedBitsInLeftOperand); const unsigned MaximalAllowedShift = LeftAvailableBitWidth - UsedBitsInLeftOperand; @@ -275,9 +275,9 @@ BugReportPtr BitwiseShiftValidator::checkLeftShiftOverflow() { if (const auto ConcreteRight = Right.getAs()) { // Here ConcreteRight must contain a small non-negative integer, because // otherwise one of the earlier checks should've reported a bug. - const unsigned RHS = ConcreteRight->getValue().getExtValue(); + const int64_t RHS = ConcreteRight->getValue()->getExtValue(); assert(RHS > MaximalAllowedShift); - const unsigned OverflownBits = RHS - MaximalAllowedShift; + const int64_t OverflownBits = RHS - MaximalAllowedShift; ShortMsg = formatv( "The shift '{0} << {1}' overflows the capacity of '{2}'", Left->getValue(), ConcreteRight->getValue(), LHSTy.getAsString()); diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index 4ab0c4c9ae7b7..cfdd3c9faa360 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -155,12 +155,14 @@ BuiltinFunctionChecker::checkOverflow(CheckerContext &C, SVal RetVal, unsigned BitWidth = C.getASTContext().getIntWidth(Res); bool IsUnsigned = Res->isUnsignedIntegerType(); + SValBuilder &SVB = C.getSValBuilder(); + BasicValueFactory &VF = SVB.getBasicValueFactory(); + auto MinValType = llvm::APSInt::getMinValue(BitWidth, IsUnsigned); auto MaxValType = llvm::APSInt::getMaxValue(BitWidth, IsUnsigned); - nonloc::ConcreteInt MinVal{MinValType}; - nonloc::ConcreteInt MaxVal{MaxValType}; + nonloc::ConcreteInt MinVal{VF.getValue(MinValType)}; + nonloc::ConcreteInt MaxVal{VF.getValue(MaxValType)}; - SValBuilder &SVB = C.getSValBuilder(); ProgramStateRef State = C.getState(); SVal IsLeMax = SVB.evalBinOp(State, BO_LE, RetVal, MaxVal, Res); SVal IsGeMin = SVB.evalBinOp(State, BO_GE, RetVal, MinVal, Res); diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 21a2d8828249d..1a14f38e34f0e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -1025,8 +1025,8 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4); - const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt, - fourInt); + std::optional maxLengthInt = + BVF.evalAPSInt(BO_Div, maxValInt, fourInt); NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt); SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, maxLength, svalBuilder.getConditionType()); diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp index 1b89951397cfb..3a66b0f11eb2e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp @@ -124,7 +124,7 @@ bool PlacementNewChecker::checkPlaceCapacityIsSufficient( "requires {1} bytes. Current overhead requires the size of {2} " "bytes", SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue(), - SizeOfPlaceCI->getValue() - SizeOfTargetCI->getValue())); + *SizeOfPlaceCI->getValue().get() - SizeOfTargetCI->getValue())); else if (IsArrayTypeAllocated && SizeOfPlaceCI->getValue() == SizeOfTargetCI->getValue()) Msg = std::string(llvm::formatv( diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 3096999e9fd16..5534ef86a7bef 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -486,8 +486,8 @@ class SymbolExpressor return Str; if (std::optional Str = Visit(S->getLHS())) return (*Str + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " + - std::to_string(S->getRHS().getLimitedValue()) + - (S->getRHS().isUnsigned() ? "U" : "")) + std::to_string(S->getRHS()->getLimitedValue()) + + (S->getRHS()->isUnsigned() ? "U" : "")) .str(); return std::nullopt; } diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp index e8d35aac2efd9..ba561ddebdb69 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp @@ -241,7 +241,7 @@ ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter, // For concrete integers we can calculate the new position nonloc::ConcreteInt IntDist = *IntDistOp; - if (IntDist.getValue().isNegative()) { + if (IntDist.getValue()->isNegative()) { IntDist = nonloc::ConcreteInt(BVF.getValue(-IntDist.getValue())); BinOp = (BinOp == BO_Add) ? BO_Sub : BO_Add; } @@ -272,9 +272,9 @@ ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, ProgramStateRef NewState = State; llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale); - SVal IsCappedFromAbove = - SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym), - nonloc::ConcreteInt(Max), SVB.getConditionType()); + SVal IsCappedFromAbove = SVB.evalBinOpNN( + State, BO_LE, nonloc::SymbolVal(Sym), + nonloc::ConcreteInt(BV.getValue(Max)), SVB.getConditionType()); if (auto DV = IsCappedFromAbove.getAs()) { NewState = NewState->assume(*DV, true); if (!NewState) @@ -282,9 +282,9 @@ ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, } llvm::APSInt Min = -Max; - SVal IsCappedFromBelow = - SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym), - nonloc::ConcreteInt(Min), SVB.getConditionType()); + SVal IsCappedFromBelow = SVB.evalBinOpNN( + State, BO_GE, nonloc::SymbolVal(Sym), + nonloc::ConcreteInt(BV.getValue(Min)), SVB.getConditionType()); if (auto DV = IsCappedFromBelow.getAs()) { NewState = NewState->assume(*DV, true); if (!NewState) diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp index 5649454b4cd47..d4ce73b03acb8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -507,8 +507,8 @@ void IteratorModeling::processComparison(CheckerContext &C, OverloadedOperatorKind Op) const { if (const auto TruthVal = RetVal.getAs()) { if ((State = relateSymbols(State, Sym1, Sym2, - (Op == OO_EqualEqual) == - (TruthVal->getValue() != 0)))) { + (Op == OO_EqualEqual) == + (TruthVal->getValue()->getBoolValue())))) { C.addTransition(State); } else { C.generateSink(State, C.getPredecessor()); diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp index 4b8e5216550d9..9a8c128edc233 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp @@ -68,7 +68,7 @@ void MmapWriteExecChecker::checkPreCall(const CallEvent &Call, auto ProtLoc = ProtVal.getAs(); if (!ProtLoc) return; - int64_t Prot = ProtLoc->getValue().getSExtValue(); + int64_t Prot = ProtLoc->getValue()->getSExtValue(); if ((Prot & ProtWrite) && (Prot & ProtExec)) { ExplodedNode *N = C.generateNonFatalErrorNode(); diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 4f30b2a0e7e7d..356d63e3e8b80 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -1643,7 +1643,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( public: GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {} std::optional operator()(QualType Ty) { - return BVF.getMaxValue(Ty).getLimitedValue(); + return BVF.getMaxValue(Ty)->getLimitedValue(); } std::optional operator()(std::optional Ty) { if (Ty) { @@ -1687,11 +1687,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( const QualType SizePtrTy = getPointerTy(SizeTy); const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy); - const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue(); + const RangeInt IntMax = BVF.getMaxValue(IntTy)->getLimitedValue(); const RangeInt UnsignedIntMax = - BVF.getMaxValue(UnsignedIntTy).getLimitedValue(); - const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue(); - const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue(); + BVF.getMaxValue(UnsignedIntTy)->getLimitedValue(); + const RangeInt LongMax = BVF.getMaxValue(LongTy)->getLimitedValue(); + const RangeInt SizeMax = BVF.getMaxValue(SizeTy)->getLimitedValue(); // Set UCharRangeMax to min of int or uchar maximum value. // The C standard states that the arguments of functions like isalpha must @@ -1700,7 +1700,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( // to be true for commonly used and well tested instruction set // architectures, but not for others. const RangeInt UCharRangeMax = - std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax); + std::min(BVF.getMaxValue(ACtx.UnsignedCharTy)->getLimitedValue(), IntMax); // Get platform dependent values of some macros. // Try our best to parse this from the Preprocessor, otherwise fallback to a @@ -3704,7 +3704,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( // Functions for testing. if (AddTestFunctions) { - const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue(); + const RangeInt IntMin = BVF.getMinValue(IntTy)->getLimitedValue(); addToFunctionSummaryMap( "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}), diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 0a823a1126ce3..80969ce664530 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -1977,7 +1977,7 @@ StreamChecker::ensureFseekWhenceCorrect(SVal WhenceVal, CheckerContext &C, if (!CI) return State; - int64_t X = CI->getValue().getSExtValue(); + int64_t X = CI->getValue()->getSExtValue(); if (X == SeekSetVal || X == SeekCurVal || X == SeekEndVal) return State; diff --git a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index 8d17ba5d690b9..ba91b3632abbf 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -96,7 +96,7 @@ ProgramStateRef VLASizeChecker::checkVLA(CheckerContext &C, SValBuilder &SVB = C.getSValBuilder(); CanQualType SizeTy = Ctx.getSizeType(); uint64_t SizeMax = - SVB.getBasicValueFactory().getMaxValue(SizeTy).getZExtValue(); + SVB.getBasicValueFactory().getMaxValue(SizeTy)->getZExtValue(); // Get the element size. CharUnits EleSize = Ctx.getTypeSizeInChars(VLALast->getElementType()); 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/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 797f3e1f3fba5..5487fea1b956c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -125,9 +125,8 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) { assert(F); const std::string &FunctionName = safeGetName(F); - return isRefType(FunctionName) || FunctionName == "makeRef" || - FunctionName == "makeRefPtr" || FunctionName == "UniqueRef" || - FunctionName == "makeUniqueRef" || + return isRefType(FunctionName) || FunctionName == "adoptRef" || + FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" || FunctionName == "makeUniqueRefWithoutFastMallocCheck" || FunctionName == "String" || FunctionName == "AtomString" || 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 bb580b06e2c53..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) @@ -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..a57499d52acd0 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 = findLambdaInArg(Arg)) { + LambdasToIgnore.insert(L); + if (!Param->hasAttr() && !TreatAllArgsAsNoEscape) Checker->visitLambdaExpr(L, shouldCheckThis()); - } } ++ArgIndex; } @@ -106,6 +126,40 @@ class UncountedLambdaCapturesChecker return true; } + LambdaExpr *findLambdaInArg(Expr *E) { + if (auto *Lambda = dyn_cast_or_null(E)) + return Lambda; + auto *TempExpr = dyn_cast_or_null(E); + if (!TempExpr) + return nullptr; + E = TempExpr->getSubExpr()->IgnoreParenCasts(); + if (!E) + return nullptr; + if (auto *Lambda = dyn_cast(E)) + return Lambda; + auto *CE = dyn_cast_or_null(E); + if (!CE || !CE->getNumArgs()) + return nullptr; + auto *CtorArg = CE->getArg(0)->IgnoreParenCasts(); + if (!CtorArg) + return nullptr; + if (auto *Lambda = dyn_cast(CtorArg)) + return Lambda; + auto *DRE = dyn_cast(CtorArg); + if (!DRE) + return nullptr; + auto *VD = dyn_cast_or_null(DRE->getDecl()); + if (!VD) + return nullptr; + auto *Init = VD->getInit(); + if (!Init) + return nullptr; + TempExpr = dyn_cast(Init->IgnoreParenCasts()); + if (!TempExpr) + return nullptr; + return dyn_cast_or_null(TempExpr->getSubExpr()); + } + void checkCalleeLambda(CallExpr *CE) { auto *Callee = CE->getCallee(); if (!Callee) @@ -117,6 +171,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 +188,7 @@ class UncountedLambdaCapturesChecker if (!L) return; DeclRefExprsToIgnore.insert(ArgRef); + LambdasToIgnore.insert(L); Checker->visitLambdaExpr(L, shouldCheckThis(), /* ignoreParamVarDecl */ true); } @@ -155,11 +214,53 @@ class UncountedLambdaCapturesChecker } else if (C.capturesThis() && shouldCheckThis) { if (ignoreParamVarDecl) // this is always a parameter to this function. continue; - reportBugOnThisPtr(C); + bool hasProtectThis = false; + for (const LambdaCapture &OtherCapture : L->captures()) { + if (!OtherCapture.capturesVariable()) + continue; + if (auto *ValueDecl = OtherCapture.getCapturedVar()) { + if (protectThis(ValueDecl)) { + hasProtectThis = true; + break; + } + } + } + if (!hasProtectThis) + reportBugOnThisPtr(C); } } } + bool protectThis(const ValueDecl *ValueDecl) const { + auto *VD = dyn_cast(ValueDecl); + if (!VD) + return false; + auto *Init = VD->getInit()->IgnoreParenCasts(); + if (!Init) + return false; + auto *BTE = dyn_cast(Init); + if (!BTE) + return false; + auto *CE = dyn_cast_or_null(BTE->getSubExpr()); + if (!CE) + return false; + auto *Ctor = CE->getConstructor(); + if (!Ctor) + return false; + auto clsName = safeGetName(Ctor->getParent()); + if (!isRefType(clsName) || !CE->getNumArgs()) + return false; + auto *Arg = CE->getArg(0)->IgnoreParenCasts(); + while (auto *UO = dyn_cast(Arg)) { + auto OpCode = UO->getOpcode(); + if (OpCode == UO_Deref || OpCode == UO_AddrOf) + Arg = UO->getSubExpr(); + else + break; + } + return isa(Arg); + } + void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar, const QualType T) const { assert(CapturedVar); diff --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index 827c04143e658..02f34bc30f554 100644 --- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -87,7 +87,7 @@ BasicValueFactory::~BasicValueFactory() { delete (PersistentSValPairsTy*) PersistentSValPairs; } -const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { +APSIntPtr BasicValueFactory::getValue(const llvm::APSInt &X) { llvm::FoldingSetNodeID ID; void *InsertPos; @@ -101,23 +101,23 @@ const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { APSIntSet.InsertNode(P, InsertPos); } - return *P; + // We own the APSInt object. It's safe here. + return APSIntPtr::unsafeConstructor(&P->getValue()); } -const llvm::APSInt& BasicValueFactory::getValue(const llvm::APInt& X, - bool isUnsigned) { +APSIntPtr BasicValueFactory::getValue(const llvm::APInt &X, bool isUnsigned) { llvm::APSInt V(X, isUnsigned); return getValue(V); } -const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, - bool isUnsigned) { +APSIntPtr BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, + bool isUnsigned) { llvm::APSInt V(BitWidth, isUnsigned); V = X; return getValue(V); } -const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) { +APSIntPtr BasicValueFactory::getValue(uint64_t X, QualType T) { return getValue(getAPSIntType(T).getValue(X)); } @@ -242,45 +242,45 @@ const PointerToMemberData *BasicValueFactory::accumCXXBase( return getPointerToMemberData(ND, BaseSpecList); } -const llvm::APSInt* -BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, - const llvm::APSInt& V1, const llvm::APSInt& V2) { +std::optional +BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt &V1, + const llvm::APSInt &V2) { switch (Op) { default: llvm_unreachable("Invalid Opcode."); case BO_Mul: - return &getValue( V1 * V2 ); + return getValue(V1 * V2); case BO_Div: if (V2 == 0) // Avoid division by zero - return nullptr; - return &getValue( V1 / V2 ); + return std::nullopt; + return getValue(V1 / V2); case BO_Rem: if (V2 == 0) // Avoid division by zero - return nullptr; - return &getValue( V1 % V2 ); + return std::nullopt; + return getValue(V1 % V2); case BO_Add: - return &getValue( V1 + V2 ); + return getValue(V1 + V2); case BO_Sub: - return &getValue( V1 - V2 ); + return getValue(V1 - V2); case BO_Shl: { // FIXME: This logic should probably go higher up, where we can // test these conditions symbolically. if (V2.isNegative() || V2.getBitWidth() > 64) - return nullptr; + return std::nullopt; uint64_t Amt = V2.getZExtValue(); if (Amt >= V1.getBitWidth()) - return nullptr; + return std::nullopt; - return &getValue( V1.operator<<( (unsigned) Amt )); + return getValue(V1.operator<<((unsigned)Amt)); } case BO_Shr: { @@ -288,44 +288,44 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, // test these conditions symbolically. if (V2.isNegative() || V2.getBitWidth() > 64) - return nullptr; + return std::nullopt; uint64_t Amt = V2.getZExtValue(); if (Amt >= V1.getBitWidth()) - return nullptr; + return std::nullopt; - return &getValue( V1.operator>>( (unsigned) Amt )); + return getValue(V1.operator>>((unsigned)Amt)); } case BO_LT: - return &getTruthValue( V1 < V2 ); + return getTruthValue(V1 < V2); case BO_GT: - return &getTruthValue( V1 > V2 ); + return getTruthValue(V1 > V2); case BO_LE: - return &getTruthValue( V1 <= V2 ); + return getTruthValue(V1 <= V2); case BO_GE: - return &getTruthValue( V1 >= V2 ); + return getTruthValue(V1 >= V2); case BO_EQ: - return &getTruthValue( V1 == V2 ); + return getTruthValue(V1 == V2); case BO_NE: - return &getTruthValue( V1 != V2 ); + return getTruthValue(V1 != V2); // Note: LAnd, LOr, Comma are handled specially by higher-level logic. case BO_And: - return &getValue( V1 & V2 ); + return getValue(V1 & V2); case BO_Or: - return &getValue( V1 | V2 ); + return getValue(V1 | V2); case BO_Xor: - return &getValue( V1 ^ V2 ); + return getValue(V1 ^ V2); } } diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index c4479db14b791..a9b4dbb39b5bd 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -264,7 +264,7 @@ getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) { if (std::optional V = getSValForVar(CondVarExpr, N)) if (auto CI = V->getAs()) - return &CI->getValue(); + return CI->getValue().get(); return std::nullopt; } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 4580d0775fd5c..4aab5ab4140b1 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1825,6 +1825,13 @@ 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::OpenACCInitConstructClass: + case Stmt::OpenACCShutdownConstructClass: case Stmt::OMPUnrollDirectiveClass: case Stmt::OMPMetaDirectiveClass: case Stmt::HLSLOutArgExprClass: { diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index bbf2303b9f6ef..559c80634c12e 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -743,7 +743,7 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const { // Index is a ConcreteInt. if (auto CI = ER->getIndex().getAs()) { llvm::SmallString<2> Idx; - CI->getValue().toString(Idx); + CI->getValue()->toString(Idx); ArrayIndices = (llvm::Twine("[") + Idx.str() + "]" + ArrayIndices).str(); } // Index is symbolic, but may have a descriptive name. @@ -1458,9 +1458,7 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const { SVal index = ER->getIndex(); if (auto CI = index.getAs()) { // Update the offset. - int64_t i = CI->getValue().getSExtValue(); - - if (i != 0) { + if (int64_t i = CI->getValue()->getSExtValue(); i != 0) { QualType elemType = ER->getElementType(); // If we are pointing to an incomplete type, go no further. @@ -1632,7 +1630,7 @@ static RegionOffset calculateOffset(const MemRegion *R) { if (SymbolicOffsetBase) continue; - int64_t i = CI->getValue().getSExtValue(); + int64_t i = CI->getValue()->getSExtValue(); // This type size is in bits. Offset += i * R->getContext().getTypeSize(EleTy); } else { diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index d4f56342d934c..34ab2388cbd2f 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -288,12 +288,10 @@ SVal ProgramState::getSVal(Loc location, QualType T) const { // The symbolic value stored to 'x' is actually the conjured // symbol for the call to foo(); the type of that symbol is 'char', // not unsigned. - const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int); - + APSIntPtr NewV = getBasicVals().Convert(T, *Int); if (V.getAs()) return loc::ConcreteInt(NewV); - else - return nonloc::ConcreteInt(NewV); + return nonloc::ConcreteInt(NewV); } } } diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index 92e9d24552034..2b85580186381 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -76,17 +76,13 @@ DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) { nonloc::SymbolVal SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt &rhs, - QualType type) { - // The Environment ensures we always get a persistent APSInt in - // BasicValueFactory, so we don't need to get the APSInt from - // BasicValueFactory again. + APSIntPtr rhs, QualType type) { assert(lhs); assert(!Loc::isLocType(type)); return nonloc::SymbolVal(SymMgr.getSymIntExpr(lhs, op, rhs, type)); } -nonloc::SymbolVal SValBuilder::makeNonLoc(const llvm::APSInt &lhs, +nonloc::SymbolVal SValBuilder::makeNonLoc(APSIntPtr lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType type) { assert(rhs); @@ -671,7 +667,7 @@ class EvalCastVisitor : public SValVisitor { SVal VisitConcreteInt(loc::ConcreteInt V) { // Pointer to bool. if (CastTy->isBooleanType()) - return VB.makeTruthVal(V.getValue().getBoolValue(), CastTy); + return VB.makeTruthVal(V.getValue()->getBoolValue(), CastTy); // Pointer to integer. if (CastTy->isIntegralOrEnumerationType()) { @@ -875,7 +871,7 @@ class EvalCastVisitor : public SValVisitor { // Integer to bool. if (CastTy->isBooleanType()) - return VB.makeTruthVal(V.getValue().getBoolValue(), CastTy); + return VB.makeTruthVal(V.getValue()->getBoolValue(), CastTy); // Integer to pointer. if (CastTy->isIntegralOrEnumerationType()) diff --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp b/clang/lib/StaticAnalyzer/Core/SVals.cpp index d009552965eca..3ab01a04dcec4 100644 --- a/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -111,9 +111,9 @@ SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const { const llvm::APSInt *SVal::getAsInteger() const { if (auto CI = getAs()) - return &CI->getValue(); + return CI->getValue().get(); if (auto CI = getAs()) - return &CI->getValue(); + return CI->getValue().get(); return nullptr; } @@ -249,9 +249,9 @@ bool SVal::isConstant() const { bool SVal::isConstant(int I) const { if (std::optional LV = getAs()) - return LV->getValue() == I; + return *LV->getValue().get() == I; if (std::optional NV = getAs()) - return NV->getValue() == I; + return *NV->getValue().get() == I; return false; } @@ -314,9 +314,9 @@ void SVal::dumpToStream(raw_ostream &os) const { void NonLoc::dumpToStream(raw_ostream &os) const { switch (getKind()) { case nonloc::ConcreteIntKind: { - const auto &Value = castAs().getValue(); - os << Value << ' ' << (Value.isSigned() ? 'S' : 'U') << Value.getBitWidth() - << 'b'; + APSIntPtr Value = castAs().getValue(); + os << Value << ' ' << (Value->isSigned() ? 'S' : 'U') + << Value->getBitWidth() << 'b'; break; } case nonloc::SymbolValKind: @@ -380,7 +380,7 @@ void NonLoc::dumpToStream(raw_ostream &os) const { void Loc::dumpToStream(raw_ostream &os) const { switch (getKind()) { case loc::ConcreteIntKind: - os << castAs().getValue().getZExtValue() << " (Loc)"; + os << castAs().getValue()->getZExtValue() << " (Loc)"; break; case loc::GotoLabelKind: os << "&&" << castAs().getLabel()->getName(); diff --git a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index 8ca2cdb9d3ab7..3c5c992fa8dbc 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -75,7 +75,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State, } case nonloc::ConcreteIntKind: { - bool b = Cond.castAs().getValue() != 0; + bool b = *Cond.castAs().getValue().get() != 0; bool isFeasible = b ? Assumption : !Assumption; return isFeasible ? State : nullptr; } diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 229169f848e22..455621739f693 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -10,10 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" #include @@ -179,8 +180,7 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, if (RHS == 0) isIdempotent = true; else if (RHS.isAllOnes()) { - const llvm::APSInt &Result = BasicVals.Convert(resultTy, RHS); - return nonloc::ConcreteInt(Result); + return nonloc::ConcreteInt(BasicVals.Convert(resultTy, RHS)); } break; } @@ -193,7 +193,7 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, // If we reach this point, the expression cannot be simplified. // Make a SymbolVal for the entire expression, after converting the RHS. - const llvm::APSInt *ConvertedRHS = &RHS; + std::optional ConvertedRHS = BasicVals.getValue(RHS); if (BinaryOperator::isComparisonOp(op)) { // We're looking for a type big enough to compare the symbolic value // with the given constant. @@ -205,13 +205,13 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, if (ValWidth < TypeWidth) { // If the value is too small, extend it. - ConvertedRHS = &BasicVals.Convert(SymbolType, RHS); + ConvertedRHS = BasicVals.Convert(SymbolType, RHS); } else if (ValWidth == TypeWidth) { // If the value is signed but the symbol is unsigned, do the comparison // in unsigned space. [C99 6.3.1.8] // (For the opposite case, the value is already unsigned.) if (RHS.isSigned() && !SymbolType->isSignedIntegerOrEnumerationType()) - ConvertedRHS = &BasicVals.Convert(SymbolType, RHS); + ConvertedRHS = BasicVals.Convert(SymbolType, RHS); } } else if (BinaryOperator::isAdditiveOp(op) && RHS.isNegative()) { // Change a+(-N) into a-N, and a-(-N) into a+N @@ -219,13 +219,13 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, // subtraction/addition of the negated value. APSIntType resultIntTy = BasicVals.getAPSIntType(resultTy); if (isNegationValuePreserving(RHS, resultIntTy)) { - ConvertedRHS = &BasicVals.getValue(-resultIntTy.convert(RHS)); + ConvertedRHS = BasicVals.getValue(-resultIntTy.convert(RHS)); op = (op == BO_Add) ? BO_Sub : BO_Add; } else { - ConvertedRHS = &BasicVals.Convert(resultTy, RHS); + ConvertedRHS = BasicVals.Convert(resultTy, RHS); } } else - ConvertedRHS = &BasicVals.Convert(resultTy, RHS); + ConvertedRHS = BasicVals.Convert(resultTy, RHS); return makeNonLoc(LHS, op, *ConvertedRHS, resultTy); } @@ -234,9 +234,10 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, static bool isInRelation(BinaryOperator::Opcode Rel, SymbolRef Sym, llvm::APSInt Bound, ProgramStateRef State) { SValBuilder &SVB = State->getStateManager().getSValBuilder(); - SVal Result = - SVB.evalBinOpNN(State, Rel, nonloc::SymbolVal(Sym), - nonloc::ConcreteInt(Bound), SVB.getConditionType()); + BasicValueFactory &BV = SVB.getBasicValueFactory(); + SVal Result = SVB.evalBinOpNN(State, Rel, nonloc::SymbolVal(Sym), + nonloc::ConcreteInt(BV.getValue(Bound)), + SVB.getConditionType()); if (auto DV = Result.getAs()) { return !State->assume(*DV, false); } @@ -273,14 +274,14 @@ static bool isWithinConstantOverflowBounds(llvm::APSInt I) { return (I <= Max) && (I >= -Max); } -static std::pair -decomposeSymbol(SymbolRef Sym, BasicValueFactory &BV) { +static std::pair decomposeSymbol(SymbolRef Sym, + BasicValueFactory &BV) { if (const auto *SymInt = dyn_cast(Sym)) if (BinaryOperator::isAdditiveOp(SymInt->getOpcode())) return std::make_pair(SymInt->getLHS(), - (SymInt->getOpcode() == BO_Add) ? - (SymInt->getRHS()) : - (-SymInt->getRHS())); + (SymInt->getOpcode() == BO_Add) + ? BV.getValue(SymInt->getRHS()) + : BV.getValue(-SymInt->getRHS())); // Fail to decompose: "reduce" the problem to the "$x + 0" case. return std::make_pair(Sym, BV.getValue(0, Sym->getType())); @@ -314,8 +315,9 @@ static NonLoc doRearrangeUnchecked(ProgramStateRef State, llvm_unreachable("Operation not suitable for unchecked rearrangement!"); if (LSym == RSym) - return SVB.evalBinOpNN(State, Op, nonloc::ConcreteInt(LInt), - nonloc::ConcreteInt(RInt), ResultTy) + return SVB + .evalBinOpNN(State, Op, nonloc::ConcreteInt(BV.getValue(LInt)), + nonloc::ConcreteInt(BV.getValue(RInt)), ResultTy) .castAs(); SymbolRef ResultSym = nullptr; @@ -347,7 +349,7 @@ static NonLoc doRearrangeUnchecked(ProgramStateRef State, return nonloc::SymbolVal(ResultSym); } } - const llvm::APSInt &PersistentResultInt = BV.getValue(ResultInt); + APSIntPtr PersistentResultInt = BV.getValue(ResultInt); return nonloc::SymbolVal( SymMgr.getSymIntExpr(ResultSym, ResultOp, PersistentResultInt, ResultTy)); } @@ -541,8 +543,8 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, IntType.apply(RHSValue); } - const llvm::APSInt *Result = - BasicVals.evalAPSInt(op, LHSValue, RHSValue); + std::optional Result = + BasicVals.evalAPSInt(op, LHSValue, RHSValue); if (!Result) { if (op == BO_Shl || op == BO_Shr) { // FIXME: At this point the constant folding claims that the result @@ -682,7 +684,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, // as consequence x+1U-10 produces x-9U, instead // of x+4294967287U, that would be produced without this // additional check. - const llvm::APSInt *newRHS; + std::optional newRHS; if (lop == op) { newRHS = BasicVals.evalAPSInt(BO_Add, first, second); } else if (first >= second) { @@ -874,7 +876,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, if (std::optional rInt = rhs.getAs()) { assert(BinaryOperator::isComparisonOp(op) || op == BO_Sub); - if (const auto *ResultInt = + if (std::optional ResultInt = BasicVals.evalAPSInt(op, L.getValue(), rInt->getValue())) return evalCast(nonloc::ConcreteInt(*ResultInt), resultTy, QualType{}); return UnknownVal(); @@ -1208,10 +1210,10 @@ const llvm::APSInt *SimpleSValBuilder::getConstValue(ProgramStateRef state, const llvm::APSInt *SimpleSValBuilder::getConcreteValue(SVal V) { if (std::optional X = V.getAs()) - return &X->getValue(); + return X->getValue().get(); if (std::optional X = V.getAs()) - return &X->getValue(); + return X->getValue().get(); return nullptr; } diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index 9025e11a3f51a..f21e5c3ad7bd7 100644 --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -261,8 +261,7 @@ SymbolManager::getCastSymbol(const SymExpr *Op, const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& v, - QualType t) { + APSIntPtr v, QualType t) { llvm::FoldingSetNodeID ID; SymIntExpr::Profile(ID, lhs, op, v, t); void *InsertPos; @@ -276,10 +275,9 @@ const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, return cast(data); } -const IntSymExpr *SymbolManager::getIntSymExpr(const llvm::APSInt& lhs, +const IntSymExpr *SymbolManager::getIntSymExpr(APSIntPtr lhs, BinaryOperator::Opcode op, - const SymExpr *rhs, - QualType t) { + const SymExpr *rhs, QualType t) { llvm::FoldingSetNodeID ID; IntSymExpr::Profile(ID, lhs, op, rhs, t); void *InsertPos; diff --git a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp index 71268af22e242..e8cf367b83346 100644 --- a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp @@ -81,7 +81,7 @@ class TextDiagnostics : public PathDiagnosticConsumer { if (llvm::Error Err = Repls.add(Repl)) { llvm::errs() << "Error applying replacement " << Repl.toString() - << ": " << Err << "\n"; + << ": " << llvm::toString(std::move(Err)) << "\n"; } } }; 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/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp index 8a5bef635b8fd..187f180afd3da 100644 --- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp +++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp @@ -507,3 +507,11 @@ 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 7dd08cb5fa1c3..c1fd1bc138150 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -1207,4 +1207,104 @@ namespace BuiltinMemcpy { } 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}} + + /// Both memcpy and memmove must support pointers. + constexpr bool moveptr() { + int a = 0; + void *x = &a; + void *z = nullptr; + + __builtin_memmove(&z, &x, sizeof(void*)); + return z == x; + } + static_assert(moveptr()); + + constexpr bool cpyptr() { + int a = 0; + void *x = &a; + void *z = nullptr; + + __builtin_memcpy(&z, &x, sizeof(void*)); + return z == x; + } + static_assert(cpyptr()); + +} + +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/if.cpp b/clang/test/AST/ByteCode/if.cpp index 540cb76fbaac3..c48b2b8d378c8 100644 --- a/clang/test/AST/ByteCode/if.cpp +++ b/clang/test/AST/ByteCode/if.cpp @@ -76,3 +76,30 @@ namespace IfScope { } static_assert(foo() == 13, ""); } + +namespace IfScope2 { + struct __bit_iterator { + unsigned __ctz_; + }; + constexpr void __fill_n_bool(__bit_iterator) {} + + constexpr void fill_n(__bit_iterator __first) { + if (false) + __fill_n_bool(__first); + else + __fill_n_bool(__first); + } + + struct bitset{ + constexpr void reset() { + auto m = __bit_iterator(8); + fill_n(m); + } + }; + consteval bool foo() { + bitset v; + v.reset(); + return true; + } + static_assert(foo()); +} 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 6cb4379ef5f55..db3f2d405e686 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -4,7 +4,7 @@ // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \ // RUN: -DRESOURCE=StructuredBuffer %s | FileCheck -DRESOURCE=StructuredBuffer \ -// RUN: -check-prefixes=CHECK,CHECK-SRV,CHECK-SUBSCRIPT %s +// RUN: -check-prefixes=CHECK,CHECK-SRV,CHECK-SUBSCRIPT,CHECK-LOAD %s // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \ // RUN: -DRESOURCE=RWStructuredBuffer %s | FileCheck -DRESOURCE=RWStructuredBuffer \ @@ -12,7 +12,7 @@ // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \ // RUN: -DRESOURCE=RWStructuredBuffer %s | FileCheck -DRESOURCE=RWStructuredBuffer \ -// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-SUBSCRIPT,CHECK-COUNTER %s +// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-SUBSCRIPT,CHECK-COUNTER,CHECK-LOAD %s // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \ // RUN: -DRESOURCE=AppendStructuredBuffer %s | FileCheck -DRESOURCE=AppendStructuredBuffer \ @@ -36,7 +36,7 @@ // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \ // RUN: -DRESOURCE=RasterizerOrderedStructuredBuffer %s | FileCheck -DRESOURCE=RasterizerOrderedStructuredBuffer \ -// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-ROV,CHECK-SUBSCRIPT %s +// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-ROV,CHECK-SUBSCRIPT,CHECK-LOAD %s // This test tests two different AST generations for each structured buffer. // The "EMPTY" test mode verifies the AST generated by forward declaration @@ -50,6 +50,14 @@ // EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <> implicit [[RESOURCE]] // EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <> typename depth 0 index 0 element_type +// EMPTY-NEXT: ConceptSpecializationExpr 0x{{[0-9A-Fa-f]+}} <> 'bool' Concept 0x{{[0-9A-Fa-f]+}} '__is_structured_resource_element_compatible' +// EMPTY-NEXT: ImplicitConceptSpecializationDecl 0x{{[0-9A-Fa-f]+}} <> +// EMPTY-NEXT: TemplateArgument type 'type-parameter-0-0' +// EMPTY-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-0' dependent depth 0 index 0 +// EMPTY-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} '' +// EMPTY-NEXT: TemplateArgument type 'element_type':'type-parameter-0-0' +// EMPTY-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'element_type' dependent depth 0 index 0 +// EMPTY-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'element_type' // EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <> implicit class [[RESOURCE]] // EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final @@ -64,6 +72,14 @@ RESOURCE Buffer; // CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <> implicit [[RESOURCE]] // CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <> typename depth 0 index 0 element_type +// CHECK-NEXT: ConceptSpecializationExpr 0x{{[0-9A-Fa-f]+}} <> 'bool' Concept 0x{{[0-9A-Fa-f]+}} '__is_structured_resource_element_compatible' +// CHECK-NEXT: ImplicitConceptSpecializationDecl 0x{{[0-9A-Fa-f]+}} <> +// CHECK-NEXT: TemplateArgument type 'type-parameter-0-0' +// CHECK-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-0' dependent depth 0 index 0 +// CHECK-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} '' +// CHECK-NEXT: TemplateArgument type 'element_type':'type-parameter-0-0' +// CHECK-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'element_type' dependent depth 0 index 0 +// CHECK-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'element_type' // CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <> implicit class [[RESOURCE]] definition // CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final @@ -109,6 +125,21 @@ RESOURCE Buffer; // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> operator[] 'const element_type &(unsigned int) const' // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> operator[] 'element_type &(unsigned int)' +// CHECK-LOAD: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> Load 'element_type (unsigned int)' +// CHECK-LOAD-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <> Index 'unsigned int' +// CHECK-LOAD-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-LOAD-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-LOAD-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <> 'element_type' prefix '*' cannot overflow +// CHECK-LOAD-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type *' +// CHECK-LOAD-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> '' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' +// CHECK-LOAD-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> '__hlsl_resource_t +// CHECK-LOAD-SAME{LITERAL}: [[hlsl::resource_class( +// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// CHECK-LOAD-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}} +// CHECK-LOAD-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> '[[RESOURCE]]' lvalue implicit this +// CHECK-LOAD-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int' +// CHECK-LOAD-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <> Implicit always_inline + // CHECK-COUNTER: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> IncrementCounter 'unsigned int ()' // CHECK-COUNTER-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> // CHECK-COUNTER-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <> 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/HLSL/is_structured_resource_element_compatible_concept.hlsl b/clang/test/AST/HLSL/is_structured_resource_element_compatible_concept.hlsl new file mode 100644 index 0000000000000..2ecd102d524c8 --- /dev/null +++ b/clang/test/AST/HLSL/is_structured_resource_element_compatible_concept.hlsl @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -ast-dump-filter=__is_structured_resource_element_compatible %s | FileCheck %s + +// CHECK: ConceptDecl 0x{{[0-9a-f]+}} <> __is_structured_resource_element_compatible +// CHECK: |-TemplateTypeParmDecl 0x{{[0-9a-f]+}} <> referenced typename depth 0 index 0 element_type +// CHECK: `-BinaryOperator 0x{{[0-9a-f]+}} <> 'bool' lvalue '&&' +// CHECK: |-UnaryOperator 0x{{[0-9a-f]+}} <> 'bool' lvalue prefix '!' cannot overflow +// CHECK: | `-TypeTraitExpr 0x{{[0-9a-f]+}} <> 'bool' __builtin_hlsl_is_intangible +// CHECK: | `-TemplateTypeParmType 0x{{[0-9a-f]+}} 'element_type' dependent depth 0 index 0 +// CHECK: | `-TemplateTypeParm 0x{{[0-9a-f]+}} 'element_type' +// CHECK: `-BinaryOperator 0x{{[0-9a-f]+}} <> 'bool' lvalue '>=' +// CHECK: |-UnaryExprOrTypeTraitExpr 0x{{[0-9a-f]+}} <> 'bool' sizeof 'element_type' +// CHECK: `-IntegerLiteral 0x{{[0-9a-f]+}} <> 'unsigned long' 1 + + +StructuredBuffer Buffer; 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-init-construct.cpp b/clang/test/AST/ast-print-openacc-init-construct.cpp new file mode 100644 index 0000000000000..0cfcbc99ab145 --- /dev/null +++ b/clang/test/AST/ast-print-openacc-init-construct.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fopenacc -ast-print %s -o - | FileCheck %s + +unsigned Int; + +void uses() { +// CHECK: #pragma acc init device_type(*) device_num(Int) if(Int == 5) +#pragma acc init device_type(*) device_num(Int) if (Int == 5) +// CHECK: #pragma acc init device_type(*) device_num(Int) +#pragma acc init device_type(*) device_num(Int) +// CHECK: #pragma acc init device_type(*) if(Int == 5) +#pragma acc init device_type(*) if (Int == 5) +// CHECK: #pragma acc init device_type(SomeName) +#pragma acc init device_type(SomeName) +} diff --git a/clang/test/AST/ast-print-openacc-shutdown-construct.cpp b/clang/test/AST/ast-print-openacc-shutdown-construct.cpp new file mode 100644 index 0000000000000..4e2529658d418 --- /dev/null +++ b/clang/test/AST/ast-print-openacc-shutdown-construct.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fopenacc -ast-print %s -o - | FileCheck %s + +unsigned Int; + +void uses() { +// CHECK: #pragma acc shutdown device_type(*) device_num(Int) if(Int == 5) +#pragma acc shutdown device_type(*) device_num(Int) if (Int == 5) +// CHECK: #pragma acc shutdown device_type(*) device_num(Int) +#pragma acc shutdown device_type(*) device_num(Int) +// CHECK: #pragma acc shutdown device_type(*) if(Int == 5) +#pragma acc shutdown device_type(*) if (Int == 5) +// CHECK: #pragma acc shutdown device_type(SomeName) +#pragma acc shutdown device_type(SomeName) +} 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..b4613d5090f29 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,33 @@ 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 { +} + +namespace call_with_adopt_ref { + class Obj { + public: + void ref() const; + void deref() const; + void method(); + }; + + // This is needed due to rdar://141692212. + struct dummy { + RefPtr any; + }; + + void foo() { + adoptRef(new Obj)->method(); + } } 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..85397c2d25951 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*; @@ -46,7 +74,10 @@ template struct DefaultRefDerefTraits { template , typename RefDerefTraits = DefaultRefDerefTraits> struct Ref { typename PtrTraits::StorageType t; + enum AdoptTag { Adopt }; + Ref() : t{} {}; + Ref(T &t, AdoptTag) : t(&t) { } Ref(T &t) : t(&RefDerefTraits::ref(t)) { } Ref(const Ref& o) : t(RefDerefTraits::refIfNotNull(PtrTraits::unwrap(o.t))) { } Ref(Ref&& o) : t(o.leakRef()) { } @@ -73,10 +104,19 @@ template , typename RefDerefTra T* leakRef() { return PtrTraits::exchange(t, nullptr); } }; +template Ref adoptRef(T& t) { + using Ref = Ref; + return Ref(t, Ref::Adopt); +} + +template class RefPtr; +template RefPtr adoptRef(T*); + template struct RefPtr { T *t; - RefPtr() : t(new T) {} + RefPtr() : t(nullptr) { } + RefPtr(T *t) : t(t) { if (t) @@ -85,6 +125,26 @@ template struct RefPtr { RefPtr(Ref&& o) : t(o.leakRef()) { } + RefPtr(RefPtr&& o) + : t(o.t) + { + o.t = nullptr; + } + RefPtr(const RefPtr& o) + : t(o.t) + { + if (t) + t->ref(); + } + RefPtr operator=(const RefPtr& o) + { + if (t) + t->deref(); + t = o.t; + if (t) + t->ref(); + return *this; + } ~RefPtr() { if (t) t->deref(); @@ -103,15 +163,26 @@ 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); return *this; } operator bool() const { return t; } + +private: + friend RefPtr adoptRef(T*); + + // call_with_adopt_ref in call-args.cpp requires this method to be private. + enum AdoptTag { Adopt }; + RefPtr(T *t, AdoptTag) : t(t) { } }; +template RefPtr adoptRef(T* t) { + return RefPtr(t, RefPtr::Adopt); +} + template bool operator==(const RefPtr &, const RefPtr &) { return false; } @@ -130,6 +201,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 +248,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 +259,7 @@ class CheckedObj { void decrementCheckedPtrCount(); void method(); int trivial() { return 123; } + CheckedObj* next(); }; class RefCountableAndCheckable { @@ -220,31 +293,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/ref-cntbl-crtp-base-no-virtual-dtor.cpp b/clang/test/Analysis/Checkers/WebKit/ref-cntbl-crtp-base-no-virtual-dtor.cpp index 33c60ea8ca64d..4209db14eaa52 100644 --- a/clang/test/Analysis/Checkers/WebKit/ref-cntbl-crtp-base-no-virtual-dtor.cpp +++ b/clang/test/Analysis/Checkers/WebKit/ref-cntbl-crtp-base-no-virtual-dtor.cpp @@ -61,14 +61,6 @@ template Function adopt(Detail::Callab return Function(impl, Function::Adopt); } -template, typename RefDerefTraits = DefaultRefDerefTraits> Ref adoptRef(T&); - -template -inline Ref adoptRef(T& reference) -{ - return Ref(reference); -} - enum class DestructionThread : unsigned char { Any, Main, MainRunLoop }; void ensureOnMainThread(Function&&); // Sync if called on main thread, async otherwise. void ensureOnMainRunLoop(Function&&); // Sync if called on main run loop, async otherwise. diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures-find-lambda-crash.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures-find-lambda-crash.cpp new file mode 100644 index 0000000000000..4d9edb75b7ff3 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures-find-lambda-crash.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.UncountedLambdaCapturesChecker -verify %s +// expected-no-diagnostics + +struct Foo { + int x; + int y; + Foo(int x, int y) : x(x) , y(y) { } + ~Foo() { } +}; + +Foo bar(const Foo&); +void foo() { + int x = 7; + int y = 5; + bar(Foo(x, y)); +} diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp index 65eee9d49106d..2173245bc7af3 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; }; -struct RefCountable { - void ref() {} - void deref() {} - void method(); - void constMethod() const; - int trivial() { return 123; } - RefCountable* next(); +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; +}; + +template Function adopt(Detail::CallableWrapperBase* impl) +{ + return Function(impl, Function::Adopt); +} + +} // namespace WTF + +struct A { + static void b(); }; RefCountable* make_obj(); @@ -151,6 +207,58 @@ struct RefCountableWithLambdaCapturingThis { }; call(lambda); } + + void method_captures_this_unsafe_capture_local_var_explicitly() { + RefCountable* x = make_obj(); + call([this, protectedThis = RefPtr { this }, x]() { + // expected-warning@-1{{Captured raw-pointer 'x' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} + nonTrivial(); + x->method(); + }); + } + + void method_captures_this_with_other_protected_var() { + RefCountable* x = make_obj(); + call([this, protectedX = RefPtr { x }]() { + // expected-warning@-1{{Captured raw-pointer 'this' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} + nonTrivial(); + protectedX->method(); + }); + } + + void method_captures_this_unsafe_capture_local_var_explicitly_with_deref() { + RefCountable* x = make_obj(); + call([this, protectedThis = Ref { *this }, x]() { + // expected-warning@-1{{Captured raw-pointer 'x' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} + nonTrivial(); + x->method(); + }); + } + + void method_captures_this_unsafe_local_var_via_vardecl() { + RefCountable* x = make_obj(); + auto lambda = [this, protectedThis = Ref { *this }, x]() { + // expected-warning@-1{{Captured raw-pointer 'x' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}} + nonTrivial(); + x->method(); + }; + call(lambda); + } + + void method_captures_this_with_guardian() { + auto lambda = [this, protectedThis = Ref { *this }]() { + nonTrivial(); + }; + call(lambda); + } + + void method_captures_this_with_guardian_refPtr() { + auto lambda = [this, protectedThis = RefPtr { &*this }]() { + nonTrivial(); + }; + call(lambda); + } + }; struct NonRefCountableWithLambdaCapturingThis { @@ -185,3 +293,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/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/CIR/global-var-simple.cpp b/clang/test/CIR/global-var-simple.cpp index 5230ff53f87d7..bbd452655a01b 100644 --- a/clang/test/CIR/global-var-simple.cpp +++ b/clang/test/CIR/global-var-simple.cpp @@ -57,3 +57,42 @@ _BitInt(20) sb20; unsigned _BitInt(48) ub48; // CHECK: cir.global @ub48 : !cir.int + +_Float16 f16; +// CHECK: cir.global @f16 : !cir.f16 + +__bf16 bf16; +// CHECK: cir.global @bf16 : !cir.bf16 + +float f; +// CHECK: cir.global @f : !cir.float + +double d; +// CHECK: cir.global @d : !cir.double + +long double ld; +// CHECK: cir.global @ld : !cir.long_double + +__float128 f128; +// CHECK: cir.global @f128 : !cir.f128 + +void *vp; +// CHECK: cir.global @vp : !cir.ptr + +int *ip; +// CHECK: cir.global @ip : !cir.ptr> + +double *dp; +// CHECK: cir.global @dp : !cir.ptr + +char **cpp; +// CHECK: cir.global @cpp : !cir.ptr>> + +void (*fp)(); +// CHECK: cir.global @fp : !cir.ptr> + +int (*fpii)(int); +// CHECK: cir.global @fpii : !cir.ptr (!cir.int)>> + +void (*fpvar)(int, ...); +// CHECK: cir.global @fpvar : !cir.ptr, ...)>> 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.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/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/fmv-mix-explicit-implicit-default.c b/clang/test/CodeGen/AArch64/fmv-mix-explicit-implicit-default.c new file mode 100644 index 0000000000000..032738fb9664d --- /dev/null +++ b/clang/test/CodeGen/AArch64/fmv-mix-explicit-implicit-default.c @@ -0,0 +1,221 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fmv -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NOFMV + +int implicit_default_decl_first(void); +__attribute__((target_version("default"))) int implicit_default_decl_first(void) { return 1; } +int caller1(void) { return implicit_default_decl_first(); } + +__attribute__((target_version("default"))) int explicit_default_def_first(void) { return 2; } +int explicit_default_def_first(void); +int caller2(void) { return explicit_default_def_first(); } + +int implicit_default_def_first(void) { return 3; } +__attribute__((target_version("default"))) int implicit_default_def_first(void); +int caller3(void) { return implicit_default_def_first(); } + +__attribute__((target_version("default"))) int explicit_default_decl_first(void); +int explicit_default_decl_first(void) { return 4; } +int caller4(void) { return explicit_default_decl_first(); } + +int no_def_implicit_default_first(void); +__attribute__((target_version("default"))) int no_def_implicit_default_first(void); +int caller5(void) { return no_def_implicit_default_first(); } + +__attribute__((target_version("default"))) int no_def_explicit_default_first(void); +int no_def_explicit_default_first(void); +int caller6(void) { return no_def_explicit_default_first(); } +//. +// CHECK: @implicit_default_decl_first = weak_odr ifunc i32 (), ptr @implicit_default_decl_first.resolver +// CHECK: @explicit_default_def_first = weak_odr ifunc i32 (), ptr @explicit_default_def_first.resolver +// CHECK: @implicit_default_def_first = weak_odr ifunc i32 (), ptr @implicit_default_def_first.resolver +// CHECK: @explicit_default_decl_first = weak_odr ifunc i32 (), ptr @explicit_default_decl_first.resolver +//. +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@implicit_default_decl_first.default +// CHECK-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@caller1 +// CHECK-SAME: () #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @implicit_default_decl_first() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@explicit_default_def_first.default +// CHECK-SAME: () #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@caller2 +// CHECK-SAME: () #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @explicit_default_def_first() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@implicit_default_def_first.default +// CHECK-SAME: () #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@caller3 +// CHECK-SAME: () #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @implicit_default_def_first() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@explicit_default_decl_first.default +// CHECK-SAME: () #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@caller4 +// CHECK-SAME: () #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @explicit_default_decl_first() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: declare i32 @no_def_implicit_default_first() #[[ATTR2:[0-9]+]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@caller5 +// CHECK-SAME: () #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @no_def_implicit_default_first() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: declare i32 @no_def_explicit_default_first() #[[ATTR2]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@caller6 +// CHECK-SAME: () #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @no_def_explicit_default_first() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK-LABEL: define {{[^@]+}}@implicit_default_decl_first.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: ret ptr @implicit_default_decl_first.default +// +// +// CHECK-LABEL: define {{[^@]+}}@explicit_default_def_first.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: ret ptr @explicit_default_def_first.default +// +// +// CHECK-LABEL: define {{[^@]+}}@implicit_default_def_first.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: ret ptr @implicit_default_def_first.default +// +// +// CHECK-LABEL: define {{[^@]+}}@explicit_default_decl_first.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: ret ptr @explicit_default_decl_first.default +// +// +// CHECK: declare i32 @no_def_implicit_default_first.default() #[[ATTR2]] +// +// +// CHECK: declare i32 @no_def_explicit_default_first.default() #[[ATTR2]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller1 +// CHECK-NOFMV-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @implicit_default_decl_first() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@implicit_default_decl_first +// CHECK-NOFMV-SAME: () #[[ATTR1:[0-9]+]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 1 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller2 +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @explicit_default_def_first() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@explicit_default_def_first +// CHECK-NOFMV-SAME: () #[[ATTR1]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 2 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@implicit_default_def_first +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 3 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller3 +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @implicit_default_def_first() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller4 +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @explicit_default_decl_first() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@explicit_default_decl_first +// CHECK-NOFMV-SAME: () #[[ATTR1]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 4 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller5 +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @no_def_implicit_default_first() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: declare i32 @no_def_implicit_default_first() #[[ATTR2:[0-9]+]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller6 +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @no_def_explicit_default_first() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: declare i32 @no_def_explicit_default_first() #[[ATTR2]] +//. 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_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/pure-scalable-args.c b/clang/test/CodeGen/AArch64/pure-scalable-args.c index a8c3dd9288a5b..b03011e70b6a6 100644 --- a/clang/test/CodeGen/AArch64/pure-scalable-args.c +++ b/clang/test/CodeGen/AArch64/pure-scalable-args.c @@ -459,3 +459,22 @@ void test_va_arg(int n, ...) { // CHECK-DARWIN-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %ap) // CHECK-DARWIN-NEXT: ret void // CHECK-DARWIN-NEXT: } + +// Regression test for incorrect passing of SVE vector tuples +// The whole `y` need to be passed indirectly. +void test_tuple_reg_count(svfloat32_t x, svfloat32x2_t y) { + void test_tuple_reg_count_callee(svfloat32_t, svfloat32_t, svfloat32_t, svfloat32_t, + svfloat32_t, svfloat32_t, svfloat32_t, svfloat32x2_t); + test_tuple_reg_count_callee(x, x, x, x, x, x, x, y); +} +// CHECK-AAPCS: declare void @test_tuple_reg_count_callee(, , , , , , , ptr noundef) +// CHECK-DARWIN: declare void @test_tuple_reg_count_callee(, , , , , , , , ) + +// Regression test for incorrect passing of SVE vector tuples +// The whole `y` need to be passed indirectly. +void test_tuple_reg_count_bool(svboolx4_t x, svboolx4_t y) { + void test_tuple_reg_count_bool_callee(svboolx4_t, svboolx4_t); + test_tuple_reg_count_bool_callee(x, y); +} +// CHECK-AAPCS: declare void @test_tuple_reg_count_bool_callee(, , , , ptr noundef) +// CHECK-DARWIN: declare void @test_tuple_reg_count_bool_callee(, , , , , , , ) 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/sve2p1-intrinsics/acle_sve2p1_st1_single.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_st1_single.c index 6c1969c446248..058ff81bdf126 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_st1_single.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_st1_single.c @@ -30,14 +30,14 @@ // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4i32( [[ZT]], [[TMP0]], ptr [[BASE]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1wq_u32u10__SVBool_tPKju12__SVUint32_t +// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1wq_u32u10__SVBool_tPju12__SVUint32_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0:[0-9]+]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4i32( [[ZT]], [[TMP0]], ptr [[BASE]]) // CPP-CHECK-NEXT: ret void // -void test_svst1wq_u32(svbool_t pred, uint32_t const * base, svuint32_t zt) { +void test_svst1wq_u32(svbool_t pred, uint32_t *base, svuint32_t zt) { SVE_ACLE_FUNC(svst1wq, _u32, , )(pred, base, zt); } @@ -51,7 +51,7 @@ void test_svst1wq_u32(svbool_t pred, uint32_t const * base, svuint32_t zt) { // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4i32( [[ZT]], [[TMP0]], ptr [[TMP3]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1wq_vnum_u32u10__SVBool_tPKju12__SVUint32_t +// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1wq_vnum_u32u10__SVBool_tPju12__SVUint32_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) @@ -61,7 +61,7 @@ void test_svst1wq_u32(svbool_t pred, uint32_t const * base, svuint32_t zt) { // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4i32( [[ZT]], [[TMP0]], ptr [[TMP3]]) // CPP-CHECK-NEXT: ret void // -void test_svst1wq_vnum_u32(svbool_t pred, uint32_t const * base, svuint32_t zt) { +void test_svst1wq_vnum_u32(svbool_t pred, uint32_t *base, svuint32_t zt) { SVE_ACLE_FUNC(svst1wq_vnum, _u32, , )(pred, base, 1, zt); } @@ -72,14 +72,14 @@ void test_svst1wq_vnum_u32(svbool_t pred, uint32_t const * base, svuint32_t zt) // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4i32( [[ZT]], [[TMP0]], ptr [[BASE]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1wq_s32u10__SVBool_tPKiu11__SVInt32_t +// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1wq_s32u10__SVBool_tPiu11__SVInt32_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4i32( [[ZT]], [[TMP0]], ptr [[BASE]]) // CPP-CHECK-NEXT: ret void // -void test_svst1wq_s32(svbool_t pred, int32_t const * base, svint32_t zt) { +void test_svst1wq_s32(svbool_t pred, int32_t *base, svint32_t zt) { SVE_ACLE_FUNC(svst1wq, _s32, , )(pred, base, zt); } @@ -93,7 +93,7 @@ void test_svst1wq_s32(svbool_t pred, int32_t const * base, svint32_t zt) { // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4i32( [[ZT]], [[TMP0]], ptr [[TMP3]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1wq_vnum_s32u10__SVBool_tPKiu11__SVInt32_t +// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1wq_vnum_s32u10__SVBool_tPiu11__SVInt32_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) @@ -103,7 +103,7 @@ void test_svst1wq_s32(svbool_t pred, int32_t const * base, svint32_t zt) { // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4i32( [[ZT]], [[TMP0]], ptr [[TMP3]]) // CPP-CHECK-NEXT: ret void // -void test_svst1wq_vnum_s32(svbool_t pred, int32_t const * base, svint32_t zt) { +void test_svst1wq_vnum_s32(svbool_t pred, int32_t *base, svint32_t zt) { SVE_ACLE_FUNC(svst1wq_vnum, _s32, , )(pred, base, 1, zt); } @@ -114,14 +114,14 @@ void test_svst1wq_vnum_s32(svbool_t pred, int32_t const * base, svint32_t zt) { // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4f32( [[ZT]], [[TMP0]], ptr [[BASE]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1wq_f32u10__SVBool_tPKfu13__SVFloat32_t +// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1wq_f32u10__SVBool_tPfu13__SVFloat32_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4f32( [[ZT]], [[TMP0]], ptr [[BASE]]) // CPP-CHECK-NEXT: ret void // -void test_svst1wq_f32(svbool_t pred, float32_t const * base, svfloat32_t zt) { +void test_svst1wq_f32(svbool_t pred, float32_t *base, svfloat32_t zt) { SVE_ACLE_FUNC(svst1wq, _f32, , )(pred, base, zt); } @@ -135,7 +135,7 @@ void test_svst1wq_f32(svbool_t pred, float32_t const * base, svfloat32_t zt) { // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4f32( [[ZT]], [[TMP0]], ptr [[TMP3]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1wq_vnum_f32u10__SVBool_tPKfu13__SVFloat32_t +// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1wq_vnum_f32u10__SVBool_tPfu13__SVFloat32_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) @@ -145,7 +145,7 @@ void test_svst1wq_f32(svbool_t pred, float32_t const * base, svfloat32_t zt) { // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1wq.nxv4f32( [[ZT]], [[TMP0]], ptr [[TMP3]]) // CPP-CHECK-NEXT: ret void // -void test_svst1wq_vnum_f32(svbool_t pred, float32_t const * base, svfloat32_t zt) { +void test_svst1wq_vnum_f32(svbool_t pred, float32_t *base, svfloat32_t zt) { SVE_ACLE_FUNC(svst1wq_vnum, _f32, , )(pred, base, 1, zt); } @@ -159,14 +159,14 @@ void test_svst1wq_vnum_f32(svbool_t pred, float32_t const * base, svfloat32_t zt // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2i64( [[ZT]], [[TMP0]], ptr [[BASE]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1dq_u64u10__SVBool_tPKmu12__SVUint64_t +// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1dq_u64u10__SVBool_tPmu12__SVUint64_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2i64( [[ZT]], [[TMP0]], ptr [[BASE]]) // CPP-CHECK-NEXT: ret void // -void test_svst1dq_u64(svbool_t pred, uint64_t const * base, svuint64_t zt) { +void test_svst1dq_u64(svbool_t pred, uint64_t *base, svuint64_t zt) { SVE_ACLE_FUNC(svst1dq, _u64, , )(pred, base, zt); } @@ -180,7 +180,7 @@ void test_svst1dq_u64(svbool_t pred, uint64_t const * base, svuint64_t zt) { // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2i64( [[ZT]], [[TMP0]], ptr [[TMP2]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1dq_vnum_u64u10__SVBool_tPKmu12__SVUint64_t +// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1dq_vnum_u64u10__SVBool_tPmu12__SVUint64_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) @@ -190,7 +190,7 @@ void test_svst1dq_u64(svbool_t pred, uint64_t const * base, svuint64_t zt) { // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2i64( [[ZT]], [[TMP0]], ptr [[TMP2]]) // CPP-CHECK-NEXT: ret void // -void test_svst1dq_vnum_u64(svbool_t pred, uint64_t const * base, svuint64_t zt) { +void test_svst1dq_vnum_u64(svbool_t pred, uint64_t *base, svuint64_t zt) { SVE_ACLE_FUNC(svst1dq_vnum, _u64, , )(pred, base, -8, zt); } @@ -201,14 +201,14 @@ void test_svst1dq_vnum_u64(svbool_t pred, uint64_t const * base, svuint64_t zt) // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2i64( [[ZT]], [[TMP0]], ptr [[BASE]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1dq_s64u10__SVBool_tPKlu11__SVInt64_t +// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1dq_s64u10__SVBool_tPlu11__SVInt64_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2i64( [[ZT]], [[TMP0]], ptr [[BASE]]) // CPP-CHECK-NEXT: ret void // -void test_svst1dq_s64(svbool_t pred, int64_t const * base, svint64_t zt) { +void test_svst1dq_s64(svbool_t pred, int64_t *base, svint64_t zt) { SVE_ACLE_FUNC(svst1dq, _s64, , )(pred, base, zt); } @@ -222,7 +222,7 @@ void test_svst1dq_s64(svbool_t pred, int64_t const * base, svint64_t zt) { // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2i64( [[ZT]], [[TMP0]], ptr [[TMP2]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1dq_vnum_s64u10__SVBool_tPKlu11__SVInt64_t +// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1dq_vnum_s64u10__SVBool_tPlu11__SVInt64_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) @@ -232,7 +232,7 @@ void test_svst1dq_s64(svbool_t pred, int64_t const * base, svint64_t zt) { // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2i64( [[ZT]], [[TMP0]], ptr [[TMP2]]) // CPP-CHECK-NEXT: ret void // -void test_svst1dq_vnum_s64(svbool_t pred, int64_t const * base, svint64_t zt) { +void test_svst1dq_vnum_s64(svbool_t pred, int64_t *base, svint64_t zt) { SVE_ACLE_FUNC(svst1dq_vnum, _s64, , )(pred, base, -8, zt); } @@ -243,14 +243,14 @@ void test_svst1dq_vnum_s64(svbool_t pred, int64_t const * base, svint64_t zt) { // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2f64( [[ZT]], [[TMP0]], ptr [[BASE]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1dq_f64u10__SVBool_tPKdu13__SVFloat64_t +// CPP-CHECK-LABEL: define dso_local void @_Z16test_svst1dq_f64u10__SVBool_tPdu13__SVFloat64_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2f64( [[ZT]], [[TMP0]], ptr [[BASE]]) // CPP-CHECK-NEXT: ret void // -void test_svst1dq_f64(svbool_t pred, float64_t const * base, svfloat64_t zt) { +void test_svst1dq_f64(svbool_t pred, float64_t *base, svfloat64_t zt) { SVE_ACLE_FUNC(svst1dq, _f64, , )(pred, base, zt); } @@ -264,7 +264,7 @@ void test_svst1dq_f64(svbool_t pred, float64_t const * base, svfloat64_t zt) { // CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2f64( [[ZT]], [[TMP0]], ptr [[TMP2]]) // CHECK-NEXT: ret void // -// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1dq_vnum_f64u10__SVBool_tPKdu13__SVFloat64_t +// CPP-CHECK-LABEL: define dso_local void @_Z21test_svst1dq_vnum_f64u10__SVBool_tPdu13__SVFloat64_t // CPP-CHECK-SAME: ( [[PRED:%.*]], ptr noundef [[BASE:%.*]], [[ZT:%.*]]) #[[ATTR0]] { // CPP-CHECK-NEXT: entry: // CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PRED]]) @@ -274,6 +274,6 @@ void test_svst1dq_f64(svbool_t pred, float64_t const * base, svfloat64_t zt) { // CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1dq.nxv2f64( [[ZT]], [[TMP0]], ptr [[TMP2]]) // CPP-CHECK-NEXT: ret void // -void test_svst1dq_vnum_f64(svbool_t pred, float64_t const * base, svfloat64_t zt) { +void test_svst1dq_vnum_f64(svbool_t pred, float64_t *base, svfloat64_t zt) { SVE_ACLE_FUNC(svst1dq_vnum, _f64, , )(pred, base, -8, zt); } diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_store.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_store.c index 657787e851ee2..b91780304dacb 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_store.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_store.c @@ -1931,6 +1931,22 @@ void test_svst1q_scatter_u64index_s16(svbool_t pg, int16_t *base, svuint64_t idx SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _s16)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv8i16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_s16u10__SVBool_tPsu11__SVInt64_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv8i16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_s16(svbool_t pg, int16_t *base, svint64_t idx, svint16_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _s16)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_u16( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -1947,6 +1963,22 @@ void test_svst1q_scatter_u64index_u16(svbool_t pg, uint16_t *base, svuint64_t id SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _u16)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv8i16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_u16u10__SVBool_tPtu11__SVInt64_tu12__SVUint16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv8i16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_u16(svbool_t pg, uint16_t *base, svint64_t idx, svuint16_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _u16)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_s32( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -1963,6 +1995,22 @@ void test_svst1q_scatter_u64index_s32(svbool_t pg, int32_t *base, svuint64_t idx SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _s32)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv4i32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_s32u10__SVBool_tPiu11__SVInt64_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv4i32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_s32(svbool_t pg, int32_t *base, svint64_t idx, svint32_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _s32)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_u32( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -1979,6 +2027,22 @@ void test_svst1q_scatter_u64index_u32(svbool_t pg, uint32_t *base, svuint64_t id SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _u32)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv4i32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_u32u10__SVBool_tPju11__SVInt64_tu12__SVUint32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv4i32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_u32(svbool_t pg, uint32_t *base, svint64_t idx, svuint32_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _u32)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_s64( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -1995,6 +2059,22 @@ void test_svst1q_scatter_u64index_s64(svbool_t pg, int64_t *base, svuint64_t idx SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _s64)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv2i64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_s64u10__SVBool_tPlu11__SVInt64_tS1_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv2i64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_s64(svbool_t pg, int64_t *base, svint64_t idx, svint64_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _s64)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_u64( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2011,6 +2091,22 @@ void test_svst1q_scatter_u64index_u64(svbool_t pg, uint64_t *base, svuint64_t id SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _u64)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv2i64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_u64u10__SVBool_tPmu11__SVInt64_tu12__SVUint64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv2i64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_u64(svbool_t pg, uint64_t *base, svint64_t idx, svuint64_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _u64)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_bf16( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2027,6 +2123,22 @@ void test_svst1q_scatter_u64index_bf16(svbool_t pg, bfloat16_t *base, svuint64_t SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _bf16)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_bf16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv8bf16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64index_bf16u10__SVBool_tPu6__bf16u11__SVInt64_tu14__SVBfloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv8bf16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_bf16(svbool_t pg, bfloat16_t *base, svint64_t idx, svbfloat16_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _bf16)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_f16( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2043,6 +2155,22 @@ void test_svst1q_scatter_u64index_f16(svbool_t pg, float16_t *base, svuint64_t i SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _f16)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv8f16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_f16u10__SVBool_tPDhu11__SVInt64_tu13__SVFloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv8f16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_f16(svbool_t pg, float16_t *base, svint64_t idx, svfloat16_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _f16)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_f32( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2059,6 +2187,22 @@ void test_svst1q_scatter_u64index_f32(svbool_t pg, float32_t *base, svuint64_t i SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _f32)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv4f32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_f32u10__SVBool_tPfu11__SVInt64_tu13__SVFloat32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv4f32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_f32(svbool_t pg, float32_t *base, svint64_t idx, svfloat32_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _f32)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64index_f64( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2075,6 +2219,22 @@ void test_svst1q_scatter_u64index_f64(svbool_t pg, float64_t *base, svuint64_t i SVE_ACLE_FUNC(svst1q_scatter_, u64, index, _f64)(pg, base, idx, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64index_f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv2f64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64index_f64u10__SVBool_tPdu11__SVInt64_tu13__SVFloat64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.index.nxv2f64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[IDX:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64index_f64(svbool_t pg, float64_t *base, svint64_t idx, svfloat64_t data) { + SVE_ACLE_FUNC(svst1q_scatter_, s64, index, _f64)(pg, base, idx, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64base_index_s16( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2271,6 +2431,22 @@ void test_svst1q_scatter_u64offset_s8(svbool_t pg, int8_t *base, svuint64_t off, SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_s8)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_s8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv16i8( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64offset_s8u10__SVBool_tPau11__SVInt64_tu10__SVInt8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv16i8( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_s8(svbool_t pg, int8_t *base, svint64_t off, svint8_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_s8)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_u8( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2287,6 +2463,22 @@ void test_svst1q_scatter_u64offset_u8(svbool_t pg, uint8_t *base, svuint64_t off SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_u8)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_u8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv16i8( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z32test_svst1q_scatter_s64offset_u8u10__SVBool_tPhu11__SVInt64_tu11__SVUint8_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv16i8( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_u8(svbool_t pg, uint8_t *base, svint64_t off, svuint8_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_u8)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_s16( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2303,6 +2495,22 @@ void test_svst1q_scatter_u64offset_s16(svbool_t pg, int16_t *base, svuint64_t of SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_s16)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_s16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv8i16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_s16u10__SVBool_tPsu11__SVInt64_tu11__SVInt16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv8i16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_s16(svbool_t pg, int16_t *base, svint64_t off, svint16_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_s16)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_u16( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2319,6 +2527,22 @@ void test_svst1q_scatter_u64offset_u16(svbool_t pg, uint16_t *base, svuint64_t o SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_u16)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_u16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv8i16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_u16u10__SVBool_tPtu11__SVInt64_tu12__SVUint16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv8i16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_u16(svbool_t pg, uint16_t *base, svint64_t off, svuint16_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_u16)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_s32( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2335,6 +2559,22 @@ void test_svst1q_scatter_u64offset_s32(svbool_t pg, int32_t *base, svuint64_t of SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_s32)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_s32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv4i32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_s32u10__SVBool_tPiu11__SVInt64_tu11__SVInt32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv4i32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_s32(svbool_t pg, int32_t *base, svint64_t off, svint32_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_s32)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_u32( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2351,6 +2591,22 @@ void test_svst1q_scatter_u64offset_u32(svbool_t pg, uint32_t *base, svuint64_t o SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_u32)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv4i32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_u32u10__SVBool_tPju11__SVInt64_tu12__SVUint32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv4i32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_u32(svbool_t pg, uint32_t *base, svint64_t off, svuint32_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_u32)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_s64( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2367,6 +2623,22 @@ void test_svst1q_scatter_u64offset_s64(svbool_t pg, int64_t *base, svuint64_t of SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_s64)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_s64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv2i64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_s64u10__SVBool_tPlu11__SVInt64_tS1_( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv2i64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_s64(svbool_t pg, int64_t *base, svint64_t off, svint64_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_s64)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_u64( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2383,6 +2655,22 @@ void test_svst1q_scatter_u64offset_u64(svbool_t pg, uint64_t *base, svuint64_t o SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_u64)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv2i64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_u64u10__SVBool_tPmu11__SVInt64_tu12__SVUint64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv2i64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_u64(svbool_t pg, uint64_t *base, svint64_t off, svuint64_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_u64)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_bf16( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2399,6 +2687,22 @@ void test_svst1q_scatter_u64offset_bf16(svbool_t pg, bfloat16_t *base, svuint64_ SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_bf16)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_bf16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv8bf16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z34test_svst1q_scatter_s64offset_bf16u10__SVBool_tPu6__bf16u11__SVInt64_tu14__SVBfloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv8bf16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_bf16(svbool_t pg, bfloat16_t *base, svint64_t off, svbfloat16_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_bf16)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_f16( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2415,6 +2719,22 @@ void test_svst1q_scatter_u64offset_f16(svbool_t pg, float16_t *base, svuint64_t SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_f16)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_f16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv8f16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_f16u10__SVBool_tPDhu11__SVInt64_tu13__SVFloat16_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv8f16( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_f16(svbool_t pg, float16_t *base, svint64_t off, svfloat16_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_f16)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_f32( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2431,6 +2751,22 @@ void test_svst1q_scatter_u64offset_f32(svbool_t pg, float32_t *base, svuint64_t SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_f32)(pg, base, off, data); } +// CHECK-LABEL: @test_svst1q_scatter_s64offset_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv4f32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_f32u10__SVBool_tPfu11__SVInt64_tu13__SVFloat32_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv4f32( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_f32(svbool_t pg, float32_t *base, svint64_t off, svfloat32_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_f32)(pg, base, off, data); +} + // CHECK-LABEL: @test_svst1q_scatter_u64offset_f64( // CHECK-NEXT: entry: // CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) @@ -2446,3 +2782,19 @@ void test_svst1q_scatter_u64offset_f32(svbool_t pg, float32_t *base, svuint64_t void test_svst1q_scatter_u64offset_f64(svbool_t pg, float64_t *base, svuint64_t off, svfloat64_t data) { SVE_ACLE_FUNC(svst1q_scatter_,u64,offset,_f64)(pg, base, off, data); } + +// CHECK-LABEL: @test_svst1q_scatter_s64offset_f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv2f64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: @_Z33test_svst1q_scatter_s64offset_f64u10__SVBool_tPdu11__SVInt64_tu13__SVFloat64_t( +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.convert.from.svbool.nxv1i1( [[PG:%.*]]) +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sve.st1q.scatter.vector.offset.nxv2f64( [[DATA:%.*]], [[TMP0]], ptr [[BASE:%.*]], [[OFF:%.*]]) +// CPP-CHECK-NEXT: ret void +// +void test_svst1q_scatter_s64offset_f64(svbool_t pg, float64_t *base, svint64_t off, svfloat64_t data) { + SVE_ACLE_FUNC(svst1q_scatter_,s64,offset,_f64)(pg, base, off, data); +} 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/X86/avx10_2_512convert-builtins.c b/clang/test/CodeGen/X86/avx10_2_512convert-builtins.c index e71cc0c9ad6b0..6662e0cbf8a91 100644 --- a/clang/test/CodeGen/X86/avx10_2_512convert-builtins.c +++ b/clang/test/CodeGen/X86/avx10_2_512convert-builtins.c @@ -299,7 +299,7 @@ __m512h test_mm512_cvtpbf8_ph(__m256i A) { return _mm512_cvtpbf8_ph(A); } -__m512h test_mm512_mask_cvtpbf8_ph(__m512h S, __mmask16 M, __m256i A) { +__m512h test_mm512_mask_cvtpbf8_ph(__m512h S, __mmask32 M, __m256i A) { // CHECK-LABEL: @test_mm512_mask_cvtpbf8_ph // CHECK: sext <32 x i8> %{{.*}} to <32 x i16> // CHECK: @llvm.x86.avx512.pslli.w.512 @@ -308,7 +308,7 @@ __m512h test_mm512_mask_cvtpbf8_ph(__m512h S, __mmask16 M, __m256i A) { return _mm512_mask_cvtpbf8_ph(S, M, A); } -__m512h test_mm512_maskz_cvtpbf8_ph(__mmask16 M, __m256i A) { +__m512h test_mm512_maskz_cvtpbf8_ph(__mmask32 M, __m256i A) { // CHECK-LABEL: @test_mm512_maskz_cvtpbf8_ph // CHECK: sext <32 x i8> %{{.*}} to <32 x i16> // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}} diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index be4c7f07e9215..6b3cad5708835 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -1043,7 +1043,7 @@ int test12_a, test12_b; // NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]] // NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]] // NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 -// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]] // NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP0]], ptr @test12_b, align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4), align 4, !tbaa [[TBAA2]] @@ -1085,7 +1085,7 @@ int test12_a, test12_b; // NO-SANITIZE-WITHOUT-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR9:[0-9]+]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 -// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 [[TMP0]], ptr @test12_b, align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4), align 4, !tbaa [[TBAA2]] 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..951401c498deb 100644 --- a/clang/test/CodeGen/attr-target-version.c +++ b/clang/test/CodeGen/attr-target-version.c @@ -143,10 +143,12 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK: @fmv_d = internal ifunc i32 (), ptr @fmv_d.resolver // CHECK: @fmv_c = weak_odr ifunc void (), ptr @fmv_c.resolver // CHECK: @fmv_inline = weak_odr ifunc i32 (), ptr @fmv_inline.resolver +// CHECK: @reca = weak_odr ifunc void (), ptr @reca.resolver // CHECK: @unused_with_default_def = weak_odr ifunc i32 (), ptr @unused_with_default_def.resolver // CHECK: @unused_with_implicit_default_def = weak_odr ifunc i32 (), ptr @unused_with_implicit_default_def.resolver // CHECK: @unused_with_implicit_forward_default_def = weak_odr ifunc i32 (), ptr @unused_with_implicit_forward_default_def.resolver // CHECK: @default_def_with_version_decls = weak_odr ifunc i32 (), ptr @default_def_with_version_decls.resolver +// CHECK: @recb = weak_odr ifunc void (), ptr @recb.resolver //. // CHECK: Function Attrs: noinline nounwind optnone // CHECK-LABEL: define {{[^@]+}}@fmv._MflagmMfp16fmlMrng @@ -287,8 +289,15 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // // // CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@fmv_default.default +// CHECK-SAME: () #[[ATTR9]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 111 +// +// +// CHECK: Function Attrs: noinline nounwind optnone // CHECK-LABEL: define {{[^@]+}}@fmv_c._Mssbs -// CHECK-SAME: () #[[ATTR16:[0-9]+]] { +// CHECK-SAME: () #[[ATTR17:[0-9]+]] { // CHECK-NEXT: entry: // CHECK-NEXT: ret void // @@ -313,13 +322,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: define {{[^@]+}}@fmv_default -// CHECK-SAME: () #[[ATTR9]] { -// CHECK-NEXT: entry: -// CHECK-NEXT: ret i32 111 -// -// -// CHECK: Function Attrs: noinline nounwind optnone // CHECK-LABEL: define {{[^@]+}}@recur // CHECK-SAME: () #[[ATTR15]] { // CHECK-NEXT: entry: @@ -460,24 +462,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 +494,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 +540,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 +562,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 +767,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: @@ -895,12 +897,25 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: ret ptr @fmv_inline.default // // +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@reca.default +// CHECK-SAME: () #[[ATTR9]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @recb() +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@reca.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: ret ptr @reca.default +// +// // CHECK-LABEL: define {{[^@]+}}@unused_with_default_def.resolver() comdat { // 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 +928,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 +956,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: @@ -959,6 +974,26 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de // CHECK-NEXT: ret ptr @default_def_with_version_decls.default // // +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@recb.default +// CHECK-SAME: () #[[ATTR9]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @func() +// CHECK-NEXT: ret void +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@func +// CHECK-SAME: () #[[ATTR15]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@recb.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: ret ptr @recb.default +// +// // CHECK-NOFMV: Function Attrs: noinline nounwind optnone // CHECK-NOFMV-LABEL: define {{[^@]+}}@foo // CHECK-NOFMV-SAME: () #[[ATTR0:[0-9]+]] { diff --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c index f6c4880e70a15..5e6b317a99969 100644 --- a/clang/test/CodeGen/bounds-checking.c +++ b/clang/test/CodeGen/bounds-checking.c @@ -1,7 +1,17 @@ -// RUN: %clang_cc1 -fsanitize=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s -// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s -// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -O3 -mllvm -bounds-checking-unique-traps -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTLOCAL -// RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -O3 -mllvm -ubsan-unique-traps -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTARRAY +// N.B. The clang driver defaults to -fsanitize-merge but clang_cc1 effectively +// defaults to -fno-sanitize-merge. +// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s +// RUN: %clang_cc1 -fsanitize=array-bounds -O -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s +// +// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s +// +// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTLOCAL +// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -fno-sanitize-merge -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTLOCAL +// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -fsanitize-merge=local-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s --check-prefixes=NOOPTLOCAL +// +// RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTARRAY +// RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -fno-sanitize-merge -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefixes=NOOPTARRAY +// RUN: %clang_cc1 -fsanitize=array-bounds -fsanitize-trap=array-bounds -fsanitize-merge=array-bounds -O3 -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s --check-prefixes=NOOPTARRAY // // REQUIRES: x86-registered-target @@ -43,7 +53,7 @@ int f4(int i) { return b[i]; } -// Union flexible-array memebers are a C99 extension. All array members with a +// Union flexible-array members are a C99 extension. All array members with a // constant size should be considered FAMs. union U { int a[0]; int b[1]; int c[2]; }; @@ -72,13 +82,17 @@ int f7(union U *u, int i) { char B[10]; char B2[10]; // CHECK-LABEL: @f8 +// Check the label to prevent spuriously matching ubsantraps from other +// functions. +// NOOPTLOCAL-LABEL: @f8 +// NOOPTARRAY-LABEL: @f8 void f8(int i, int k) { - // NOOPTLOCAL: call void @llvm.ubsantrap(i8 3) - // NOOPTARRAY: call void @llvm.ubsantrap(i8 18) + // NOOPTLOCAL: call void @llvm.ubsantrap(i8 3) #[[ATTR1:[0-9]+]] + // NOOPTARRAY: call void @llvm.ubsantrap(i8 18) #[[ATTR2:[0-9]+]] B[i] = '\0'; - // NOOPTLOCAL: call void @llvm.ubsantrap(i8 5) - // NOOPTARRAY: call void @llvm.ubsantrap(i8 18) + // NOOPTLOCAL: call void @llvm.ubsantrap(i8 5) #[[ATTR1:[0-9]+]] + // NOOPTARRAY: call void @llvm.ubsantrap(i8 18) #[[ATTR2:[0-9]+]] B2[k] = '\0'; } @@ -90,3 +104,5 @@ struct S { struct S *f9(int i) { return &s[i]; } +// NOOPTLOCAL: attributes #[[ATTR1]] = { nomerge noreturn nounwind } +// NOOPTARRAY: attributes #[[ATTR2]] = { nomerge noreturn nounwind } 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/sanitize-type-globals.cpp b/clang/test/CodeGen/sanitize-type-globals.cpp new file mode 100644 index 0000000000000..7cb8de8b238cc --- /dev/null +++ b/clang/test/CodeGen/sanitize-type-globals.cpp @@ -0,0 +1,58 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --filter-out "attributes" --filter-out "attributes #" --version 5 +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type | FileCheck -check-prefix=CHECK %s + +//. +// CHECK: @x = global %struct.CompleteS zeroinitializer, align 8 +// CHECK: @y = external global %struct.S, align 1 +// CHECK: @__tysan_shadow_memory_address = external global i64 +// CHECK: @__tysan_app_memory_mask = external global i64 +// CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat +// CHECK: @__tysan_v1_omnipotent_20char = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat +// CHECK: @__tysan_v1_int = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat +// CHECK: @__tysan_v1_any_20pointer = linkonce_odr constant { i64, i64, ptr, i64, [12 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [12 x i8] c"any pointer\00" }, comdat +// CHECK: @__tysan_v1_p1_20int = linkonce_odr constant { i64, i64, ptr, i64, [7 x i8] } { i64 2, i64 1, ptr @__tysan_v1_any_20pointer, i64 0, [7 x i8] c"p1 int\00" }, comdat +// CHECK: @__tysan_v1___ZTS9CompleteS = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, [15 x i8] } { i64 2, i64 2, ptr @__tysan_v1_int, i64 0, ptr @__tysan_v1_p1_20int, i64 8, [15 x i8] c"_ZTS9CompleteS\00" }, comdat +// CHECK: @llvm.used = appending global [7 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_p1_20int, ptr @__tysan_v1___ZTS9CompleteS], section "llvm.metadata" +// CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }] +//. +struct CompleteS { + int x; + int *ptr; +}; + +void f(CompleteS *); +CompleteS x; +// CHECK-LABEL: define dso_local void @_Z1gv( +// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { +// CHECK: [[ENTRY:.*:]] +// CHECK: call void @_Z1fP9CompleteS(ptr noundef @x) +// CHECK: ret void +// +void g() { f(&x); } + +typedef struct S IncompleteS; +void f(IncompleteS *); +extern IncompleteS y; +// CHECK-LABEL: define dso_local void @_Z1hv( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// CHECK: call void @_Z1fP1S(ptr noundef @y) +// CHECK: ret void +// +void h() { f(&y); } +//. +// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone sanitize_type "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK: attributes #[[ATTR1:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK: attributes #[[ATTR2:[0-9]+]] = { nounwind "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } +// CHECK: attributes #[[ATTR3:[0-9]+]] = { nounwind } +//. +// CHECK: [[META0:![0-9]+]] = !{ptr @x, [[META1:![0-9]+]]} +// CHECK: [[META1]] = !{!"_ZTS9CompleteS", [[META2:![0-9]+]], i64 0, [[META5:![0-9]+]], i64 8} +// CHECK: [[META2]] = !{!"int", [[META3:![0-9]+]], i64 0} +// CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0} +// CHECK: [[META4]] = !{!"Simple C++ TBAA"} +// CHECK: [[META5]] = !{!"p1 int", [[META6:![0-9]+]], i64 0} +// CHECK: [[META6]] = !{!"any pointer", [[META3]], i64 0} +// CHECK: [[META7:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} +// CHECK: [[META8:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} +//. 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 412ec7b09744e..486aa55f5b811 100644 --- a/clang/test/CodeGen/ubsan-trap-merge.c +++ b/clang/test/CodeGen/ubsan-trap-merge.c @@ -1,10 +1,22 @@ // 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 whether -ubsan-unique-traps attaches 'nomerge' to each ubsan call. +// 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 -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP -// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - | FileCheck %s --check-prefix=HANDLER -// 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-prefix=MINRT +// 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 -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 @@ -47,6 +59,85 @@ // 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; @@ -91,32 +182,90 @@ int f(int x) { // 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; } -// TRAP-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h( -// 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 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:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]] -// TRAP-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]] -// TRAP-NEXT: br i1 [[TMP3]], label %[[TRAP1:.*]], label %[[CONT2:.*]], !nosanitize [[META2]] -// TRAP: [[TRAP1]]: -// TRAP-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]] -// TRAP-NEXT: unreachable, !nosanitize [[META2]] -// TRAP: [[CONT2]]: -// TRAP-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]] -// TRAP-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]] -// TRAP-NEXT: [[COND:%.*]] = tail call i32 @llvm.smin.i32(i32 [[TMP5]], i32 [[TMP4]]) -// TRAP-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]] { @@ -163,6 +312,138 @@ int g(int x) { // 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; @@ -260,10 +541,196 @@ int h(int x, int y) { // 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); } -// TRAP: attributes #[[ATTR4]] = { nomerge noreturn nounwind } -// HANDLER: attributes #[[ATTR4]] = { nomerge noreturn nounwind } -// MINRT: 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/CodeGen/union-tbaa1.c b/clang/test/CodeGen/union-tbaa1.c index 7d44c9a3fbe6b..0f7a67cb7eccd 100644 --- a/clang/test/CodeGen/union-tbaa1.c +++ b/clang/test/CodeGen/union-tbaa1.c @@ -16,17 +16,17 @@ void bar(vect32 p[][2]); // CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARR]], i32 [[TMP0]] // CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP1]], [[NUM]] -// CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds nuw [4 x [2 x %union.vect32]], ptr [[TMP]], i32 0, i32 [[TMP0]] +// CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [4 x [2 x %union.vect32]], ptr [[TMP]], i32 0, i32 [[TMP0]] // CHECK-NEXT: store i32 [[MUL]], ptr [[ARRAYIDX2]], align 8, !tbaa [[TBAA6:![0-9]+]] // CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARR]], i32 [[TMP0]], i32 1 // CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX5]], align 4, !tbaa [[TBAA2]] // CHECK-NEXT: [[MUL6:%.*]] = mul i32 [[TMP2]], [[NUM]] -// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds nuw [4 x [2 x %union.vect32]], ptr [[TMP]], i32 0, i32 [[TMP0]], i32 1 +// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [4 x [2 x %union.vect32]], ptr [[TMP]], i32 0, i32 [[TMP0]], i32 1 // CHECK-NEXT: store i32 [[MUL6]], ptr [[ARRAYIDX8]], align 4, !tbaa [[TBAA6]] // CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[MUL]], 16 // CHECK-NEXT: store i32 [[TMP3]], ptr [[VEC]], align 4, !tbaa [[TBAA2]] // CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[INDEX]], align 4, !tbaa [[TBAA2]] -// CHECK-NEXT: [[ARRAYIDX14:%.*]] = getelementptr inbounds nuw [4 x [2 x %union.vect32]], ptr [[TMP]], i32 0, i32 [[TMP4]], i32 1 +// CHECK-NEXT: [[ARRAYIDX14:%.*]] = getelementptr inbounds [4 x [2 x %union.vect32]], ptr [[TMP]], i32 0, i32 [[TMP4]], i32 1 // CHECK-NEXT: [[ARRAYIDX15:%.*]] = getelementptr inbounds nuw i8, ptr [[ARRAYIDX14]], i32 2 // CHECK-NEXT: [[TMP5:%.*]] = load i16, ptr [[ARRAYIDX15]], align 2, !tbaa [[TBAA6]] // CHECK-NEXT: [[CONV16:%.*]] = zext i16 [[TMP5]] to i32 diff --git a/clang/test/CodeGenCXX/aarch64-mangle-sve-vectors.cpp b/clang/test/CodeGenCXX/aarch64-mangle-sve-vectors.cpp index 9f481e1f0f085..152be26948f28 100644 --- a/clang/test/CodeGenCXX/aarch64-mangle-sve-vectors.cpp +++ b/clang/test/CodeGenCXX/aarch64-mangle-sve-vectors.cpp @@ -141,13 +141,13 @@ void f(__clang_svmfloat8x4_t, __clang_svmfloat8x4_t); // CHECK-NEXT: [[COERCE72:%.*]] = alloca { , }, align 2 // CHECK-NEXT: [[COERCE73:%.*]] = alloca { , }, align 2 // CHECK-NEXT: [[COERCE74:%.*]] = alloca { , , , }, align 2 -// CHECK-NEXT: [[COERCE75:%.*]] = alloca { , , , }, align 2 +// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca { , , , }, align 2 +// CHECK-NEXT: [[COERCE75:%.*]] = alloca { , }, align 16 // CHECK-NEXT: [[COERCE76:%.*]] = alloca { , }, align 16 -// CHECK-NEXT: [[COERCE77:%.*]] = alloca { , }, align 16 +// CHECK-NEXT: [[COERCE77:%.*]] = alloca { , , }, align 16 // CHECK-NEXT: [[COERCE78:%.*]] = alloca { , , }, align 16 -// CHECK-NEXT: [[COERCE79:%.*]] = alloca { , , }, align 16 +// CHECK-NEXT: [[COERCE79:%.*]] = alloca { , , , }, align 16 // CHECK-NEXT: [[COERCE80:%.*]] = alloca { , , , }, align 16 -// CHECK-NEXT: [[COERCE81:%.*]] = alloca { , , , }, align 16 // CHECK-NEXT: call void @_Z1fu10__SVInt8_tS_( zeroinitializer, zeroinitializer) // CHECK-NEXT: call void @_Z1fu11__SVInt16_tS_( zeroinitializer, zeroinitializer) // CHECK-NEXT: call void @_Z1fu11__SVInt16_tS_( zeroinitializer, zeroinitializer) @@ -575,46 +575,41 @@ void f(__clang_svmfloat8x4_t, __clang_svmfloat8x4_t); // CHECK-NEXT: [[COERCE74_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE74_TUPLE]], 1 // CHECK-NEXT: [[COERCE74_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE74_TUPLE]], 2 // CHECK-NEXT: [[COERCE74_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE74_TUPLE]], 3 -// CHECK-NEXT: store { , , , } zeroinitializer, ptr [[COERCE75]], align 2 -// CHECK-NEXT: [[COERCE75_TUPLE:%.*]] = load { , , , }, ptr [[COERCE75]], align 2 -// CHECK-NEXT: [[COERCE75_EXTRACT0:%.*]] = extractvalue { , , , } [[COERCE75_TUPLE]], 0 -// CHECK-NEXT: [[COERCE75_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE75_TUPLE]], 1 -// CHECK-NEXT: [[COERCE75_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE75_TUPLE]], 2 -// CHECK-NEXT: [[COERCE75_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE75_TUPLE]], 3 -// CHECK-NEXT: call void @_Z1f10svboolx4_tS_( [[COERCE74_EXTRACT0]], [[COERCE74_EXTRACT1]], [[COERCE74_EXTRACT2]], [[COERCE74_EXTRACT3]], [[COERCE75_EXTRACT0]], [[COERCE75_EXTRACT1]], [[COERCE75_EXTRACT2]], [[COERCE75_EXTRACT3]]) +// CHECK-NEXT: store { , , , } zeroinitializer, ptr [[BYVAL_TEMP]], align 2 +// CHECK-NEXT: call void @_Z1f10svboolx4_tS_( [[COERCE74_EXTRACT0]], [[COERCE74_EXTRACT1]], [[COERCE74_EXTRACT2]], [[COERCE74_EXTRACT3]], ptr noundef [[BYVAL_TEMP]]) +// CHECK-NEXT: store { , } zeroinitializer, ptr [[COERCE75]], align 16 +// CHECK-NEXT: [[COERCE75_TUPLE:%.*]] = load { , }, ptr [[COERCE75]], align 16 +// CHECK-NEXT: [[COERCE75_EXTRACT0:%.*]] = extractvalue { , } [[COERCE75_TUPLE]], 0 +// CHECK-NEXT: [[COERCE75_EXTRACT1:%.*]] = extractvalue { , } [[COERCE75_TUPLE]], 1 // CHECK-NEXT: store { , } zeroinitializer, ptr [[COERCE76]], align 16 // CHECK-NEXT: [[COERCE76_TUPLE:%.*]] = load { , }, ptr [[COERCE76]], align 16 // CHECK-NEXT: [[COERCE76_EXTRACT0:%.*]] = extractvalue { , } [[COERCE76_TUPLE]], 0 // CHECK-NEXT: [[COERCE76_EXTRACT1:%.*]] = extractvalue { , } [[COERCE76_TUPLE]], 1 -// CHECK-NEXT: store { , } zeroinitializer, ptr [[COERCE77]], align 16 -// CHECK-NEXT: [[COERCE77_TUPLE:%.*]] = load { , }, ptr [[COERCE77]], align 16 -// CHECK-NEXT: [[COERCE77_EXTRACT0:%.*]] = extractvalue { , } [[COERCE77_TUPLE]], 0 -// CHECK-NEXT: [[COERCE77_EXTRACT1:%.*]] = extractvalue { , } [[COERCE77_TUPLE]], 1 -// CHECK-NEXT: call void @_Z1f13svmfloat8x2_tS_( [[COERCE76_EXTRACT0]], [[COERCE76_EXTRACT1]], [[COERCE77_EXTRACT0]], [[COERCE77_EXTRACT1]]) +// CHECK-NEXT: call void @_Z1f13svmfloat8x2_tS_( [[COERCE75_EXTRACT0]], [[COERCE75_EXTRACT1]], [[COERCE76_EXTRACT0]], [[COERCE76_EXTRACT1]]) +// CHECK-NEXT: store { , , } zeroinitializer, ptr [[COERCE77]], align 16 +// CHECK-NEXT: [[COERCE77_TUPLE:%.*]] = load { , , }, ptr [[COERCE77]], align 16 +// CHECK-NEXT: [[COERCE77_EXTRACT0:%.*]] = extractvalue { , , } [[COERCE77_TUPLE]], 0 +// CHECK-NEXT: [[COERCE77_EXTRACT1:%.*]] = extractvalue { , , } [[COERCE77_TUPLE]], 1 +// CHECK-NEXT: [[COERCE77_EXTRACT2:%.*]] = extractvalue { , , } [[COERCE77_TUPLE]], 2 // CHECK-NEXT: store { , , } zeroinitializer, ptr [[COERCE78]], align 16 // CHECK-NEXT: [[COERCE78_TUPLE:%.*]] = load { , , }, ptr [[COERCE78]], align 16 // CHECK-NEXT: [[COERCE78_EXTRACT0:%.*]] = extractvalue { , , } [[COERCE78_TUPLE]], 0 // CHECK-NEXT: [[COERCE78_EXTRACT1:%.*]] = extractvalue { , , } [[COERCE78_TUPLE]], 1 // CHECK-NEXT: [[COERCE78_EXTRACT2:%.*]] = extractvalue { , , } [[COERCE78_TUPLE]], 2 -// CHECK-NEXT: store { , , } zeroinitializer, ptr [[COERCE79]], align 16 -// CHECK-NEXT: [[COERCE79_TUPLE:%.*]] = load { , , }, ptr [[COERCE79]], align 16 -// CHECK-NEXT: [[COERCE79_EXTRACT0:%.*]] = extractvalue { , , } [[COERCE79_TUPLE]], 0 -// CHECK-NEXT: [[COERCE79_EXTRACT1:%.*]] = extractvalue { , , } [[COERCE79_TUPLE]], 1 -// CHECK-NEXT: [[COERCE79_EXTRACT2:%.*]] = extractvalue { , , } [[COERCE79_TUPLE]], 2 -// CHECK-NEXT: call void @_Z1f13svmfloat8x3_tS_( [[COERCE78_EXTRACT0]], [[COERCE78_EXTRACT1]], [[COERCE78_EXTRACT2]], [[COERCE79_EXTRACT0]], [[COERCE79_EXTRACT1]], [[COERCE79_EXTRACT2]]) +// CHECK-NEXT: call void @_Z1f13svmfloat8x3_tS_( [[COERCE77_EXTRACT0]], [[COERCE77_EXTRACT1]], [[COERCE77_EXTRACT2]], [[COERCE78_EXTRACT0]], [[COERCE78_EXTRACT1]], [[COERCE78_EXTRACT2]]) +// CHECK-NEXT: store { , , , } zeroinitializer, ptr [[COERCE79]], align 16 +// CHECK-NEXT: [[COERCE79_TUPLE:%.*]] = load { , , , }, ptr [[COERCE79]], align 16 +// CHECK-NEXT: [[COERCE79_EXTRACT0:%.*]] = extractvalue { , , , } [[COERCE79_TUPLE]], 0 +// CHECK-NEXT: [[COERCE79_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE79_TUPLE]], 1 +// CHECK-NEXT: [[COERCE79_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE79_TUPLE]], 2 +// CHECK-NEXT: [[COERCE79_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE79_TUPLE]], 3 // CHECK-NEXT: store { , , , } zeroinitializer, ptr [[COERCE80]], align 16 // CHECK-NEXT: [[COERCE80_TUPLE:%.*]] = load { , , , }, ptr [[COERCE80]], align 16 // CHECK-NEXT: [[COERCE80_EXTRACT0:%.*]] = extractvalue { , , , } [[COERCE80_TUPLE]], 0 // CHECK-NEXT: [[COERCE80_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE80_TUPLE]], 1 // CHECK-NEXT: [[COERCE80_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE80_TUPLE]], 2 // CHECK-NEXT: [[COERCE80_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE80_TUPLE]], 3 -// CHECK-NEXT: store { , , , } zeroinitializer, ptr [[COERCE81]], align 16 -// CHECK-NEXT: [[COERCE81_TUPLE:%.*]] = load { , , , }, ptr [[COERCE81]], align 16 -// CHECK-NEXT: [[COERCE81_EXTRACT0:%.*]] = extractvalue { , , , } [[COERCE81_TUPLE]], 0 -// CHECK-NEXT: [[COERCE81_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE81_TUPLE]], 1 -// CHECK-NEXT: [[COERCE81_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE81_TUPLE]], 2 -// CHECK-NEXT: [[COERCE81_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE81_TUPLE]], 3 -// CHECK-NEXT: call void @_Z1f13svmfloat8x4_tS_( [[COERCE80_EXTRACT0]], [[COERCE80_EXTRACT1]], [[COERCE80_EXTRACT2]], [[COERCE80_EXTRACT3]], [[COERCE81_EXTRACT0]], [[COERCE81_EXTRACT1]], [[COERCE81_EXTRACT2]], [[COERCE81_EXTRACT3]]) +// CHECK-NEXT: call void @_Z1f13svmfloat8x4_tS_( [[COERCE79_EXTRACT0]], [[COERCE79_EXTRACT1]], [[COERCE79_EXTRACT2]], [[COERCE79_EXTRACT3]], [[COERCE80_EXTRACT0]], [[COERCE80_EXTRACT1]], [[COERCE80_EXTRACT2]], [[COERCE80_EXTRACT3]]) // CHECK-NEXT: ret void // // COMPAT_17-LABEL: define dso_local void @_Z3foov( @@ -695,13 +690,13 @@ void f(__clang_svmfloat8x4_t, __clang_svmfloat8x4_t); // COMPAT_17-NEXT: [[COERCE72:%.*]] = alloca { , }, align 2 // COMPAT_17-NEXT: [[COERCE73:%.*]] = alloca { , }, align 2 // COMPAT_17-NEXT: [[COERCE74:%.*]] = alloca { , , , }, align 2 -// COMPAT_17-NEXT: [[COERCE75:%.*]] = alloca { , , , }, align 2 +// COMPAT_17-NEXT: [[BYVAL_TEMP:%.*]] = alloca { , , , }, align 2 +// COMPAT_17-NEXT: [[COERCE75:%.*]] = alloca { , }, align 16 // COMPAT_17-NEXT: [[COERCE76:%.*]] = alloca { , }, align 16 -// COMPAT_17-NEXT: [[COERCE77:%.*]] = alloca { , }, align 16 +// COMPAT_17-NEXT: [[COERCE77:%.*]] = alloca { , , }, align 16 // COMPAT_17-NEXT: [[COERCE78:%.*]] = alloca { , , }, align 16 -// COMPAT_17-NEXT: [[COERCE79:%.*]] = alloca { , , }, align 16 +// COMPAT_17-NEXT: [[COERCE79:%.*]] = alloca { , , , }, align 16 // COMPAT_17-NEXT: [[COERCE80:%.*]] = alloca { , , , }, align 16 -// COMPAT_17-NEXT: [[COERCE81:%.*]] = alloca { , , , }, align 16 // COMPAT_17-NEXT: call void @_Z1fu10__SVInt8_tu10__SVInt8_t( zeroinitializer, zeroinitializer) // COMPAT_17-NEXT: call void @_Z1fu11__SVInt16_tu11__SVInt16_t( zeroinitializer, zeroinitializer) // COMPAT_17-NEXT: call void @_Z1fu11__SVInt16_tu11__SVInt16_t( zeroinitializer, zeroinitializer) @@ -1129,46 +1124,41 @@ void f(__clang_svmfloat8x4_t, __clang_svmfloat8x4_t); // COMPAT_17-NEXT: [[COERCE74_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE74_TUPLE]], 1 // COMPAT_17-NEXT: [[COERCE74_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE74_TUPLE]], 2 // COMPAT_17-NEXT: [[COERCE74_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE74_TUPLE]], 3 -// COMPAT_17-NEXT: store { , , , } zeroinitializer, ptr [[COERCE75]], align 2 -// COMPAT_17-NEXT: [[COERCE75_TUPLE:%.*]] = load { , , , }, ptr [[COERCE75]], align 2 -// COMPAT_17-NEXT: [[COERCE75_EXTRACT0:%.*]] = extractvalue { , , , } [[COERCE75_TUPLE]], 0 -// COMPAT_17-NEXT: [[COERCE75_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE75_TUPLE]], 1 -// COMPAT_17-NEXT: [[COERCE75_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE75_TUPLE]], 2 -// COMPAT_17-NEXT: [[COERCE75_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE75_TUPLE]], 3 -// COMPAT_17-NEXT: call void @_Z1f10svboolx4_t10svboolx4_t( [[COERCE74_EXTRACT0]], [[COERCE74_EXTRACT1]], [[COERCE74_EXTRACT2]], [[COERCE74_EXTRACT3]], [[COERCE75_EXTRACT0]], [[COERCE75_EXTRACT1]], [[COERCE75_EXTRACT2]], [[COERCE75_EXTRACT3]]) +// COMPAT_17-NEXT: store { , , , } zeroinitializer, ptr [[BYVAL_TEMP]], align 2 +// COMPAT_17-NEXT: call void @_Z1f10svboolx4_t10svboolx4_t( [[COERCE74_EXTRACT0]], [[COERCE74_EXTRACT1]], [[COERCE74_EXTRACT2]], [[COERCE74_EXTRACT3]], ptr noundef [[BYVAL_TEMP]]) +// COMPAT_17-NEXT: store { , } zeroinitializer, ptr [[COERCE75]], align 16 +// COMPAT_17-NEXT: [[COERCE75_TUPLE:%.*]] = load { , }, ptr [[COERCE75]], align 16 +// COMPAT_17-NEXT: [[COERCE75_EXTRACT0:%.*]] = extractvalue { , } [[COERCE75_TUPLE]], 0 +// COMPAT_17-NEXT: [[COERCE75_EXTRACT1:%.*]] = extractvalue { , } [[COERCE75_TUPLE]], 1 // COMPAT_17-NEXT: store { , } zeroinitializer, ptr [[COERCE76]], align 16 // COMPAT_17-NEXT: [[COERCE76_TUPLE:%.*]] = load { , }, ptr [[COERCE76]], align 16 // COMPAT_17-NEXT: [[COERCE76_EXTRACT0:%.*]] = extractvalue { , } [[COERCE76_TUPLE]], 0 // COMPAT_17-NEXT: [[COERCE76_EXTRACT1:%.*]] = extractvalue { , } [[COERCE76_TUPLE]], 1 -// COMPAT_17-NEXT: store { , } zeroinitializer, ptr [[COERCE77]], align 16 -// COMPAT_17-NEXT: [[COERCE77_TUPLE:%.*]] = load { , }, ptr [[COERCE77]], align 16 -// COMPAT_17-NEXT: [[COERCE77_EXTRACT0:%.*]] = extractvalue { , } [[COERCE77_TUPLE]], 0 -// COMPAT_17-NEXT: [[COERCE77_EXTRACT1:%.*]] = extractvalue { , } [[COERCE77_TUPLE]], 1 -// COMPAT_17-NEXT: call void @_Z1f13svmfloat8x2_t13svmfloat8x2_t( [[COERCE76_EXTRACT0]], [[COERCE76_EXTRACT1]], [[COERCE77_EXTRACT0]], [[COERCE77_EXTRACT1]]) +// COMPAT_17-NEXT: call void @_Z1f13svmfloat8x2_t13svmfloat8x2_t( [[COERCE75_EXTRACT0]], [[COERCE75_EXTRACT1]], [[COERCE76_EXTRACT0]], [[COERCE76_EXTRACT1]]) +// COMPAT_17-NEXT: store { , , } zeroinitializer, ptr [[COERCE77]], align 16 +// COMPAT_17-NEXT: [[COERCE77_TUPLE:%.*]] = load { , , }, ptr [[COERCE77]], align 16 +// COMPAT_17-NEXT: [[COERCE77_EXTRACT0:%.*]] = extractvalue { , , } [[COERCE77_TUPLE]], 0 +// COMPAT_17-NEXT: [[COERCE77_EXTRACT1:%.*]] = extractvalue { , , } [[COERCE77_TUPLE]], 1 +// COMPAT_17-NEXT: [[COERCE77_EXTRACT2:%.*]] = extractvalue { , , } [[COERCE77_TUPLE]], 2 // COMPAT_17-NEXT: store { , , } zeroinitializer, ptr [[COERCE78]], align 16 // COMPAT_17-NEXT: [[COERCE78_TUPLE:%.*]] = load { , , }, ptr [[COERCE78]], align 16 // COMPAT_17-NEXT: [[COERCE78_EXTRACT0:%.*]] = extractvalue { , , } [[COERCE78_TUPLE]], 0 // COMPAT_17-NEXT: [[COERCE78_EXTRACT1:%.*]] = extractvalue { , , } [[COERCE78_TUPLE]], 1 // COMPAT_17-NEXT: [[COERCE78_EXTRACT2:%.*]] = extractvalue { , , } [[COERCE78_TUPLE]], 2 -// COMPAT_17-NEXT: store { , , } zeroinitializer, ptr [[COERCE79]], align 16 -// COMPAT_17-NEXT: [[COERCE79_TUPLE:%.*]] = load { , , }, ptr [[COERCE79]], align 16 -// COMPAT_17-NEXT: [[COERCE79_EXTRACT0:%.*]] = extractvalue { , , } [[COERCE79_TUPLE]], 0 -// COMPAT_17-NEXT: [[COERCE79_EXTRACT1:%.*]] = extractvalue { , , } [[COERCE79_TUPLE]], 1 -// COMPAT_17-NEXT: [[COERCE79_EXTRACT2:%.*]] = extractvalue { , , } [[COERCE79_TUPLE]], 2 -// COMPAT_17-NEXT: call void @_Z1f13svmfloat8x3_t13svmfloat8x3_t( [[COERCE78_EXTRACT0]], [[COERCE78_EXTRACT1]], [[COERCE78_EXTRACT2]], [[COERCE79_EXTRACT0]], [[COERCE79_EXTRACT1]], [[COERCE79_EXTRACT2]]) +// COMPAT_17-NEXT: call void @_Z1f13svmfloat8x3_t13svmfloat8x3_t( [[COERCE77_EXTRACT0]], [[COERCE77_EXTRACT1]], [[COERCE77_EXTRACT2]], [[COERCE78_EXTRACT0]], [[COERCE78_EXTRACT1]], [[COERCE78_EXTRACT2]]) +// COMPAT_17-NEXT: store { , , , } zeroinitializer, ptr [[COERCE79]], align 16 +// COMPAT_17-NEXT: [[COERCE79_TUPLE:%.*]] = load { , , , }, ptr [[COERCE79]], align 16 +// COMPAT_17-NEXT: [[COERCE79_EXTRACT0:%.*]] = extractvalue { , , , } [[COERCE79_TUPLE]], 0 +// COMPAT_17-NEXT: [[COERCE79_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE79_TUPLE]], 1 +// COMPAT_17-NEXT: [[COERCE79_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE79_TUPLE]], 2 +// COMPAT_17-NEXT: [[COERCE79_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE79_TUPLE]], 3 // COMPAT_17-NEXT: store { , , , } zeroinitializer, ptr [[COERCE80]], align 16 // COMPAT_17-NEXT: [[COERCE80_TUPLE:%.*]] = load { , , , }, ptr [[COERCE80]], align 16 // COMPAT_17-NEXT: [[COERCE80_EXTRACT0:%.*]] = extractvalue { , , , } [[COERCE80_TUPLE]], 0 // COMPAT_17-NEXT: [[COERCE80_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE80_TUPLE]], 1 // COMPAT_17-NEXT: [[COERCE80_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE80_TUPLE]], 2 // COMPAT_17-NEXT: [[COERCE80_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE80_TUPLE]], 3 -// COMPAT_17-NEXT: store { , , , } zeroinitializer, ptr [[COERCE81]], align 16 -// COMPAT_17-NEXT: [[COERCE81_TUPLE:%.*]] = load { , , , }, ptr [[COERCE81]], align 16 -// COMPAT_17-NEXT: [[COERCE81_EXTRACT0:%.*]] = extractvalue { , , , } [[COERCE81_TUPLE]], 0 -// COMPAT_17-NEXT: [[COERCE81_EXTRACT1:%.*]] = extractvalue { , , , } [[COERCE81_TUPLE]], 1 -// COMPAT_17-NEXT: [[COERCE81_EXTRACT2:%.*]] = extractvalue { , , , } [[COERCE81_TUPLE]], 2 -// COMPAT_17-NEXT: [[COERCE81_EXTRACT3:%.*]] = extractvalue { , , , } [[COERCE81_TUPLE]], 3 -// COMPAT_17-NEXT: call void @_Z1f13svmfloat8x4_t13svmfloat8x4_t( [[COERCE80_EXTRACT0]], [[COERCE80_EXTRACT1]], [[COERCE80_EXTRACT2]], [[COERCE80_EXTRACT3]], [[COERCE81_EXTRACT0]], [[COERCE81_EXTRACT1]], [[COERCE81_EXTRACT2]], [[COERCE81_EXTRACT3]]) +// COMPAT_17-NEXT: call void @_Z1f13svmfloat8x4_t13svmfloat8x4_t( [[COERCE79_EXTRACT0]], [[COERCE79_EXTRACT1]], [[COERCE79_EXTRACT2]], [[COERCE79_EXTRACT3]], [[COERCE80_EXTRACT0]], [[COERCE80_EXTRACT1]], [[COERCE80_EXTRACT2]], [[COERCE80_EXTRACT3]]) // COMPAT_17-NEXT: ret void // void foo() { 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/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..75f29e1c77975 100644 --- a/clang/test/CodeGenCXX/fmv-namespace.cpp +++ b/clang/test/CodeGenCXX/fmv-namespace.cpp @@ -28,34 +28,40 @@ __attribute((target_version("mops"))) int bar() { return 1; } // CHECK: @_ZN4Name3fooEv = weak_odr ifunc i32 (), ptr @_ZN4Name3fooEv.resolver // CHECK: @_ZN3Foo3barEv = weak_odr ifunc i32 (), ptr @_ZN3Foo3barEv.resolver //. -// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve( +// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default( // CHECK-SAME: ) #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i32 0 +// +// +// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve( +// CHECK-SAME: ) #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: ret i32 1 // // // CHECK-LABEL: define dso_local noundef i32 @_Z3barv( -// CHECK-SAME: ) #[[ATTR1:[0-9]+]] { +// CHECK-SAME: ) #[[ATTR2:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN4Name3fooEv() // CHECK-NEXT: ret i32 [[CALL]] // // // CHECK-LABEL: define dso_local noundef i32 @_ZN9OtherName3fooEv._Msve( -// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-SAME: ) #[[ATTR1]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: ret i32 2 // // // CHECK-LABEL: define dso_local noundef i32 @_Z3bazv( -// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-SAME: ) #[[ATTR2]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN9OtherName3fooEv() // CHECK-NEXT: ret i32 [[CALL]] // // // CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv.default( -// CHECK-SAME: ) #[[ATTR3:[0-9]+]] { +// CHECK-SAME: ) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: ret i32 0 // @@ -66,18 +72,12 @@ __attribute((target_version("mops"))) int bar() { return 1; } // CHECK-NEXT: ret i32 1 // // -// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default( -// CHECK-SAME: ) #[[ATTR3]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: ret i32 0 -// -// // CHECK-LABEL: define weak_odr ptr @_ZN4Name3fooEv.resolver() comdat { // 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/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl index 45e135427ba9c..7507e741a9c9b 100644 --- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl @@ -21,9 +21,9 @@ RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4); // CHECK: define internal void @_init_resource_bindings() { // CHECK-NEXT: entry: -// CHECK-DXIL-NEXT: %Buffer0_h = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: %Buffer0_h = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) // CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 0, 0) %Buffer0_h, ptr @Buffer0, align 4 -// CHECK-DXIL-NEXT: %Buffer1_h = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_1_0t(i32 2, i32 1, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: %Buffer1_h = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 2, i32 1, i32 1, i32 0, i1 false) // CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 1, 0) %Buffer1_h, ptr @Buffer1, align 4 -// CHECK-DXIL-NEXT: %Buffer2_h = call target("dx.RawBuffer", i8, 1, 1) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: %Buffer2_h = call target("dx.RawBuffer", i8, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, i32 0, i1 false) // CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 1, 1) %Buffer2_h, ptr @Buffer2, align 4 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..237b97394024c --- /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.resource.handlefrombinding.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.resource.handlefrombinding.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-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl index c2db56e2b2bdd..e4226abf71b8e 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -// FIXME: SPIR-V codegen of llvm.spv.handle.fromBinding is not yet implemented +// FIXME: SPIR-V codegen of llvm.spv.resource.handlefrombinding is not yet implemented // RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV // NOTE: SPIRV codegen for resource types is not yet implemented @@ -19,7 +19,7 @@ RWBuffer Buf : register(u5, space3); // CHECK: define internal void @_init_resource_bindings() { // CHECK-NEXT: entry: -// CHECK-DXIL-NEXT: %Buf_h = 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: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.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, ptr @Buf, align 4 -// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.spv.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.spv.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) // CHECK-SPIRV-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @Buf, align 4 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/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl index d84e92242ffb4..16f4f80231dae 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl @@ -37,24 +37,24 @@ RasterizerOrderedStructuredBuffer Buf5 : register(u1, space2); // CHECK: define internal void @_init_resource_bindings() { // CHECK-NEXT: entry: -// CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) // CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf, align 4 -// CHECK-DXIL-NEXT: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) // CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2, align 4 -// CHECK-DXIL-NEXT: %Buf3_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: %Buf3_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false) // CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf3_h, ptr @Buf3, align 4 -// CHECK-DXIL-NEXT: %Buf4_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: %Buf4_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, i32 0, i1 false) // CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf4_h, ptr @Buf4, align 4 -// CHECK-DXIL-NEXT: %Buf5_h = call target("dx.RawBuffer", float, 1, 1) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: %Buf5_h = call target("dx.RawBuffer", float, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false) // CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 1) %Buf5_h, ptr @Buf5, align 4 -// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.spv.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) // CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf", align 4 -// CHECK-SPIRV-NEXT: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.spv.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) // CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2", align 4 -// CHECK-SPIRV-NEXT: %Buf3_h = call target("dx.RawBuffer", float, 0, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: %Buf3_h = call target("dx.RawBuffer", float, 0, 0) @llvm.spv.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false) // CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf3_h, ptr @Buf3, align 4 -// CHECK-SPIRV-NEXT: %Buf4_h = call target("dx.RawBuffer", float, 1, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: %Buf4_h = call target("dx.RawBuffer", float, 1, 0) @llvm.spv.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, i32 0, i1 false) // CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf4_h, ptr @Buf4, align 4 -// CHECK-SPIRV-NEXT: %Buf5_h = call target("dx.RawBuffer", float, 1, 1) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: %Buf5_h = call target("dx.RawBuffer", float, 1, 1) @llvm.spv.resource.handlefrombinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false) // CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 1) %Buf5_h, ptr @Buf5, align 4 diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl index 53abdc71bdd4b..383f591f676d9 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-lib.hlsl @@ -3,26 +3,30 @@ // NOTE: SPIRV codegen for resource methods is not yet implemented +StructuredBuffer SB1 : register(t0); RWStructuredBuffer RWSB1 : register(u0); RWStructuredBuffer RWSB2 : register(u1); AppendStructuredBuffer ASB : register(u2); ConsumeStructuredBuffer CSB : register(u3); +// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0) } // CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } +// CHECK: %"class.hlsl::AppendStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } +// CHECK: %"class.hlsl::ConsumeStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } export int TestIncrementCounter() { return RWSB1.IncrementCounter(); } // 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: %[[INDEX:.*]] = call i32 @llvm.dx.resource.updatecounter.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: %[[INDEX:.*]] = call i32 @llvm.dx.resource.updatecounter.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) { @@ -31,7 +35,7 @@ export void TestAppend(float 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: %[[INDEX:.*]] = call i32 @llvm.dx.resource.updatecounter.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 @@ -40,10 +44,21 @@ export float TestConsume() { } // 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: %[[INDEX:.*]] = call i32 @llvm.dx.resource.updatecounter.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) +export float TestLoad() { + return RWSB1.Load(1) + SB1.Load(2); +} + +// CHECK: define noundef float @_Z8TestLoadv() +// CHECK: %[[PTR1:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i32 %{{[0-9]+}}) +// CHECK: %[[VALUE1:.*]] = load float, ptr %[[PTR1]] +// CHECK: %[[PTR2:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %{{[0-9]+}}, i32 %{{[0-9]+}}) +// CHECK: %[[VALUE2:.*]] = load float, ptr %[[PTR2]] + +// CHECK: declare i32 @llvm.dx.resource.updatecounter.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) +// CHECK: declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0), i32) diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-ps.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-ps.hlsl index f6959b5cefb7c..3d9f4f68ec7d2 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-ps.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-methods-ps.hlsl @@ -10,19 +10,28 @@ RasterizerOrderedStructuredBuffer ROSB1, ROSB2; export void TestIncrementCounter() { // 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-DXIL: call i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %{{[0-9]+}}, i8 1) +// CHECK-DXIL: call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i8 1) +// CHECK-DXIL: call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %{{[0-9]+}}, i8 1) RWSB1.IncrementCounter(); ROSB1.IncrementCounter(); } export void TestDecrementCounter() { // 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-DXIL: call i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %{{[0-9]+}}, i8 -1) +// CHECK-DXIL: call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %{{[0-9]+}}, i8 -1) +// CHECK-DXIL: call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %{{[0-9]+}}, i8 -1) RWSB2.DecrementCounter(); ROSB2.DecrementCounter(); } -// CHECK: declare i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8) -// CHECK: declare i32 @llvm.dx.bufferUpdateCounter.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1), i8) +export float TestLoad() { + return ROSB1.Load(10); +} + +// CHECK: define noundef float @_Z8TestLoadv() +// CHECK: %[[PTR1:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %{{[0-9]+}}, i32 %{{[0-9]+}}) +// CHECK: %[[VALUE1:.*]] = load float, ptr %[[PTR1]] + +// CHECK: declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8) #3 +// CHECK: declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1), i8) #3 +// CHECK: declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1), i32) #4 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/resource-bindings.hlsl b/clang/test/CodeGenHLSL/resource-bindings.hlsl index d4e6308210653..4049a87a8ab71 100644 --- a/clang/test/CodeGenHLSL/resource-bindings.hlsl +++ b/clang/test/CodeGenHLSL/resource-bindings.hlsl @@ -2,18 +2,18 @@ // CHECK: define internal void @_init_resource_bindings() { -// CHECK: %U0S0_h = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) +// CHECK: %U0S0_h = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) RWBuffer U0S0 : register(u0); -// CHECK: %U5S3_h = 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: %U5S3_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) RWBuffer U5S3 : register(u5, space3); -// CHECK: %T2S2_h = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i32_0_0t(i32 2, i32 2, i32 1, i32 0, i1 false) +// CHECK: %T2S2_h = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(i32 2, i32 2, i32 1, i32 0, i1 false) StructuredBuffer T2S2 : register(t2, space2); struct S { float4 f; int i; }; -// 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) +// CHECK: %T3S0_h = call target("dx.RawBuffer", %struct.S, 0, 0) @llvm.dx.resource.handlefrombinding.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/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/single-byte-counters.cpp b/clang/test/CoverageMapping/single-byte-counters.cpp index 8e9b613dcc68f..4c0987eea4b98 100644 --- a/clang/test/CoverageMapping/single-byte-counters.cpp +++ b/clang/test/CoverageMapping/single-byte-counters.cpp @@ -1,169 +1,153 @@ // RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -mllvm -enable-single-byte-coverage=true -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name single-byte-counters.cpp %s | FileCheck %s // CHECK: testIf -int testIf(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE+10]]:2 = #0 - // CHECK-NEXT: File 0, [[@LINE+5]]:7 -> [[@LINE+5]]:13 = #0 - // CHECK-NEXT: Gap,File 0, [[@LINE+4]]:14 -> [[@LINE+5]]:5 = #1 - // CHECK-NEXT: File 0, [[@LINE+4]]:5 -> [[@LINE+4]]:16 = #1 - // CHECK-NEXT: File 0, [[@LINE+5]]:3 -> [[@LINE+5]]:16 = #2 +int testIf(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE+7]]:2 = [[C00:#0]] int result = 0; - if (x == 0) - result = -1; + if (x == 0) // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = [[C00]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:5 = [[C0T:#1]] + result = -1; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:16 = [[C0T]] - return result; + return result; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:16 = [[C0E:#2]] } // CHECK-NEXT: testIfElse -int testIfElse(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+13]]:2 = #0 - // CHECK-NEXT: File 0, [[@LINE+7]]:7 -> [[@LINE+7]]:12 = #0 - // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:13 -> [[@LINE+7]]:5 = #1 - // CHECK-NEXT: File 0, [[@LINE+6]]:5 -> [[@LINE+6]]:15 = #1 - // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:16 -> [[@LINE+7]]:5 = #2 - // CHECK-NEXT: File 0, [[@LINE+6]]:5 -> [[@LINE+6]]:19 = #2 - // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+6]]:16 = #3 +int testIfElse(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+8]]:2 = [[C10:#0]] int result = 0; - if (x < 0) - result = 0; - else - result = x * x; - return result; + if (x < 0) // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = [[C10]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:5 = [[C1T:#1]] + result = 0; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:15 = [[C1T]] + else // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:16 -> [[@LINE+1]]:5 = [[C1F:#2]] + result = x * x; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:19 = [[C1F]] + return result; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:16 = [[C1E:#3]] } // CHECK-NEXT: testIfElseReturn -int testIfElseReturn(int x) { // CHECK-NEXT: File 0, [[@LINE]]:29 -> [[@LINE+14]]:2 = #0 - // CHECK-NEXT: File 0, [[@LINE+8]]:7 -> [[@LINE+8]]:12 = #0 - // CHECK-NEXT: Gap,File 0, [[@LINE+7]]:13 -> [[@LINE+8]]:5 = #1 - // CHECK-NEXT: File 0, [[@LINE+7]]:5 -> [[@LINE+7]]:19 = #1 - // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:20 -> [[@LINE+8]]:5 = #2 - // CHECK-NEXT: File 0, [[@LINE+7]]:5 -> [[@LINE+7]]:13 = #2 - // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:14 -> [[@LINE+7]]:3 = #3 - // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+6]]:16 = #3 +int testIfElseReturn(int x) { // CHECK-NEXT: File 0, [[@LINE]]:29 -> [[@LINE+9]]:2 = [[C20:#0]] + int result = 0; + if (x > 0) // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = [[C20]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:5 = [[C2T:#1]] + result = x * x; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:19 = [[C2T]] + else // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:20 -> [[@LINE+1]]:5 = [[C2F:#2]] + return 0; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:13 = [[C2F]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = [[C2E:#3]] + return result; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:16 = [[C2E:#3]] +} + +// CHECK-NEXT: testIfBothReturn +int testIfBothReturn(int x) { // CHECK-NEXT: File 0, [[@LINE]]:29 -> [[@LINE+9]]:2 = [[C20:#0]] int result = 0; - if (x > 0) - result = x * x; - else - return 0; - return result; + if (x > 0) // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = [[C20]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:5 = [[C2T:#1]] + return 42; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:14 = [[C2T]] + else // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:15 -> [[@LINE+1]]:5 = [[C2F:#2]] + return 0; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:13 = [[C2F]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = #3 + return -1; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:12 = #3 } // CHECK-NEXT: testSwitch -int testSwitch(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+22]]:2 = #0 - // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:14 -> [[@LINE+17]]:15 = 0 - // CHECK-NEXT: File 0, [[@LINE+9]]:3 -> [[@LINE+11]]:10 = #2 - // CHECK-NEXT: Gap,File 0, [[@LINE+10]]:11 -> [[@LINE+11]]:3 = 0 - // CHECK-NEXT: File 0, [[@LINE+10]]:3 -> [[@LINE+12]]:10 = #3 - // CHECK-NEXT: Gap,File 0, [[@LINE+11]]:11 -> [[@LINE+12]]:3 = 0 - // CHECK-NEXT: File 0, [[@LINE+11]]:3 -> [[@LINE+12]]:15 = #4 - // CHECK-NEXT: Gap,File 0, [[@LINE+12]]:4 -> [[@LINE+14]]:3 = #1 - // CHECK-NEXT: File 0, [[@LINE+13]]:3 -> [[@LINE+13]]:16 = #1 +int testSwitch(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+17]]:2 = [[C30:#0]] int result; switch (x) { - case 1: + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+10]]:15 = 0 + case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = [[C31:#2]] result = 1; break; - case 2: + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = 0 + case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = [[C32:#3]] result = 2; break; - default: + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = 0 + default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:15 = [[C3D:#4]] result = 0; } - - return result; + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE+1]]:3 = [[C3E:#1]] + return result; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:16 = [[C3E]] } // CHECK-NEXT: testWhile -int testWhile() { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+13]]:2 = #0 - // CHECK-NEXT: File 0, [[@LINE+6]]:10 -> [[@LINE+6]]:16 = #1 - // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:17 -> [[@LINE+5]]:18 = #2 - // CHECK-NEXT: File 0, [[@LINE+4]]:18 -> [[@LINE+7]]:4 = #2 - // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #3 +int testWhile() { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+11]]:2 = [[C40:#0]] int i = 0; int sum = 0; - while (i < 10) { + while (i < 10) { // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE]]:16 = [[C4C:#1]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:17 -> [[@LINE-1]]:18 = [[C4T:#2]] + // CHECK-NEXT: File 0, [[@LINE-2]]:18 -> [[@LINE+3]]:4 = [[C4T]] sum += i; i++; } - return sum; + return sum; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C4E:#3]] } -// CHECK-NEXT: testContinue -int testContinue() { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+21]]:2 = #0 - // CHECK-NEXT: File 0, [[@LINE+12]]:10 -> [[@LINE+12]]:16 = #1 - // CHECK-NEXT: Gap,File 0, [[@LINE+11]]:17 -> [[@LINE+11]]:18 = #2 - // CHECK-NEXT: File 0, [[@LINE+10]]:18 -> [[@LINE+15]]:4 = #2 - // CHECK-NEXT: File 0, [[@LINE+10]]:9 -> [[@LINE+10]]:15 = #2 - // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:16 -> [[@LINE+10]]:7 = #4 - // CHECK-NEXT: File 0, [[@LINE+9]]:7 -> [[@LINE+9]]:15 = #4 - // CHECK-NEXT: Gap,File 0, [[@LINE+8]]:16 -> [[@LINE+9]]:5 = #5 - // CHECK-NEXT: File 0, [[@LINE+8]]:5 -> [[@LINE+10]]:4 = #5 - // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:4 -> [[@LINE+11]]:3 = #3 - // CHECK-NEXT: File 0, [[@LINE+10]]:3 -> [[@LINE+10]]:13 = #3 +// CHECK-NEXT: testContinueBreak +int testContinueBreak() { // CHECK-NEXT: File 0, [[@LINE]]:25 -> [[@LINE+20]]:2 = #0 int i = 0; int sum = 0; - while (i < 10) { - if (i == 4) - continue; - sum += i; + while (i < 10) { // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE]]:16 = #1 + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:17 -> [[@LINE-1]]:18 = [[C5B:#2]] + // CHECK-NEXT: File 0, [[@LINE-2]]:18 -> [[@LINE+12]]:4 = [[C5B]] + if (i == 4) // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:15 = [[C5B]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:16 -> [[@LINE+1]]:7 = [[C5T:#4]] + continue; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:15 = [[C5T]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:16 -> [[@LINE+2]]:5 = [[C5F:#5]] + // CHECK-NEXT: File 0, [[@LINE+1]]:5 -> [[@LINE+7]]:4 = [[C5F]] + if (i == 5) // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:15 = [[C5F]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:16 -> [[@LINE+1]]:7 = [[C5T1:#6]] + break; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = [[C5T1]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:5 = [[C5F1:#7]] + sum += i; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+2]]:4 = [[C5F1]] i++; } - - return sum; + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE+1]]:3 = [[C5E:#3]] + return sum; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C5E]] } // CHECK-NEXT: testFor -int testFor() { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+13]]:2 = #0 - // CHECK-NEXT: File 0, [[@LINE+7]]:19 -> [[@LINE+7]]:25 = #1 - // CHECK-NEXT: File 0, [[@LINE+6]]:27 -> [[@LINE+6]]:30 = #2 - // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:31 -> [[@LINE+5]]:32 = #3 - // CHECK-NEXT: File 0, [[@LINE+4]]:32 -> [[@LINE+6]]:4 = #3 - // CHECK-NEXT: File 0, [[@LINE+7]]:3 -> [[@LINE+7]]:13 = #4 +int testFor() { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+12]]:2 = [[C60:#0]] int i; int sum = 0; + // CHECK-NEXT: File 0, [[@LINE+2]]:19 -> [[@LINE+2]]:25 = [[C61:#1]] + // CHECK-NEXT: File 0, [[@LINE+1]]:27 -> [[@LINE+1]]:30 = [[C6C:#2]] for (int i = 0; i < 10; i++) { + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:31 -> [[@LINE-1]]:32 = [[C6B:#3]] + // CHECK-NEXT: File 0, [[@LINE-2]]:32 -> [[@LINE+2]]:4 = [[C6B]] sum += i; } - return sum; + return sum; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C6E:#4]] } // CHECK-NEXT: testForRange -int testForRange() { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+12]]:2 = #0 - // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:28 -> [[@LINE+6]]:29 = #1 - // CHECK-NEXT: File 0, [[@LINE+5]]:29 -> [[@LINE+7]]:4 = #1 - // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #2 +int testForRange() { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+11]]:2 = [[C70:#0]] int sum = 0; int array[] = {1, 2, 3, 4, 5}; for (int element : array) { + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:28 -> [[@LINE-1]]:29 = [[C7B:#1]] + // CHECK-NEXT: File 0, [[@LINE-2]]:29 -> [[@LINE+2]]:4 = [[C7B]] sum += element; } - return sum; + return sum; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C7E:#2]] } // CHECK-NEXT: testDo -int testDo() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+12]]:2 = #0 - // CHECK-NEXT: File 0, [[@LINE+5]]:6 -> [[@LINE+8]]:4 = #1 - // CHECK-NEXT: File 0, [[@LINE+7]]:12 -> [[@LINE+7]]:17 = #2 - // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #3 +int testDo() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+9]]:2 = [[C80:#0]] int i = 0; int sum = 0; - do { + do { // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE+3]]:4 = [[C8B:#1]] sum += i; i++; - } while (i < 5); + } while (i < 5); // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE]]:17 = [[C8C:#2]] - return sum; + return sum; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C8E:#3]] } // CHECK-NEXT: testConditional -int testConditional(int x) { // CHECK-NEXT: File 0, [[@LINE]]:28 -> [[@LINE+8]]:2 = #0 - // CHECK-NEXT: File 0, [[@LINE+5]]:15 -> [[@LINE+5]]:22 = #0 - // CHECK-NEXT: Gap,File 0, [[@LINE+4]]:24 -> [[@LINE+4]]:25 = #2 - // CHECK-NEXT: File 0, [[@LINE+3]]:25 -> [[@LINE+3]]:26 = #2 - // CHECK-NEXT: File 0, [[@LINE+2]]:29 -> [[@LINE+2]]:31 = #3 - // CHECK-NEXT: File 0, [[@LINE+2]]:2 -> [[@LINE+2]]:15 = #1 - int result = (x > 0) ? 1 : -1; - return result; +int testConditional(int x) { // CHECK-NEXT: File 0, [[@LINE]]:28 -> [[@LINE+6]]:2 = [[C90:#0]] + int result = (x > 0) ? 1 : -1; // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE]]:22 = [[C90]] + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:24 -> [[@LINE-1]]:25 = [[C9T:#2]] + // CHECK-NEXT: File 0, [[@LINE-2]]:25 -> [[@LINE-2]]:26 = [[C9T]] + // CHECK-NEXT: File 0, [[@LINE-3]]:29 -> [[@LINE-3]]:31 = [[C9F:#3]] + return result; // CHECK-NEXT: File 0, [[@LINE]]:2 -> [[@LINE]]:15 = [[C9E:#1]] } 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/cl-options.c b/clang/test/Driver/cl-options.c index 69e1e7ed471eb..728d1a8ef2794 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -684,6 +684,7 @@ // RUN: -fcoverage-mapping \ // RUN: -fno-coverage-mapping \ // RUN: -fdiagnostics-color \ +// RUN: -fdiagnostics-color=auto \ // RUN: -fno-diagnostics-color \ // RUN: -fdebug-compilation-dir . \ // RUN: -fdebug-compilation-dir=. \ 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/dxc_options.hlsl b/clang/test/Driver/dxc_options.hlsl new file mode 100644 index 0000000000000..09fdba1c3dd5f --- /dev/null +++ b/clang/test/Driver/dxc_options.hlsl @@ -0,0 +1,8 @@ +// RUN: %clang_dxc \ +// RUN: -fcolor-diagnostics \ +// RUN: -fno-color-diagnostics \ +// RUN: -fdiagnostics-color \ +// RUN: -fno-diagnostics-color \ +// RUN: -fdiagnostics-color=auto \ +// RUN: -Tlib_6_7 -Vd -fdriver-only -- %s 2>&1 |count 0 + 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/hexagon-toolchain-elf.c b/clang/test/Driver/hexagon-toolchain-elf.c index 716d82bcf316b..be812dda40d57 100644 --- a/clang/test/Driver/hexagon-toolchain-elf.c +++ b/clang/test/Driver/hexagon-toolchain-elf.c @@ -152,6 +152,20 @@ // CHECK230: "-cc1" {{.*}} "-target-cpu" "hexagonv73" // CHECK230: hexagon-link{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v73/crt0 +// RUN: not %clang -### --target=hexagon-unknown-elf \ +// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \ +// RUN: -mcpu=hexagonv75 -fuse-ld=hexagon-link \ +// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK240 %s +// CHECK240: "-cc1" {{.*}} "-target-cpu" "hexagonv75" +// CHECK240: hexagon-link{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v75/crt0 + +// RUN: not %clang -### --target=hexagon-unknown-elf \ +// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \ +// RUN: -mcpu=hexagonv79 -fuse-ld=hexagon-link \ +// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK250 %s +// CHECK250: "-cc1" {{.*}} "-target-cpu" "hexagonv79" +// CHECK250: hexagon-link{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon/lib/v79/crt0 + // ----------------------------------------------------------------------------- // Test Linker related args // ----------------------------------------------------------------------------- diff --git a/clang/test/Driver/print-enabled-extensions/aarch64-armv9.4-a.c b/clang/test/Driver/print-enabled-extensions/aarch64-armv9.4-a.c index 0032c926c22d9..1cfda6c996b9e 100644 --- a/clang/test/Driver/print-enabled-extensions/aarch64-armv9.4-a.c +++ b/clang/test/Driver/print-enabled-extensions/aarch64-armv9.4-a.c @@ -58,6 +58,7 @@ // CHECK-NEXT: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit // CHECK-NEXT: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions // CHECK-NEXT: FEAT_SVE2 Enable Scalable Vector Extension 2 (SVE2) instructions +// CHECK-NEXT: FEAT_SVE2p1 Enable Scalable Vector Extension 2.1 instructions // CHECK-NEXT: FEAT_TLBIOS, FEAT_TLBIRANGE Enable Armv8.4-A TLB Range and Maintenance instructions // CHECK-NEXT: FEAT_TRBE Enable Trace Buffer Extension // CHECK-NEXT: FEAT_TRF Enable Armv8.4-A Trace extension diff --git a/clang/test/Driver/print-enabled-extensions/aarch64-armv9.5-a.c b/clang/test/Driver/print-enabled-extensions/aarch64-armv9.5-a.c index be24bd0bbddb6..76c8b34a56b75 100644 --- a/clang/test/Driver/print-enabled-extensions/aarch64-armv9.5-a.c +++ b/clang/test/Driver/print-enabled-extensions/aarch64-armv9.5-a.c @@ -61,6 +61,7 @@ // CHECK-NEXT: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit // CHECK-NEXT: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions // CHECK-NEXT: FEAT_SVE2 Enable Scalable Vector Extension 2 (SVE2) instructions +// CHECK-NEXT: FEAT_SVE2p1 Enable Scalable Vector Extension 2.1 instructions // CHECK-NEXT: FEAT_TLBIOS, FEAT_TLBIRANGE Enable Armv8.4-A TLB Range and Maintenance instructions // CHECK-NEXT: FEAT_TRBE Enable Trace Buffer Extension // CHECK-NEXT: FEAT_TRF Enable Armv8.4-A Trace extension 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/ps5-linker.c b/clang/test/Driver/ps5-linker.c index 62aa3a40e455a..53f89a914f4fa 100644 --- a/clang/test/Driver/ps5-linker.c +++ b/clang/test/Driver/ps5-linker.c @@ -172,29 +172,27 @@ // CHECK-SYSROOT: {{ld(\.exe)?}}" // CHECK-SYSROOT-SAME: "--sysroot=mysdk" -// Test that "." is always added to library search paths. This is long-standing -// behavior, unique to PlayStation toolchains. - -// RUN: %clang --target=x64_64-sie-ps5 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LDOT %s - -// CHECK-LDOT: {{ld(\.exe)?}}" -// CHECK-LDOT-SAME: "-L." - -// Test that /target/lib is added to library search paths, if it -// exists and no --sysroot is specified. Also confirm that CRT objects are -// found there. +// Test implicit library search paths are supplied to the linker, after any +// search paths specified by the user. /target/lib is implicitly +// added if it exists and no --sysroot is specified. CRT objects are found +// there. "." is always implicitly added to library search paths. This is +// long-standing behavior, unique to PlayStation toolchains. // RUN: rm -rf %t.dir && mkdir %t.dir -// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-NO-TARGETLIB %s -// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### --sysroot=%t.dir 2>&1 | FileCheck --check-prefixes=CHECK-NO-TARGETLIB %s +// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### -Luser 2>&1 | FileCheck --check-prefixes=CHECK-NO-TARGETLIB %s +// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### -Luser --sysroot=%t.dir 2>&1 | FileCheck --check-prefixes=CHECK-NO-TARGETLIB %s // CHECK-NO-TARGETLIB: {{ld(\.exe)?}}" +// CHECK-NO-TARGETLIB-SAME: "-Luser" // CHECK-NO-TARGETLIB-NOT: "-L{{.*[/\\]}}target/lib" +// CHECK-NO-TARGETLIB-SAME: "-L." // RUN: mkdir -p %t.dir/target/lib // RUN: touch %t.dir/target/lib/crti.o -// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-TARGETLIB %s +// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### -Luser 2>&1 | FileCheck --check-prefixes=CHECK-TARGETLIB %s // CHECK-TARGETLIB: {{ld(\.exe)?}}" +// CHECK-TARGETLIB-SAME: "-Luser" // CHECK-TARGETLIB-SAME: "-L{{.*[/\\]}}target/lib" +// CHECK-TARGETLIB-SAME: "-L." // CHECK-TARGETLIB-SAME: "{{.*[/\\]}}target{{/|\\\\}}lib{{/|\\\\}}crti.o" 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..8347f9c45935d 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 \ @@ -132,18 +132,78 @@ // RUN: -resource-dir=%S/Inputs/empty_resource_dir \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \ // RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-CXX %s -// + +// RUN: %clangxx -### %s 2>&1 \ +// RUN: --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \ +// RUN: -resource-dir=%S/Inputs/empty_resource_dir \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: -fsanitize-link-c++-runtime \ +// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-CXX %s + // CHECK-ASAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}" -// CHECK-ASAN-LINUX-CXX-NOT: "-lc" -// CHECK-ASAN-LINUX-CXX: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive" -// CHECK-ASAN-LINUX-CXX: "--whole-archive" "{{.*}}libclang_rt.asan_cxx.a" "--no-whole-archive" +// CHECK-ASAN-LINUX-CXX-SAME: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive" +// CHECK-ASAN-LINUX-CXX-SAME: "--whole-archive" "{{.*}}libclang_rt.asan_cxx.a" "--no-whole-archive" // CHECK-ASAN-LINUX-CXX-NOT: "--dynamic-list" -// CHECK-ASAN-LINUX-CXX: "--export-dynamic" -// CHECK-ASAN-LINUX-CXX: stdc++ -// 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-SAME: "--export-dynamic" +// CHECK-ASAN-LINUX-CXX-SAME: "-lstdc++" +// CHECK-ASAN-LINUX-CXX-SAME: "-lpthread" +// CHECK-ASAN-LINUX-CXX-SAME: "-lrt" +// CHECK-ASAN-LINUX-CXX-SAME: "-ldl" +// CHECK-ASAN-LINUX-CXX-SAME: "-lresolv" +// CHECK-ASAN-LINUX-CXX-SAME: "-lc" + +// RUN: %clang -### %s 2>&1 \ +// RUN: --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \ +// RUN: -resource-dir=%S/Inputs/empty_resource_dir \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: -fno-sanitize-link-c++-runtime \ +// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-CNOCXX %s + +// CHECK-ASAN-LINUX-CNOCXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}" +// CHECK-ASAN-LINUX-CNOCXX-SAME: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive" +// CHECK-ASAN-LINUX-CNOCXX-NOT: libclang_rt.asan_cxx +// CHECK-ASAN-LINUX-CNOCXX-SAME: "--export-dynamic" +// CHECK-ASAN-LINUX-CNOCXX-NOT: stdc++ +// CHECK-ASAN-LINUX-CNOCXX-SAME: "-lpthread" +// CHECK-ASAN-LINUX-CNOCXX-SAME: "-lrt" +// CHECK-ASAN-LINUX-CNOCXX-SAME: "-ldl" +// CHECK-ASAN-LINUX-CNOCXX-SAME: "-lresolv" +// CHECK-ASAN-LINUX-CNOCXX-SAME: "-lc" + +// RUN: %clangxx -### %s 2>&1 \ +// RUN: --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \ +// RUN: -resource-dir=%S/Inputs/empty_resource_dir \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: -fno-sanitize-link-c++-runtime \ +// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-NOCXX %s + +// CHECK-ASAN-LINUX-NOCXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}" +// CHECK-ASAN-LINUX-NOCXX-SAME: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive" +// CHECK-ASAN-LINUX-NOCXX-NOT: libclang_rt.asan_cxx +// CHECK-ASAN-LINUX-NOCXX-SAME: "--export-dynamic" +// CHECK-ASAN-LINUX-NOCXX-SAME: "-lstdc++" +// CHECK-ASAN-LINUX-NOCXX-SAME: "-lpthread" +// CHECK-ASAN-LINUX-NOCXX-SAME: "-lrt" +// CHECK-ASAN-LINUX-NOCXX-SAME: "-ldl" +// CHECK-ASAN-LINUX-NOCXX-SAME: "-lresolv" +// CHECK-ASAN-LINUX-NOCXX-SAME: "-lc" + +// RUN: %clangxx -### %s 2>&1 \ +// RUN: --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \ +// RUN: -resource-dir=%S/Inputs/empty_resource_dir \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: -nostdlib++ \ +// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-NOSTDCXX %s + +// CHECK-ASAN-LINUX-NOSTDCXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}" +// CHECK-ASAN-LINUX-NOSTDCXX-SAME: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive" +// CHECK-ASAN-LINUX-NOSTDCXX-SAME: libclang_rt.asan_cxx +// CHECK-ASAN-LINUX-NOSTDCXX-SAME: "--export-dynamic" +// CHECK-ASAN-LINUX-NOSTDCXX-SAME: "-lpthread" +// CHECK-ASAN-LINUX-NOSTDCXX-SAME: "-lrt" +// CHECK-ASAN-LINUX-NOSTDCXX-SAME: "-ldl" +// CHECK-ASAN-LINUX-NOSTDCXX-SAME: "-lresolv" +// CHECK-ASAN-LINUX-NOSTDCXX-SAME: "-lc" // RUN: %clang -### %s -o /dev/null -fsanitize=address \ // RUN: --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform \ @@ -274,6 +334,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 +375,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 +448,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 +521,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 +531,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 +568,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 +581,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 +624,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 +647,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 +669,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 +693,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 +704,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 +715,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 +727,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 +840,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 +1040,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 +1101,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 +1150,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/uefi-defines.c b/clang/test/Driver/uefi-defines.c new file mode 100644 index 0000000000000..45f27bfdb9fa9 --- /dev/null +++ b/clang/test/Driver/uefi-defines.c @@ -0,0 +1,6 @@ +// RUN: %clang -target x86_64-unknown-uefi %s -emit-llvm -S -c -o - | FileCheck %s + +// CHECK: __UEFI__defined +#ifdef __UEFI__ +void __UEFI__defined() {} +#endif diff --git a/clang/test/Driver/unknown-arg-drivermodes.test b/clang/test/Driver/unknown-arg-drivermodes.test new file mode 100644 index 0000000000000..0125d79b47afa --- /dev/null +++ b/clang/test/Driver/unknown-arg-drivermodes.test @@ -0,0 +1,51 @@ +// RUN: %clang_cl \ +// RUN: --config \ +// 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: -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: '-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: '-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/Interpreter/crash.cpp b/clang/test/Interpreter/crash.cpp deleted file mode 100644 index 1ab24b0febfa1..0000000000000 --- a/clang/test/Interpreter/crash.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// REQUIRES: host-supports-jit, x86_64-linux - -// RUN: rm -rf %t -// RUN: mkdir -p %t -// -// RUN: split-file %s %t -// -// RUN: %clang++ -std=c++20 -fPIC -c %t/vec.cpp -o %t/vec.o -// RUN: %clang++ -shared %t/vec.o -o %t/vec.so -// -// RUN: cat %t/Test.cpp | LD_LIBRARY_PATH=%t:$LD_LIBRARY_PATH clang-repl - -//--- vec.cpp -#include - -//--- Test.cpp -%lib vec.so -#include -std::vector v; -%quit 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/hexagon.c b/clang/test/Misc/target-invalid-cpu-note/hexagon.c index a7b73f33cccae..e3f5ef0fae1b3 100644 --- a/clang/test/Misc/target-invalid-cpu-note/hexagon.c +++ b/clang/test/Misc/target-invalid-cpu-note/hexagon.c @@ -18,4 +18,6 @@ // CHECK-SAME: {{^}}, hexagonv71 // CHECK-SAME: {{^}}, hexagonv71t // CHECK-SAME: {{^}}, hexagonv73 +// CHECK-SAME: {{^}}, hexagonv75 +// CHECK-SAME: {{^}}, hexagonv79 // CHECK-SAME: {{$}} 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/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/pr120277.cppm b/clang/test/Modules/pr120277.cppm new file mode 100644 index 0000000000000..a4f55ef113b2c --- /dev/null +++ b/clang/test/Modules/pr120277.cppm @@ -0,0 +1,58 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \ +// RUN: -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface -o %t/c.pcm \ +// RUN: -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 %t/d.cppm -emit-module-interface -o %t/d.pcm \ +// RUN: -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 %t/d.pcm -emit-llvm -o %t/d.ll \ +// RUN: -fprebuilt-module-path=%t +// RUN: cat %t/d.ll | FileCheck %t/d.cppm + +//--- a.cppm +export module a; + +export template +struct a { + static auto f() { + } +}; + +//--- b.cppm +export module b; + +import a; + +void b() { + a<0> t; +} + +//--- c.cppm +export module c; + +import a; + +void c() { + a<0>::f(); +} + +//--- d.cppm +export module d; + +import a; +import b; +import c; + +struct d { + static void g() { + a<0>::f(); + a<1>::f(); + } +}; + +// fine enough to check it won't crash +// CHECK: define 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/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/objc-coloncolon.m b/clang/test/Parser/objc-coloncolon.m new file mode 100644 index 0000000000000..04a24fd81ec08 --- /dev/null +++ b/clang/test/Parser/objc-coloncolon.m @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -x objective-c -fsyntax-only -Wno-objc-root-class -verify %s + +int GV = 42; + +@interface A ++ (int) getGV; +- (instancetype)init:(::A *) foo; // expected-error {{expected a type}} +@end + +@implementation A +- (void)performSelector:(SEL)selector {} +- (void)double:(int)firstArg :(int)secondArg colon:(int)thirdArg {} +- (void)test { + // The `::` below should not trigger an error. + [self performSelector:@selector(double::colon:)]; +} ++ (int) getGV { return ::GV; } // expected-error {{expected a type}} +- (instancetype)init:(::A *) foo { return self; } // expected-error {{expected a type}} +@end diff --git a/clang/test/Parser/objcxx-coloncolon.mm b/clang/test/Parser/objcxx-coloncolon.mm new file mode 100644 index 0000000000000..864a7df8400c1 --- /dev/null +++ b/clang/test/Parser/objcxx-coloncolon.mm @@ -0,0 +1,9 @@ +// Test to make sure the parser does not get stuck on the optional +// scope specifier on the type B. +// RUN: %clang_cc1 -fsyntax-only %s + +class B; + +@interface A +- (void) init:(::B *) foo; +@end diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c index 656b31444a9ee..8a404a5a1987d 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-warning@+1{{OpenACC clause 'use_device' not yet implemented, clause ignored}} -#pragma acc serial use_device(s.array[s.value : 5]), self + // 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) {} + +#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 ','}} @@ -822,29 +803,21 @@ void IntExprParsing() { #pragma acc parallel num_workers(returns_int()) {} - // expected-error@+2{{expected '('}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented, pragma ignored}} + // expected-error@+1{{expected '('}} #pragma acc init device_num - // expected-error@+2{{expected expression}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented, pragma ignored}} + // expected-error@+1{{expected expression}} #pragma acc init device_num() - // expected-error@+2{{use of undeclared identifier 'invalid'}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented, pragma ignored}} + // expected-error@+1{{use of undeclared identifier 'invalid'}} #pragma acc init device_num(invalid) - // expected-error@+3{{expected ')'}} - // expected-note@+2{{to match this '('}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented, pragma ignored}} + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} #pragma acc init device_num(5, 4) - // expected-warning@+2{{OpenACC clause 'device_num' not yet implemented, clause ignored}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented, pragma ignored}} #pragma acc init device_num(5) - // expected-warning@+2{{OpenACC clause 'device_num' not yet implemented, clause ignored}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented, pragma ignored}} #pragma acc init device_num(returns_int()) // 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..878c38e8bedc7 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'}} @@ -141,12 +141,10 @@ void func() { // expected-warning@+1{{OpenACC construct 'declare' not yet implemented, pragma ignored}} #pragma acc declare clause list for(;;){} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc init clause list for(;;){} - // expected-error@+2{{invalid OpenACC clause 'clause'}} - // expected-warning@+1{{OpenACC construct 'shutdown' not yet implemented, pragma ignored}} + // expected-error@+1{{invalid OpenACC clause 'clause'}} #pragma acc shutdown clause list for(;;){} // expected-error@+2{{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/hexagon-predefines.c b/clang/test/Preprocessor/hexagon-predefines.c index 188f465520056..eebf48117d80c 100644 --- a/clang/test/Preprocessor/hexagon-predefines.c +++ b/clang/test/Preprocessor/hexagon-predefines.c @@ -137,6 +137,39 @@ // CHECK-V73HVX-128B: #define __HVX__ 1 // CHECK-V73HVX-128B: #define __hexagon__ 1 +// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv75 %s\ +// RUN: | FileCheck %s -check-prefix CHECK-V75 +// CHECK-V75: #define __HEXAGON_ARCH__ 75 +// CHECK-V75: #define __HEXAGON_PHYSICAL_SLOTS__ 4 +// CHECK-V75: #define __HEXAGON_V75__ 1 +// CHECK-V75: #define __hexagon__ 1 + +// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv75 \ +// RUN: -target-feature +hvxv75 -target-feature +hvx-length128b %s | FileCheck \ +// RUN: %s -check-prefix CHECK-V75HVX-128B +// CHECK-V75HVX-128B: #define __HEXAGON_ARCH__ 75 +// CHECK-V75HVX-128B: #define __HEXAGON_V75__ 1 +// CHECK-V75HVX-128B: #define __HVX_ARCH__ 75 +// CHECK-V75HVX-128B: #define __HVX_LENGTH__ 128 +// CHECK-V75HVX-128B: #define __HVX__ 1 +// CHECK-V75HVX-128B: #define __hexagon__ 1 + +// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv79 %s\ +// RUN: | FileCheck %s -check-prefix CHECK-V79 +// CHECK-V79: #define __HEXAGON_ARCH__ 79 +// CHECK-V79: #define __HEXAGON_PHYSICAL_SLOTS__ 4 +// CHECK-V79: #define __HEXAGON_V79__ 1 +// CHECK-V79: #define __hexagon__ 1 + +// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv79 \ +// RUN: -target-feature +hvxv79 -target-feature +hvx-length128b %s | FileCheck \ +// RUN: %s -check-prefix CHECK-V79HVX-128B +// CHECK-V79HVX-128B: #define __HEXAGON_ARCH__ 79 +// CHECK-V79HVX-128B: #define __HEXAGON_V79__ 1 +// CHECK-V79HVX-128B: #define __HVX_ARCH__ 79 +// CHECK-V79HVX-128B: #define __HVX_LENGTH__ 128 +// CHECK-V79HVX-128B: #define __HVX__ 1 +// CHECK-V79HVX-128B: #define __hexagon__ 1 // RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv67 \ // RUN: -target-feature +hvxv67 -target-feature +hvx-length128b %s | FileCheck \ diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c index 05225c120b13d..3b99204acd7a4 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -2742,3 +2742,7 @@ // RISCV64-LINUX: #define __unix__ 1 // RISCV64-LINUX: #define linux 1 // RISCV64-LINUX: #define unix 1 + +// RUN: %clang_cc1 -dM -triple=x86_64-uefi -E /dev/null | FileCheck -match-full-lines -check-prefix UEFI %s + +// UEFI: #define __UEFI__ 1 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 index 2e94c2314f182..192d200eb4910 100644 --- a/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_fp8.c +++ b/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_fp8.c @@ -1,10 +1,10 @@ // REQUIRES: aarch64-registered-target -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -verify -emit-llvm -o - %s +// 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, fpm_t fpm) { +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); @@ -21,4 +21,83 @@ void test_features(svmfloat8_t zn, fpm_t 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/attr-target-version.c b/clang/test/Sema/attr-target-version.c index 5ea370aa980f1..096d2f003a004 100644 --- a/clang/test/Sema/attr-target-version.c +++ b/clang/test/Sema/attr-target-version.c @@ -102,13 +102,17 @@ int __attribute__((target_version("sha2"))) combine(void) { return 1; } // expected-error@+1 {{multiversioned function declaration has a different calling convention}} int __attribute__((aarch64_vector_pcs, target_version("sha3"))) combine(void) { return 2; } +// expected-error@+1 {{multiversioned function must have a prototype}} int __attribute__((target_version("fp+aes+rcpc"))) unspec_args() { return -1; } // expected-error@-1 {{multiversioned function must have a prototype}} +// expected-note@+1 {{function multiversioning caused by this declaration}} int __attribute__((target_version("default"))) unspec_args() { return 0; } int cargs() { return unspec_args(); } +// expected-error@+1 {{multiversioned function must have a prototype}} int unspec_args_implicit_default_first(); // expected-error@-1 {{multiversioned function must have a prototype}} // expected-note@+1 {{function multiversioning caused by this declaration}} int __attribute__((target_version("aes"))) unspec_args_implicit_default_first() { return -1; } +// expected-note@+1 {{function multiversioning caused by this declaration}} int __attribute__((target_version("default"))) unspec_args_implicit_default_first() { return 0; } diff --git a/clang/test/Sema/builtin-assume-aligned-downgrade.c b/clang/test/Sema/builtin-assume-aligned-downgrade.c new file mode 100644 index 0000000000000..93631e7364373 --- /dev/null +++ b/clang/test/Sema/builtin-assume-aligned-downgrade.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -Wno-int-conversion -triple x86_64-linux -verify %s + +// Check that the pointer->int conversion error is not downgradable for the +// pointer argument to __builtin_assume_aligned. + +int test(int *a, int b) { + a = (int *)__builtin_assume_aligned(b, 32); // expected-error {{non-pointer argument to '__builtin_assume_aligned' is not allowed}} + int *y = __builtin_assume_aligned(1, 1); // expected-error {{non-pointer argument to '__builtin_assume_aligned' is not allowed}} +} diff --git a/clang/test/Sema/builtin-assume-aligned.c b/clang/test/Sema/builtin-assume-aligned.c index 33e8557845152..57378a3426524 100644 --- a/clang/test/Sema/builtin-assume-aligned.c +++ b/clang/test/Sema/builtin-assume-aligned.c @@ -74,7 +74,7 @@ int test13(int *a) { } int test14(int *a, int b) { - a = (int *)__builtin_assume_aligned(b, 32); // expected-error {{incompatible integer to pointer conversion passing 'int' to parameter of type 'const void *}} + a = (int *)__builtin_assume_aligned(b, 32); // expected-error {{non-pointer argument to '__builtin_assume_aligned' is not allowed}} } int test15(int *b) { diff --git a/clang/test/Sema/constant_builtins_vector.cpp b/clang/test/Sema/constant_builtins_vector.cpp index b2f56e5a87ab1..8659fa9e46612 100644 --- a/clang/test/Sema/constant_builtins_vector.cpp +++ b/clang/test/Sema/constant_builtins_vector.cpp @@ -798,6 +798,21 @@ static_assert(__builtin_reduce_xor((vector4long){(long long)0x1111111111111111L, static_assert(__builtin_reduce_xor((vector4uint){0x11111111U, 0x22222222U, 0x44444444U, 0x88888888U}) == 0xFFFFFFFFU); static_assert(__builtin_reduce_xor((vector4ulong){0x1111111111111111UL, 0x2222222222222222UL, 0x4444444444444444UL, 0x8888888888888888UL}) == 0xFFFFFFFFFFFFFFFFUL); +static_assert(__builtin_reduce_min((vector4char){}) == 0); +static_assert(__builtin_reduce_min((vector4char){(char)0x11, (char)0x22, (char)0x44, (char)0x88}) == (char)0x88); +static_assert(__builtin_reduce_min((vector4short){(short)0x1111, (short)0x2222, (short)0x4444, (short)0x8888}) == (short)0x8888); +static_assert(__builtin_reduce_min((vector4int){(int)0x11111111, (int)0x22222222, (int)0x44444444, (int)0x88888888}) == (int)0x88888888); +static_assert(__builtin_reduce_min((vector4long){(long long)0x1111111111111111L, (long long)0x2222222222222222L, (long long)0x4444444444444444L, (long long)0x8888888888888888L}) == (long long)0x8888888888888888L); +static_assert(__builtin_reduce_min((vector4uint){0x11111111U, 0x22222222U, 0x44444444U, 0x88888888U}) == 0x11111111U); +static_assert(__builtin_reduce_min((vector4ulong){0x1111111111111111UL, 0x2222222222222222UL, 0x4444444444444444UL, 0x8888888888888888UL}) == 0x1111111111111111UL); +static_assert(__builtin_reduce_max((vector4char){}) == 0); +static_assert(__builtin_reduce_max((vector4char){(char)0x11, (char)0x22, (char)0x44, (char)0x88}) == (char)0x44); +static_assert(__builtin_reduce_max((vector4short){(short)0x1111, (short)0x2222, (short)0x4444, (short)0x8888}) == (short)0x4444); +static_assert(__builtin_reduce_max((vector4int){(int)0x11111111, (int)0x22222222, (int)0x44444444, (int)0x88888888}) == (int)0x44444444); +static_assert(__builtin_reduce_max((vector4long){(long long)0x1111111111111111L, (long long)0x2222222222222222L, (long long)0x4444444444444444L, (long long)0x8888888888888888L}) == (long long)0x4444444444444444L); +static_assert(__builtin_reduce_max((vector4uint){0x11111111U, 0x22222222U, 0x44444444U, 0x88888888U}) == 0x88888888U); +static_assert(__builtin_reduce_max((vector4ulong){0x1111111111111111UL, 0x2222222222222222UL, 0x4444444444444444UL, 0x8888888888888888UL}) == 0x8888888888888888UL); + static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_popcount((vector4char){1, 2, 3, 4})) == (LITTLE_END ? 0x01020101 : 0x01010201)); static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_popcount((vector4short){0, 0x0F0F, ~0, ~0x0F0F})) == (LITTLE_END ? 0x0008001000080000 : 0x0000000800100008)); static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4int){1, 2, 3, 4})) == 5); diff --git a/clang/test/Sema/tautological-pointer-comparison.c b/clang/test/Sema/tautological-pointer-comparison.c new file mode 100644 index 0000000000000..1c5973b01a30d --- /dev/null +++ b/clang/test/Sema/tautological-pointer-comparison.c @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fwrapv -verify=fwrapv %s + +// fwrapv-no-diagnostics + +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..4c19367bb7f3d 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,115 @@ 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 + +namespace GH120206 { +struct S { + std::string_view s; +}; + +struct [[gsl::Owner]] Q1 { + const S* get() const [[clang::lifetimebound]]; +}; +std::string_view test1(int c, std::string_view sv) { + std::string_view k = c > 1 ? Q1().get()->s : sv; + if (c == 1) + return c > 1 ? Q1().get()->s : sv; + Q1 q; + return c > 1 ? q.get()->s : sv; +} + +struct Q2 { + const S* get() const [[clang::lifetimebound]]; +}; +std::string_view test2(int c, std::string_view sv) { + std::string_view k = c > 1 ? Q2().get()->s : sv; + if (c == 1) + return c > 1 ? Q2().get()->s : sv; + Q2 q; + return c > 1 ? q.get()->s : sv; +} + +} // namespace GH120206 diff --git a/clang/test/SemaCXX/attr-target-version.cpp b/clang/test/SemaCXX/attr-target-version.cpp index 32fb97a9dc98d..974f88e77a3f7 100644 --- a/clang/test/SemaCXX/attr-target-version.cpp +++ b/clang/test/SemaCXX/attr-target-version.cpp @@ -57,7 +57,7 @@ int __attribute__((target_version("fp16fml"))) diff_type3(void) noexcept(false) int __attribute__((target_version("sve2-sha3"))) diff_type3(void) noexcept(true) { return 2; } template int __attribute__((target_version("default"))) temp(T) { return 1; } - +// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support function templates}} template int __attribute__((target_version("simd"))) temp1(T) { return 1; } // expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support function templates}} @@ -68,6 +68,7 @@ int __attribute__((target_version("aes"))) extc(void) { return 1; } int __attribute__((target_version("lse"))) extc(void) { return 1; } auto __attribute__((target_version("default"))) ret1(void) { return 1; } +// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support deduced return types}} auto __attribute__((target_version("dpb"))) ret2(void) { return 1; } // expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support deduced return types}} auto __attribute__((target_version("dpb2"))) ret3(void) -> int { return 1; } @@ -84,6 +85,7 @@ class Cls { // expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support deleted functions}} virtual void __attribute__((target_version("default"))) vfunc(); + // expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support virtual functions}} virtual void __attribute__((target_version("sm4"))) vfunc1(); // expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support virtual functions}} }; 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/vector-bool.cpp b/clang/test/SemaCXX/vector-bool.cpp index e99d420e73fab..cd638056f348b 100644 --- a/clang/test/SemaCXX/vector-bool.cpp +++ b/clang/test/SemaCXX/vector-bool.cpp @@ -85,10 +85,10 @@ void foo(const bool& X); // Disallow element-wise access. bool* ElementRefs() { - eight_bools.y = false; // expected-error@88 {{illegal vector component name ''y''}} - &eight_bools.z; // expected-error@89 {{illegal vector component name ''z''}} - foo(eight_bools.w); // expected-error@90 {{illegal vector component name ''w''}} - foo(eight_bools.wyx); // expected-error@91 {{illegal vector component name ''wyx''}} + eight_bools.y = false; // expected-error@88 {{illegal vector component name 'y'}} + &eight_bools.z; // expected-error@89 {{illegal vector component name 'z'}} + foo(eight_bools.w); // expected-error@90 {{illegal vector component name 'w'}} + foo(eight_bools.wyx); // expected-error@91 {{illegal vector component name 'wyx'}} } void Sizeof() { diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp index 8477200456d98..018d6d1bb258b 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); @@ -3171,6 +3196,378 @@ void lockUnlock() EXCLUSIVE_LOCKS_REQUIRED(mu) { } // end namespace ScopedUnlock +namespace PassingScope { + +class SCOPED_LOCKABLE RelockableScope { +public: + RelockableScope(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu); + void Release() UNLOCK_FUNCTION(); + void Acquire() EXCLUSIVE_LOCK_FUNCTION(); + ~RelockableScope() EXCLUSIVE_UNLOCK_FUNCTION(); +}; + +class SCOPED_LOCKABLE ReaderRelockableScope { +public: + ReaderRelockableScope(Mutex *mu) SHARED_LOCK_FUNCTION(mu); + void Release() UNLOCK_FUNCTION(); + void Acquire() SHARED_LOCK_FUNCTION(); + ~ReaderRelockableScope() UNLOCK_FUNCTION(); +}; + +Mutex mu; +Mutex mu1; +Mutex mu2; +int x GUARDED_BY(mu); +int y GUARDED_BY(mu) GUARDED_BY(mu2); +void print(int); + +// Analysis inside the function with annotated parameters + +void sharedRequired(ReleasableMutexLock& scope SHARED_LOCKS_REQUIRED(mu)) { + print(x); // OK. +} + +void sharedAcquire(ReaderRelockableScope& scope SHARED_LOCK_FUNCTION(mu)) { + scope.Acquire(); + print(x); +} + +void sharedRelease(RelockableScope& scope SHARED_UNLOCK_FUNCTION(mu)) { + print(x); + scope.Release(); + print(x); // expected-warning{{reading variable 'x' requires holding mutex 'mu'}} +} + +void requiredLock(ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)) { + x = 1; // OK. +} + +void reacquireRequiredLock(RelockableScope& scope EXCLUSIVE_LOCKS_REQUIRED(mu)) { + scope.Release(); + scope.Acquire(); + x = 2; // OK. +} + +void releaseSingleMutex(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)) { + x = 1; // OK. + scope.Release(); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void releaseMultipleMutexes(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu, mu2)) { + y = 1; // OK. + scope.Release(); + y = 2; // expected-warning{{writing variable 'y' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{writing variable 'y' requires holding mutex 'mu2' exclusively}} +} + +void acquireLock(RelockableScope& scope EXCLUSIVE_LOCK_FUNCTION(mu)) { + x = 1; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} + scope.Acquire(); + x = 2; // OK. +} + +void acquireMultipleLocks(RelockableScope& scope EXCLUSIVE_LOCK_FUNCTION(mu, mu2)) { + y = 1; // expected-warning{{writing variable 'y' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{writing variable 'y' requires holding mutex 'mu2' exclusively}} + scope.Acquire(); + y = 2; // OK. +} + +void excludedLock(ReleasableMutexLock& scope LOCKS_EXCLUDED(mu)) { + x = 1; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void acquireAndReleaseExcludedLocks(RelockableScope& scope LOCKS_EXCLUDED(mu)) { + scope.Acquire(); + scope.Release(); +} + +// expected-note@+1{{mutex acquired here}} +void unreleasedMutex(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)) { + x = 1; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void acquireAlreadyHeldMutex(RelockableScope& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)) { + scope.Acquire(); // expected-warning{{acquiring mutex 'mu' that is already held}} + scope.Release(); +} + +void reacquireMutex(RelockableScope& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)) { + scope.Release(); + scope.Acquire(); // expected-note{{mutex acquired here}} + x = 2; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void requireSingleMutex(ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)) { + x = 1; // OK. + scope.Release(); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +// expected-note@+1 2{{mutex acquired here}} +void requireMultipleMutexes(ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu, mu2)) { + y = 1; // OK. + scope.Release(); + y = 2; // expected-warning{{writing variable 'y' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{writing variable 'y' requires holding mutex 'mu2' exclusively}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + // expected-warning@-1{{expecting mutex 'mu2' to be held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void acquireAlreadyHeldLock(RelockableScope& scope EXCLUSIVE_LOCKS_REQUIRED(mu)) { + scope.Acquire(); // expected-warning{{acquiring mutex 'mu' that is already held}} +} + +// expected-note@+1 {{mutex acquired here}} +void releaseWithoutHoldingLock(ReleasableMutexLock& scope EXCLUSIVE_LOCK_FUNCTION(mu)) { + scope.Release(); // expected-warning{{releasing mutex 'mu' that was not held}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +// expected-note@+1 {{mutex acquired here}} +void endWithReleasedMutex(RelockableScope& scope EXCLUSIVE_LOCK_FUNCTION(mu)) { + scope.Acquire(); + scope.Release(); +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +void acquireExcludedLock(RelockableScope& scope LOCKS_EXCLUDED(mu)) { + x = 1; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} + scope.Acquire(); // expected-note {{mutex acquired here}} + x = 2; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + +void acquireMultipleExcludedLocks(RelockableScope& scope LOCKS_EXCLUDED(mu, mu2)) { + y = 1; // expected-warning{{writing variable 'y' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{writing variable 'y' requires holding mutex 'mu2' exclusively}} + scope.Acquire(); // expected-note 2{{mutex acquired here}} + y = 2; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + // expected-warning@-1{{mutex 'mu2' is still held at the end of function}} + +void reacquireExcludedLocks(RelockableScope& scope LOCKS_EXCLUDED(mu)) { + scope.Release(); // expected-warning{{releasing mutex 'mu' that was not held}} + scope.Acquire(); // expected-note {{mutex acquired here}} + x = 2; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void sharedRequired2(ReleasableMutexLock& scope SHARED_LOCKS_REQUIRED(mu)) { + print(x); // OK. + scope.Release(); + print(x); // expected-warning{{reading variable 'x' requires holding mutex 'mu'}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void sharedAcquire2(RelockableScope& scope SHARED_LOCK_FUNCTION(mu)) { + print(x); // expected-warning{{reading variable 'x' requires holding mutex 'mu'}} + scope.Release(); // expected-warning{{releasing mutex 'mu' that was not held}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +// expected-note@+1 2{{mutex acquired here}} +void sharedRelease2(RelockableScope& scope SHARED_UNLOCK_FUNCTION(mu)) { + scope.Acquire(); //expected-warning{{acquiring mutex 'mu' that is already held}} +} //expected-warning{{mutex 'mu' is still held at the end of function}} + +// Handling the call of the function with annotated parameters + +// expected-note@+1{{see attribute on parameter here}} +void release(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)); +// expected-note@+1{{see attribute on parameter here}} +void release_DoubleMutexLock(DoubleMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)); +// expected-note@+1 2{{see attribute on parameter here}} +void release_two(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu, mu2)); +// expected-note@+1{{see attribute on parameter here}} +void release_double(DoubleMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu, mu2)); +void require(ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)); +void acquire(RelockableScope& scope EXCLUSIVE_LOCK_FUNCTION(mu)); +void exclude(RelockableScope& scope LOCKS_EXCLUDED(mu)); + +void release_shared(ReaderRelockableScope& scope SHARED_UNLOCK_FUNCTION(mu)); +void require_shared(ReleasableMutexLock& scope SHARED_LOCKS_REQUIRED(mu)); +void acquire_shared(ReaderRelockableScope& scope SHARED_LOCK_FUNCTION(mu)); + +void unlockCall() { + ReleasableMutexLock scope(&mu); + x = 1; // OK. + release(scope); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void unlockSharedCall() { + ReaderRelockableScope scope(&mu); + print(x); // OK. + release_shared(scope); + print(x); // expected-warning{{reading variable 'x' requires holding mutex 'mu'}} +} + +void requireCall() { + ReleasableMutexLock scope(&mu); + x = 1; // OK. + require(scope); + x = 2; // Ok. +} + +void requireSharedCall() { + ReleasableMutexLock scope(&mu); + print(x); // OK. + require_shared(scope); + print(x); // Ok. +} + +void acquireCall() { + RelockableScope scope(&mu); + scope.Release(); + acquire(scope); + x = 2; // Ok. +} + +void acquireSharedCall() { + ReaderRelockableScope scope(&mu); + scope.Release(); + acquire_shared(scope); + print(x); // Ok. +} + +void writeAfterExcludeCall() { + RelockableScope scope(&mu); + scope.Release(); + exclude(scope); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void unlockCallAfterExplicitRelease() { + ReleasableMutexLock scope(&mu); + x = 1; // OK. + scope.Release(); // expected-note{{mutex released here}} + release(scope); // expected-warning{{releasing mutex 'mu' that was not held}} + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void unmatchedMutexes() { + ReleasableMutexLock scope(&mu2); + release(scope); // expected-warning{{mutex managed by 'scope' is 'mu2' instead of 'mu'}} + // expected-warning@-1{{releasing mutex 'mu' that was not held}} +} + +void wrongOrder() { + DoubleMutexLock scope(&mu2, &mu); + release_double(scope); // expected-warning{{mutex managed by 'scope' is 'mu2' instead of 'mu'}} +} + +void differentNumberOfMutexes() { + ReleasableMutexLock scope(&mu); + release_two(scope); // expected-warning{{mutex 'mu2' not managed by 'scope'}} + // expected-warning@-1{{releasing mutex 'mu2' that was not held}} +} + +void differentNumberOfMutexes2() { + ReleasableMutexLock scope(&mu2); + release_two(scope); // expected-warning{{mutex managed by 'scope' is 'mu2' instead of 'mu'}} + // expected-warning@-1{{releasing mutex 'mu' that was not held}} +} + +void differentNumberOfMutexes3() { + DoubleMutexLock scope(&mu, &mu2); + release_DoubleMutexLock(scope); // expected-warning{{did not expect mutex 'mu2' to be managed by 'scope'}} +} + +void releaseDefault(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu), int = 0); + +void unlockFunctionDefault() { + ReleasableMutexLock scope(&mu); + x = 1; // OK. + releaseDefault(scope); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void requireCallWithReleasedLock() { + ReleasableMutexLock scope(&mu); + scope.Release(); + require(scope); // expected-warning{{calling function 'require' requires holding mutex 'mu' exclusively}} +} + +void acquireCallWithAlreadyHeldLock() { + RelockableScope scope(&mu); // expected-note{{mutex acquired here}} + acquire(scope); // expected-warning{{acquiring mutex 'mu' that is already held}} + x = 1; +} + +void excludeCallWithAlreadyHeldLock() { + RelockableScope scope(&mu); + exclude(scope); // expected-warning{{cannot call function 'exclude' while mutex 'mu' is held}} + x = 2; // OK. +} + +void requireConst(const ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)); +void requireConstCall() { + requireConst(ReleasableMutexLock(&mu)); +} + +void passScopeUndeclared(ReleasableMutexLock &scope) { + release(scope); // expected-warning{{calling function 'release' requires holding mutex 'scope' exclusively}} + // expected-warning@-1{{releasing mutex 'mu' that was not held}} +} + +class SCOPED_LOCKABLE ScopedWithoutLock { +public: + ScopedWithoutLock(); + + ~ScopedWithoutLock() EXCLUSIVE_UNLOCK_FUNCTION(); +}; + +void require(ScopedWithoutLock &scope EXCLUSIVE_LOCKS_REQUIRED(mu)); + +void constructWithoutLock() { + ScopedWithoutLock scope; + require(scope); // expected-warning{{calling function 'require' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{calling function 'require' requires holding mutex 'scope' exclusively}} +} // expected-warning {{releasing mutex 'scope' that was not held}} + +void requireConst(const ScopedWithoutLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)); + +void requireCallWithReleasedLock2() { + requireConst(ScopedWithoutLock()); + // expected-warning@-1{{calling function 'requireConst' requires holding mutex '#undefined' exclusively}} + // expected-warning@-2{{calling function 'requireConst' requires holding mutex 'mu' exclusively}} +} + +void requireDecl(RelockableScope &scope EXCLUSIVE_LOCKS_REQUIRED(mu)); +void requireDecl(RelockableScope &scope) { + scope.Release(); + scope.Acquire(); +} + +struct foo +{ + Mutex mu; + // expected-note@+1{{see attribute on parameter here}} + void require(RelockableScope &scope EXCLUSIVE_LOCKS_REQUIRED(mu)); + void callRequire(){ + RelockableScope scope(&mu); + // TODO: False positive due to incorrect parsing of parameter attribute arguments. + require(scope); + // expected-warning@-1{{calling function 'require' requires holding mutex 'mu' exclusively}} + // expected-warning@-2{{mutex managed by 'scope' is 'mu' instead of 'mu'}} + } +}; + +struct ObjectWithMutex { + Mutex mu; + int x GUARDED_BY(mu); +}; +void releaseMember(ObjectWithMutex& object, ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(object.mu)) { + object.x = 1; + scope.Release(); +} +void releaseMemberCall() { + ObjectWithMutex obj; + ReleasableMutexLock lock(&obj.mu); + releaseMember(obj, lock); +} + +} // end namespace PassingScope namespace TrylockFunctionTest { @@ -5172,9 +5569,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-thread-safety-parsing.cpp b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp index 0c5b0cc85897b..752803e4a0543 100644 --- a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp @@ -62,6 +62,12 @@ class MuDoubleWrapper { } }; +class SCOPED_LOCKABLE MutexLock { + public: + MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu); + ~MutexLock() UNLOCK_FUNCTION(); +}; + Mutex mu1; UnlockableMu umu; Mutex mu2; @@ -599,8 +605,11 @@ class EXCLUSIVE_LOCK_FUNCTION() ElfTestClass { // \ // expected-warning {{'exclusive_lock_function' attribute only applies to functions}} }; -void elf_fun_params(int lvar EXCLUSIVE_LOCK_FUNCTION()); // \ - // expected-warning {{'exclusive_lock_function' attribute only applies to functions}} +void elf_fun_params1(MutexLock& scope EXCLUSIVE_LOCK_FUNCTION(mu1)); +void elf_fun_params2(int lvar EXCLUSIVE_LOCK_FUNCTION(mu1)); // \ + // expected-warning{{'exclusive_lock_function' attribute applies to function parameters only if their type is a reference to a 'scoped_lockable'-annotated type}} +void elf_fun_params3(MutexLock& scope EXCLUSIVE_LOCK_FUNCTION()); // \ + // expected-warning{{'exclusive_lock_function' attribute without capability arguments can only be applied to non-static methods of a class}} // Check argument parsing. @@ -660,8 +669,11 @@ int slf_testfn(int y) { int slf_test_var SHARED_LOCK_FUNCTION(); // \ // expected-warning {{'shared_lock_function' attribute only applies to functions}} -void slf_fun_params(int lvar SHARED_LOCK_FUNCTION()); // \ - // expected-warning {{'shared_lock_function' attribute only applies to functions}} +void slf_fun_params1(MutexLock& scope SHARED_LOCK_FUNCTION(mu1)); +void slf_fun_params2(int lvar SHARED_LOCK_FUNCTION(mu1)); // \ + // expected-warning {{'shared_lock_function' attribute applies to function parameters only if their type is a reference to a 'scoped_lockable'-annotated type}} +void slf_fun_params3(MutexLock& scope SHARED_LOCK_FUNCTION()); // \ + // expected-warning {{'shared_lock_function' attribute without capability arguments can only be applied to non-static methods of a class}} class SlfFoo { private: @@ -903,8 +915,11 @@ class NO_THREAD_SAFETY_ANALYSIS UfTestClass { // \ // expected-warning {{'no_thread_safety_analysis' attribute only applies to functions}} }; -void uf_fun_params(int lvar UNLOCK_FUNCTION()); // \ - // expected-warning {{'unlock_function' attribute only applies to functions}} +void uf_fun_params1(MutexLock& scope UNLOCK_FUNCTION(mu1)); +void uf_fun_params2(int lvar UNLOCK_FUNCTION(mu1)); // \ + // expected-warning {{'unlock_function' attribute applies to function parameters only if their type is a reference to a 'scoped_lockable'-annotated type}} +void uf_fun_params3(MutexLock& scope UNLOCK_FUNCTION()); // \ + // expected-warning {{'unlock_function' attribute without capability arguments can only be applied to non-static methods of a class}} // Check argument parsing. @@ -1035,8 +1050,9 @@ int le_testfn(int y) { int le_test_var LOCKS_EXCLUDED(mu1); // \ // expected-warning {{'locks_excluded' attribute only applies to functions}} -void le_fun_params(int lvar LOCKS_EXCLUDED(mu1)); // \ - // expected-warning {{'locks_excluded' attribute only applies to functions}} +void le_fun_params1(MutexLock& scope LOCKS_EXCLUDED(mu1)); +void le_fun_params2(int lvar LOCKS_EXCLUDED(mu1)); // \ + // expected-warning{{'locks_excluded' attribute applies to function parameters only if their type is a reference to a 'scoped_lockable'-annotated type}} class LeFoo { private: @@ -1102,8 +1118,9 @@ int elr_testfn(int y) { int elr_test_var EXCLUSIVE_LOCKS_REQUIRED(mu1); // \ // expected-warning {{'exclusive_locks_required' attribute only applies to functions}} -void elr_fun_params(int lvar EXCLUSIVE_LOCKS_REQUIRED(mu1)); // \ - // expected-warning {{'exclusive_locks_required' attribute only applies to functions}} +void elr_fun_params1(MutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu1)); +void elr_fun_params2(int lvar EXCLUSIVE_LOCKS_REQUIRED(mu1)); // \ + // expected-warning {{'exclusive_locks_required' attribute applies to function parameters only if their type is a reference to a 'scoped_lockable'-annotated type}} class ElrFoo { private: @@ -1170,8 +1187,9 @@ int slr_testfn(int y) { int slr_test_var SHARED_LOCKS_REQUIRED(mu1); // \ // expected-warning {{'shared_locks_required' attribute only applies to functions}} -void slr_fun_params(int lvar SHARED_LOCKS_REQUIRED(mu1)); // \ - // expected-warning {{'shared_locks_required' attribute only applies to functions}} +void slr_fun_params1(MutexLock& scope SHARED_LOCKS_REQUIRED(mu1)); +void slr_fun_params2(int lvar SHARED_LOCKS_REQUIRED(mu1)); // \ + // expected-warning {{'shared_locks_required' attribute applies to function parameters only if their type is a reference to a 'scoped_lockable'-annotated type}} class SlrFoo { private: 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/StructuredBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl index edfc1b48037c9..fb14429025d5a 100644 --- a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl +++ b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl @@ -5,13 +5,25 @@ typedef vector float3; StructuredBuffer Buffer; // expected-error@+2 {{class template 'StructuredBuffer' requires template arguments}} -// expected-note@*:* {{template declaration from hidden source: template class StructuredBuffer {}}} +// expected-note@*:* {{template declaration from hidden source: template requires __is_structured_resource_element_compatible class StructuredBuffer {}}} StructuredBuffer BufferErr1; // expected-error@+2 {{too few template arguments for class template 'StructuredBuffer'}} -// expected-note@*:* {{template declaration from hidden source: template class StructuredBuffer {}}} +// expected-note@*:* {{template declaration from hidden source: template requires __is_structured_resource_element_compatible class StructuredBuffer {}}} StructuredBuffer<> BufferErr2; +// test elements of 0 size +// expected-error@+3{{constraints not satisfied for class template 'StructuredBuffer' [with element_type = int[0]]}} +// expected-note@*:*{{because 'int[0]' does not satisfy '__is_structured_resource_element_compatible'}} +// expected-note@*:*{{because 'sizeof(int[0]) >= 1UL' (0 >= 1) evaluated to false}} +StructuredBuffer BufferErr3; + +// In C++, empty structs do have a size of 1. So should HLSL. +// The concept will accept empty structs as element types, despite it being unintuitive. +struct Empty {}; +StructuredBuffer BufferErr4; + + [numthreads(1,1,1)] void main() { (void)Buffer.__handle; // expected-error {{'__handle' is a private member of 'hlsl::StructuredBuffer>'}} 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/SemaOpenACC/combined-construct-async-clause.cpp b/clang/test/SemaOpenACC/combined-construct-async-clause.cpp index 872586acbaffa..c54f340cdfd96 100644 --- a/clang/test/SemaOpenACC/combined-construct-async-clause.cpp +++ b/clang/test/SemaOpenACC/combined-construct-async-clause.cpp @@ -48,7 +48,7 @@ void Test() { #pragma acc parallel loop async(Convert) for (int i = 5; i < 10; ++i); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc kernels loop async(Explicit) for (int i = 5; i < 10; ++i); @@ -94,12 +94,12 @@ void TestInst() { #pragma acc kernels loop async(T::ACValue) for (int i = 5; i < 10; ++i); - // expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel loop async(HasInt::EXValue) for (int i = 5; i < 10; ++i); - // expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc kernels loop async(T::EXValue) for (int i = 5; i < 10; ++i); 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 16bdcc177bfde..f37c1d7e72928 100644 --- a/clang/test/SemaOpenACC/combined-construct-auto_seq_independent-clauses.c +++ b/clang/test/SemaOpenACC/combined-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 '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 @@ -64,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}} @@ -134,7 +134,7 @@ void uses() { for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop auto num_workers(1) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop auto device_num(1) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' not yet implemented}} @@ -154,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 @@ -181,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}} @@ -251,7 +251,7 @@ void uses() { for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop num_workers(1) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop device_num(1) auto for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' not yet implemented}} @@ -272,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 @@ -299,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}} @@ -369,7 +369,7 @@ void uses() { for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop independent num_workers(1) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop independent device_num(1) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' not yet implemented}} @@ -389,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 @@ -416,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}} @@ -486,7 +486,7 @@ void uses() { for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop num_workers(1) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop device_num(1) independent for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' not yet implemented}} @@ -519,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}} @@ -542,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}} @@ -612,7 +612,7 @@ void uses() { for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop seq num_workers(1) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop seq device_num(1) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' not yet implemented}} @@ -642,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}} @@ -665,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}} @@ -735,7 +735,7 @@ void uses() { for(unsigned i = 0; i < 5; ++i); #pragma acc parallel loop num_workers(1) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'parallel loop' directive}} #pragma acc parallel loop device_num(1) seq for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' not yet implemented}} 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..50612c2a4685e 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}} @@ -195,8 +190,7 @@ void uses() { for(int i = 0; i < 5; ++i); #pragma acc parallel loop device_type(*) num_workers(1) for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'device_num' may not follow a 'device_type' clause in a 'serial loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'serial loop' directive}} #pragma acc serial loop device_type(*) device_num(1) for(int i = 0; i < 5; ++i); // expected-error@+2{{OpenACC clause 'default_async' may not follow a 'device_type' clause in a 'serial 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-wait-clause.cpp b/clang/test/SemaOpenACC/combined-construct-wait-clause.cpp index 9ce04290cbe5a..e0411925e9f20 100644 --- a/clang/test/SemaOpenACC/combined-construct-wait-clause.cpp +++ b/clang/test/SemaOpenACC/combined-construct-wait-clause.cpp @@ -18,7 +18,7 @@ void Test() { #pragma acc parallel loop wait(Ambiguous) for (unsigned i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel loop wait(4, Explicit, 5) for (unsigned i = 0; i < 5; ++i); @@ -29,12 +29,12 @@ void Test() { #pragma acc parallel loop wait(queues: Ambiguous, 5) for (unsigned i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel loop wait(devnum: Explicit: 5) for (unsigned i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel loop wait(devnum: Explicit:queues: 5) for (unsigned i = 0; i < 5; ++i); @@ -70,7 +70,7 @@ void TestInst() { #pragma acc parallel loop wait(devnum:T::value :queues:T::ACValue) for (unsigned i = 0; i < 5; ++i); - // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' 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'}} @@ -78,7 +78,7 @@ void TestInst() { #pragma acc parallel loop wait(devnum:T::EXValue :queues:T::ACValue) for (unsigned i = 0; i < 5; ++i); - // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' 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'}} @@ -86,7 +86,7 @@ void TestInst() { #pragma acc parallel loop wait(T::EXValue, T::ACValue) for (unsigned i = 0; i < 5; ++i); - // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' 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'}} diff --git a/clang/test/SemaOpenACC/compute-construct-async-clause.cpp b/clang/test/SemaOpenACC/compute-construct-async-clause.cpp index a5da7c8f4e56e..44b1540a934c2 100644 --- a/clang/test/SemaOpenACC/compute-construct-async-clause.cpp +++ b/clang/test/SemaOpenACC/compute-construct-async-clause.cpp @@ -46,7 +46,7 @@ void Test() { #pragma acc parallel async(Convert) while(1); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc kernels async(Explicit) while(1); @@ -92,12 +92,12 @@ void TestInst() { #pragma acc kernels async(T::ACValue) while (1); - // expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel async(HasInt::EXValue) while (1); - // expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc kernels async(T::EXValue) while (1); 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..bbad68c425f3e 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}} @@ -200,8 +195,7 @@ void uses() { while(1); #pragma acc kernels device_type(*) num_workers(1) while(1); - // expected-error@+2{{OpenACC clause 'device_num' may not follow a 'device_type' clause in a 'kernels' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'kernels' directive}} #pragma acc kernels device_type(*) device_num(1) while(1); // expected-error@+2{{OpenACC clause 'default_async' 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-num_gangs-clause.cpp b/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp index c50f52afda7c1..c6dbe4db2be64 100644 --- a/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp +++ b/clang/test/SemaOpenACC/compute-construct-num_gangs-clause.cpp @@ -74,20 +74,20 @@ void Test() { #pragma acc parallel num_gangs(SomeE, NC) while(1); - // expected-error@+3{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+3{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} // expected-error@+1{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}} #pragma acc parallel num_gangs(Explicit, NC) while(1); - // expected-error@+4{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+4{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} // expected-error@+2{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}} // expected-error@+1{{OpenACC 'num_gangs' clause is not valid on 'serial' directive}} #pragma acc serial num_gangs(Explicit, NC) while(1); - // expected-error@+6{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+6{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} // expected-error@+4{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}} // expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}} @@ -96,7 +96,7 @@ void Test() { #pragma acc parallel num_gangs(Explicit, NC, Ambiguous) while(1); - // expected-error@+7{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+7{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} // expected-error@+5{{OpenACC clause 'num_gangs' requires expression of integer type ('struct NotConvertible' invalid)}} // expected-error@+4{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}} diff --git a/clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp b/clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp index 9449b77d092f4..c73f421222e86 100644 --- a/clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp +++ b/clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp @@ -44,7 +44,7 @@ void Test() { #pragma acc parallel num_workers(Convert) while(1); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc kernels num_workers(Explicit) while(1); @@ -90,12 +90,12 @@ void TestInst() { #pragma acc kernels num_workers(T::ACValue) while (1); - // expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel num_workers(HasInt::EXValue) while (1); - // expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc kernels num_workers(T::EXValue) while (1); diff --git a/clang/test/SemaOpenACC/compute-construct-private-clause.c b/clang/test/SemaOpenACC/compute-construct-private-clause.c index d979fd909f11c..a40d84c669d9a 100644 --- a/clang/test/SemaOpenACC/compute-construct-private-clause.c +++ b/clang/test/SemaOpenACC/compute-construct-private-clause.c @@ -135,8 +135,7 @@ void uses(int IntParam, short *PointerParam, float ArrayParam[5], Complete Compo #pragma acc parallel private((float)ArrayParam[2]) while(1); - // expected-error@+2{{OpenACC 'private' clause is not valid on 'init' directive}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented}} + // expected-error@+1{{OpenACC 'private' clause is not valid on 'init' directive}} #pragma acc init private(LocalInt) for(;;); } diff --git a/clang/test/SemaOpenACC/compute-construct-reduction-clause.c b/clang/test/SemaOpenACC/compute-construct-reduction-clause.c index fcc4ca2655c20..4d426cf189fca 100644 --- a/clang/test/SemaOpenACC/compute-construct-reduction-clause.c +++ b/clang/test/SemaOpenACC/compute-construct-reduction-clause.c @@ -105,8 +105,7 @@ void uses(unsigned Parm) { #pragma acc parallel reduction(&:HA.array[1:2]) while (1); - // expected-error@+2{{OpenACC 'reduction' clause is not valid on 'init' directive}} - // expected-warning@+1{{OpenACC construct 'init' not yet implemented}} + // expected-error@+1{{OpenACC 'reduction' clause is not valid on 'init' directive}} #pragma acc init reduction(+:I) for(;;); } diff --git a/clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp b/clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp index f6c5dde1a0235..f2bbe0f022a07 100644 --- a/clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp +++ b/clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp @@ -44,7 +44,7 @@ void Test() { #pragma acc parallel vector_length(Convert) while(1); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc kernels vector_length(Explicit) while(1); @@ -90,12 +90,12 @@ void TestInst() { #pragma acc kernels vector_length(T::ACValue) while (1); - // expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel vector_length(HasInt::EXValue) while (1); - // expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc kernels vector_length(T::EXValue) while (1); diff --git a/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp b/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp index 94f669be0f672..fbe40ce5f31c1 100644 --- a/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp +++ b/clang/test/SemaOpenACC/compute-construct-wait-clause.cpp @@ -18,7 +18,7 @@ void Test() { #pragma acc parallel wait(Ambiguous) while (true); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel wait(4, Explicit, 5) while (true); @@ -29,12 +29,12 @@ void Test() { #pragma acc parallel wait(queues: Ambiguous, 5) while (true); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel wait(devnum: Explicit: 5) while (true); - // expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} #pragma acc parallel wait(devnum: Explicit:queues: 5) while (true); @@ -70,7 +70,7 @@ void TestInst() { #pragma acc parallel wait(devnum:T::value :queues:T::ACValue) while (true); - // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' 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'}} @@ -78,7 +78,7 @@ void TestInst() { #pragma acc parallel wait(devnum:T::EXValue :queues:T::ACValue) while (true); - // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' 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'}} @@ -86,7 +86,7 @@ void TestInst() { #pragma acc parallel wait(T::EXValue, T::ACValue) while (true); - // expected-error@+5{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}} + // expected-error@+5{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' 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'}} 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/init-construct-ast.cpp b/clang/test/SemaOpenACC/init-construct-ast.cpp new file mode 100644 index 0000000000000..7c7d07a450d51 --- /dev/null +++ b/clang/test/SemaOpenACC/init-construct-ast.cpp @@ -0,0 +1,148 @@ +// 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 init + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init +#pragma acc init if (some_int() < some_long()) + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' 'long ()' +#pragma acc init device_num(some_int()) + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: device_num clause + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' +#pragma acc init device_type(T) + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: device_type(T) +#pragma acc init if (some_int() < some_long()) device_type(T) device_num(some_int()) + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' 'long ()' + // CHECK-NEXT: device_type(T) + // CHECK-NEXT: device_num clause + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' +} + +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 init + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init +#pragma acc init if (T::value > t) + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '' '>' + // CHECK-NEXT: DependentScopeDeclRefExpr + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T' +#pragma acc init device_num(t) + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: device_num clause + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T' +#pragma acc init device_type(T) + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: device_type(T) +#pragma acc init if (T::value > t) device_type(T) device_num(t) + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '' '>' + // CHECK-NEXT: DependentScopeDeclRefExpr + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T' + // CHECK-NEXT: device_type(T) + // CHECK-NEXT: device_num clause + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T' + + // Instantiation: + // CHECK-NEXT: FunctionDecl{{.*}} TemplFunc 'void (SomeStruct)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'SomeStruct' + // CHECK-NEXT: RecordType{{.*}} 'SomeStruct' + // CHECK-NEXT: CXXRecord{{.*}} 'SomeStruct' + // CHECK-NEXT: ParmVarDecl{{.*}} t 'SomeStruct' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const unsigned int' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'SomeStruct' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'unsigned int' + // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct' + + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: device_num clause + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'unsigned int' + // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct' + + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: device_type(T) + + // CHECK-NEXT: OpenACCInitConstruct{{.*}}init + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const unsigned int' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'SomeStruct' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'unsigned int' + // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct' + // CHECK-NEXT: device_type(T) + // CHECK-NEXT: device_num clause + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'unsigned int' + // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct' +} + +struct SomeStruct{ + static constexpr unsigned value = 5; + operator unsigned(); +}; + +void use() { + TemplFunc(SomeStruct{}); +} +#endif diff --git a/clang/test/SemaOpenACC/init-construct.cpp b/clang/test/SemaOpenACC/init-construct.cpp new file mode 100644 index 0000000000000..e4491ee905f3f --- /dev/null +++ b/clang/test/SemaOpenACC/init-construct.cpp @@ -0,0 +1,71 @@ +// 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() { +#pragma acc init +#pragma acc init if (getI() < getS()) +#pragma acc init device_num(getI()) +#pragma acc init device_type(SOMETHING) device_num(getI()) +#pragma acc init device_type(SOMETHING) if (getI() < getS()) +#pragma acc init device_type(SOMETHING) device_num(getI()) if (getI() < getS()) + + // expected-error@+1{{value of type 'struct NotConvertible' is not contextually convertible to 'bool'}} +#pragma acc init if (NC) + + // expected-error@+1{{OpenACC clause 'device_num' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc init device_num(NC) + // 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 init device_num(Ambiguous) + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} +#pragma acc init device_num(Explicit) +} + +template +void TestInst() { + T t; +#pragma acc init +#pragma acc init if (T::value < T{}) +#pragma acc init device_type(SOMETHING) device_num(getI()) if (getI() < getS()) +#pragma acc init device_type(SOMETHING) device_type(T) device_num(t) if (t < T::value) device_num(getI()) if (getI() < getS()) + + // expected-error@+1{{value of type 'const NotConvertible' is not contextually convertible to 'bool'}} +#pragma acc init if (T::NCValue) + + // expected-error@+1{{OpenACC clause 'device_num' requires expression of integer type ('const NotConvertible' invalid)}} +#pragma acc init device_num(T::NCValue) + // 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 init device_num(T::ACValue) + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} +#pragma acc init device_num(T::EXValue) +} + +struct HasStuff { + static constexpr AmbiguousConvert ACValue; + static constexpr ExplicitConvertOnly EXValue; + static constexpr NotConvertible NCValue; + static constexpr unsigned value = 5; + operator char(); +}; + +void Inst() { + TestInst(); // expected-note {{in instantiation of function template specialization}} +} 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..d75d6abb99f6f 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}} @@ -149,7 +149,7 @@ void uses() { // expected-error@+1{{OpenACC 'num_workers' clause is not valid on 'loop' directive}} #pragma acc loop auto num_workers(1) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'loop' directive}} #pragma acc loop auto device_num(1) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' 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}} @@ -283,7 +283,7 @@ void uses() { // expected-error@+1{{OpenACC 'num_workers' clause is not valid on 'loop' directive}} #pragma acc loop num_workers(1) auto for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'loop' directive}} #pragma acc loop device_num(1) auto for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' 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}} @@ -418,7 +418,7 @@ void uses() { // expected-error@+1{{OpenACC 'num_workers' clause is not valid on 'loop' directive}} #pragma acc loop independent num_workers(1) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'loop' directive}} #pragma acc loop independent device_num(1) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' 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}} @@ -552,7 +552,7 @@ void uses() { // expected-error@+1{{OpenACC 'num_workers' clause is not valid on 'loop' directive}} #pragma acc loop num_workers(1) independent for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'loop' directive}} #pragma acc loop device_num(1) independent for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' 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}} @@ -695,7 +695,7 @@ void uses() { // expected-error@+1{{OpenACC 'num_workers' clause is not valid on 'loop' directive}} #pragma acc loop seq num_workers(1) for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'loop' directive}} #pragma acc loop seq device_num(1) for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' 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}} @@ -835,7 +835,7 @@ void uses() { // expected-error@+1{{OpenACC 'num_workers' clause is not valid on 'loop' directive}} #pragma acc loop num_workers(1) seq for(unsigned i = 0; i < 5; ++i); - // expected-warning@+1{{OpenACC clause 'device_num' not yet implemented}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'loop' directive}} #pragma acc loop device_num(1) seq for(unsigned i = 0; i < 5; ++i); // expected-warning@+1{{OpenACC clause 'default_async' 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..bf2a2499c3436 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}} @@ -175,8 +170,7 @@ void uses() { // expected-error@+1{{OpenACC 'num_workers' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) num_workers(1) for(int i = 0; i < 5; ++i); - // expected-error@+2{{OpenACC clause 'device_num' may not follow a 'device_type' clause in a 'loop' construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'device_num' clause is not valid on 'loop' directive}} #pragma acc loop device_type(*) device_num(1) for(int i = 0; i < 5; ++i); // expected-error@+2{{OpenACC clause 'default_async' may not follow a 'device_type' clause in a 'loop' construct}} diff --git a/clang/test/SemaOpenACC/shutdown-construct-ast.cpp b/clang/test/SemaOpenACC/shutdown-construct-ast.cpp new file mode 100644 index 0000000000000..3ec1c0d936493 --- /dev/null +++ b/clang/test/SemaOpenACC/shutdown-construct-ast.cpp @@ -0,0 +1,148 @@ +// 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 shutdown + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown +#pragma acc shutdown if (some_int() < some_long()) + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' 'long ()' +#pragma acc shutdown device_num(some_int()) + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: device_num clause + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' +#pragma acc shutdown device_type(T) + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: device_type(T) +#pragma acc shutdown if (some_int() < some_long()) device_type(T) device_num(some_int()) + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '<' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'long' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_long' 'long ()' + // CHECK-NEXT: device_type(T) + // CHECK-NEXT: device_num clause + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr + // CHECK-NEXT: DeclRefExpr{{.*}}'some_int' 'int ()' +} + +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 shutdown + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown +#pragma acc shutdown if (T::value > t) + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '' '>' + // CHECK-NEXT: DependentScopeDeclRefExpr + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T' +#pragma acc shutdown device_num(t) + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: device_num clause + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T' +#pragma acc shutdown device_type(T) + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: device_type(T) +#pragma acc shutdown if (T::value > t) device_type(T) device_num(t) + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} '' '>' + // CHECK-NEXT: DependentScopeDeclRefExpr + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'T' + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T' + // CHECK-NEXT: device_type(T) + // CHECK-NEXT: device_num clause + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'T' + + // Instantiation: + // CHECK-NEXT: FunctionDecl{{.*}} TemplFunc 'void (SomeStruct)' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'SomeStruct' + // CHECK-NEXT: RecordType{{.*}} 'SomeStruct' + // CHECK-NEXT: CXXRecord{{.*}} 'SomeStruct' + // CHECK-NEXT: ParmVarDecl{{.*}} t 'SomeStruct' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const unsigned int' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'SomeStruct' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'unsigned int' + // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct' + + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: device_num clause + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'unsigned int' + // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct' + + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: device_type(T) + + // CHECK-NEXT: OpenACCShutdownConstruct{{.*}}shutdown + // CHECK-NEXT: if clause + // CHECK-NEXT: BinaryOperator{{.*}} 'bool' '>' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: DeclRefExpr{{.*}}'value' 'const unsigned int' + // CHECK-NEXT: NestedNameSpecifier{{.*}} 'SomeStruct' + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'unsigned int' + // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct' + // CHECK-NEXT: device_type(T) + // CHECK-NEXT: device_num clause + // CHECK-NEXT: ImplicitCastExpr{{.*}}'unsigned int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}}'unsigned int' + // CHECK-NEXT: MemberExpr{{.*}} .operator unsigned int + // CHECK-NEXT: DeclRefExpr{{.*}} 't' 'SomeStruct' +} + +struct SomeStruct{ + static constexpr unsigned value = 5; + operator unsigned(); +}; + +void use() { + TemplFunc(SomeStruct{}); +} +#endif diff --git a/clang/test/SemaOpenACC/shutdown-construct.cpp b/clang/test/SemaOpenACC/shutdown-construct.cpp new file mode 100644 index 0000000000000..c3390b0412873 --- /dev/null +++ b/clang/test/SemaOpenACC/shutdown-construct.cpp @@ -0,0 +1,71 @@ +// 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() { +#pragma acc shutdown +#pragma acc shutdown if (getI() < getS()) +#pragma acc shutdown device_num(getI()) +#pragma acc shutdown device_type(SOMETHING) device_num(getI()) +#pragma acc shutdown device_type(SOMETHING) if (getI() < getS()) +#pragma acc shutdown device_type(SOMETHING) device_num(getI()) if (getI() < getS()) + + // expected-error@+1{{value of type 'struct NotConvertible' is not contextually convertible to 'bool'}} +#pragma acc shutdown if (NC) + + // expected-error@+1{{OpenACC clause 'device_num' requires expression of integer type ('struct NotConvertible' invalid)}} +#pragma acc shutdown device_num(NC) + // 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 shutdown device_num(Ambiguous) + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'struct ExplicitConvertOnly' to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} +#pragma acc shutdown device_num(Explicit) +} + +template +void TestInst() { + T t; +#pragma acc shutdown +#pragma acc shutdown if (T::value < T{}) +#pragma acc shutdown device_type(SOMETHING) device_num(getI()) if (getI() < getS()) +#pragma acc shutdown device_type(SOMETHING) device_type(T) device_num(t) if (t < T::value) device_num(getI()) if (getI() < getS()) + + // expected-error@+1{{value of type 'const NotConvertible' is not contextually convertible to 'bool'}} +#pragma acc shutdown if (T::NCValue) + + // expected-error@+1{{OpenACC clause 'device_num' requires expression of integer type ('const NotConvertible' invalid)}} +#pragma acc shutdown device_num(T::NCValue) + // 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 shutdown device_num(T::ACValue) + // expected-error@+2{{OpenACC integer expression requires explicit conversion from 'const ExplicitConvertOnly' to 'int'}} + // expected-note@#EXPL_CONV{{conversion to integral type 'int'}} +#pragma acc shutdown device_num(T::EXValue) +} + +struct HasStuff { + static constexpr AmbiguousConvert ACValue; + static constexpr ExplicitConvertOnly EXValue; + static constexpr NotConvertible NCValue; + static constexpr unsigned value = 5; + operator char(); +}; + +void Inst() { + TestInst(); // expected-note {{in instantiation of function template specialization}} +} 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..2de98762ea600 --- /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 requires explicit conversion from 'struct ExplicitConvertOnly' 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 requires explicit conversion from 'const ExplicitConvertOnly' 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/test/SemaTemplate/pack-deduction.cpp b/clang/test/SemaTemplate/pack-deduction.cpp index 28fb127a38644..b3104609994a4 100644 --- a/clang/test/SemaTemplate/pack-deduction.cpp +++ b/clang/test/SemaTemplate/pack-deduction.cpp @@ -199,3 +199,62 @@ constexpr auto baz(Int(T())>... x) -> int { return 1; } static_assert(baz, Int<2>, Int<3>>(Int<10>(), Int<10>(), Int<10>()) == 1, ""); } + +namespace GH17042 { + +template struct X { + template using Y = X; // #GH17042_Y +}; + +template +using any_pairs_list = X::Y; // #any_pairs_list + +template +using any_pairs_list_2 = X::Y<>; +// expected-error@#GH17042_Y {{different length (2 vs. 0)}} \ +// expected-note@-1 {{requested here}} + +template +using any_pairs_list_3 = X::Y; // #any_pairs_list_3 + +template +using any_pairs_list_4 = X::Y; +// expected-error@#GH17042_Y {{different length (2 vs. at least 3)}} \ +// expected-note@-1 {{requested here}} + +static_assert(__is_same(any_pairs_list, X), ""); + +static_assert(!__is_same(any_pairs_list, X), ""); +// expected-error@#GH17042_Y {{different length (2 vs. 3)}} \ +// expected-note@#any_pairs_list {{requested here}} \ +// expected-note@-1 {{requested here}} + +static_assert(__is_same(any_pairs_list_3, X), ""); + +static_assert(!__is_same(any_pairs_list_3, X), ""); +// expected-error@#GH17042_Y {{different length (2 vs. 3)}} \ +// expected-note@#any_pairs_list_3 {{requested here}} \ +// expected-note@-1 {{requested here}} + +namespace TemplateTemplateParameters { +template struct C {}; + +template class... Args1> struct Ttp { + template